From 26027c7321390cc59be5247f36d4b3b43c7b6ca8 Mon Sep 17 00:00:00 2001 From: Chris Llanwarne Date: Fri, 7 Aug 2026 17:34:39 -0400 Subject: [PATCH 1/4] run quick checks only on the head of stacks --- .github/workflows/static-and-unit-tests.yml | 48 ++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/.github/workflows/static-and-unit-tests.yml b/.github/workflows/static-and-unit-tests.yml index 67be05d17ff..789cdcc4807 100644 --- a/.github/workflows/static-and-unit-tests.yml +++ b/.github/workflows/static-and-unit-tests.yml @@ -13,8 +13,31 @@ env: PYTHONPATH: hail/python:auth:batch:ci:gear:monitoring:website:web_common jobs: + should-run: + name: Should run checks + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + run: ${{ steps.check.outputs.run }} + steps: + - id: check + # Run checks on standalone PRs targeting main, and on the tail of a + # stack (the final PR, which accumulates all changes). Skip intermediates. + # github.event.pull_request.stack is null when not part of a stack. + # Within a stack, position and size are 1-based; position==size is tail. + run: | + if [[ "${{ github.event.pull_request.stack == null }}" == "true" ]] \ + || [[ "${{ github.event.pull_request.stack != null && github.event.pull_request.stack.position == github.event.pull_request.stack.size }}" == "true" ]] \ + || [[ "${{ contains(github.event.pull_request.labels.*.name, 'mergeable') }}" == "true" ]]; then + echo "run=true" >> "$GITHUB_OUTPUT" + else + echo "run=false" >> "$GITHUB_OUTPUT" + fi + check-pip-requirements: name: Check pip requirements + needs: should-run + if: needs.should-run.outputs.run == 'true' runs-on: ubuntu-latest timeout-minutes: 10 steps: @@ -36,10 +59,17 @@ jobs: check-services: name: Check services + needs: should-run + if: needs.should-run.outputs.run == 'true' runs-on: ubuntu-latest timeout-minutes: 15 env: - HAIL_TARGET_SHA: ${{ github.event.pull_request.base.sha }} + # For stacked PRs, use the stack's ultimate base (main HEAD) rather than + # the direct base (another PR's branch), so check-sql.sh diffs correctly. + HAIL_TARGET_SHA: >- + ${{ github.event.pull_request.stack != null && + github.event.pull_request.stack.base.sha || + github.event.pull_request.base.sha }} steps: - uses: actions/checkout@v4 with: @@ -72,6 +102,8 @@ jobs: # Runs ruff, pyright, pylint on hail Python code. Skips Scala format and # scalafix checks via Mill because they raised runtime too high. name: Check hail fast + needs: should-run + if: needs.should-run.outputs.run == 'true' runs-on: ubuntu-latest timeout-minutes: 15 steps: @@ -104,6 +136,8 @@ jobs: test-gcp-ar-cleanup: name: Test GCP AR cleanup policies + needs: should-run + if: needs.should-run.outputs.run == 'true' runs-on: ubuntu-latest timeout-minutes: 5 steps: @@ -131,6 +165,8 @@ jobs: test-ci-unit: name: Test CI unit + needs: should-run + if: needs.should-run.outputs.run == 'true' runs-on: ubuntu-latest timeout-minutes: 20 steps: @@ -179,6 +215,8 @@ jobs: test-auth: name: Test auth + needs: should-run + if: needs.should-run.outputs.run == 'true' runs-on: ubuntu-latest timeout-minutes: 10 steps: @@ -224,6 +262,8 @@ jobs: test-batch-unit: name: Test batch unit + needs: should-run + if: needs.should-run.outputs.run == 'true' runs-on: ubuntu-latest timeout-minutes: 10 steps: @@ -271,6 +311,8 @@ jobs: check-ui: name: Check UI + needs: should-run + if: needs.should-run.outputs.run == 'true' runs-on: ubuntu-latest timeout-minutes: 10 steps: @@ -292,6 +334,8 @@ jobs: test-ci-envoy: name: Test CI envoy + needs: should-run + if: needs.should-run.outputs.run == 'true' runs-on: ubuntu-latest timeout-minutes: 10 steps: @@ -340,6 +384,7 @@ jobs: name: Gate if: always() needs: + - should-run - check-pip-requirements - check-services - check-hail-fast @@ -353,6 +398,7 @@ jobs: timeout-minutes: 1 steps: - name: Verify all checks passed + if: needs.should-run.outputs.run == 'true' run: | results=( \ "${{ needs.check-pip-requirements.result }}" \ From da1e2ea60c93b25b7154af9936965441e8dbce08 Mon Sep 17 00:00:00 2001 From: Chris Llanwarne Date: Fri, 7 Aug 2026 17:39:39 -0400 Subject: [PATCH 2/4] gate passes for skipped check PRs --- .github/workflows/static-and-unit-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/static-and-unit-tests.yml b/.github/workflows/static-and-unit-tests.yml index 789cdcc4807..fefe01ae633 100644 --- a/.github/workflows/static-and-unit-tests.yml +++ b/.github/workflows/static-and-unit-tests.yml @@ -398,8 +398,8 @@ jobs: timeout-minutes: 1 steps: - name: Verify all checks passed - if: needs.should-run.outputs.run == 'true' run: | + [[ "${{ needs.should-run.outputs.run }}" != "true" ]] && exit 0 results=( \ "${{ needs.check-pip-requirements.result }}" \ "${{ needs.check-services.result }}" \ From c1245c0c0c41ad41cbaea9f1d7563af257bbdb67 Mon Sep 17 00:00:00 2001 From: Chris Llanwarne Date: Thu, 27 Aug 2026 16:19:03 -0400 Subject: [PATCH 3/4] run on stack base too --- .github/workflows/static-and-unit-tests.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/static-and-unit-tests.yml b/.github/workflows/static-and-unit-tests.yml index fefe01ae633..bad2cd5219c 100644 --- a/.github/workflows/static-and-unit-tests.yml +++ b/.github/workflows/static-and-unit-tests.yml @@ -21,13 +21,12 @@ jobs: run: ${{ steps.check.outputs.run }} steps: - id: check - # Run checks on standalone PRs targeting main, and on the tail of a - # stack (the final PR, which accumulates all changes). Skip intermediates. - # github.event.pull_request.stack is null when not part of a stack. - # Within a stack, position and size are 1-based; position==size is tail. + # Run on standalone PRs targeting main, the first PR in a stack + # (position == 1, which targets main directly), or any stacked PR + # with a 'mergeable' label. Skip all other stack intermediates. run: | if [[ "${{ github.event.pull_request.stack == null }}" == "true" ]] \ - || [[ "${{ github.event.pull_request.stack != null && github.event.pull_request.stack.position == github.event.pull_request.stack.size }}" == "true" ]] \ + || [[ "${{ github.event.pull_request.stack != null && github.event.pull_request.stack.position == 1 }}" == "true" ]] \ || [[ "${{ contains(github.event.pull_request.labels.*.name, 'mergeable') }}" == "true" ]]; then echo "run=true" >> "$GITHUB_OUTPUT" else From e7ce165fc32ddfc8d938799d58fd57d2a8c41d1a Mon Sep 17 00:00:00 2001 From: Chris Llanwarne Date: Thu, 3 Sep 2026 15:46:43 -0400 Subject: [PATCH 4/4] thanks copilot --- .github/workflows/static-and-unit-tests.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/static-and-unit-tests.yml b/.github/workflows/static-and-unit-tests.yml index bad2cd5219c..e88e3346106 100644 --- a/.github/workflows/static-and-unit-tests.yml +++ b/.github/workflows/static-and-unit-tests.yml @@ -398,6 +398,10 @@ jobs: steps: - name: Verify all checks passed run: | + if [[ "${{ needs.should-run.result }}" != "success" ]]; then + echo "should-run job failed; cannot determine whether to run checks." + exit 1 + fi [[ "${{ needs.should-run.outputs.run }}" != "true" ]] && exit 0 results=( \ "${{ needs.check-pip-requirements.result }}" \