ci(seed): keep maintainer commits on the open seed PR, publish only from main, survive long ratchet reports

/review on #3253 (gpt-6.1-sol): a refresh force-pushed over maintainer repairs
on the seed PR, a dispatch from a feature branch would publish that branch's
commits, and grep | head under pipefail could abort the step on a long ratchet
report. The refresh now leaves an open seed PR alone when it holds any commit
besides the bot's one refresh commit and pushes with an exact lease; only main
publishes; the report is cut with sed. Each has a functional test that fails on
the old workflow.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
garrytanandcapy-ai[bot] committed 2026-10-17 18:14:45 +00:00
1 parent 7177605e8f
commit 546a838f84
3 files changed
+89 -8

No files matched your search

+16 -6
View File
@@ -101,7 +101,7 @@ jobs:
- name: Open or refresh the seed PR when either seed's file set changed
env:
GH_TOKEN: ${{ github.token }}
OPEN_PR: ${{ github.event_name == 'schedule' || inputs.open_pr }}
OPEN_PR: ${{ github.ref == 'refs/heads/main' && (github.event_name == 'schedule' || inputs.open_pr) }}
run: |
set -euo pipefail
linux_failed=$(wc -l < "$RUNNER_TEMP/linux/record-failures.txt")
@@ -127,22 +127,32 @@ jobs:
if ratchet=$(GSTACK_FREE_SEED_BASE="$(git rev-parse HEAD)" bun test test/free-seed-ratchet.test.ts 2>&1); then
ratchet_line="passes"
else
ratchet_line="FAILS; a maintainer must split the named file or add an annotated allowlist entry on this branch before merge:"$'\n\n'"\`\`\`"$'\n'"$(printf '%s\n' "$ratchet" | grep -E 'Free seed ratchet|^- ' | head -20)"$'\n'"\`\`\`"
ratchet_line="FAILS; a maintainer must split the named file or add an annotated allowlist entry on this branch before merge:"$'\n\n'"\`\`\`"$'\n'"$(printf '%s\n' "$ratchet" | sed -n -E '/Free seed ratchet|^- /p' | sed -n '1,20p')"$'\n'"\`\`\`"
fi
failed_line="Linux: $(failures "$RUNNER_TEMP/linux/record-failures.txt"); Windows: $(failures "$RUNNER_TEMP/windows/record-failures.txt")"
echo "Seed growth ratchet: $ratchet_line" >> "$GITHUB_STEP_SUMMARY"
echo "Failed while recording: $failed_line" | tee -a "$GITHUB_STEP_SUMMARY"
if [ "$OPEN_PR" != true ]; then
echo "open_pr=false: recorded and reported only." | tee -a "$GITHUB_STEP_SUMMARY"
echo "Report only (open_pr=false, or a ref other than main): no branch pushed." | tee -a "$GITHUB_STEP_SUMMARY"
exit 0
fi
branch=bot/free-duration-seeds
subject="test(seed): refresh the free-suite duration seeds from the weekly recording"
number=$(gh pr list --head "$branch" --state open --json number -q '.[0].number // empty')
remote_head=
if git fetch -q origin "+refs/heads/$branch:refs/remotes/origin/$branch" 2>/dev/null; then
remote_head=$(git rev-parse "origin/$branch")
fi
if [ -n "$number" ] && [ -n "$remote_head" ] && [ "$(git log --format=%s "HEAD..$remote_head")" != "$subject" ]; then
echo "::warning::Seed PR #$number has commits besides the bot's one refresh commit; this run leaves them in place. Merge or close that PR and the next run refreshes the seeds." | tee -a "$GITHUB_STEP_SUMMARY"
exit 0
fi
git switch -C "$branch"
git config user.name github-actions[bot]
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
git add scripts/free-test-durations.json scripts/free-test-durations-windows.json
git commit -m "test(seed): refresh the free-suite duration seeds from the weekly recording"
git push --force origin "$branch"
git commit -m "$subject"
git push --force-with-lease="refs/heads/$branch:$remote_head" origin "HEAD:refs/heads/$branch"
cat > pr-body.md <<EOF
Weekly recording from run $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID on $GITHUB_SHA.
@@ -153,7 +163,7 @@ jobs:
Data only. Stamp and merge per docs/ship-policy.md; the stamp push runs the full PR checks.
EOF
if number=$(gh pr list --head "$branch" --state open --json number -q '.[0].number') && [ -n "$number" ]; then
if [ -n "$number" ]; then
gh pr edit "$number" --body-file pr-body.md
else
gh pr create --base main --head "$branch" --title "test(seed): refresh the free-suite duration seeds" --body-file pr-body.md
+3 -1
View File
@@ -1200,7 +1200,9 @@ refresh to a maintainer.
free checks decide whether the tree is healthy. An interrupted recording
uploads no seed, and more than 5 red files on either OS proposes nothing. The
bot never edits the allowlist: a ratchet failure is fixed on the branch by a
maintainer before the PR merges.
maintainer before the PR merges, and while the open seed PR holds any commit
besides the bot's one refresh commit, later runs leave it alone. Only runs on
`main` push the branch; a dispatch from another ref reports only.
### Windows free lane
+70 -1
View File
@@ -82,11 +82,80 @@ test('the propose step touches only the two seeds, never the allowlist, on one b
expect(script).toContain('branch=bot/free-duration-seeds');
expect(script).toContain('bun test test/free-seed-ratchet.test.ts');
expect(script).toContain('gh workflow run free-tests.yml');
expect(proposeStep.env.OPEN_PR).toBe("${{ github.event_name == 'schedule' || inputs.open_pr }}");
expect(proposeStep.env.OPEN_PR).toBe("${{ github.ref == 'refs/heads/main' && (github.event_name == 'schedule' || inputs.open_pr) }}");
expect(script.indexOf('if [ "$OPEN_PR" != true ]')).toBeLessThan(script.indexOf('git push'));
expect(recorder.on.workflow_dispatch.inputs.open_pr).toMatchObject({ type: 'boolean', default: true });
});
test('a long ratchet report reaches the PR body instead of aborting the step under pipefail', () => {
const script: string = proposeStep.run;
const line = script.split('\n').find(entry => entry.trimStart().startsWith('ratchet_line="FAILS'))!.trim();
const ratchet = ['error: Free seed ratchet:', ...Array.from({ length: 3000 }, (_, i) => `- test/f${i}.test.ts is seeded at 61s, over the 60s ceiling. Fix: split it, then rerun the recording.`)].join('\n');
const dir = mkdtempSync(path.join(os.tmpdir(), 'seed-ratchet-'));
dirs.push(dir);
writeFileSync(path.join(dir, 'ratchet.txt'), ratchet);
const result = spawnSync('bash', ['-c', `set -euo pipefail\nratchet=$(cat "$1")\n${line}\nprintf '%s' "$ratchet_line"`, 'ratchet', path.join(dir, 'ratchet.txt')], { encoding: 'utf8', timeout: 10_000 });
expect(result.status, result.stderr).toBe(0);
expect(result.stdout).toContain('- test/f18.test.ts is seeded at 61s, over');
expect(result.stdout).not.toContain('- test/f19.test.ts');
});
test('a refresh keeps a maintainer\'s commits on the open seed PR and leases the bot branch it replaces', () => {
const script: string = proposeStep.run;
const publish = script.slice(script.indexOf('branch=bot/free-duration-seeds'), script.indexOf('cat > pr-body.md'));
const dir = mkdtempSync(path.join(os.tmpdir(), 'seed-publish-'));
dirs.push(dir);
const env = Object.fromEntries(Object.entries(process.env).filter(([key]) => !key.startsWith('GIT_')));
const git = (cwd: string, ...args: string[]) => {
const result = spawnSync('git', args, { cwd, encoding: 'utf8', timeout: 10_000, env });
expect(result.status, result.stderr).toBe(0);
return result.stdout.trim();
};
const origin = path.join(dir, 'origin.git');
const work = path.join(dir, 'work');
git(dir, 'init', '-q', '--bare', '-b', 'main', origin);
git(dir, 'clone', '-q', origin, work);
const commit = (email: string, file: string, message: string) => {
git(work, 'config', 'user.name', email);
git(work, 'config', 'user.email', email);
writeFileSync(path.join(work, file), message);
git(work, 'add', file);
git(work, 'commit', '-q', '-m', message);
};
for (const file of ['free-test-durations.json', 'free-test-durations-windows.json']) {
writeFileSync(path.join(work, file), '{}');
}
git(work, 'checkout', '-q', '-b', 'main');
commit('dev@example.com', 'README', 'main');
git(work, 'push', '-q', 'origin', 'main');
const subject = 'test(seed): refresh the free-suite duration seeds from the weekly recording';
git(work, 'checkout', '-q', '-b', 'bot/free-duration-seeds');
commit('bot@example.com', 'seed.txt', subject);
git(work, 'push', '-q', 'origin', 'bot/free-duration-seeds');
const stub = path.join(dir, 'bin');
spawnSync('mkdir', [stub], { timeout: 10_000 });
writeFileSync(path.join(stub, 'gh'), '#!/bin/sh\necho 7\n', { mode: 0o755 });
const run = () => {
git(work, 'checkout', '-q', 'main');
spawnSync('mkdir', ['-p', path.join(work, 'scripts')], { timeout: 10_000 });
writeFileSync(path.join(work, 'scripts/free-test-durations.json'), `{"run":${Date.now()}}`);
writeFileSync(path.join(work, 'scripts/free-test-durations-windows.json'), '{}');
const result = spawnSync('bash', ['-c', `set -euo pipefail\n${publish}`], { cwd: work, encoding: 'utf8', timeout: 20_000,
env: { ...env, PATH: `${stub}:${process.env.PATH}`, GITHUB_STEP_SUMMARY: path.join(dir, 'summary.md') } });
expect(result.status, result.stderr).toBe(0);
return git(origin, 'rev-parse', 'refs/heads/bot/free-duration-seeds');
};
const replaced = run();
expect(git(origin, 'log', '--format=%s', `main..${replaced}`)).toBe(subject);
expect(git(origin, 'show', `${replaced}:scripts/free-test-durations.json`)).toContain('"run"');
git(work, 'checkout', '-q', '-B', 'bot/free-duration-seeds', replaced);
commit('maintainer@example.com', 'allowlist.json', 'maintainer repair');
git(work, 'push', '-q', 'origin', 'HEAD:refs/heads/bot/free-duration-seeds');
const repaired = git(origin, 'rev-parse', 'refs/heads/bot/free-duration-seeds');
expect(run()).toBe(repaired);
expect(readFileSync(path.join(dir, 'summary.md'), 'utf8')).toContain("Seed PR #7 has commits besides the bot's one refresh commit");
});
test('the drift check counts added and removed files, so an unchanged file set proposes nothing', () => {
const script: string = proposeStep.run;
const drift = script.slice(script.indexOf('drift() {'), script.indexOf('\n}', script.indexOf('drift() {')) + 2);