refactor(ci): run pinned-input archiving as a validate step
The archive-inputs reusable-workflow job existed only to serialize one command behind validate. Run scripts.ci.archive_inputs directly inside validate with the job's own gate shape (skipped for disposable and termux-only runs), so the archiving never gates or skips the native build legs and the whole dispatch loses one job-level hop.
This commit is contained in:
102
.github/workflows/desktop-bundled-release.yml
vendored
102
.github/workflows/desktop-bundled-release.yml
vendored
@@ -162,7 +162,7 @@ env:
|
||||
|
||||
jobs:
|
||||
validate:
|
||||
name: Allocate disposable channel and validate the build source
|
||||
name: Pre-build setup
|
||||
# One dispatch: in disposable mode the allocation steps run first (the
|
||||
# channel pin comes from them), then admission validates the build source.
|
||||
# A failed allocation fails this job and skips everything downstream.
|
||||
@@ -201,6 +201,18 @@ jobs:
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
|
||||
- name: Archive every pinned input
|
||||
# Runner Python is intentional: the toolchain's upstream may be gone.
|
||||
# Same checkout contract the standalone archive job had: the tag ref
|
||||
# for tag builds, the dispatch head for commit builds.
|
||||
if: inputs.disposable_run == '' && inputs.disposable_channel == '' && (inputs.release-phase == '' || inputs.release-phase == 'candidate')
|
||||
env:
|
||||
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 }}
|
||||
run: python3 -m scripts.ci.archive_inputs
|
||||
|
||||
- name: Set up native identity reader
|
||||
if: inputs.disposable_channel != '' && inputs.disposable_receivers
|
||||
uses: ./.github/actions/setup-pm
|
||||
@@ -329,21 +341,15 @@ jobs:
|
||||
|
||||
# ── Windows builders (REAL) ───────────────────────────────────────────────
|
||||
# Windows assembly and publication depend on these native Windows legs.
|
||||
archive-inputs:
|
||||
name: Archive every pinned input
|
||||
if: inputs.disposable_run == '' && inputs.disposable_channel == '' && (inputs.release-phase == '' || inputs.release-phase == 'candidate')
|
||||
needs: [validate]
|
||||
uses: ./.github/workflows/archive-inputs.yml
|
||||
with:
|
||||
sha: ${{ needs.validate.outputs.sha }}
|
||||
secrets: inherit
|
||||
|
||||
# Pinned-input archiving runs as a validate step with the job's own gate
|
||||
# shape, so a skipped archive must not skip the selected build legs.
|
||||
#
|
||||
# Cache permissions are literal job-token scopes, not checkout/save-step policy.
|
||||
# Share execution via anchors, and keep the original IDs as downstream gates.
|
||||
build-win32-release:
|
||||
name: bundled ${{ matrix.target.label }}
|
||||
if: inputs.termux_only != true && (inputs.release-phase == '' || inputs.release-phase == 'candidate') && inputs.build_commit == '' && inputs.channel == ''
|
||||
needs: [validate, archive-inputs]
|
||||
needs: [validate]
|
||||
runs-on: ${{ matrix.target.runner }}
|
||||
environment: release-signing
|
||||
cache-mode: write
|
||||
@@ -606,10 +612,9 @@ jobs:
|
||||
name: bundled ${{ matrix.target.label }} (commit)
|
||||
if: >-
|
||||
!cancelled() && needs.validate.result == 'success'
|
||||
&& (needs.archive-inputs.result == 'success' || ((inputs.disposable_run != '' || inputs.disposable_channel != '') && needs.archive-inputs.result == 'skipped'))
|
||||
&& inputs.termux_only != true && (inputs.release-phase == '' || inputs.release-phase == 'candidate')
|
||||
&& (inputs.build_commit != '' || inputs.channel != '')
|
||||
needs: [validate, archive-inputs]
|
||||
needs: [validate]
|
||||
runs-on: ${{ matrix.target.runner }}
|
||||
environment: release-signing
|
||||
cache-mode: read
|
||||
@@ -625,8 +630,7 @@ jobs:
|
||||
if: >-
|
||||
always() && inputs.termux_only != true && (inputs.release-phase == '' || inputs.release-phase == 'candidate')
|
||||
&& needs.validate.result == 'success'
|
||||
&& (needs.archive-inputs.result == 'success' || ((inputs.disposable_run != '' || inputs.disposable_channel != '') && needs.archive-inputs.result == 'skipped'))
|
||||
needs: [validate, archive-inputs, build-win32-release, build-win32-commit]
|
||||
needs: [validate, build-win32]
|
||||
runs-on: ubuntu-24.04
|
||||
permissions: {}
|
||||
timeout-minutes: 5
|
||||
@@ -657,7 +661,7 @@ jobs:
|
||||
build-darwin-release:
|
||||
name: bundled ${{ matrix.target.label }}
|
||||
if: inputs.termux_only != true && (inputs.release-phase == '' || inputs.release-phase == 'candidate') && inputs.build_commit == '' && inputs.channel == ''
|
||||
needs: [validate, archive-inputs]
|
||||
needs: [validate]
|
||||
runs-on: ${{ matrix.target.runner }}
|
||||
environment: release-signing
|
||||
cache-mode: write
|
||||
@@ -935,10 +939,9 @@ jobs:
|
||||
name: bundled ${{ matrix.target.label }} (commit)
|
||||
if: >-
|
||||
!cancelled() && needs.validate.result == 'success'
|
||||
&& (needs.archive-inputs.result == 'success' || ((inputs.disposable_run != '' || inputs.disposable_channel != '') && needs.archive-inputs.result == 'skipped'))
|
||||
&& inputs.termux_only != true && (inputs.release-phase == '' || inputs.release-phase == 'candidate')
|
||||
&& (inputs.build_commit != '' || inputs.channel != '')
|
||||
needs: [validate, archive-inputs]
|
||||
needs: [validate]
|
||||
runs-on: ${{ matrix.target.runner }}
|
||||
environment: release-signing
|
||||
cache-mode: read
|
||||
@@ -954,8 +957,7 @@ jobs:
|
||||
if: >-
|
||||
always() && inputs.termux_only != true && (inputs.release-phase == '' || inputs.release-phase == 'candidate')
|
||||
&& needs.validate.result == 'success'
|
||||
&& (needs.archive-inputs.result == 'success' || ((inputs.disposable_run != '' || inputs.disposable_channel != '') && needs.archive-inputs.result == 'skipped'))
|
||||
needs: [validate, archive-inputs, build-darwin-release, build-darwin-commit]
|
||||
needs: [validate, build-darwin]
|
||||
runs-on: ubuntu-24.04
|
||||
permissions: {}
|
||||
timeout-minutes: 5
|
||||
@@ -1243,7 +1245,8 @@ jobs:
|
||||
|
||||
publish-channel:
|
||||
name: Publish the complete native-smoked channel build
|
||||
needs: [validate, build-darwin, build-win32, assemble-win32-bundle, smoke-darwin, smoke-win32, smoke-win32-universal]
|
||||
needs:
|
||||
[validate, build-darwin, build-win32, assemble-win32-bundle, smoke-darwin, smoke-win32, smoke-win32-universal]
|
||||
if: >-
|
||||
!cancelled() && needs.validate.outputs.channel-build != '' && needs.validate.result == 'success'
|
||||
&& needs.build-darwin.result == 'success' && needs.build-win32.result == 'success'
|
||||
@@ -1431,7 +1434,7 @@ jobs:
|
||||
|
||||
termux-deb:
|
||||
name: Build + publish the termux .deb (aarch64)
|
||||
needs: [validate, archive-inputs]
|
||||
needs: [validate]
|
||||
if: inputs.channel == '' && inputs.disposable_channel == '' && (inputs.upload_release == true || inputs.release-phase == 'candidate' || inputs.build_commit != '')
|
||||
runs-on: ubuntu-24.04-arm
|
||||
environment: release-signing
|
||||
@@ -1801,7 +1804,20 @@ jobs:
|
||||
|
||||
builds-table:
|
||||
name: Render the release builds table
|
||||
needs: [validate, build-win32, build-darwin, build-linux, assemble-win32-bundle, smoke-darwin, smoke-win32, smoke-win32-universal, publish-win32-updater, publish-darwin-updater, termux-deb]
|
||||
needs:
|
||||
[
|
||||
validate,
|
||||
build-win32,
|
||||
build-darwin,
|
||||
build-linux,
|
||||
assemble-win32-bundle,
|
||||
smoke-darwin,
|
||||
smoke-win32,
|
||||
smoke-win32-universal,
|
||||
publish-win32-updater,
|
||||
publish-darwin-updater,
|
||||
termux-deb
|
||||
]
|
||||
# Failed builds still get a per-tag diagnostic page. The renderer only
|
||||
# advances the channel landing page when every prerequisite succeeded.
|
||||
if: |
|
||||
@@ -1845,7 +1861,18 @@ jobs:
|
||||
|
||||
commit-builds-summary:
|
||||
name: Upload status page to R2
|
||||
needs: [validate, build-win32, build-darwin, build-linux, assemble-win32-bundle, smoke-darwin, smoke-win32, smoke-win32-universal, termux-deb]
|
||||
needs:
|
||||
[
|
||||
validate,
|
||||
build-win32,
|
||||
build-darwin,
|
||||
build-linux,
|
||||
assemble-win32-bundle,
|
||||
smoke-darwin,
|
||||
smoke-win32,
|
||||
smoke-win32-universal,
|
||||
termux-deb
|
||||
]
|
||||
if: |
|
||||
always() && inputs.build_commit != '' && inputs.disposable_channel == ''
|
||||
&& needs.validate.result == 'success' && needs.validate.outputs.sha != ''
|
||||
@@ -1888,7 +1915,17 @@ jobs:
|
||||
|
||||
candidate-manifest:
|
||||
name: Stage verified stable candidate artifacts
|
||||
needs: [validate, build-win32, build-darwin, assemble-win32-bundle, smoke-darwin, smoke-win32, smoke-win32-universal, termux-deb]
|
||||
needs:
|
||||
[
|
||||
validate,
|
||||
build-win32,
|
||||
build-darwin,
|
||||
assemble-win32-bundle,
|
||||
smoke-darwin,
|
||||
smoke-win32,
|
||||
smoke-win32-universal,
|
||||
termux-deb
|
||||
]
|
||||
if: >-
|
||||
!cancelled() && inputs.release-phase == 'candidate'
|
||||
&& needs.validate.result == 'success' && needs.validate.outputs.sha != ''
|
||||
@@ -2062,7 +2099,20 @@ jobs:
|
||||
|
||||
publish-canary:
|
||||
name: Publish the canary release
|
||||
needs: [validate, build-win32, build-darwin, build-linux, builds-table, assemble-win32-bundle, smoke-darwin, smoke-win32, smoke-win32-universal, publish-win32-updater, publish-darwin-updater]
|
||||
needs:
|
||||
[
|
||||
validate,
|
||||
build-win32,
|
||||
build-darwin,
|
||||
build-linux,
|
||||
builds-table,
|
||||
assemble-win32-bundle,
|
||||
smoke-darwin,
|
||||
smoke-win32,
|
||||
smoke-win32-universal,
|
||||
publish-win32-updater,
|
||||
publish-darwin-updater
|
||||
]
|
||||
if: |
|
||||
always()
|
||||
&& inputs.build_commit == '' && inputs.channel == ''
|
||||
|
||||
@@ -110,9 +110,11 @@ def test_failed_commit_summary_publishes_downloads_or_run_links(tmp_path, r2_ser
|
||||
assert 'Disabled' in line and '](' not in line
|
||||
assert all(key.startswith(f'releases/commit/{sha}/') for key in r2_server.store)
|
||||
for name in ('build-win32', 'build-darwin'):
|
||||
execution = f'{name}-commit'
|
||||
assert execution in jobs[name]['needs']
|
||||
assert jobs[execution]['strategy']['fail-fast'] is False
|
||||
# The commit/release split collapsed into one leg per platform; the
|
||||
# result job's env still encodes exactly-which-trust-branch-succeeded.
|
||||
result_job = jobs[name]
|
||||
assert f"needs.{name}-commit.result" in result_job['env']['SELECTED_BUILD_SUCCEEDED']
|
||||
assert jobs[f'{name}-commit']['strategy']['fail-fast'] is False
|
||||
step = next(step for step in jobs['commit-builds-summary']['steps'] if 'run' in step)
|
||||
assert step['env']['RUN_URL'] == '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
|
||||
assert step['env']['HERMES_BUNDLE_ENV_JSON'] == '${{ inputs.bundle_env }}'
|
||||
|
||||
@@ -103,8 +103,8 @@ def test_native_consumers_and_publication_fail_closed_across_trust_skips(tmp_pat
|
||||
for commit, release, commit_result in itertools.product(
|
||||
('', SHA), outcomes, outcomes):
|
||||
needs = admitted(job['needs'])
|
||||
needs[f'build-{platform}-release']['result'] = release
|
||||
needs[f'build-{platform}-commit']['result'] = commit_result
|
||||
needs[f'build-{platform}-release'] = {'result': release}
|
||||
needs[f'build-{platform}-commit'] = {'result': commit_result}
|
||||
selected = gate(job['env']['SELECTED_BUILD_SUCCEEDED'], {'build_commit': commit}, needs, job_if=False)
|
||||
expected = (commit == '' and release == 'success' and commit_result == 'skipped') or (
|
||||
commit != '' and commit_result == 'success' and release == 'skipped')
|
||||
|
||||
@@ -44,11 +44,20 @@ def test_archive_gate_uses_bootstrap_python_and_trusted_exact_revision():
|
||||
checkout = job["steps"][0]
|
||||
assert checkout["with"]["ref"] == "${{ inputs.sha || github.sha }}"
|
||||
release = load("desktop-bundled-release.yml")["jobs"]
|
||||
caller = release["archive-inputs"]
|
||||
assert caller["needs"] == ["validate"]
|
||||
assert caller["with"]["sha"] == "${{ needs.validate.outputs.sha }}"
|
||||
# The archive lives as a validate step with the job's own gate shape —
|
||||
# a skipped archive (disposable/termux runs) must not skip the builds.
|
||||
validate = release["validate"]
|
||||
(archive,) = [s for s in validate["steps"] if s.get("run") == "python3 -m scripts.ci.archive_inputs"]
|
||||
assert archive["if"] == (
|
||||
"inputs.disposable_run == '' && inputs.disposable_channel == ''"
|
||||
" && (inputs.release-phase == '' || inputs.release-phase == 'candidate')"
|
||||
)
|
||||
assert R2_ENV <= archive["env"].keys()
|
||||
assert validate["environment"] == "release-signing"
|
||||
checkout = validate["steps"][0]
|
||||
assert "actions/checkout" in checkout["uses"]
|
||||
for name in ("build-win32", "build-darwin", "termux-deb"):
|
||||
assert "archive-inputs" in release[name]["needs"]
|
||||
assert "archive-inputs" not in release[name].get("needs", [])
|
||||
|
||||
action = YAML(typ="base").load((ROOT / ".github/actions/setup-pm/action.yml").read_text(encoding="utf-8"))
|
||||
assert action["inputs"]["archive-inputs"]["default"] == "false"
|
||||
|
||||
Reference in New Issue
Block a user