name: Stable Release run-name: Stable release ${{ inputs.tag }} # Dispatch on the tag so reusable workflows and github.sha identify the same tree. on: workflow_dispatch: inputs: tag: description: Exact annotated claim tag, matching the selected workflow ref required: true type: string baseline-manifest: description: Optional HTTPS manifest of the previous published stable packages default: '' type: string permissions: contents: read # Every reusable workflow called below inherits secrets (`secrets: inherit`) # because their release-signing jobs need protected-environment secrets. A # called workflow only sees them when the caller inherits AND the called job # declares the environment: the job-level `environment:` alone attaches the # deployment and exposes `vars`, but leaves `secrets.*` empty # (actions/runner#1490). ci.yaml is deliberately excluded — it runs # PR-controlled code and must stay secret-free. concurrency: group: stable-release cancel-in-progress: false jobs: admit: name: Admit the claim # A read token cannot see a draft release, so gh release view answers # "release not found" for a draft that exists. Write is the permission # that can read it. permissions: contents: write runs-on: ubuntu-24.04 outputs: claim-tag: ${{ steps.admit.outputs.claim-tag }} claim-object: ${{ steps.admit.outputs.claim-object }} tag: ${{ steps.admit.outputs.tag }} commit: ${{ steps.admit.outputs.commit }} version: ${{ steps.admit.outputs.version }} release-id: ${{ steps.admit.outputs.release-id }} release-epoch: ${{ steps.admit.outputs.release-epoch }} skip-bundles: ${{ steps.admit.outputs.skip-bundles }} skip-tests: ${{ steps.admit.outputs.skip-tests }} steps: - uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v7.0.1 with: ref: ${{ github.sha }} fetch-depth: 0 - uses: ./.github/actions/setup-pm with: cache-python: false - id: admit run: python -m scripts.releases.stable admit env: GH_TOKEN: ${{ github.token }} RELEASE_CLAIM_TAG: ${{ inputs.tag }} ci: name: Full CI pipeline needs: admit if: needs.admit.outputs.skip-tests != 'true' permissions: contents: read pull-requests: write actions: read security-events: write uses: ./.github/workflows/ci.yaml with: release: true docker: name: Docker build and tests needs: admit # The image publish-docker pushes is built here, so a claim that skipped # tests still runs this job with its tests off. It builds alongside the # gates; only the acceptance join waits for CI. if: >- !cancelled() && needs.admit.result == 'success' uses: ./.github/workflows/docker.yml secrets: inherit with: release-phase: test skip-tests: ${{ needs.admit.outputs.skip-tests == 'true' }} tag: ${{ needs.admit.outputs.tag }} version: ${{ needs.admit.outputs.version }} nix: needs: admit # The claim's policy removes it, not a gate it happens to need. if: needs.admit.outputs.skip-tests != 'true' uses: ./.github/workflows/nix.yml with: release: true version: ${{ needs.admit.outputs.version }} pm-bundle: needs: admit # Bundle acceptance is a test of bundles, so either claim flag removes it. if: >- needs.admit.outputs.skip-bundles != 'true' && needs.admit.outputs.skip-tests != 'true' uses: ./.github/workflows/pm-bundle.yml with: release: true ref: ${{ github.sha }} termux-checks: needs: admit if: needs.admit.outputs.skip-tests != 'true' permissions: contents: read actions: read uses: ./.github/workflows/termux-verify.yml secrets: inherit with: release: true windows-live: needs: admit if: needs.admit.outputs.skip-tests != 'true' uses: ./.github/workflows/windows-venv-e2e.yml with: release: true install-e2e: name: Install and update E2E needs: admit if: needs.admit.outputs.skip-tests != 'true' permissions: contents: read actions: read uses: ./.github/workflows/install-e2e.yml with: release: true route: all tag-count: '3' exclude-ref: ${{ inputs.tag }} candidates-darwin-arm64: name: Build signed release candidates (darwin-arm64) needs: admit # Starts with the gates; the acceptance join is what requires CI. if: >- !cancelled() && needs.admit.result == 'success' && needs.admit.outputs.skip-bundles != 'true' permissions: contents: write actions: read packages: write id-token: write uses: ./.github/workflows/desktop-bundled-release.yml secrets: inherit with: tag: ${{ needs.admit.outputs.tag }} claim-tag: ${{ needs.admit.outputs.claim-tag }} claim-object: ${{ needs.admit.outputs.claim-object }} release-phase: candidate jobs: darwin-arm64 skip-tests: ${{ needs.admit.outputs.skip-tests == 'true' }} candidates-darwin-x64: name: Build signed release candidates (darwin-x64) needs: admit # Starts with the gates; the acceptance join is what requires CI. if: >- !cancelled() && needs.admit.result == 'success' && needs.admit.outputs.skip-bundles != 'true' permissions: contents: write actions: read packages: write id-token: write uses: ./.github/workflows/desktop-bundled-release.yml secrets: inherit with: tag: ${{ needs.admit.outputs.tag }} claim-tag: ${{ needs.admit.outputs.claim-tag }} claim-object: ${{ needs.admit.outputs.claim-object }} release-phase: candidate jobs: darwin-x64 skip-tests: ${{ needs.admit.outputs.skip-tests == 'true' }} candidates-win32-arm64: name: Build signed release candidates (win32-arm64) needs: admit # Starts with the gates; the acceptance join is what requires CI. if: >- !cancelled() && needs.admit.result == 'success' && needs.admit.outputs.skip-bundles != 'true' permissions: contents: write actions: read packages: write id-token: write uses: ./.github/workflows/desktop-bundled-release.yml secrets: inherit with: tag: ${{ needs.admit.outputs.tag }} claim-tag: ${{ needs.admit.outputs.claim-tag }} claim-object: ${{ needs.admit.outputs.claim-object }} release-phase: candidate jobs: win32-arm64 skip-tests: ${{ needs.admit.outputs.skip-tests == 'true' }} candidates-win32-x64: name: Build signed release candidates (win32-x64) needs: admit # Starts with the gates; the acceptance join is what requires CI. if: >- !cancelled() && needs.admit.result == 'success' && needs.admit.outputs.skip-bundles != 'true' permissions: contents: write actions: read packages: write id-token: write uses: ./.github/workflows/desktop-bundled-release.yml secrets: inherit with: tag: ${{ needs.admit.outputs.tag }} claim-tag: ${{ needs.admit.outputs.claim-tag }} claim-object: ${{ needs.admit.outputs.claim-object }} release-phase: candidate jobs: win32-x64 skip-tests: ${{ needs.admit.outputs.skip-tests == 'true' }} candidates-win32-bundle: name: Build signed release candidates (win32-bundle) needs: [admit, candidates-win32-arm64, candidates-win32-x64] # Starts with the gates; the acceptance join is what requires CI. if: >- !cancelled() && needs.admit.result == 'success' && needs.admit.outputs.skip-bundles != 'true' && needs.candidates-win32-arm64.result == 'success' && needs.candidates-win32-x64.result == 'success' permissions: contents: write actions: read packages: write id-token: write uses: ./.github/workflows/desktop-bundled-release.yml secrets: inherit with: tag: ${{ needs.admit.outputs.tag }} claim-tag: ${{ needs.admit.outputs.claim-tag }} claim-object: ${{ needs.admit.outputs.claim-object }} release-phase: candidate jobs: win32-bundle skip-tests: ${{ needs.admit.outputs.skip-tests == 'true' }} candidates-termux: name: Build signed release candidates (termux) needs: admit # Starts with the gates; the acceptance join is what requires CI. if: >- !cancelled() && needs.admit.result == 'success' && needs.admit.outputs.skip-bundles != 'true' permissions: contents: write actions: read packages: write id-token: write uses: ./.github/workflows/desktop-bundled-release.yml secrets: inherit with: tag: ${{ needs.admit.outputs.tag }} claim-tag: ${{ needs.admit.outputs.claim-tag }} claim-object: ${{ needs.admit.outputs.claim-object }} release-phase: candidate jobs: termux skip-tests: ${{ needs.admit.outputs.skip-tests == 'true' }} transitions-darwin-arm64: name: Pin actual OLD and NEW signed packages (darwin-arm64) needs: [admit, candidates-darwin-arm64] if: needs.admit.outputs.skip-tests != 'true' runs-on: ubuntu-24.04 environment: release-signing outputs: windows: ${{ steps.plan.outputs.windows }} macos: ${{ steps.plan.outputs.macos }} steps: - uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v7.0.1 with: ref: ${{ github.sha }} fetch-depth: 0 - uses: ./.github/actions/setup-pm with: cache-python: false - id: plan run: python -m scripts.releases.stable transitions env: GH_TOKEN: ${{ github.token }} RECEIPT: darwin-arm64 RECEIPT_URL: ${{ needs.candidates-darwin-arm64.outputs.darwin-arm64-receipt-url }} RECEIPT_SHA256: ${{ needs.candidates-darwin-arm64.outputs.darwin-arm64-receipt-sha256 }} RELEASE_TAG: ${{ needs.admit.outputs.tag }} RELEASE_CLAIM_TAG: ${{ needs.admit.outputs.claim-tag }} RELEASE_CLAIM_OBJECT: ${{ needs.admit.outputs.claim-object }} BASELINE_MANIFEST_URL: ${{ inputs.baseline-manifest }} CLOUDFLARE_R2_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_R2_ACCOUNT_ID }} CLOUDFLARE_R2_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_ACCESS_KEY_ID }} CLOUDFLARE_R2_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_R2_SECRET_ACCESS_KEY }} CLOUDFLARE_R2_BUCKET: ${{ vars.CLOUDFLARE_R2_BUCKET }} CLOUDFLARE_R2_PUBLIC_URL: ${{ vars.CLOUDFLARE_R2_PUBLIC_URL }} transitions-darwin-x64: name: Pin actual OLD and NEW signed packages (darwin-x64) needs: [admit, candidates-darwin-x64] if: needs.admit.outputs.skip-tests != 'true' runs-on: ubuntu-24.04 environment: release-signing outputs: windows: ${{ steps.plan.outputs.windows }} macos: ${{ steps.plan.outputs.macos }} steps: - uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v7.0.1 with: ref: ${{ github.sha }} fetch-depth: 0 - uses: ./.github/actions/setup-pm with: cache-python: false - id: plan run: python -m scripts.releases.stable transitions env: GH_TOKEN: ${{ github.token }} RECEIPT: darwin-x64 RECEIPT_URL: ${{ needs.candidates-darwin-x64.outputs.darwin-x64-receipt-url }} RECEIPT_SHA256: ${{ needs.candidates-darwin-x64.outputs.darwin-x64-receipt-sha256 }} RELEASE_TAG: ${{ needs.admit.outputs.tag }} RELEASE_CLAIM_TAG: ${{ needs.admit.outputs.claim-tag }} RELEASE_CLAIM_OBJECT: ${{ needs.admit.outputs.claim-object }} BASELINE_MANIFEST_URL: ${{ inputs.baseline-manifest }} CLOUDFLARE_R2_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_R2_ACCOUNT_ID }} CLOUDFLARE_R2_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_ACCESS_KEY_ID }} CLOUDFLARE_R2_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_R2_SECRET_ACCESS_KEY }} CLOUDFLARE_R2_BUCKET: ${{ vars.CLOUDFLARE_R2_BUCKET }} CLOUDFLARE_R2_PUBLIC_URL: ${{ vars.CLOUDFLARE_R2_PUBLIC_URL }} transitions-win32: name: Pin actual OLD and NEW signed packages (win32) needs: [admit, candidates-win32-bundle] if: needs.admit.outputs.skip-tests != 'true' runs-on: ubuntu-24.04 environment: release-signing outputs: windows: ${{ steps.plan.outputs.windows }} macos: ${{ steps.plan.outputs.macos }} steps: - uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v7.0.1 with: ref: ${{ github.sha }} fetch-depth: 0 - uses: ./.github/actions/setup-pm with: cache-python: false - id: plan run: python -m scripts.releases.stable transitions env: GH_TOKEN: ${{ github.token }} RECEIPT: win32-bundle RECEIPT_URL: ${{ needs.candidates-win32-bundle.outputs.win32-bundle-receipt-url }} RECEIPT_SHA256: ${{ needs.candidates-win32-bundle.outputs.win32-bundle-receipt-sha256 }} RELEASE_TAG: ${{ needs.admit.outputs.tag }} RELEASE_CLAIM_TAG: ${{ needs.admit.outputs.claim-tag }} RELEASE_CLAIM_OBJECT: ${{ needs.admit.outputs.claim-object }} BASELINE_MANIFEST_URL: ${{ inputs.baseline-manifest }} CLOUDFLARE_R2_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_R2_ACCOUNT_ID }} CLOUDFLARE_R2_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_ACCESS_KEY_ID }} CLOUDFLARE_R2_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_R2_SECRET_ACCESS_KEY }} CLOUDFLARE_R2_BUCKET: ${{ vars.CLOUDFLARE_R2_BUCKET }} CLOUDFLARE_R2_PUBLIC_URL: ${{ vars.CLOUDFLARE_R2_PUBLIC_URL }} candidate-manifest: name: Stage verified stable candidate artifacts # Runs after every candidate call, so after every smoke (decision 23). # The recorded smoke results are the calls' own workflow results: a # call's stable-phase-result fails when its smokes fail, so a failed # smoke fails this job's RELEASE_NEEDS check and stages no manifest. if: always() && needs.admit.outputs.skip-bundles != 'true' needs: [admit, candidates-darwin-arm64, candidates-darwin-x64, candidates-win32-arm64, candidates-win32-x64, candidates-win32-bundle, candidates-termux] runs-on: ubuntu-24.04 environment: release-signing timeout-minutes: 90 outputs: manifest-url: ${{ steps.manifest.outputs.manifest-url }} manifest-sha256: ${{ steps.manifest.outputs.manifest-sha256 }} env: RELEASE_TAG: ${{ needs.admit.outputs.tag }} RELEASE_CLAIM_TAG: ${{ needs.admit.outputs.claim-tag }} RELEASE_CLAIM_OBJECT: ${{ needs.admit.outputs.claim-object }} RELEASE_NEEDS: ${{ toJSON(needs) }} CLOUDFLARE_R2_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_R2_ACCOUNT_ID }} CLOUDFLARE_R2_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_ACCESS_KEY_ID }} CLOUDFLARE_R2_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_R2_SECRET_ACCESS_KEY }} CLOUDFLARE_R2_BUCKET: ${{ vars.CLOUDFLARE_R2_BUCKET }} CLOUDFLARE_R2_PUBLIC_URL: ${{ vars.CLOUDFLARE_R2_PUBLIC_URL }} steps: - uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v7.0.1 with: ref: ${{ github.sha }} fetch-depth: 0 fetch-tags: true - uses: ./.github/actions/setup-pm with: cache-python: false - id: manifest run: python -m scripts.releases.stable candidate-manifest windows-packaged: name: Windows signed-package acceptance needs: transitions-win32 strategy: fail-fast: false matrix: ${{ fromJSON(needs.transitions-win32.outputs.windows) }} uses: ./.github/workflows/install-e2e-windows-run.yml with: install-method: packaged-app update-method: open-app-update install-ref: ${{ matrix.old }} leg-id: stable-${{ matrix.id }} bundle-manifest-url: ${{ matrix.manifest }} bundle-manifest-sha256: ${{ matrix.manifest_sha256 }} bundle-arch: ${{ matrix.arch }} macos-packaged-arm64: name: macOS arm64 signed-package acceptance needs: transitions-darwin-arm64 strategy: fail-fast: false matrix: ${{ fromJSON(needs.transitions-darwin-arm64.outputs.macos) }} uses: ./.github/workflows/install-e2e-macos-run.yml with: install-method: packaged-app update-method: open-app-update install-ref: ${{ matrix.old }} leg-id: stable-${{ matrix.id }} bundle-manifest-url: ${{ matrix.manifest }} bundle-manifest-sha256: ${{ matrix.manifest_sha256 }} bundle-arch: ${{ matrix.arch }} macos-packaged-x64: name: macOS x64 signed-package acceptance needs: transitions-darwin-x64 strategy: fail-fast: false matrix: ${{ fromJSON(needs.transitions-darwin-x64.outputs.macos) }} uses: ./.github/workflows/install-e2e-macos-run.yml with: install-method: packaged-app update-method: open-app-update install-ref: ${{ matrix.old }} leg-id: stable-${{ matrix.id }} bundle-manifest-url: ${{ matrix.manifest }} bundle-manifest-sha256: ${{ matrix.manifest_sha256 }} bundle-arch: ${{ matrix.arch }} bootstrap-version: name: Bootstrap installer release identity needs: admit if: needs.admit.outputs.skip-tests != 'true' runs-on: ubuntu-24.04 steps: - uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v7.0.1 with: ref: ${{ needs.admit.outputs.commit }} - name: Stamp and verify the Cargo and Tauri release identity env: RELEASE_COMMIT: ${{ needs.admit.outputs.commit }} RELEASE_VERSION: ${{ needs.admit.outputs.version }} run: | set -euo pipefail tree="$RUNNER_TEMP/bootstrap-release" mkdir -p "$tree" git archive "$RELEASE_COMMIT" | tar -x -C "$tree" python3 -m scripts.releases.stamping --tree "$tree" \ --version "$RELEASE_VERSION" actual="$(cargo metadata --no-deps --format-version 1 \ --manifest-path "$tree/apps/bootstrap-installer/src-tauri/Cargo.toml" \ | jq -r '.packages[] | select(.name == "hermes-bootstrap") | .version')" test "$actual" = "$RELEASE_VERSION" || { echo "::error::Bootstrap Cargo version $actual != $RELEASE_VERSION" exit 1 } actual_tauri="$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1]))["version"])' \ "$tree/apps/bootstrap-installer/src-tauri/tauri.conf.json")" test "$actual_tauri" = "$RELEASE_VERSION" || { echo "::error::Bootstrap Tauri version $actual_tauri != $RELEASE_VERSION" exit 1 } acceptance: name: All release acceptance checks pass if: always() needs: [admit, ci, docker, nix, pm-bundle, termux-checks, windows-live, install-e2e, candidates-darwin-arm64, candidates-darwin-x64, candidates-win32-arm64, candidates-win32-x64, candidates-win32-bundle, candidates-termux, candidate-manifest, transitions-darwin-arm64, transitions-darwin-x64, transitions-win32, windows-packaged, macos-packaged-arm64, macos-packaged-x64, bootstrap-version] runs-on: ubuntu-24.04 steps: - uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v7.0.1 with: ref: ${{ github.sha }} - uses: ./.github/actions/setup-pm with: cache-python: false - run: python -m scripts.releases.stable gate admit ci docker nix pm-bundle termux-checks windows-live install-e2e candidates-darwin-arm64 candidates-darwin-x64 candidates-win32-arm64 candidates-win32-x64 candidates-win32-bundle candidates-termux candidate-manifest transitions-darwin-arm64 transitions-darwin-x64 transitions-win32 windows-packaged macos-packaged-arm64 macos-packaged-x64 bootstrap-version env: RELEASE_NEEDS: ${{ toJSON(needs) }} SKIP_BUNDLES: ${{ needs.admit.outputs.skip-bundles }} SKIP_TESTS: ${{ needs.admit.outputs.skip-tests }} publish-docker: name: Publish tested Docker image # B5: this job pushes only the immutable attempt-ref image tags; the # stable/latest aliases move in the ordered publication pass. needs: [admit, docker] uses: ./.github/workflows/docker.yml secrets: inherit with: release-phase: publish tag: ${{ needs.admit.outputs.tag }} version: ${{ needs.admit.outputs.version }} publish-bundles: name: Publish tested bundle artifacts needs: [admit, acceptance, candidate-manifest] if: needs.admit.outputs.skip-bundles != 'true' permissions: contents: write actions: read packages: write id-token: write uses: ./.github/workflows/desktop-bundled-release.yml secrets: inherit with: tag: ${{ needs.admit.outputs.tag }} claim-tag: ${{ needs.admit.outputs.claim-tag }} claim-object: ${{ needs.admit.outputs.claim-object }} release-phase: publish manifest-sha256: ${{ needs.candidate-manifest.outputs.manifest-sha256 }} publication: name: All artifact publication succeeded if: always() needs: [admit, acceptance, publish-docker, publish-bundles] runs-on: ubuntu-24.04 steps: - uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v7.0.1 with: ref: ${{ github.sha }} - uses: ./.github/actions/setup-pm with: cache-python: false - run: python -m scripts.releases.stable gate acceptance publish-docker publish-bundles env: RELEASE_NEEDS: ${{ toJSON(needs) }} SKIP_BUNDLES: ${{ needs.admit.outputs.skip-bundles }} SKIP_TESTS: ${{ needs.admit.outputs.skip-tests }} complete: name: Stable release is green if: always() needs: [admit, ci, docker, acceptance, candidate-manifest, publication, publish-docker, windows-packaged, macos-packaged-arm64, macos-packaged-x64] runs-on: ubuntu-24.04 environment: release-signing permissions: contents: write actions: read steps: - uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v7.0.1 with: ref: ${{ github.sha }} fetch-depth: 0 - uses: ./.github/actions/setup-pm with: cache-python: false - name: Set up the native identity reader uses: ./.github/actions/setup-pm with: toolchain: node cache-python: false - run: python -m scripts.releases.stable gate admit ci docker acceptance candidate-manifest publication publish-docker env: RELEASE_NEEDS: ${{ toJSON(needs) }} SKIP_BUNDLES: ${{ needs.admit.outputs.skip-bundles }} SKIP_TESTS: ${{ needs.admit.outputs.skip-tests }} - name: Validate the accepted candidate archive if: needs.admit.outputs.skip-bundles != 'true' run: python -m scripts.releases.stable complete env: RELEASE_TAG: ${{ needs.admit.outputs.tag }} RELEASE_CLAIM_TAG: ${{ needs.admit.outputs.claim-tag }} RELEASE_CLAIM_OBJECT: ${{ needs.admit.outputs.claim-object }} CANDIDATE_MANIFEST_URL: ${{ needs.candidate-manifest.outputs.manifest-url }} CANDIDATE_MANIFEST_SHA256: ${{ needs.candidate-manifest.outputs.manifest-sha256 }} CLOUDFLARE_R2_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_R2_ACCOUNT_ID }} CLOUDFLARE_R2_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_ACCESS_KEY_ID }} CLOUDFLARE_R2_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_R2_SECRET_ACCESS_KEY }} CLOUDFLARE_R2_BUCKET: ${{ vars.CLOUDFLARE_R2_BUCKET }} CLOUDFLARE_R2_PUBLIC_URL: ${{ vars.CLOUDFLARE_R2_PUBLIC_URL }} - name: Render the admitted candidate smoke results if: needs.admit.outputs.skip-bundles != 'true' env: GH_TOKEN: ${{ github.token }} RELEASE_TAG: ${{ needs.admit.outputs.tag }} RELEASE_COMMIT: ${{ needs.admit.outputs.commit }} CANDIDATE_MANIFEST_SHA256: ${{ needs.candidate-manifest.outputs.manifest-sha256 }} run: | python scripts/render-builds-table.py --tag "$RELEASE_TAG" --repo "$GITHUB_REPOSITORY" \ --archive "$RELEASE_CLAIM_TAG" \ --candidate-manifest-sha256 "$CANDIDATE_MANIFEST_SHA256" --candidate-commit "$RELEASE_COMMIT" - name: Set up Docker Buildx for ordered alias promotion uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 - name: Log in to Docker Hub for ordered alias promotion uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Reconcile ordered stable publication run: python -m scripts.releases.sequencer env: GH_TOKEN: ${{ github.token }} REQUESTED_VERSION: '' CLOUDFLARE_R2_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_R2_ACCOUNT_ID }} CLOUDFLARE_R2_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_ACCESS_KEY_ID }} CLOUDFLARE_R2_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_R2_SECRET_ACCESS_KEY }} CLOUDFLARE_R2_BUCKET: ${{ vars.CLOUDFLARE_R2_BUCKET }} CLOUDFLARE_R2_PUBLIC_URL: ${{ vars.CLOUDFLARE_R2_PUBLIC_URL }}