mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-13 11:57:19 +01:00
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> # Conflicts: # test/ship-queue-train.test.ts
65 lines
3.4 KiB
TypeScript
65 lines
3.4 KiB
TypeScript
/** Train setups shared by the test/ship-queue-train*.test.ts files (moved from test/ship-queue-train.test.ts, GSTA-151). */
|
|
import { expect } from 'bun:test';
|
|
import { spawnSync } from 'node:child_process';
|
|
import * as fs from 'node:fs';
|
|
import * as path from 'node:path';
|
|
import { mergeChangelogs } from '../../lib/changelog-check';
|
|
import { EXIT } from '../../lib/headless-artifacts';
|
|
import { runBin } from './restamp-fixture';
|
|
import { GREEN_GATE, line, nonceOf, openPr, queue, readyReceipt, type Rule, type TrainFixture } from './ship-queue-train-fixture';
|
|
|
|
export function twoPrTrain(fx: TrainFixture, gate: Rule = GREEN_GATE) {
|
|
const h1 = openPr(fx, '1');
|
|
const h2 = openPr(fx, '2');
|
|
readyReceipt(fx, '1', h1);
|
|
readyReceipt(fx, '2', h2);
|
|
fx.write(d => { d.rules['evals.yml'] = gate; });
|
|
const r = queue(fx, ['train', 'build', '--prs', `1@${h1},2@${h2}`]);
|
|
return { h1, h2, r, nonce: nonceOf(r.out) };
|
|
}
|
|
|
|
/** A main commit with a prefix's tree plus a VERSION stamp, the way stamp-at-merge publishes it. */
|
|
export function publishMain(fx: TrainFixture, prefixCommit: string, version: string, extra?: { file: string; text: string }): string {
|
|
const { repo } = fx;
|
|
repo.git('checkout', '-q', '-B', 'mainsim', 'origin/main');
|
|
repo.git('rm', '-rq', '.');
|
|
repo.git('checkout', prefixCommit, '--', '.');
|
|
fs.writeFileSync(path.join(repo.work, 'VERSION'), version + '\n');
|
|
if (extra) fs.writeFileSync(path.join(repo.work, extra.file), extra.text);
|
|
repo.git('add', '-A');
|
|
repo.git('commit', '-q', '-m', `merge to ${version}`);
|
|
repo.git('push', '-q', 'origin', 'HEAD:refs/heads/main');
|
|
repo.git('fetch', '-q', 'origin');
|
|
return repo.git('rev-parse', 'HEAD');
|
|
}
|
|
|
|
/** The lane's slot stamp on its pin (main merged in first from slot 2 on): gstack-restamp --next, then the stamp files committed and pushed as the PR head. */
|
|
export function laneStamp(fx: TrainFixture, pr: string, pin: string, o: { mergeMain?: boolean; dropStamp?: boolean } = {}): string {
|
|
const { repo } = fx;
|
|
repo.git('reset', '-q', '--hard');
|
|
repo.git('fetch', '-q', 'origin');
|
|
repo.git('checkout', '-q', '-B', `lane${pr}`, pin);
|
|
if (o.mergeMain) {
|
|
const m = spawnSync('git', ['merge', '--no-ff', '--no-commit', '-q', 'origin/main'], { cwd: repo.work, encoding: 'utf8', timeout: 30_000, env: { ...process.env, ...repo.env } });
|
|
if (m.status !== 0) {
|
|
const side = (n: number) => repo.git('show', `:${n}:CHANGELOG.md`) + '\n';
|
|
fs.writeFileSync(path.join(repo.work, 'CHANGELOG.md'), mergeChangelogs(side(2), side(3), side(1))!);
|
|
repo.git('add', 'CHANGELOG.md');
|
|
}
|
|
}
|
|
const index = repo.git('write-tree');
|
|
const stamp = runBin(repo, 'gstack-restamp', ['--next', '--base', 'main', '--allow-repo-commands'], fx.env);
|
|
expect(stamp.status, stamp.err).toBe(EXIT.ok);
|
|
const files = line(stamp.out, 'FILES:').slice('FILES: '.length).split(' ').filter(Boolean);
|
|
if (o.dropStamp) repo.git('read-tree', index);
|
|
else repo.git('add', '-A', '--', ...files);
|
|
repo.git('commit', '-q', '--no-edit', '-m', `slot stamp #${pr}`);
|
|
if (o.dropStamp) repo.git('checkout', '-q', '--', '.');
|
|
const head = repo.git('rev-parse', 'HEAD');
|
|
repo.git('push', '-q', '-f', 'origin', `${head}:refs/pull/${pr}/head`);
|
|
return head;
|
|
}
|
|
|
|
/** GitHub reports the PR MERGED, which verify --train needs before it confirms a merge (#3531). */
|
|
export const markMerged = (fx: TrainFixture, pr: string) => fx.write(d => { (d.prs[pr] as any).state = 'MERGED'; });
|