name: Build on: push: branches: - main - next - maint/** pull_request: types: - opened - synchronize - reopened - ready_for_review merge_group: workflow_dispatch: inputs: dryRun: description: 'Dry-Run' default: 'true' required: false permissions: contents: read concurrency: group: ${{ github.workflow }}-${{ github.event.number || github.ref }} cancel-in-progress: ${{ github.event_name == 'pull_request' || github.event_name == 'merge_group' }} env: # are we on a release branch? DO_RELEASE: ${{ github.ref_name == github.event.repository.default_branch || github.ref_name == 'next' || startsWith(github.ref_name, 'maint/')}} NODE_VERSION: 24 DRY_RUN: true SPARSE_CHECKOUT: |- .github/actions/ data/ patches/ tools/ package.json pnpm-workspace.yaml pnpm-lock.yaml jobs: setup: runs-on: ubuntu-latest outputs: os-matrix: ${{ steps.os-matrix.outputs.os-matrix }} os-matrix-is-full: ${{ steps.os-matrix-is-full.outputs.os-matrix-is-full }} os-matrix-prefetch: ${{ steps.os-matrix-prefetch.outputs.matrix }} test-shard-matrix: ${{ steps.schedule-test-shards.outputs.test-shard-matrix }} test-matrix-empty: ${{ steps.schedule-test-shards.outputs.test-matrix-empty }} steps: - name: Calculate `os-matrix-is-full` output id: os-matrix-is-full env: IS_FULL: >- ${{ ( github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'ci:fulltest') ) && 'true' || '' }} run: | echo 'OS_MATRIX_IS_FULL=${{ env.IS_FULL }}' >> "$GITHUB_ENV" echo 'os-matrix-is-full=${{ env.IS_FULL }}' >> "$GITHUB_OUTPUT" - name: Calculate `os-matrix` output id: os-matrix env: OS_ALL: '["ubuntu-latest", "macos-latest", "windows-latest"]' OS_LINUX_ONLY: '["ubuntu-latest"]' run: | echo 'os-matrix=${{ env.OS_MATRIX_IS_FULL && env.OS_ALL || env.OS_LINUX_ONLY }}' >> "$GITHUB_OUTPUT" - name: Detect changed files if: ${{ github.event_name == 'pull_request' }} id: changed-files env: GH_TOKEN: ${{ github.token }} GH_REPO: ${{ github.event.repository.full_name }} PR_URL: >- https://api.github.com/repos/{owner}/{repo}/compare/${{ github.event.pull_request.base.sha }}...${{ github.event.pull_request.head.sha }} JQ_FILTER: >- "changed-files=" + ([.files[].filename] | tostring) run: gh api ${{ env.PR_URL }} | jq -rc '${{ env.JQ_FILTER }}' >> "$GITHUB_OUTPUT" - name: Checkout code uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false filter: blob:none # we don't need all blobs sparse-checkout: ${{ env.SPARSE_CHECKOUT }} show-progress: false - name: Calculate matrix for `node_modules` prefetch uses: ./.github/actions/calculate-prefetch-matrix id: os-matrix-prefetch with: repo: ${{ github.event.repository.full_name }} token: ${{ github.token }} node-version: ${{ env.NODE_VERSION }} - name: Prefetch test modules for `ubuntu-latest` id: setup-node uses: ./.github/actions/setup-node with: node-version: ${{ env.NODE_VERSION }} os: ${{ runner.os }} save-cache: true - name: Schedule test shards id: schedule-test-shards env: ALL_PLATFORMS: ${{ env.OS_MATRIX_IS_FULL }} FILTER_SHARDS: ${{ github.event.pull_request.draft && 'true' || '' }} CHANGED_FILES: ${{ steps.changed-files.outputs.changed-files }} run: | pnpm -s --config.verify-deps-before-run=false schedule-test-shards >> "$GITHUB_OUTPUT" setup-build: runs-on: ubuntu-latest outputs: node-version: ${{ steps.setup-outputs.outputs.node-version }} steps: - name: Checkout code uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false filter: blob:none # we don't need all blobs sparse-checkout: ${{ env.SPARSE_CHECKOUT }} show-progress: false - name: Setup outputs id: setup-outputs run: | echo "node-version=${{ env.NODE_VERSION }}" >> "$GITHUB_OUTPUT" - name: Prefetch build modules for `ubuntu-latest` uses: ./.github/actions/setup-node with: node-version: ${{ env.NODE_VERSION }} os: ${{ runner.os }} save-cache: true prefetch: needs: [setup] # We can't check `needs.setup.outputs.os-matrix-is-full` here, # as it will lead to further complications that aren't solvable # with current GitHub Actions feature set. # # Although this job sometimes may act as short-lived `no-op`, # it's actually the best option available. # # However, in draft mode we can skip this step. if: | !(github.event.pull_request.draft == true && needs.setup.outputs.test-matrix-empty == 'true') strategy: matrix: os: ${{ fromJSON(needs.setup.outputs.os-matrix-prefetch) }} runs-on: ${{ matrix.os }} timeout-minutes: 10 steps: - name: Checkout code if: needs.setup.outputs.os-matrix-is-full && runner.os != 'Linux' uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false filter: blob:none # we don't need all blobs sparse-checkout: ${{ env.SPARSE_CHECKOUT }} show-progress: false - name: Setup Node.js if: needs.setup.outputs.os-matrix-is-full && runner.os != 'Linux' uses: ./.github/actions/setup-node with: node-version: ${{ env.NODE_VERSION }} os: ${{ runner.os }} save-cache: true lint-oxlint: needs: - setup-build runs-on: ubuntu-latest timeout-minutes: 15 steps: - name: Checkout code uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false show-progress: false - name: Setup Node.js uses: ./.github/actions/setup-node with: node-version: ${{ needs.setup-build.outputs.node-version }} os: ${{ runner.os }} - name: Lint with oxlint run: pnpm oxlint -f github - name: Lint with biome run: pnpm biome-ci lint-prettier: needs: - setup-build runs-on: ubuntu-latest timeout-minutes: 7 steps: - name: Checkout code uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false show-progress: false - name: Setup Node.js uses: ./.github/actions/setup-node with: node-version: ${{ needs.setup-build.outputs.node-version }} os: ${{ runner.os }} - name: Restore prettier cache uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: .cache/prettier # we need to add the hash because prettier cache doesn't detect plugin changes key: prettier-cache-${{ hashFiles('pnpm-lock.yaml', 'package.json') }} restore-keys: prettier-cache-${{ hashFiles('pnpm-lock.yaml', 'package.json') }}- - name: Lint run: | pnpm prettier-fix --cache-location .cache/prettier git diff --quiet || { echo "[ERROR] Please apply the changes prettier suggests:" git diff --color=always exit 1 } - name: Save prettier cache if: github.event_name == 'push' uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: .cache/prettier key: prettier-cache-${{ hashFiles('pnpm-lock.yaml', 'package.json') }}-${{ github.run_id }}-${{ github.run_attempt }} lint-docs: needs: - setup-build runs-on: ubuntu-latest timeout-minutes: 7 steps: - name: Checkout code uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false show-progress: false - name: Setup Node.js uses: ./.github/actions/setup-node with: node-version: ${{ needs.setup-build.outputs.node-version }} os: ${{ runner.os }} - name: Lint markdown run: pnpm markdown-lint - name: Generate JSON schema run: pnpm create-json-schema - name: Lint fenced code blocks run: pnpm doc-fence-check - name: Lint documentation run: pnpm lint-documentation lint-other: needs: - setup-build runs-on: ubuntu-latest timeout-minutes: 7 steps: - name: Checkout code uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false show-progress: false - name: Setup Node.js uses: ./.github/actions/setup-node with: node-version: ${{ needs.setup-build.outputs.node-version }} os: ${{ runner.os }} - name: Restore tsbuildinfo cache uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: .cache/tsbuildinfo key: tsbuildinfo-${{ hashFiles('pnpm-lock.yaml') }} restore-keys: | tsbuildinfo-${{ hashFiles('pnpm-lock.yaml') }}- tsbuildinfo- - name: Type check run: pnpm type-check - name: Save tsbuildinfo cache if: github.event_name == 'push' uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: .cache/tsbuildinfo key: tsbuildinfo-${{ hashFiles('pnpm-lock.yaml') }}-${{ github.run_id }}-${{ github.run_attempt }} - name: Lint project file structure run: pnpm ls-lint - name: Check git version run: pnpm git-check - name: Test schema run: pnpm test-schema - name: Lint other run: pnpm lint-other lint-actions: runs-on: ubuntu-latest timeout-minutes: 7 permissions: security-events: write steps: - name: Checkout code uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false show-progress: false # include local composite actions, so that actionlint validates # their metadata, and zizmor audits them sparse-checkout: .github/ - name: Check workflow files uses: docker://rhysd/actionlint:1.7.12@sha256:b1934ee5f1c509618f2508e6eb47ee0d3520686341fec936f3b79331f9315667 with: args: -color -ignore "invalid activity type \"destroyed\" for \"merge_group\" Webhook event. available types are \"checks_requested\"" - name: Run zizmor uses: zizmorcore/zizmor-action@cc914d7f3750a2d13d75c7f184a1060aa0e9d482 # v0.6.4 with: version: 1.30.1 test: needs: [setup, prefetch] if: | !(github.event.pull_request.draft == true && needs.setup.outputs.test-matrix-empty == 'true') name: ${{ matrix.name }} runs-on: ${{ matrix.os }} timeout-minutes: ${{ matrix.runner-timeout-minutes }} permissions: id-token: write # required for codecov OIDC strategy: fail-fast: false matrix: include: ${{ fromJSON(needs.setup.outputs.test-shard-matrix) }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false show-progress: false - name: Setup Node.js uses: ./.github/actions/setup-node with: node-version: ${{ env.NODE_VERSION }} os: ${{ runner.os }} - name: Cache vitest uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: .cache/vitest # the shard cache key comes before the lockfile hash so that # `restore-keys` can fall back to the same shard's cache after # a lockfile change key: | vitest-cache-${{ runner.os }}-${{ env.NODE_VERSION }}-${{ matrix.cache-key }}-${{ hashFiles('pnpm-lock.yaml') }} restore-keys: | vitest-cache-${{ runner.os }}-${{ env.NODE_VERSION }}-${{ matrix.cache-key }}- - name: Unit tests shell: bash run: | for shard in ${{ matrix.shards }}; do TEST_SHARD="$shard" pnpm vitest \ --test-timeout ${{ matrix.test-timeout-milliseconds }} \ --coverage ${{ matrix.coverage }} done - name: Codecov Test if: github.event_name != 'merge_group' && !cancelled() uses: codecov/codecov-action@0b35c9ecc4f0529d0eb674914510c22f85b196b4 # v7.1.0 with: use_oidc: true report_type: test_results directory: ./coverage/shard # TODO: compute proper flags per job # flags: ${{ matrix.name }} verbose: true - name: Move coverage files if: success() && github.event.pull_request.draft != true && matrix.coverage run: | mkdir -p ./coverage/lcov mkdir -p ./coverage/json for shard in ${{ matrix.shards }}; do mv ./coverage/shard/$shard/lcov.info ./coverage/lcov/$shard.lcov mv ./coverage/shard/$shard/coverage-final.json ./coverage/json/$shard.json done - name: Save coverage artifacts if: success() && github.event.pull_request.draft != true && matrix.coverage uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: ${{ matrix.upload-artifact-name }} path: | ./coverage/lcov ./coverage/json codecov: needs: [test] runs-on: ubuntu-latest timeout-minutes: 3 if: success() && github.event_name != 'merge_group' && github.event.pull_request.draft != true permissions: id-token: write # required for codecov OIDC steps: - name: Checkout code uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false filter: blob:none # we don't need all blobs show-progress: false - name: Download coverage reports uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: pattern: coverage-* path: coverage merge-multiple: true - name: Codecov Coverage if: github.event_name != 'merge_group' uses: codecov/codecov-action@0b35c9ecc4f0529d0eb674914510c22f85b196b4 # v7.1.0 with: use_oidc: true directory: coverage/lcov fail_ci_if_error: ${{ github.event_name != 'pull_request' }} verbose: true coverage-threshold: needs: - test - setup-build runs-on: ubuntu-latest timeout-minutes: 3 if: success() && github.event.pull_request.draft != true steps: - name: Checkout code uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false filter: blob:none # we don't need all blobs sparse-checkout: ${{ env.SPARSE_CHECKOUT }} show-progress: false - name: Setup Node.js uses: ./.github/actions/setup-node with: node-version: ${{ needs.setup-build.outputs.node-version }} os: ${{ runner.os }} - name: Download coverage reports uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: pattern: coverage-* path: coverage merge-multiple: true - name: Merge coverage reports run: pnpm nyc merge ./coverage/json ./coverage/nyc/coverage.json - name: Report coverage run: pnpm nyc report -t ./coverage/nyc --skip-full -r text -r text-summary - name: Check coverage threshold run: | pnpm nyc check-coverage -t ./coverage/nyc \ --statements 100 \ --branches 99.14 \ --functions 100 \ --lines 100 \ # Catch-all required check for test matrix and coverage test-success: needs: - setup - test - codecov - coverage-threshold - lint-actions - lint-docs - lint-other - lint-oxlint - lint-prettier - build-docker - build-docs runs-on: ubuntu-latest timeout-minutes: 1 if: always() steps: - name: Fail for failed or cancelled tests if: | needs.test.result == 'failure' || needs.test.result == 'cancelled' run: exit 1 - name: Fail for skipped tests when PR is ready for review if: | github.event_name == 'pull_request' && github.event.pull_request.draft != true && needs.test.result == 'skipped' run: exit 1 - name: Fail for failed or cancelled codecov if: | needs.codecov.result == 'failure' || needs.codecov.result == 'cancelled' run: exit 1 - name: Fail for skipped codecov when PR is ready for review if: | github.event_name == 'pull_request' && github.event.pull_request.draft != true && needs.codecov.result == 'skipped' run: exit 1 - name: Fail for failed or cancelled coverage-threshold if: | needs.coverage-threshold.result == 'failure' || needs.coverage-threshold.result == 'cancelled' run: exit 1 - name: Fail for skipped coverage-threshold when PR is ready for review if: | github.event_name == 'pull_request' && github.event.pull_request.draft != true && needs.coverage-threshold.result == 'skipped' run: exit 1 - name: Fail for failed or cancelled Actions linting if: | needs.lint-actions.result == 'failure' || needs.lint-actions.result == 'cancelled' run: exit 1 - name: Fail for skipped Actions linting when PR is ready for review if: | github.event_name == 'pull_request' && github.event.pull_request.draft != true && needs.lint-actions.result == 'skipped' run: exit 1 - name: Fail for failed or cancelled linting if: | needs.lint-docs.result == 'failure' || needs.lint-docs.result == 'cancelled' || needs.lint-other.result == 'failure' || needs.lint-other.result == 'cancelled' || needs.lint-oxlint.result == 'failure' || needs.lint-oxlint.result == 'cancelled' || needs.lint-prettier.result == 'failure' || needs.lint-prettier.result == 'cancelled' run: exit 1 - name: Fail for skipped linting when PR is ready for review if: | github.event_name == 'pull_request' && github.event.pull_request.draft != true && ( needs.lint-docs.result == 'skipped' || needs.lint-other.result == 'skipped' || needs.lint-oxlint.result == 'skipped' || needs.lint-prettier.result == 'skipped' ) run: exit 1 - name: Fail for failed or cancelled docs build if: | needs.build-docs.result == 'failure' || needs.build-docs.result == 'cancelled' run: exit 1 - name: Fail for skipped docs build when PR is ready for review if: | github.event_name == 'pull_request' && github.event.pull_request.draft != true && needs.build-docs.result == 'skipped' run: exit 1 - name: Fail for skipped or failed docker build when needed if: | ( github.event_name != 'pull_request' || (github.event.pull_request.draft != true && contains(github.event.pull_request.labels.*.name, 'ci:fulltest')) ) && (needs.build-docker.result == 'skipped' || needs.build-docker.result == 'failure') run: exit 1 build: needs: - setup-build runs-on: ubuntu-latest timeout-minutes: 15 if: github.event.pull_request.draft != true steps: - name: Checkout code uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false show-progress: false - name: Setup Node.js uses: ./.github/actions/setup-node with: node-version: ${{ needs.setup-build.outputs.node-version }} os: ${{ runner.os }} - name: Build run: pnpm build - name: Upload dist uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: renovate-dist path: dist/ build-docker: needs: - setup-build # we need the outputs - build runs-on: ubuntu-latest timeout-minutes: 15 if: github.event_name != 'pull_request' || (github.event.pull_request.draft != true && contains(github.event.pull_request.labels.*.name, 'ci:fulltest')) steps: - name: Checkout code uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false show-progress: false - name: Setup Docker uses: ./.github/actions/setup-docker - name: Download dist uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: renovate-dist path: dist/ - name: Setup Node.js uses: ./.github/actions/setup-node with: node-version: ${{ needs.setup-build.outputs.node-version }} os: ${{ runner.os }} - name: Build docker run: pnpm build:docker build --platform linux/amd64,linux/arm64 --tries=3 --args '--load' env: LOG_LEVEL: debug - name: Test docker run: docker run -e LOG_LEVEL=debug --rm renovate/renovate --version - name: dry-run if: github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && env.DO_RELEASE != 'true') run: docker run -e LOG_LEVEL=debug -e RENOVATE_TOKEN --rm renovate/renovate --dry-run=lookup ${{ github.repository }} env: RENOVATE_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: df -h if: ${{ !cancelled() }} build-docs: needs: - setup-build runs-on: ubuntu-latest timeout-minutes: 5 if: github.event.pull_request.draft != true steps: - name: Checkout code uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false show-progress: false - name: Setup Node.js uses: ./.github/actions/setup-node with: node-version: ${{ needs.setup-build.outputs.node-version }} os: ${{ runner.os }} - name: Setup uv uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0 with: version: 0.12.14 enable-cache: true cache-python: true - name: Install uv dependencies run: uv sync --locked - name: Build run: pnpm build:docs env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SKIP_GITHUB_ISSUES: ${{ (github.event_name == 'pull_request' || github.event_name == 'merge_group' || github.event.repository.has_issues == false) && 'true' || '' }} - name: Test docs run: pnpm test:docs - name: Upload uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: docs path: tmp/docs/ - name: Build mkdocs run: pnpm mkdocs build --no-build test-e2e: needs: - setup-build - build runs-on: 'ubuntu-latest' timeout-minutes: 7 if: github.event.pull_request.draft != true steps: - name: Checkout code uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false show-progress: false - name: Setup Node.js uses: ./.github/actions/setup-node with: node-version: ${{ needs.setup-build.outputs.node-version }} os: ${{ runner.os }} - name: Download dist uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: renovate-dist path: dist/ - name: Pack run: pnpm test-e2e:pack - name: Install dependencies run: pnpm test-e2e:install - name: E2E Test run: pnpm test-e2e:run release: needs: - setup-build - build-docker - lint-oxlint - lint-prettier - lint-docs - lint-other - test-e2e - test-success - build-docs - codecov - coverage-threshold if: github.repository == 'renovatebot/renovate' && github.event_name != 'pull_request' runs-on: ubuntu-latest timeout-minutes: 60 concurrency: group: ${{ github.workflow }}-release-${{ github.ref }} # never cancel a release that has already started, as it may have started pushing artifacts cancel-in-progress: false permissions: actions: write contents: write issues: write pull-requests: write id-token: write packages: write steps: # right at the start of the job, make sure we're not seeing another commit that's landed - name: Check for newer commits env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: renovatebot/renovate REF_NAME: ${{ github.ref_name }} EXPECTED_SHA: ${{ github.sha }} RUN_ID: ${{ github.run_id }} run: | latest_sha=$(git ls-remote https://github.com/renovatebot/renovate "refs/heads/$REF_NAME" | cut -f1) if [[ "$latest_sha" != "$EXPECTED_SHA" ]]; then echo "Newer commit detected on $REF_NAME ($latest_sha), cancelling release run" gh run cancel "$RUN_ID" sleep 5 fi - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false fetch-depth: 0 # zero stands for full checkout, which is required for semantic-release filter: blob:none # we don't need all blobs, only the full tree show-progress: false - name: Setup Docker uses: ./.github/actions/setup-docker - name: Setup Node.js uses: ./.github/actions/setup-node with: node-version: ${{ needs.setup-build.outputs.node-version }} os: ${{ runner.os }} # ensure that the release job installs fresh, with installed pacakges verified against the lockfile's integrity hashes use-cache: false - name: Install newer npm if needed run: 'dpkg --compare-versions "$(npm -v)" lt 11.5.1 && (npm update -g npm; echo "updated npm to: $(npm -v)") || echo "npm is new enough: $(npm -v)"' - uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2 - name: Docker registry login env: DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} REPOSITORY_OWNER: ${{ github.repository_owner }} run: | echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin echo "$GITHUB_TOKEN" | docker login ghcr.io -u "$REPOSITORY_OWNER" --password-stdin - name: Setup uv uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0 with: version: 0.12.14 # ensure that the release job installs fresh, with installed pacakges verified against the lockfile's integrity hashes enable-cache: false cache-python: true - name: Install uv dependencies run: uv sync --locked - name: Check dry run env: EVENT_NAME: ${{ github.event_name }} INPUT_DRY_RUN: ${{ github.event.inputs.dryRun }} run: | if [[ "$EVENT_NAME" == "workflow_dispatch" && "$INPUT_DRY_RUN" != "true" ]]; then echo "DRY_RUN=false" >> "$GITHUB_ENV" elif [[ "$DO_RELEASE" == "true" ]]; then echo "DRY_RUN=false" >> "$GITHUB_ENV" fi # and one final check, in case preparing the environment has taken long enough for new commits - name: Check for newer commits env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} REF_NAME: ${{ github.ref_name }} EXPECTED_SHA: ${{ github.sha }} RUN_ID: ${{ github.run_id }} run: | latest_sha=$(git ls-remote https://github.com/renovatebot/renovate "refs/heads/$REF_NAME" | cut -f1) if [[ "$latest_sha" != "$EXPECTED_SHA" ]]; then echo "Newer commit detected on $REF_NAME ($latest_sha), cancelling release run" gh run cancel "$RUN_ID" sleep 5 fi - name: semantic-release run: | pnpm semantic-release --dry-run "$DRY_RUN" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} LOG_LEVEL: debug - name: Build mkdocs site for deployment if: github.ref_name == 'main' run: | # Always rebuild the docs site with the announcement bar for deployment to GitHub Pages, including the announcement bar (which isn't included when preparing a release's docs) latest_tag=$(gh release view --json tagName -q .tagName) pnpm mkdocs build --version "$latest_tag" mkdir -p tmp tar -czf tmp/mkdocs-site.tgz -C tools/mkdocs/site . env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} MKDOCS_INCLUDE_ANNOUNCEMENT: 'true' - name: Upload docs artifact for deployment if: github.ref_name == 'main' uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: mkdocs-site path: tmp/mkdocs-site.tgz retention-days: 1 - run: df -h if: ${{ !cancelled() }} deploy-docs-site: if: ${{ github.repository == 'renovatebot/renovate' && github.ref_name == 'main' && github.event_name == 'push' }} needs: - setup-build - release permissions: pages: write id-token: write environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest steps: - name: Download mkdocs site from release uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: mkdocs-site path: tmp - name: Extract docs site run: | mkdir -p tools/mkdocs/site tar -xzf tmp/mkdocs-site.tgz -C tools/mkdocs/site # Per https://github.com/renovatebot/helm-charts/issues/3752, when we migrated the docs site from renovatebot/renovatebot.github.io to renovatebot/renovate, the `/helm-charts/` repository would no longer work as a subdomain, due to a known GitHub Pages limitation - name: Mirror helm-charts/index.yaml from helm-charts' GitHub Pages site run: | mkdir tools/mkdocs/site/helm-charts curl --retry 5 --silent https://renovatebot.github.io/helm-charts/index.yaml -o tools/mkdocs/site/helm-charts/index.yaml - name: Upload GitHub Pages artifact uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 with: path: tools/mkdocs/site - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1 notify-release-failure: runs-on: ubuntu-latest if: ${{ always() && (github.repository == 'renovatebot/renovate' && github.ref_name == 'main' && github.event_name == 'push') && (needs.release.result == 'failure' || needs.release.result == 'timed_out') }} needs: - release steps: - name: Post to Slack id: slack uses: slackapi/slack-github-action@dcb1066f776dd043e64d0e8ba94ca15cc7e1875d # v4.0.0 with: webhook: ${{ secrets.RENOVATEBOT_SLACK_WEBHOOK_MAIN_FAILURES }} webhook-type: incoming-webhook payload: | text: "*Release from `main` failed*:\nAction Run: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\nCommit: ${{ github.event.head_commit.url }}" blocks: - type: "section" text: type: "mrkdwn" text: "*Release from `main` failed*:\nAction Run: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\nCommit: ${{ github.event.head_commit.url }}" notify-docs-failure: runs-on: ubuntu-latest if: ${{ always() && (github.repository == 'renovatebot/renovate' && github.ref_name == 'main' && github.event_name == 'push') && (needs.deploy-docs-site.result == 'failure' || needs.deploy-docs-site.result == 'timed_out') }} needs: - deploy-docs-site steps: - name: Post to Slack id: slack uses: slackapi/slack-github-action@dcb1066f776dd043e64d0e8ba94ca15cc7e1875d # v4.0.0 with: webhook: ${{ secrets.RENOVATEBOT_SLACK_WEBHOOK_MAIN_FAILURES }} webhook-type: incoming-webhook payload: | text: "*Docs build from `main` failed*:\nAction Run: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\nCommit: ${{ github.event.head_commit.url }}" blocks: - type: "section" text: type: "mrkdwn" text: "*Docs build from `main` failed*:\nAction Run: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\nCommit: ${{ github.event.head_commit.url }}"