Skip to content

Commit c5f6fb3

Browse files
committed
up
1 parent 1e4a688 commit c5f6fb3

4 files changed

Lines changed: 63 additions & 12 deletions

File tree

.github/workflows/_ci-run-decision.yml

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,11 @@ jobs:
3434
outputs:
3535
is-full-run: ${{ steps.compute.outputs.is-full-run }}
3636
steps:
37-
# Full history needed to compute commit depth via `git rev-list --count`.
38-
# The depth-based sample (every 4th commit) needs the SHA to be reachable
39-
# from the repo root.
37+
# Full history needed to compute commit depth via
38+
# `git rev-list --first-parent --count`. The --first-parent flag
39+
# follows only the linear main-branch history through merge
40+
# commits, so the count maps 1:1 to pushes on main regardless of
41+
# how many commits were in any merged PR.
4042
- name: Checkout
4143
uses: actions/checkout@v4
4244
with:
@@ -65,17 +67,21 @@ jobs:
6567
;;
6668
esac
6769
68-
# Depth-based 25% sample on push: every 4th commit (depth from
69-
# the repo root, mod 4 == 0). Hard guarantees:
70-
# - Exactly 25% sample rate (no statistical variance).
70+
# Depth-based 25% sample on push: every 4th commit on the
71+
# linear main-branch history (depth %% 4 == 0). --first-parent
72+
# is required — plain `git rev-list --count` would walk all
73+
# merge parents, so the count would jump by (1 + PR_size) at
74+
# each merge commit and the sample rate would be unpredictable.
75+
# Hard guarantees with --first-parent:
76+
# - Exactly 25% of pushes on main are sampled.
7177
# - At most 3 non-sampled commits between any two samples.
7278
# Re-runs of the same commit always have the same outcome.
7379
if [ "$IS_FULL" = "false" ] && [ "$EVENT_NAME" = "push" ]; then
74-
DEPTH=$(git rev-list --count "$SHA")
80+
DEPTH=$(git rev-list --first-parent --count "$SHA")
7581
if [ $((DEPTH % 4)) -eq 0 ]; then
7682
IS_FULL=true
7783
fi
78-
echo "Depth: $DEPTH (depth %% 4 = $((DEPTH % 4)))"
84+
echo "Depth: $DEPTH (first-parent; depth %% 4 = $((DEPTH % 4)))"
7985
fi
8086
8187
echo "Event: $EVENT_NAME"

.github/workflows/promote-to-viable-strict.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ on:
3030

3131
permissions:
3232
contents: write
33+
# Needed to delete the failed `viable-strict-gate` run that the
34+
# original push triggered — see the "Delete failed gate runs" step.
35+
actions: write
3336

3437
concurrency:
3538
# One in-flight promotion at a time; safer than racing tag pushes.
@@ -96,3 +99,41 @@ jobs:
9699
git push origin "$TAG"
97100
98101
echo "::notice::Pushed $TAG. Watch the tag-triggered workflow runs (pull / trunk / viable-strict-gate); once they pass, the next update-viablestrict cron (every 30 min) will advance viable/strict."
102+
103+
# Defense-in-depth: the push that originally landed this commit
104+
# triggered a `viable-strict-gate` run that failed (because the
105+
# commit wasn't sampled). The tag push above triggers a NEW run
106+
# of the gate workflow that will succeed. Standard PyTorch viable/
107+
# strict resolves multiple runs by taking the latest conclusion,
108+
# so this is usually fine — but to remove ambiguity (and keep the
109+
# commit's HUD row clean), explicitly delete any prior failed/
110+
# cancelled gate runs on this SHA.
111+
- name: Delete failed viable-strict-gate runs on this SHA
112+
env:
113+
GH_TOKEN: ${{ github.token }}
114+
SHA: ${{ inputs.sha }}
115+
REPO: ${{ github.repository }}
116+
run: |
117+
set -euo pipefail
118+
119+
# List all viable-strict-gate runs for the SHA, filter to
120+
# those that completed unsuccessfully, and delete each one.
121+
# Failures here are non-fatal: the tag push above is the
122+
# primary mechanism; this cleanup is best-effort.
123+
RUNS=$(gh api "repos/$REPO/actions/runs?head_sha=$SHA&per_page=100" \
124+
--jq '.workflow_runs[]
125+
| select(.name == "viable-strict-gate")
126+
| select(.conclusion == "failure" or .conclusion == "cancelled" or .conclusion == "timed_out")
127+
| .id' 2>/dev/null || true)
128+
129+
if [ -z "$RUNS" ]; then
130+
echo "No prior failed viable-strict-gate runs to clean up."
131+
exit 0
132+
fi
133+
134+
while IFS= read -r RUN_ID; do
135+
[ -z "$RUN_ID" ] && continue
136+
echo "Deleting failed viable-strict-gate run $RUN_ID"
137+
gh api -X DELETE "repos/$REPO/actions/runs/$RUN_ID" || \
138+
echo "::warning::Failed to delete run $RUN_ID; continuing anyway."
139+
done <<< "$RUNS"

.github/workflows/pull.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@ concurrency:
1515
cancel-in-progress: true
1616

1717
jobs:
18-
# Emits PR diff file list; non-PR events emit '*' so the per-job
19-
# `if:` short-circuits via `event_name != 'pull_request'`.
18+
# Emits PR diff file list; non-PR events emit '*' (every contains()
19+
# check returns true). Gated jobs combine this with run-decision's
20+
# is-full-run output: on push, jobs run only if a path matches OR
21+
# the commit is a sampled full-run.
2022
changed-files:
2123
name: Get changed files
2224
uses: ./.github/workflows/_get-changed-files.yml

.github/workflows/trunk.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@ concurrency:
1919
cancel-in-progress: true
2020

2121
jobs:
22-
# Emits PR diff file list; non-PR events emit '*' so the per-job
23-
# `if:` short-circuits via `event_name != 'pull_request'`.
22+
# Emits PR diff file list; non-PR events emit '*' (every contains()
23+
# check returns true). Gated jobs combine this with run-decision's
24+
# is-full-run output: on push, jobs run only if a path matches OR
25+
# the commit is a sampled full-run.
2426
changed-files:
2527
name: Get changed files
2628
uses: ./.github/workflows/_get-changed-files.yml

0 commit comments

Comments
 (0)