Renovate #42
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Renovate | |
| on: | |
| schedule: | |
| - cron: "37 2 * * 1-5" # Every Monday to Friday at 02:37 UTC | |
| workflow_dispatch: # Manual runs from the Actions tab | |
| inputs: | |
| dry_run: | |
| description: "Dry run (log only, create no branches/PRs)" | |
| type: boolean | |
| default: false | |
| log_level: | |
| description: "Renovate log level" | |
| type: choice | |
| options: [info, debug] | |
| default: info | |
| base_branch: | |
| description: "Base branch to scan + target PRs against (blank = default branch). Set a feature branch to test config/hook changes that only live on that branch." | |
| type: string | |
| default: "" | |
| add_unique_branch_prefix: | |
| description: "Add a unique section to every Renovate branch name (renovate/<dep> -> renovate/<unique>/<dep>). Useful for testing, so each run creates new branches instead of skipping existing ones." | |
| type: boolean | |
| default: false | |
| pr_hourly_limit: | |
| description: "Maximum Renovate PRs per hour. Positive values only, no 0, Renovate default = 2. Increase if you need more for testing!" | |
| type: number | |
| default: 10 | |
| recreate_when: | |
| description: "Re-raise update closed/merged PRs?. 'always' = propose again every run even after revert (repeat testing). 'auto' (Renovate default) = only when the update changed. 'never' = fully respect closed PRs." | |
| type: choice | |
| options: [auto, always, never] | |
| default: auto | |
| # Empty block required. | |
| # When using GITHUB_TOKEN instead of App, scope permission here! | |
| # Restrictions apply on possible permission here. | |
| permissions: {} | |
| jobs: | |
| renovate: | |
| runs-on: ubuntu-latest | |
| environment: renovate-vidispine-content-wf | |
| steps: | |
| # IMPORTANT: Keep version comments after action digests here, required by Renovate! | |
| # | |
| # Using GitHub App instead of GITHUB_TOKEN, to get all necessary permissions. | |
| # The GitHub App must be installed in GitHub, and | |
| # the secret AppID and private key must be in the environment. | |
| - name: Generate GitHub App token | |
| id: app-token | |
| uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 | |
| with: | |
| client-id: ${{ secrets.APP_ID }} | |
| private-key: ${{ secrets.APP_PRIVATE_KEY }} | |
| # Least privilege: only permissions requested here, must be set for GitHub app. | |
| # HTTP 422 error, if the app doesn't hold the requested permission. | |
| permission-contents: write # push renovate/* branches + commits | |
| permission-pull-requests: write # open/update/close update PRs | |
| permission-issues: write # maintain the Dependency Dashboard issue | |
| # NOTE: "Checks: write" in the GitHub app, and 'permission-checks: write' here, may | |
| # be necessary if automerge is enabled in the future. | |
| permission-statuses: write # write Renovate's own renovate/* commit statuses | |
| permission-workflows: write # REQUIRED to commit changes to .github/workflows/* | |
| # (the github-actions manager bumps action versions). | |
| # This does NOT affect whether CI is triggered. | |
| permission-administration: read # read branch protection / required checks | |
| permission-vulnerability-alerts: read # "Dependabot alerts" - drives vulnerabilityAlerts | |
| permission-metadata: read # implicit on every installation; listed for clarity | |
| - name: Run Renovate | |
| id: renovate | |
| uses: renovatebot/github-action@39b914146caeff8cd512e61c8992f1d5913af85c # v46.2.5 | |
| with: | |
| token: ${{ steps.app-token.outputs.token }} | |
| env: | |
| # Only look at this repository. | |
| RENOVATE_REPOSITORIES: ${{ github.repository }} | |
| RENOVATE_PR_HOURLY_LIMIT: ${{ inputs.pr_hourly_limit || 10 }} | |
| # Allowlist for postUpgradeTasks commands (self-hosted requirement). Only commands | |
| # matching one of these regexes may run. Keeps the checksum-refresh hook (see | |
| # renovate.json -> postUpgradeTasks) in sync with each version bump. | |
| RENOVATE_ALLOWED_COMMANDS: '["^bash \.github/renovate/update-checksum\.sh "]' | |
| # Manual-run options (empty/ignored on scheduled runs). | |
| RENOVATE_DRY_RUN: ${{ inputs.dry_run && 'full' || '' }} | |
| LOG_LEVEL: ${{ inputs.log_level || 'info' }} | |
| RENOVATE_REPORT_TYPE: 'file' | |
| RENOVATE_REPORT_PATH: '/tmp/renovate-report.json' | |
| # config breakage -> hard exit. | |
| RENOVATE_CONFIG_VALIDATION_ERROR: 'true' | |
| # Which branch Renovate reads its config from AND targets update PRs against. The | |
| # workflow_dispatch "Use workflow from" selector only picks which YAML runs - it does | |
| # NOT change this. Blank -> repo default branch (normal operation); set a feature | |
| # branch to test config/hook changes that only exist on that branch. | |
| RENOVATE_BASE_BRANCHES: ${{ inputs.base_branch != '' && format('["{0}"]', inputs.base_branch) || format('["{0}"]', github.event.repository.default_branch) }} | |
| # Only set a branch prefix with timestamp 'renovate-yyyyymmddhhmmss' if the input is true. Otherwise, leave it blank to use Renovate's default 'renovate/<dep>'. | |
| RENOVATE_BRANCH_PREFIX: ${{ inputs.add_unique_branch_prefix && format('renovate/{0}/', github.run_id) || 'renovate/' }} | |
| # Defeat Renovate's memory of CLOSED/MERGED PRs. Renovate does NOT read git history - | |
| # it compares the current file contents on the base branch to the datasource - but it | |
| # WILL refuse to re-raise an update whose PR you previously closed. recreateWhen=auto | |
| # (the default) only recreates when the update content changed; 'always' re-proposes | |
| # every run, so a reverted version comes back and repeat testing works; 'never' fully | |
| # respects closed PRs. Scheduled runs get the default 'auto'. | |
| RENOVATE_RECREATE_WHEN: ${{ inputs.recreate_when || 'auto' }} | |
| # Namespace every Renovate branch AND PR by its target (base) branch, always - | |
| # for the default branch too, not just test branches. This keeps each base | |
| # branch's updates fully separate so they can't cross-contaminate: | |
| # * ADDITIONAL_BRANCH_PREFIX folds the base branch into the head-branch name | |
| # (renovate/master-<dep> vs renovate/<test-branch>-<dep>). Renovate detects | |
| # "already handled" updates by head-branch name, so a run targeting one base | |
| # branch never sees - and is never skipped/blocked by - another branch's PRs. | |
| # Testing against a feature branch therefore leaves the master namespace | |
| # untouched; delete the test branch + its renovate/<test-branch>-* branches | |
| # to clean up afterwards. | |
| # * COMMIT_MESSAGE_SUFFIX tags the PR title with the base branch (e.g. "[master]") | |
| # so PRs are also distinguishable by name, on top of the branch separation. | |
| # NOTE: enabling this renames master's head branches from renovate/<dep> to | |
| # renovate/master-<dep>; on the first run any pre-existing renovate/<dep> PRs are | |
| # recreated once under the new names. | |
| RENOVATE_ADDITIONAL_BRANCH_PREFIX: ${{ inputs.base_branch != '' && format('{0}-', inputs.base_branch) || format('{0}-', github.event.repository.default_branch) }} | |
| RENOVATE_COMMIT_MESSAGE_SUFFIX: ${{ inputs.base_branch != '' && format('[{0}]', inputs.base_branch) || format('[{0}]', github.event.repository.default_branch) }} | |
| # Credentials for cr.vidinet.net. A single host rule (no hostType) covers | |
| # both Docker images and Helm charts pulled from this registry. | |
| RENOVATE_HOST_RULES: >- | |
| [{"matchHost":"cr.vidinet.net","username":"${{ secrets.VIDINET_REGISTRY_USERNAME }}","password":"${{ secrets.VIDINET_REGISTRY_PASSWORD }}"}] | |
| # Keep the JSON report as a downloadable run artifact (like an Azure DevOps pipeline | |
| # artifact) so it can be inspected after the run. Uploaded before the check step and | |
| # with if: always() so it survives even when the check below fails or Renovate errored. | |
| # if-no-files-found: ignore -> no failure when Renovate crashed before writing a report. | |
| - name: Upload Renovate report | |
| if: always() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: renovate-report | |
| path: /tmp/renovate-report.json | |
| if-no-files-found: ignore | |
| retention-days: 30 | |
| # Renovate almost always exits 0, even when parts of a run silently fail (a failed | |
| # postUpgradeTask/artifact update, a branch it couldn't push). This step reads the | |
| # structured JSON report (RENOVATE_REPORT_TYPE=file above) and turns real problems | |
| # into a red job. GitHub has no "warning"/partially-succeeded status like Azure DevOps: | |
| # a run is only green or red, so soft issues are emitted as yellow ::warning:: | |
| # annotations (run stays green) and only the three hard signals below fail the job. | |
| - name: Check Renovate report | |
| if: always() | |
| env: | |
| REPORT: /tmp/renovate-report.json | |
| # Branch results that mean Renovate could not do its job. 'error' is the real | |
| # failure result; add '*-limit-reached' here only if you want throttling to be red. | |
| FAILURE_RESULTS: '["error"]' | |
| run: | | |
| set -uo pipefail # not -e: collect all issues first, then decide | |
| repo="$GITHUB_REPOSITORY" | |
| issues=0 | |
| # 1) Renovate process itself failed. The action step already goes red on a | |
| # non-zero exit; surface it explicitly so this step is one source of truth. | |
| if [ "${{ steps.renovate.outcome }}" = "failure" ]; then | |
| echo "::error::Renovate exited non-zero for ${repo}." | |
| issues=$((issues+1)) | |
| fi | |
| if [ ! -f "$REPORT" ]; then | |
| echo "::error::No report at ${REPORT} - Renovate crashed before reporting." | |
| exit 1 | |
| fi | |
| # 2) PR-creation / branch failures: branches whose result is in FAILURE_RESULTS. | |
| failed=$(jq -r --arg repo "$repo" --argjson fails "$FAILURE_RESULTS" ' | |
| (.repositories[$repo].branches // []) | |
| | map(select(.result as $r | $fails | index($r))) | |
| | .[] | "\(.branchName // .prTitle // "?") -> \(.result)" | |
| ' "$REPORT") | |
| if [ -n "$failed" ]; then | |
| echo "::error::Renovate could not create/update branch(es) for ${repo}:" | |
| echo "$failed" | while IFS= read -r line; do echo "::error:: $line"; done | |
| issues=$((issues+1)) | |
| fi | |
| # 3) Artifact / postUpgradeTask failures (e.g. update-checksum.sh), read | |
| # structurally from the report instead of log-scraping - no regex false positives. | |
| artifacts=$(jq --arg repo "$repo" ' | |
| [ (.repositories[$repo] // {}) | .. | objects | |
| | select(has("artifactErrors")) | .artifactErrors[] ] | length | |
| ' "$REPORT") | |
| if [ "$artifacts" -gt 0 ]; then | |
| echo "::error::${artifacts} artifact/postUpgradeTask error(s) for ${repo} (e.g. update-checksum.sh)." | |
| issues=$((issues+1)) | |
| fi | |
| # 4) Everything else worth seeing but not failing -> yellow annotations (stays green). | |
| jq -r --arg repo "$repo" ' | |
| def lvl: if type=="number" then . else ({"warn":40,"error":50,"fatal":60}[.] // 0) end; | |
| [ (.problems // [])[], ((.repositories[$repo] // {}).problems // [])[] ] | |
| | .[] | select((.level|lvl) == 40) | "::warning::" + (.msg // "warning") | |
| ' "$REPORT" | tee -a "$GITHUB_STEP_SUMMARY" | |
| [ "$issues" -eq 0 ] || exit 1 |