Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .codespellrc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Lint Codespell configurations
[codespell]
skip = .codespellrc,.git,node_modules,build,dist,*.zst,CHANGELOG.md,.playwright,.terraform,*.svg,**/pepr/operator/crd/generated/*.ts,**/uds-docs/**
skip = .codespellrc,.git,node_modules,build,dist,*.zst,CHANGELOG.md,.playwright,.terraform,*.svg,**/pepr/operator/crd/generated/*.ts,**/uds-docs/**,**/package-lock.json
ignore-words-list = NotIn,AKS,LICENS,aks,afterAll
enable-colors =
check-hidden =
1 change: 1 addition & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"jest.*.js",
"test/playwright/",
"test/jest/",
"scripts/",
"uds-docs/"
],
"root": true,
Expand Down
82 changes: 82 additions & 0 deletions .github/actions/renovate-readiness/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Renovate Readiness Action

This GitHub Action automates the process of checking if Renovate PRs are ready for testing.

## Overview

UDS Core uses [Renovate](https://github.com/renovatebot/renovate) to track and automate dependency updates. Due to support for 3 flavors of core (upstream, registry1, and unicorn), most dependency updates are not ready when the PRs are first opened. This action automates the process of checking if a PR is ready for testing.

## How It Works

The action performs the following steps:

1. **Manual Override Check**: If the PR has the `renovate-ready` label, the action will set `should_process` to `false` and skip all other checks, allowing CI to proceed.

2. **Branch Name Processing**: The action extracts the package name from the branch name by removing the `renovate/` prefix.

3. **Special Case Handling**:
- **Pepr Updates**: For Pepr updates, the action compares the version in `package.json` with the image versions in `tasks/create.yaml`. If they don't match, it adds the `waiting on ironbank` label.
- **Support Dependencies**: For support dependency updates, the action adds the `needs-review` label and sets `should_process` to `false` to prevent excessive IAC runs.

4. **Regular Package Updates**:
- The action performs sparse checkouts of the relevant package directory from both the PR branch and the main branch.
- It extracts images and charts from both branches using the `getImagesAndCharts.ts` script.
- It compares the extracted data using the `compareImagesAndCharts.ts` script.
- Based on the comparison, it applies appropriate labels to the PR:
- `waiting on ironbank`: If a registry1 image is behind
- `waiting on cgr`: If a chainguard image is behind
- `helm-chart-only`: If a PR only contains a helm chart update
- `needs-review`: If PR is NOT waiting on image updates
- `major-helm-update`: If the PR contains a major chart version bump
- `major-image-update`: If the PR contains a major image version bump
- If any `waiting on` labels are applied, the action sets `should_process` to `false` to prevent running CI.

## Usage

The action is automatically triggered for all Renovate PRs in the slim-dev-test.yaml workflow. No manual intervention is required.

### Manual Override

If you want to force a PR to run CI regardless of its readiness status, add the `renovate-ready` label to the PR.

## Implementation Details

- **TypeScript Scripts**: The core logic for extracting and comparing images and charts is implemented in TypeScript scripts located in the `scripts/renovate` directory.
- `getImagesAndCharts.ts`: Extracts images and charts from zarf.yaml files in a directory.
- `compareImagesAndCharts.ts`: Compares extracted images and charts between two directories and determines if the PR is ready for testing.
- **GitHub Action**: The GitHub Action orchestrates the process, handling special cases and applying labels based on the script outputs.
- **Workflow Integration**: The action is integrated into the slim-dev-test.yaml workflow, which is triggered for all PRs.
- **Output Variables**:
- `should_process`: Indicates whether the PR should proceed with CI. Set to `false` if the PR has the `renovate-ready` label or if it's waiting on image updates.
- `needs_comparison`: Indicates whether the PR needs to run the comparison scripts. Set to `false` for special cases like Pepr updates.

## Testing

The TypeScript scripts are thoroughly tested using Jest:

- **getImagesAndCharts.test.ts**: Tests the extraction of images and charts from zarf.yaml files, including edge cases like:
- Empty directories
- Invalid YAML files
- Missing components
- Images without version tags

- **compareImagesAndCharts.test.ts**: Tests the comparison of images and charts, including:
- Helm chart updates (both regular and major)
- Image updates (including major updates)
- Waiting conditions for Ironbank and Chainguard images
- Missing or empty extract files
- Invalid version formats

## Troubleshooting

If you encounter issues with the action, check the following:

1. **PR Labels**: Check if the PR has any `waiting on` labels, which indicate what the PR is waiting for.
2. **Action Logs**: Check the action logs for any errors or warnings.
3. **Manual Override**: If needed, add the `renovate-ready` label to force the PR to run CI.
4. **Debug Output**: The action outputs detailed information about its decisions, which can help diagnose issues.

## Related Documentation

- [Renovate PR Process](https://www.notion.so/Renovate-PR-Process-182e512f24fc80479d35f956a7c42388?pvs=21)
- [Renovate Documentation](https://docs.renovatebot.com/)
193 changes: 189 additions & 4 deletions .github/actions/renovate-readiness/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,199 @@
name: renovate-readiness
description: "Check if Renovate PRs are ready for testing"

inputs:
github_token:
description: "GitHub token for API calls"
required: true

runs:
using: composite
steps:
# This is current a stub for future logic that would auto-detect readiness
# In lieu of that, we require an engineer to review changes and manually add the `renovate-ready` label
# Check if PR has the renovate-ready label (manual override)
- name: Check if PR has the ready label
if: ${{ ! contains(github.event.pull_request.labels.*.name, 'renovate-ready') }}
id: check-ready-label
run: |
if [[ "${{ contains(github.event.pull_request.labels.*.name, 'renovate-ready') }}" == "true" ]]; then
echo "PR has the renovate-ready label. Skipping readiness check."
echo "should_process=false" >> $GITHUB_OUTPUT
else
echo "PR does not have the renovate-ready label. Proceeding with readiness check."
echo "should_process=true" >> $GITHUB_OUTPUT
fi
shell: bash

# Process branch name to determine package
- name: Process branch name
id: process-branch
if: steps.check-ready-label.outputs.should_process == 'true'
run: |
BRANCH_NAME="${{ github.head_ref }}"
echo "Branch name: $BRANCH_NAME"

# Remove 'renovate/' prefix if present
if [[ $BRANCH_NAME == renovate/* ]]; then
PACKAGE_NAME=${BRANCH_NAME#renovate/}
echo "Package name after removing prefix: $PACKAGE_NAME"
else
PACKAGE_NAME=$BRANCH_NAME
echo "Branch doesn't have renovate/ prefix, using as is: $PACKAGE_NAME"
fi

# Handle special cases
if [[ "$PACKAGE_NAME" == "pepr" ]]; then
echo "Detected Pepr update"
echo "package=pepr" >> $GITHUB_OUTPUT
echo "is_pepr=true" >> $GITHUB_OUTPUT
echo "needs_comparison=false" >> $GITHUB_OUTPUT
elif [[ "$PACKAGE_NAME" == "support-deps" ]]; then
echo "Detected support dependencies update"
echo "package=support-deps" >> $GITHUB_OUTPUT
echo "is_support_deps=true" >> $GITHUB_OUTPUT
echo "needs_comparison=false" >> $GITHUB_OUTPUT
else
echo "Regular package update: $PACKAGE_NAME"
echo "package=$PACKAGE_NAME" >> $GITHUB_OUTPUT
echo "needs_comparison=true" >> $GITHUB_OUTPUT
fi
Comment thread Fixed
shell: bash
Comment thread
mjnagel marked this conversation as resolved.
Outdated

# Handle Pepr updates
- name: Handle Pepr update
if: steps.check-ready-label.outputs.should_process == 'true' && steps.process-branch.outputs.is_pepr == 'true'
run: |
# Get Pepr version from package.json
PEPR_VERSION=$(jq -r '.dependencies.pepr' package.json)
echo "Pepr version from package.json: $PEPR_VERSION"

# Get image versions from tasks/create.yaml
IRONBANK_IMAGE_VERSION=$(yq e '.tasks[].actions[].args[] | select(. == "registry1.dso.mil/ironbank/opensource/pepr/pepr-*") | split(":")[1]' tasks/create.yaml)
echo "Ironbank image version: $IRONBANK_IMAGE_VERSION"

# Compare versions
if [[ "$PEPR_VERSION" != "$IRONBANK_IMAGE_VERSION" ]]; then
echo "Pepr version mismatch. Waiting on Ironbank image update."
gh pr edit ${{ github.event.pull_request.number }} --add-label "waiting on ironbank"
exit 1
else
echo "Pepr versions match. Ready for review."
gh pr edit ${{ github.event.pull_request.number }} --add-label "needs-review"
fi
shell: bash
env:
GH_TOKEN: ${{ inputs.github_token }}

# Handle support dependencies
- name: Handle support dependencies
if: steps.check-ready-label.outputs.should_process == 'true' && steps.process-branch.outputs.is_support_deps == 'true'
run: |
echo "Support dependencies update detected. Needs manual review."
gh pr edit ${{ github.event.pull_request.number }} --add-label "needs-review"
exit 1
shell: bash
env:
GH_TOKEN: ${{ inputs.github_token }}

# Checkout PR branch (sparse checkout of src/<pkg>)
- name: Checkout PR branch
if: steps.check-ready-label.outputs.should_process == 'true' && steps.process-branch.outputs.needs_comparison == 'true'
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with:
ref: ${{ github.event.pull_request.head.ref }}
path: new
sparse-checkout: |
src/${{ steps.process-branch.outputs.package }}
sparse-checkout-cone-mode: false

# Checkout main branch (sparse checkout of src/<pkg>)
- name: Checkout main branch
if: steps.check-ready-label.outputs.should_process == 'true' && steps.process-branch.outputs.needs_comparison == 'true'
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with:
ref: main
path: old
sparse-checkout: |
src/${{ steps.process-branch.outputs.package }}
sparse-checkout-cone-mode: false

# Install dependencies
- name: Install dependencies
if: steps.check-ready-label.outputs.should_process == 'true' && steps.process-branch.outputs.needs_comparison == 'true'
run: |
cd scripts/renovate
npm install
shell: bash

# Extract images and charts from old branch
- name: Extract images and charts from old branch
if: steps.check-ready-label.outputs.should_process == 'true' && steps.process-branch.outputs.needs_comparison == 'true'
run: |
cd scripts/renovate
npx ts-node getImagesAndCharts.ts $GITHUB_WORKSPACE/old
shell: bash

# Extract images and charts from new branch
- name: Extract images and charts from new branch
if: steps.check-ready-label.outputs.should_process == 'true' && steps.process-branch.outputs.needs_comparison == 'true'
run: |
cd scripts/renovate
npx ts-node getImagesAndCharts.ts $GITHUB_WORKSPACE/new
shell: bash

# Compare images and charts
- name: Compare images and charts
id: compare
if: steps.check-ready-label.outputs.should_process == 'true' && steps.process-branch.outputs.needs_comparison == 'true'
run: |
cd scripts/renovate
OUTPUT=$(npx ts-node compareImagesAndCharts.ts $GITHUB_WORKSPACE/old/extract $GITHUB_WORKSPACE/new/extract)
echo "$OUTPUT"

# Extract labels from output
LABELS=$(echo "$OUTPUT" | grep "LABELS=" | cut -d'=' -f2)
echo "labels=$LABELS" >> $GITHUB_OUTPUT

# Check if waiting on labels are present
if [[ "$LABELS" == *"waiting on ironbank"* ]] || [[ "$LABELS" == *"waiting on cgr"* ]]; then
echo "waiting=true" >> $GITHUB_OUTPUT
else
echo "waiting=false" >> $GITHUB_OUTPUT
fi
shell: bash

# Apply labels
- name: Apply labels
if: steps.check-ready-label.outputs.should_process == 'true' && steps.process-branch.outputs.needs_comparison == 'true'
run: |
LABELS="${{ steps.compare.outputs.labels }}"
if [[ -n "$LABELS" ]]; then
echo "New labels to apply: $LABELS"

# Get current labels on the PR
CURRENT_LABELS=$(gh pr view ${{ github.event.pull_request.number }} --json labels --jq '.labels[].name' | tr '\n' ' ')
echo "Current labels: $CURRENT_LABELS"

# Define the managed labels we care about
MANAGED_LABELS=("waiting on ironbank" "waiting on cgr" "needs-review" "helm-chart-only" "major-helm-update" "major-image-update")

# Remove labels that are currently on the PR but not in the new set
for LABEL in "${MANAGED_LABELS[@]}"; do
if [[ "$CURRENT_LABELS" == *"$LABEL"* ]] && [[ "$LABELS" != *"$LABEL"* ]]; then
echo "Removing outdated label: $LABEL"
gh pr edit ${{ github.event.pull_request.number }} --remove-label "$LABEL" || true
fi
done

# Add the new labels
gh pr edit ${{ github.event.pull_request.number }} --add-label "$LABELS"
fi
shell: bash
env:
GH_TOKEN: ${{ inputs.github_token }}

# Fail if waiting on images
- name: Fail if waiting on images
if: steps.check-ready-label.outputs.should_process == 'true' && steps.compare.outputs.waiting == 'true'
run: |
echo "This PR is not ready to run CI. Failing job."
echo "PR is waiting on image updates. Failing job."
exit 1
shell: bash
7 changes: 5 additions & 2 deletions .github/workflows/checkpoint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ permissions:
on:
pull_request:
# milestoned is added here as a workaround for release-please not triggering PR workflows (PRs should be added to a milestone to trigger the workflow).
# labeled is added here to allow for "manual" triggering of CI on renovate PRs
types: [milestoned, opened, reopened, synchronize, labeled]
# removed labeled trigger to prevent infinite loops when renovate-readiness applies labels
types: [milestoned, opened, reopened, synchronize]
paths:
- packages/checkpoint-dev/**
- .github/workflows/checkpoint**
Expand All @@ -38,13 +38,16 @@ jobs:
contents: read
packages: write
id-token: write # This is needed for OIDC federation.
pull-requests: write # Allows writing to pull requests (needed for renovate-readiness)

steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Check renovate readiness
if: startsWith(github.event.pull_request.head.ref, 'renovate/') # Only call for Renovate PRs
uses: ./.github/actions/renovate-readiness
with:
github_token: ${{ secrets.GITHUB_TOKEN }}

- name: Environment setup
uses: ./.github/actions/setup
Expand Down
10 changes: 8 additions & 2 deletions .github/workflows/docs-shim.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ permissions:
on:
pull_request:
# milestoned is added here as a workaround for release-please not triggering PR workflows (PRs should be added to a milestone to trigger the workflow).
# labeled is added here to allow for "manual" triggering of CI on renovate PRs
types: [milestoned, opened, reopened, synchronize, labeled]
# removed labeled trigger to prevent infinite loops when renovate-readiness applies labels
types: [milestoned, opened, reopened, synchronize]
paths:
- "**.md"
- "**.jpg"
Expand All @@ -31,13 +31,19 @@ on:
jobs:
lint-check:
runs-on: ubuntu-latest
# Job-level permissions override workflow-level permissions
permissions:
contents: read # Allows reading the content of the repository.
pull-requests: write # Allows writing to pull requests (needed for renovate-readiness)
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Check renovate readiness
if: startsWith(github.event.pull_request.head.ref, 'renovate/') # Only call for Renovate PRs
uses: ./.github/actions/renovate-readiness
with:
github_token: ${{ secrets.GITHUB_TOKEN }}

- name: lint-check
uses: ./.github/actions/lint-check
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/pull-request-conditionals.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ name: Filter
on:
pull_request:
# milestoned is added here as a workaround for release-please not triggering PR workflows (PRs should be added to a milestone to trigger the workflow).
# labeled is added here to allow for "manual" triggering of CI on renovate PRs
types: [milestoned, opened, reopened, synchronize, labeled]
# removed labeled trigger to prevent infinite loops when renovate-readiness applies labels
types: [milestoned, opened, reopened, synchronize]
paths-ignore:
- "**.md"
- "**.jpg"
Expand Down Expand Up @@ -66,6 +66,8 @@ jobs:
- name: Check renovate readiness
if: startsWith(github.event.pull_request.head.ref, 'renovate/') # Only call for Renovate PRs
uses: ./.github/actions/renovate-readiness
with:
github_token: ${{ secrets.GITHUB_TOKEN }}

# Uses a custom action to filter paths for source packages.
- name: Check src paths
Expand Down
Loading