mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-02 15:04:37 +01:00
v1.92.39.0 ci: main pushes reuse the merged PR's verified run of the same tree; dispatch-ci and --from-run go through the run verifier (GSTA-156 P3b) (#3709)
* feat(pregate): gstack run profiles, dispatch-ci clears through the run verifier, --from-run tests stage (GSTA-156 P3b) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * ci(free-tests): main pushes reuse the merged pull request's verified run of the same tree (GSTA-156 P3b) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * test(cso): the free-tests aggregate still requires cso-docker-integration on its strict path, and only a verified reuse skips it (GSTA-156 P3b) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix(pregate): name the reuse profiles after no lane, so lane clears and ready --dispatch-ci keep the URL path until GST-555 (GSTA-156 P3b) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix(ci): the duration recorder grants actions: read to its windows-free-tests call, and --from-run refuses a run that recorded zero tests (GSTA-156 P3b) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs: pregate run_profiles row, no_verified_run code; changelog for caller grant and zero-test refusal Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --------- Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
ab2852fb40
commit
77fe28c397
24 files changed
+1114
-66
No files matched your search
@@ -71,6 +71,9 @@ jobs:
|
||||
|
||||
windows:
|
||||
uses: ./.github/workflows/windows-free-tests.yml
|
||||
permissions:
|
||||
contents: read
|
||||
actions: read
|
||||
with:
|
||||
record_durations: true
|
||||
|
||||
|
||||
@@ -14,6 +14,15 @@ name: Free Tests
|
||||
# is permanent false comfort.
|
||||
#
|
||||
# Local `bun run test` still uses the existing bounded process pool.
|
||||
#
|
||||
# One full suite per tree (GSTA-156, docs/pregate.md#ci-reuse). The aggregate
|
||||
# uploads a `tested-tree` record (tree.json) only after strict verification
|
||||
# passes. A push to main first runs `reuse`: when the merged pull request's
|
||||
# head has the pushed tree and a green pull_request or workflow_dispatch run of
|
||||
# this workflow verifies (lib/run-evidence.ts), every suite job is skipped and
|
||||
# the aggregate links that run instead. Any other answer, a reuse failure
|
||||
# included, runs every job as before. Pull request and dispatch runs never
|
||||
# consume; reused runs never upload a record, so they are never reused.
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
@@ -54,7 +63,40 @@ permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
# Main pushes only, and the one job with actions: read (it reads this
|
||||
# repository's runs and their tested-tree artifacts). Every suite job below
|
||||
# runs unless this job succeeded and reused a run; a skipped or failed reuse
|
||||
# job runs them all. Their conditions start with !cancelled() because a
|
||||
# skipped needed job would otherwise skip its dependents on pull_request and
|
||||
# dispatch runs, where reuse never runs.
|
||||
reuse:
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 5
|
||||
permissions:
|
||||
contents: read
|
||||
actions: read
|
||||
outputs:
|
||||
reused: ${{ steps.find.outputs.reused }}
|
||||
run_id: ${{ steps.find.outputs.run_id }}
|
||||
run_url: ${{ steps.find.outputs.run_url }}
|
||||
tree: ${{ steps.find.outputs.tree }}
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
with:
|
||||
bun-version: 1.4.2
|
||||
- id: find
|
||||
name: Find a green pull request or dispatch run of this exact tree
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: bun run scripts/ci-tree-reuse.ts find --workflow free-tests.yml --profile ci-reuse/free-tests
|
||||
|
||||
free-plan:
|
||||
needs: reuse
|
||||
if: ${{ !cancelled() && (needs.reuse.result != 'success' || needs.reuse.outputs.reused != 'true') }}
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 5
|
||||
outputs:
|
||||
@@ -106,6 +148,8 @@ jobs:
|
||||
if-no-files-found: error
|
||||
|
||||
cso-macos-launcher:
|
||||
needs: reuse
|
||||
if: ${{ !cancelled() && (needs.reuse.result != 'success' || needs.reuse.outputs.reused != 'true') }}
|
||||
runs-on: macos-latest
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
@@ -144,6 +188,8 @@ jobs:
|
||||
# default, and the job fails if that layout is not symlinked. It also sources
|
||||
# the Codex probe from zsh, macOS's default shell (#3024; no paid call).
|
||||
macos-named-regressions:
|
||||
needs: reuse
|
||||
if: ${{ !cancelled() && (needs.reuse.result != 'success' || needs.reuse.outputs.reused != 'true') }}
|
||||
runs-on: macos-latest
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
@@ -188,6 +234,8 @@ jobs:
|
||||
bun test "${files[@]}"
|
||||
|
||||
cso-windows-launcher:
|
||||
needs: reuse
|
||||
if: ${{ !cancelled() && (needs.reuse.result != 'success' || needs.reuse.outputs.reused != 'true') }}
|
||||
runs-on: windows-latest
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
@@ -216,6 +264,8 @@ jobs:
|
||||
retention-days: 14
|
||||
|
||||
cso-docker-integration:
|
||||
needs: reuse
|
||||
if: ${{ !cancelled() && (needs.reuse.result != 'success' || needs.reuse.outputs.reused != 'true') }}
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
@@ -246,6 +296,8 @@ jobs:
|
||||
DOCKER_HOST: unix:///var/run/docker.sock
|
||||
|
||||
typecheck:
|
||||
needs: reuse
|
||||
if: ${{ !cancelled() && (needs.reuse.result != 'success' || needs.reuse.outputs.reused != 'true') }}
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
@@ -269,6 +321,8 @@ jobs:
|
||||
# the quick tier also runs on it. Its pin equals GSTACK_BUN_DEFAULT;
|
||||
# test/bun-version-drift.test.ts checks this job exists and agrees.
|
||||
quick-bun-default:
|
||||
needs: reuse
|
||||
if: ${{ !cancelled() && (needs.reuse.result != 'success' || needs.reuse.outputs.reused != 'true') }}
|
||||
runs-on: ubicloud-standard-8
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
@@ -365,7 +419,8 @@ jobs:
|
||||
run: xvfb-run -a bun run test:quick
|
||||
|
||||
free-suite:
|
||||
needs: free-plan
|
||||
needs: [free-plan, reuse]
|
||||
if: ${{ !cancelled() && needs.free-plan.result == 'success' && (needs.reuse.result != 'success' || needs.reuse.outputs.reused != 'true') }}
|
||||
runs-on: ${{ needs.free-plan.outputs.runner }}
|
||||
timeout-minutes: 20
|
||||
strategy:
|
||||
@@ -590,13 +645,38 @@ jobs:
|
||||
# Branch protection already requires the `free-tests` context. Keep that
|
||||
# stable name as an always-running aggregate so every platform-specific CSO
|
||||
# gate is merge-blocking without a separate branch-protection migration.
|
||||
# Its first step picks one of two exclusive paths before any download: a
|
||||
# verified reuse (main pushes only) links the reused run and passes; anything
|
||||
# else takes the strict path below unchanged, which alone uploads tested-tree.
|
||||
free-tests:
|
||||
if: always()
|
||||
needs: [free-suite, typecheck, quick-bun-default, cso-macos-launcher, macos-named-regressions, cso-windows-launcher, cso-docker-integration]
|
||||
needs: [reuse, free-suite, typecheck, quick-bun-default, cso-macos-launcher, macos-named-regressions, cso-windows-launcher, cso-docker-integration]
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- name: Take the reuse path only for a verified main-push reuse
|
||||
id: route
|
||||
env:
|
||||
REUSE_RESULT: ${{ needs.reuse.result }}
|
||||
REUSED: ${{ needs.reuse.outputs.reused }}
|
||||
REUSE_RUN_ID: ${{ needs.reuse.outputs.run_id }}
|
||||
REUSE_RUN_URL: ${{ needs.reuse.outputs.run_url }}
|
||||
REUSE_TREE: ${{ needs.reuse.outputs.tree }}
|
||||
run: |
|
||||
set -eu
|
||||
if [ "$REUSE_RESULT" != success ] || [ "$REUSED" != true ]; then
|
||||
echo 'reused=false' >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
test "$GITHUB_EVENT_NAME" = push
|
||||
test "$GITHUB_REF" = refs/heads/main
|
||||
case "$REUSE_RUN_ID" in ''|*[!0-9]*) echo "::error::the reuse job named no run id"; exit 1 ;; esac
|
||||
case "$REUSE_TREE" in ''|*[!0-9a-f]*) echo "::error::the reuse job named no tree"; exit 1 ;; esac
|
||||
test "$REUSE_RUN_URL" = "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$REUSE_RUN_ID"
|
||||
echo "Reused $REUSE_RUN_URL, which passed on tree $REUSE_TREE; this push ran no suite of its own." >> "$GITHUB_STEP_SUMMARY"
|
||||
echo 'reused=true' >> "$GITHUB_OUTPUT"
|
||||
- name: Require the free suite, typecheck, the quick tier on the default Bun, macOS regressions, and every CSO platform gate
|
||||
if: steps.route.outputs.reused != 'true'
|
||||
env:
|
||||
FREE_SUITE_RESULT: ${{ needs.free-suite.result }}
|
||||
TYPECHECK_RESULT: ${{ needs.typecheck.result }}
|
||||
@@ -615,16 +695,20 @@ jobs:
|
||||
test "$CSO_WINDOWS_RESULT" = success
|
||||
test "$CSO_DOCKER_RESULT" = success
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
if: steps.route.outputs.reused != 'true'
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
if: steps.route.outputs.reused != 'true'
|
||||
with:
|
||||
bun-version: 1.4.2
|
||||
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
||||
if: steps.route.outputs.reused != 'true'
|
||||
with:
|
||||
name: free-plan
|
||||
path: ${{ runner.temp }}
|
||||
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
||||
if: steps.route.outputs.reused != 'true'
|
||||
with:
|
||||
pattern: free-result-*
|
||||
merge-multiple: true
|
||||
@@ -633,10 +717,27 @@ jobs:
|
||||
# flake-ledger.jsonl). A green run is where a retried flake hides, so the
|
||||
# summary runs before strict verification.
|
||||
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
||||
if: steps.route.outputs.reused != 'true'
|
||||
with:
|
||||
pattern: flake-ledger-*
|
||||
path: ${{ runner.temp }}/flake-ledgers
|
||||
- name: Summarize flaky passes absorbed by the serial retry
|
||||
if: steps.route.outputs.reused != 'true'
|
||||
run: bun run scripts/test-health-report.ts flake-summary "$RUNNER_TEMP/flake-ledgers" >> "$GITHUB_STEP_SUMMARY"
|
||||
- name: Require exact coverage and complete strict results
|
||||
if: steps.route.outputs.reused != 'true'
|
||||
run: bun run scripts/test-free-shards.ts --ci-verify "$RUNNER_TEMP/free-plan.json" --results "$RUNNER_TEMP/free-results"
|
||||
# Only after strict verification passed, so a red or partial run never
|
||||
# leaves a record; the reuse path never reaches here.
|
||||
- name: Record the tested tree
|
||||
if: steps.route.outputs.reused != 'true'
|
||||
env:
|
||||
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
run: bun run scripts/ci-tree-reuse.ts record --plan "$RUNNER_TEMP/free-plan.json" --results "$RUNNER_TEMP/free-results" --os Linux,macOS,Windows --out "$RUNNER_TEMP/tested-tree/tree.json"
|
||||
- name: Upload the tested tree
|
||||
if: steps.route.outputs.reused != 'true'
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: tested-tree
|
||||
path: ${{ runner.temp }}/tested-tree/tree.json
|
||||
if-no-files-found: error
|
||||
@@ -19,6 +19,12 @@ name: Windows Free Tests
|
||||
#
|
||||
# Native browser qualification campaigns (Windows cookie extraction, launch
|
||||
# diagnostics) are dispatch-only in native-qualification.yml.
|
||||
#
|
||||
# One full suite per tree (GSTA-156, docs/pregate.md#ci-reuse), as in
|
||||
# free-tests.yml: the aggregate uploads `tested-tree` only after strict
|
||||
# verification passes, and a push to main whose merged pull request already
|
||||
# ran this workflow green on the same tree reuses that run. Pull request,
|
||||
# dispatch and duration-recording runs never consume.
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
@@ -50,8 +56,36 @@ permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
# Main pushes only, and the one job with actions: read; see free-tests.yml.
|
||||
# A skipped or failed reuse job runs every job below as before.
|
||||
reuse:
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 5
|
||||
permissions:
|
||||
contents: read
|
||||
actions: read
|
||||
outputs:
|
||||
reused: ${{ steps.find.outputs.reused }}
|
||||
run_id: ${{ steps.find.outputs.run_id }}
|
||||
run_url: ${{ steps.find.outputs.run_url }}
|
||||
tree: ${{ steps.find.outputs.tree }}
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
with:
|
||||
bun-version: 1.4.2
|
||||
- id: find
|
||||
name: Find a green pull request or dispatch run of this exact tree
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: bun run scripts/ci-tree-reuse.ts find --workflow windows-free-tests.yml --profile ci-reuse/windows-free-tests
|
||||
|
||||
windows-plan:
|
||||
if: ${{ !inputs.record_durations }}
|
||||
needs: reuse
|
||||
if: ${{ !cancelled() && !inputs.record_durations && (needs.reuse.result != 'success' || needs.reuse.outputs.reused != 'true') }}
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 5
|
||||
outputs:
|
||||
@@ -79,7 +113,8 @@ jobs:
|
||||
if-no-files-found: error
|
||||
|
||||
windows-free-shard:
|
||||
needs: windows-plan
|
||||
needs: [windows-plan, reuse]
|
||||
if: ${{ !cancelled() && needs.windows-plan.result == 'success' && (needs.reuse.result != 'success' || needs.reuse.outputs.reused != 'true') }}
|
||||
runs-on: windows-latest
|
||||
timeout-minutes: 15
|
||||
strategy:
|
||||
@@ -184,11 +219,33 @@ jobs:
|
||||
|
||||
windows-free-tests:
|
||||
if: ${{ always() && !inputs.record_durations }}
|
||||
needs: [windows-plan, windows-free-shard]
|
||||
needs: [reuse, windows-plan, windows-free-shard]
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- name: Take the reuse path only for a verified main-push reuse
|
||||
id: route
|
||||
env:
|
||||
REUSE_RESULT: ${{ needs.reuse.result }}
|
||||
REUSED: ${{ needs.reuse.outputs.reused }}
|
||||
REUSE_RUN_ID: ${{ needs.reuse.outputs.run_id }}
|
||||
REUSE_RUN_URL: ${{ needs.reuse.outputs.run_url }}
|
||||
REUSE_TREE: ${{ needs.reuse.outputs.tree }}
|
||||
run: |
|
||||
set -eu
|
||||
if [ "$REUSE_RESULT" != success ] || [ "$REUSED" != true ]; then
|
||||
echo 'reused=false' >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
test "$GITHUB_EVENT_NAME" = push
|
||||
test "$GITHUB_REF" = refs/heads/main
|
||||
case "$REUSE_RUN_ID" in ''|*[!0-9]*) echo "::error::the reuse job named no run id"; exit 1 ;; esac
|
||||
case "$REUSE_TREE" in ''|*[!0-9a-f]*) echo "::error::the reuse job named no tree"; exit 1 ;; esac
|
||||
test "$REUSE_RUN_URL" = "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$REUSE_RUN_ID"
|
||||
echo "Reused $REUSE_RUN_URL, which passed on tree $REUSE_TREE; this push ran no suite of its own." >> "$GITHUB_STEP_SUMMARY"
|
||||
echo 'reused=true' >> "$GITHUB_OUTPUT"
|
||||
- name: Require the plan and every Windows shard
|
||||
if: steps.route.outputs.reused != 'true'
|
||||
env:
|
||||
PLAN_RESULT: ${{ needs.windows-plan.result }}
|
||||
SHARD_RESULT: ${{ needs.windows-free-shard.result }}
|
||||
@@ -197,22 +254,40 @@ jobs:
|
||||
test "$PLAN_RESULT" = success
|
||||
test "$SHARD_RESULT" = success
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
if: steps.route.outputs.reused != 'true'
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
if: steps.route.outputs.reused != 'true'
|
||||
with:
|
||||
bun-version: 1.4.2
|
||||
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
||||
if: steps.route.outputs.reused != 'true'
|
||||
with:
|
||||
name: windows-plan
|
||||
path: ${{ runner.temp }}
|
||||
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
||||
if: steps.route.outputs.reused != 'true'
|
||||
with:
|
||||
pattern: windows-result-*
|
||||
merge-multiple: true
|
||||
path: ${{ runner.temp }}/windows-results
|
||||
- name: Require exact coverage and complete strict results
|
||||
if: steps.route.outputs.reused != 'true'
|
||||
run: bun run scripts/test-free-shards.ts --windows-only --ci-verify "$RUNNER_TEMP/windows-plan.json" --results "$RUNNER_TEMP/windows-results"
|
||||
# Only after strict verification passed; the reuse path never reaches here.
|
||||
- name: Record the tested tree
|
||||
if: steps.route.outputs.reused != 'true'
|
||||
env:
|
||||
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
run: bun run scripts/ci-tree-reuse.ts record --plan "$RUNNER_TEMP/windows-plan.json" --results "$RUNNER_TEMP/windows-results" --os Windows --out "$RUNNER_TEMP/tested-tree/tree.json"
|
||||
- name: Upload the tested tree
|
||||
if: steps.route.outputs.reused != 'true'
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: tested-tree
|
||||
path: ${{ runner.temp }}/tested-tree/tree.json
|
||||
if-no-files-found: error
|
||||
|
||||
windows-record-durations:
|
||||
if: ${{ inputs.record_durations }}
|
||||
|
||||
Reference in new issue
Block a user