@intentius/chant 0.124.29 → 0.124.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/handlers/build.d.ts.map +1 -1
- package/dist/cli/handlers/build.js +4 -1
- package/dist/cli/handlers/fan-out.d.ts.map +1 -1
- package/dist/cli/handlers/fan-out.js +27 -5
- package/dist/cli/handlers/pr.d.ts.map +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +30 -0
- package/dist/cli/parse-args.d.ts.map +1 -1
- package/dist/cli/parse-args.js +49 -0
- package/dist/cli/registry.d.ts +17 -1
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/components/pr-pipeline.d.ts +24 -0
- package/dist/components/pr-pipeline.d.ts.map +1 -1
- package/dist/components/pr-pipeline.js +16 -0
- package/dist/components/pr-run.d.ts +20 -2
- package/dist/components/pr-run.d.ts.map +1 -1
- package/dist/components/pr-run.js +26 -13
- package/dist/components/wave-plan.d.ts +11 -0
- package/dist/components/wave-plan.d.ts.map +1 -1
- package/dist/components/wave-plan.js +26 -0
- package/dist/lifecycle/release-ledger.d.ts +8 -3
- package/dist/lifecycle/release-ledger.d.ts.map +1 -1
- package/dist/lifecycle/release-ledger.js +2 -0
- package/dist/lifecycle/run-ledger.d.ts +1 -1
- package/dist/lifecycle/run-ledger.d.ts.map +1 -1
- package/dist/lifecycle/run-ledger.js +9 -0
- package/dist/op/activities/activity-contracts.d.ts +1 -0
- package/dist/op/activities/activity-contracts.d.ts.map +1 -1
- package/dist/op/activities/activity-contracts.js +1 -0
- package/dist/op/activities/shell.d.ts +6 -0
- package/dist/op/activities/shell.d.ts.map +1 -1
- package/dist/op/activities/shell.js +1 -1
- package/dist/op/local-executor.d.ts +23 -1
- package/dist/op/local-executor.d.ts.map +1 -1
- package/dist/op/local-executor.js +9 -3
- package/dist/op/runtime.d.ts +27 -0
- package/dist/op/runtime.d.ts.map +1 -1
- package/dist/op/runtime.js +20 -0
- package/dist/pr-forge.d.ts +23 -0
- package/dist/pr-forge.d.ts.map +1 -1
- package/dist/pr-forge.js +44 -0
- package/dist/pr-loop.d.ts +10 -0
- package/dist/pr-loop.d.ts.map +1 -1
- package/dist/pr-loop.js +7 -0
- package/dist/run-event-stream.d.ts +2 -2
- package/dist/run-event-stream.d.ts.map +1 -1
- package/dist/run-event-stream.js +2 -2
- package/dist/run-event.d.ts +15 -0
- package/dist/run-event.d.ts.map +1 -1
- package/dist/run-event.js +2 -0
- package/dist/wave-runtime.mjs +171 -171
- package/dist/workspace/ci-green-forge.d.ts +2 -0
- package/dist/workspace/ci-green-forge.d.ts.map +1 -1
- package/dist/workspace/ci-green.d.ts +2 -0
- package/dist/workspace/ci-green.d.ts.map +1 -1
- package/dist/workspace/ci-green.js +4 -2
- package/dist/workspace/ci-run.d.ts +222 -0
- package/dist/workspace/ci-run.d.ts.map +1 -0
- package/dist/workspace/ci-run.js +464 -0
- package/dist/workspace/ci-serve.d.ts +214 -0
- package/dist/workspace/ci-serve.d.ts.map +1 -0
- package/dist/workspace/ci-serve.js +412 -0
- package/dist/workspace/pr-report.schema.json +5 -0
- package/dist/workspace/run-event.schema.json +14 -3
- package/dist/workspace/status-stewards.d.ts +2 -0
- package/dist/workspace/status-stewards.d.ts.map +1 -1
- package/dist/workspace/status-stewards.js +1 -0
- package/dist/workspace/status.schema.json +12 -1
- package/package.json +1 -1
- package/src/cli/handlers/build.test.ts +15 -0
- package/src/cli/handlers/build.ts +4 -1
- package/src/cli/handlers/fan-out.test.ts +82 -0
- package/src/cli/handlers/fan-out.ts +34 -5
- package/src/cli/handlers/pr.ts +5 -0
- package/src/cli/main.ts +30 -0
- package/src/cli/parse-args.ts +35 -0
- package/src/cli/registry.ts +17 -1
- package/src/components/pr-pipeline.ts +32 -0
- package/src/components/pr-run.test.ts +127 -0
- package/src/components/pr-run.ts +32 -12
- package/src/components/wave-plan.ts +30 -0
- package/src/lifecycle/release-ledger.ts +9 -3
- package/src/lifecycle/run-ledger.ts +7 -1
- package/src/op/activities/activity-contracts.ts +1 -0
- package/src/op/activities/shell.ts +7 -1
- package/src/op/local-executor.ts +27 -4
- package/src/op/runtime.ts +42 -0
- package/src/pr-forge.test.ts +25 -0
- package/src/pr-forge.ts +62 -0
- package/src/pr-loop.test.ts +13 -1
- package/src/pr-loop.ts +16 -0
- package/src/run-event-stream.ts +4 -3
- package/src/run-event.ts +17 -0
- package/src/workspace/ci-green-forge.ts +2 -0
- package/src/workspace/ci-green.ts +6 -2
- package/src/workspace/ci-run.test.ts +416 -0
- package/src/workspace/ci-run.ts +571 -0
- package/src/workspace/ci-serve.test.ts +268 -0
- package/src/workspace/ci-serve.ts +521 -0
- package/src/workspace/pr-report.schema.json +5 -0
- package/src/workspace/run-event.schema.json +14 -3
- package/src/workspace/status-stewards.ts +3 -0
- package/src/workspace/status.schema.json +12 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ci-serve.d.ts","sourceRoot":"","sources":["../../src/workspace/ci-serve.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `chant ci serve` (#4095, epic #4101): the chant runner's trigger loop on one
|
|
3
|
+
* host. It polls the forge for the open pull requests into the target branch
|
|
4
|
+
* and for the branch's head, and runs the pull-request jobs with
|
|
5
|
+
* {@link ciRun} (./ci-run.ts): `plan` for each new pull request head, and
|
|
6
|
+
* `apply` for each new commit on the target branch, measured from the head
|
|
7
|
+
* the previous poll saw (the push's `before`).
|
|
8
|
+
*
|
|
9
|
+
* - Dedupe. A state file in the state directory keeps every job it started,
|
|
10
|
+
* keyed by job and commit (`plan:<pr>:<sha>`, `apply:<sha>`), with how it
|
|
11
|
+
* ended, and the target head the last apply was measured to. A job already
|
|
12
|
+
* in it is not started again, unless it failed and `rerunFailed` asks for
|
|
13
|
+
* it: the forge's "re-run failed jobs".
|
|
14
|
+
* - One apply per group. An apply takes the git-ref lease (../lifecycle/lease.ts,
|
|
15
|
+
* the one `chant operator` holds) named for `prApplyGroup`, renews it while
|
|
16
|
+
* it runs and releases it after. An apply that finds it held waits for a
|
|
17
|
+
* later poll, as a forge's concurrency group queues it.
|
|
18
|
+
* - Resume records. Each apply gets `<state>/resume/<prApplyRecordKey>.json`
|
|
19
|
+
* as its `--resume` record, so a re-run of a failed apply at the same
|
|
20
|
+
* commit finishes under the approval it has. This replaces the forge's CI
|
|
21
|
+
* cache.
|
|
22
|
+
* - Capacity. At most `maxJobs` jobs run at once. A job over the limit is not
|
|
23
|
+
* recorded, so a later poll starts it.
|
|
24
|
+
*
|
|
25
|
+
* Host mode only: each job runs in a fresh worktree on this host as this
|
|
26
|
+
* user, with the clean environment `ciRun` gives it. A pull request from a
|
|
27
|
+
* fork is never planned, and with `authors` only those people's pull requests
|
|
28
|
+
* are. Container isolation is #4015.
|
|
29
|
+
*
|
|
30
|
+
* A webhook is not here yet. {@link ciServeSchedule} takes triggers, and
|
|
31
|
+
* {@link ciServeObserve} is the poll that makes them; a webhook handler would
|
|
32
|
+
* turn a checked payload into the same triggers and schedule them.
|
|
33
|
+
*/
|
|
34
|
+
import { execFileSync } from "node:child_process";
|
|
35
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
36
|
+
import { isAbsolute, join, resolve } from "node:path";
|
|
37
|
+
import { prApplyGroup, prApplyRecordKey } from "../components/pr-pipeline.js";
|
|
38
|
+
import { forgeFromEnv } from "../pr-forge.js";
|
|
39
|
+
import { formatError, formatWarning } from "../cli/format.js";
|
|
40
|
+
import { acquireLease, currentHolderId, releaseLease, DEFAULT_LEASE_TTL_MS } from "../lifecycle/lease.js";
|
|
41
|
+
import { parseDuration } from "../op/duration.js";
|
|
42
|
+
import { CI_JOB_OPS, ciJobPlace, ciRun, CiRunError } from "./ci-run.js";
|
|
43
|
+
import { RUNNER_KEY_ENV } from "./ci-green.js";
|
|
44
|
+
import { gitTop } from "./tree.js";
|
|
45
|
+
export const newCiServeRuntime = () => ({ inflight: new Map() });
|
|
46
|
+
/** The state key of a job. */
|
|
47
|
+
export function ciServeKey(t) {
|
|
48
|
+
return t.job === "plan" ? `plan:${t.pr}:${t.commit}` : `apply:${t.commit}`;
|
|
49
|
+
}
|
|
50
|
+
const message = (err) => (err instanceof Error ? err.message : String(err));
|
|
51
|
+
function tryGit(cwd, args) {
|
|
52
|
+
try {
|
|
53
|
+
return execFileSync("git", args, { cwd, encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }).trim();
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/** Where a serve keeps its state when `--state` names nowhere: beside the run events, in the repository's common git directory. */
|
|
60
|
+
export function defaultCiServeStateDir(cwd) {
|
|
61
|
+
const common = tryGit(cwd, ["rev-parse", "--path-format=absolute", "--git-common-dir"]);
|
|
62
|
+
if (!common)
|
|
63
|
+
throw new CiRunError("ci serve runs in a clone of the repository it serves, and this directory is not in a git repository");
|
|
64
|
+
return join(common, "chant", "ci-serve");
|
|
65
|
+
}
|
|
66
|
+
function servePlace(opts) {
|
|
67
|
+
const cwd = resolve(opts.cwd);
|
|
68
|
+
const top = gitTop(cwd);
|
|
69
|
+
if (!top)
|
|
70
|
+
throw new CiRunError("ci serve runs in a clone of the repository it serves, and this directory is not in a git repository");
|
|
71
|
+
const { member } = ciJobPlace(cwd, top);
|
|
72
|
+
const group = prApplyGroup(opts.env, member);
|
|
73
|
+
const stateDir = opts.stateDir ? resolve(cwd, opts.stateDir) : defaultCiServeStateDir(cwd);
|
|
74
|
+
return { top, ...(member ? { member } : {}), branch: opts.job?.loop?.branch ?? "main", group, stateDir, stateFile: join(stateDir, `${group}.json`) };
|
|
75
|
+
}
|
|
76
|
+
/** The state file, or a new one. */
|
|
77
|
+
export function readCiServeState(file, fresh) {
|
|
78
|
+
if (existsSync(file)) {
|
|
79
|
+
const s = JSON.parse(readFileSync(file, "utf-8"));
|
|
80
|
+
if (s.schema !== 1 || typeof s.jobs !== "object" || s.jobs === null)
|
|
81
|
+
throw new CiRunError(`${file} is not a ci serve state file this chant reads`);
|
|
82
|
+
return s;
|
|
83
|
+
}
|
|
84
|
+
return { schema: 1, ...fresh, jobs: {} };
|
|
85
|
+
}
|
|
86
|
+
function writeState(file, state) {
|
|
87
|
+
mkdirSync(resolve(file, ".."), { recursive: true });
|
|
88
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
89
|
+
writeFileSync(tmp, `${JSON.stringify(state, null, 2)}\n`);
|
|
90
|
+
renameSync(tmp, file);
|
|
91
|
+
}
|
|
92
|
+
/** A job entry that can run again with `rerunFailed`: it failed, or it says `running` and no job of this process runs it. */
|
|
93
|
+
const failedEntry = (entry, key, rt) => !!entry && (entry.status === "fail" || (entry.status === "running" && !rt.inflight.has(key)));
|
|
94
|
+
/**
|
|
95
|
+
* One poll of the forge, as triggers: an apply when the target's head moved
|
|
96
|
+
* since the last apply (none on the first poll, which only notes the head),
|
|
97
|
+
* then a plan for each open pull request head not yet planned, oldest pull
|
|
98
|
+
* request first. A job already in the state file is left out unless it
|
|
99
|
+
* failed and `rerunFailed` is set. The first poll's head is written to the
|
|
100
|
+
* state file.
|
|
101
|
+
*/
|
|
102
|
+
export async function ciServeObserve(opts, rt = newCiServeRuntime()) {
|
|
103
|
+
const place = servePlace(opts);
|
|
104
|
+
const state = readCiServeState(place.stateFile, { forge: opts.forge, repo: opts.repo, env: opts.env, branch: place.branch, ...(place.member ? { member: place.member } : {}) });
|
|
105
|
+
const triggers = [];
|
|
106
|
+
const events = [];
|
|
107
|
+
const [head, prs] = await Promise.all([opts.client.branchHead(place.branch), opts.client.openPullRequests(place.branch)]);
|
|
108
|
+
if (head === undefined) {
|
|
109
|
+
events.push({ type: "no-branch", branch: place.branch });
|
|
110
|
+
}
|
|
111
|
+
else if (state.target === undefined) {
|
|
112
|
+
// What the branch held before this runner watched it was applied by whatever ran then.
|
|
113
|
+
state.target = head;
|
|
114
|
+
writeState(place.stateFile, state);
|
|
115
|
+
events.push({ type: "baseline", commit: head });
|
|
116
|
+
}
|
|
117
|
+
else if (head !== state.target) {
|
|
118
|
+
const entry = state.jobs[ciServeKey({ job: "apply", commit: head })];
|
|
119
|
+
if (!entry)
|
|
120
|
+
triggers.push({ job: "apply", commit: head, base: state.target });
|
|
121
|
+
else if (opts.rerunFailed && failedEntry(entry, ciServeKey(entry), rt))
|
|
122
|
+
triggers.push({ job: "apply", commit: head, base: entry.base, rerun: true });
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
const key = ciServeKey({ job: "apply", commit: head });
|
|
126
|
+
const entry = state.jobs[key];
|
|
127
|
+
if (opts.rerunFailed && failedEntry(entry, key, rt))
|
|
128
|
+
triggers.push({ job: "apply", commit: head, base: entry.base, rerun: true });
|
|
129
|
+
}
|
|
130
|
+
const authors = opts.authors?.length ? new Set(opts.authors.map((a) => a.toLowerCase())) : undefined;
|
|
131
|
+
for (const pr of prs) {
|
|
132
|
+
if (pr.fork) {
|
|
133
|
+
events.push({ type: "skipped", pr: pr.number, reason: "fork" });
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (authors && !authors.has((pr.author ?? "").toLowerCase())) {
|
|
137
|
+
events.push({ type: "skipped", pr: pr.number, reason: "author", ...(pr.author ? { author: pr.author } : {}) });
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
const key = ciServeKey({ job: "plan", commit: pr.headSha, pr: pr.number });
|
|
141
|
+
const entry = state.jobs[key];
|
|
142
|
+
const base = pr.baseSha ?? head;
|
|
143
|
+
if (!base)
|
|
144
|
+
continue;
|
|
145
|
+
if (!entry)
|
|
146
|
+
triggers.push({ job: "plan", commit: pr.headSha, base, pr: pr.number });
|
|
147
|
+
else if (opts.rerunFailed && failedEntry(entry, key, rt))
|
|
148
|
+
triggers.push({ job: "plan", commit: pr.headSha, base: entry.base, pr: pr.number, rerun: true });
|
|
149
|
+
}
|
|
150
|
+
return { triggers, events };
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Start the triggers' jobs, at most `maxJobs` at once with the jobs this
|
|
154
|
+
* process already runs. An apply first takes its group's lease. A trigger
|
|
155
|
+
* that can't start (over capacity, lease held, or already running here) is
|
|
156
|
+
* reported and not recorded, so the next poll finds it again.
|
|
157
|
+
*/
|
|
158
|
+
export async function ciServeSchedule(opts, triggers, rt = newCiServeRuntime()) {
|
|
159
|
+
const place = servePlace(opts);
|
|
160
|
+
const max = opts.maxJobs ?? 1;
|
|
161
|
+
const holder = opts.holder ?? currentHolderId();
|
|
162
|
+
const ttlMs = opts.leaseTtlMs ?? DEFAULT_LEASE_TTL_MS;
|
|
163
|
+
const now = opts.now ?? (() => new Date());
|
|
164
|
+
const log = opts.log ?? (() => { });
|
|
165
|
+
const events = [];
|
|
166
|
+
const emit = (e) => {
|
|
167
|
+
events.push(e);
|
|
168
|
+
log(e);
|
|
169
|
+
};
|
|
170
|
+
const started = [];
|
|
171
|
+
const fresh = { forge: opts.forge, repo: opts.repo, env: opts.env, branch: place.branch, ...(place.member ? { member: place.member } : {}) };
|
|
172
|
+
const update = (fn) => {
|
|
173
|
+
const s = readCiServeState(place.stateFile, fresh);
|
|
174
|
+
fn(s);
|
|
175
|
+
writeState(place.stateFile, s);
|
|
176
|
+
};
|
|
177
|
+
for (const t of triggers) {
|
|
178
|
+
const key = ciServeKey(t);
|
|
179
|
+
const pr = t.job === "plan" ? { pr: t.pr } : {};
|
|
180
|
+
if (rt.inflight.has(key))
|
|
181
|
+
continue;
|
|
182
|
+
if (rt.inflight.size >= max) {
|
|
183
|
+
emit({ type: "held", job: t.job, commit: t.commit, ...pr, reason: "capacity" });
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
let lease;
|
|
187
|
+
if (t.job === "apply") {
|
|
188
|
+
let got;
|
|
189
|
+
try {
|
|
190
|
+
got = await acquireLease(place.group, holder, { cwd: opts.cwd, ttlMs, mode: "claim", requirePush: true, now });
|
|
191
|
+
}
|
|
192
|
+
catch (err) {
|
|
193
|
+
emit({ type: "error", message: `the ${place.group} lease could not be taken: ${message(err)}` });
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
if (!got.acquired || !got.lease) {
|
|
197
|
+
emit({ type: "held", job: "apply", commit: t.commit, reason: "lease", ...(got.heldBy ? { heldBy: got.heldBy.holder } : {}) });
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
lease = got.lease;
|
|
201
|
+
}
|
|
202
|
+
const previous = readCiServeState(place.stateFile, fresh).jobs[key];
|
|
203
|
+
const attempt = (previous?.attempts ?? 0) + 1;
|
|
204
|
+
const runId = `chant-serve-${now().getTime()}-${t.job}-${t.commit.slice(0, 8)}`;
|
|
205
|
+
const resume = t.job === "apply" ? join(place.stateDir, "resume", `${prApplyRecordKey(opts.env, t.commit, place.member)}.json`) : undefined;
|
|
206
|
+
const report = join(place.stateDir, "reports", place.group, `${CI_JOB_OPS[t.job]}${t.job === "plan" ? `-${t.pr}` : ""}-${t.commit.slice(0, 12)}`);
|
|
207
|
+
const entry = { job: t.job, commit: t.commit, base: t.base, ...pr, status: "running", runId, attempts: attempt, startedAt: now().toISOString() };
|
|
208
|
+
update((s) => {
|
|
209
|
+
s.jobs[key] = entry;
|
|
210
|
+
if (t.job === "apply" && !t.rerun)
|
|
211
|
+
s.target = t.commit;
|
|
212
|
+
});
|
|
213
|
+
emit({ type: "started", job: t.job, commit: t.commit, ...pr, base: t.base, runId, attempt, ...(resume && existsSync(resume) ? { resume } : {}) });
|
|
214
|
+
const job = runJob(opts, place, t, { runId, report, ...(resume ? { resume } : {}) }, lease ? { lease, holder, ttlMs, now } : undefined).then((done) => {
|
|
215
|
+
rt.inflight.delete(key);
|
|
216
|
+
const settled = { ...entry, ...done, settledAt: now().toISOString() };
|
|
217
|
+
try {
|
|
218
|
+
update((s) => {
|
|
219
|
+
s.jobs[key] = settled;
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
catch (err) {
|
|
223
|
+
emit({ type: "error", message: `${key} settled, and the state file could not be written: ${message(err)}` });
|
|
224
|
+
}
|
|
225
|
+
emit({ type: "settled", job: t.job, commit: t.commit, ...pr, status: settled.status === "ok" ? "ok" : "fail", ...(settled.failure ? { failure: settled.failure } : {}), ...(settled.report ? { report: settled.report } : {}) });
|
|
226
|
+
return settled;
|
|
227
|
+
});
|
|
228
|
+
rt.inflight.set(key, job);
|
|
229
|
+
started.push(job);
|
|
230
|
+
}
|
|
231
|
+
return { started, events };
|
|
232
|
+
}
|
|
233
|
+
/** Run one job: fetch its commit, run it with `ciRun`, keep the lease renewed while it runs, and release it after. Never throws. */
|
|
234
|
+
async function runJob(opts, place, t, paths, held) {
|
|
235
|
+
const renew = held
|
|
236
|
+
? setInterval(() => {
|
|
237
|
+
void acquireLease(place.group, held.holder, { cwd: opts.cwd, ttlMs: held.ttlMs, mode: "renew", token: held.lease.token, now: held.now }).catch(() => undefined);
|
|
238
|
+
}, Math.max(1000, Math.floor(held.ttlMs / 3)))
|
|
239
|
+
: undefined;
|
|
240
|
+
renew?.unref?.();
|
|
241
|
+
try {
|
|
242
|
+
// The pull request's head is on the forge's refs/pull/<n>/head, the target's on the branch.
|
|
243
|
+
tryGit(place.top, ["fetch", "--quiet", "--no-tags", "origin", t.job === "plan" ? `refs/pull/${t.pr}/head` : place.branch]);
|
|
244
|
+
const hostEnv = { ...(opts.job?.hostEnv ?? process.env), GITHUB_REPOSITORY: opts.repo };
|
|
245
|
+
const run = opts.run ?? ciRun;
|
|
246
|
+
const r = await run({
|
|
247
|
+
...opts.job,
|
|
248
|
+
hostEnv,
|
|
249
|
+
cwd: opts.cwd,
|
|
250
|
+
job: t.job,
|
|
251
|
+
env: opts.env,
|
|
252
|
+
forge: opts.forge,
|
|
253
|
+
base: t.base,
|
|
254
|
+
...(t.job === "plan" ? { pr: t.pr } : {}),
|
|
255
|
+
commit: t.commit,
|
|
256
|
+
output: paths.report,
|
|
257
|
+
runId: paths.runId,
|
|
258
|
+
...(paths.resume ? { resumeRecord: paths.resume } : {}),
|
|
259
|
+
});
|
|
260
|
+
const why = r.record.failure ? `${r.record.failure.code}: ${r.record.failure.reason}` : r.failure ? `${r.failure.phase}: ${r.failure.error.split("\n")[0]}` : undefined;
|
|
261
|
+
return { status: r.status === "ok" ? "ok" : "fail", ...(why && r.status !== "ok" ? { failure: why } : {}), ...(r.report ? { report: r.report } : {}) };
|
|
262
|
+
}
|
|
263
|
+
catch (err) {
|
|
264
|
+
return { status: "fail", failure: message(err) };
|
|
265
|
+
}
|
|
266
|
+
finally {
|
|
267
|
+
if (renew)
|
|
268
|
+
clearInterval(renew);
|
|
269
|
+
if (held)
|
|
270
|
+
await releaseLease(place.group, held.holder, held.lease.token, { cwd: opts.cwd }).catch(() => false);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
/** One pass: observe, schedule, and with `wait` wait for the jobs it started. */
|
|
274
|
+
export async function ciServePass(opts, rt = newCiServeRuntime(), wait = true) {
|
|
275
|
+
const observed = await ciServeObserve(opts, rt);
|
|
276
|
+
for (const e of observed.events)
|
|
277
|
+
opts.log?.(e);
|
|
278
|
+
const scheduled = await ciServeSchedule(opts, observed.triggers, rt);
|
|
279
|
+
const jobs = wait ? await Promise.all(scheduled.started) : [];
|
|
280
|
+
return { events: [...observed.events, ...scheduled.events], jobs };
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* The loop: a pass every `intervalMs` until `signal` aborts, jobs running
|
|
284
|
+
* across passes up to `maxJobs`. A pass the forge fails is logged and the
|
|
285
|
+
* loop goes on. On abort it waits for the jobs that run.
|
|
286
|
+
*/
|
|
287
|
+
export async function ciServeLoop(opts) {
|
|
288
|
+
const rt = newCiServeRuntime();
|
|
289
|
+
while (!opts.signal?.aborted) {
|
|
290
|
+
try {
|
|
291
|
+
await ciServePass(opts, rt, false);
|
|
292
|
+
}
|
|
293
|
+
catch (err) {
|
|
294
|
+
opts.log?.({ type: "error", message: message(err) });
|
|
295
|
+
}
|
|
296
|
+
await new Promise((done) => {
|
|
297
|
+
const timer = setTimeout(done, opts.intervalMs);
|
|
298
|
+
opts.signal?.addEventListener("abort", () => {
|
|
299
|
+
clearTimeout(timer);
|
|
300
|
+
done();
|
|
301
|
+
}, { once: true });
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
await Promise.allSettled([...rt.inflight.values()]);
|
|
305
|
+
}
|
|
306
|
+
/** One line for an event, as `ci serve` prints it. */
|
|
307
|
+
export function formatCiServeEvent(e) {
|
|
308
|
+
const at = (job, commit, pr) => `${CI_JOB_OPS[job]} ${commit.slice(0, 12)}${pr !== undefined ? ` (pull request ${pr})` : ""}`;
|
|
309
|
+
switch (e.type) {
|
|
310
|
+
case "baseline":
|
|
311
|
+
return `target at ${e.commit.slice(0, 12)}; the next commit there is applied`;
|
|
312
|
+
case "no-branch":
|
|
313
|
+
return `the forge has no branch ${e.branch}`;
|
|
314
|
+
case "skipped":
|
|
315
|
+
return e.reason === "fork" ? `pull request ${e.pr} is from a fork, and host mode plans none` : `pull request ${e.pr} is by ${e.author ?? "an unknown author"}, who is not an --author`;
|
|
316
|
+
case "held":
|
|
317
|
+
return `${at(e.job, e.commit, e.pr)} waits: ${e.reason === "capacity" ? "--max-jobs jobs run" : `the apply lease is held${e.heldBy ? ` by ${e.heldBy}` : ""}`}`;
|
|
318
|
+
case "started":
|
|
319
|
+
return `${at(e.job, e.commit, e.pr)} started, run ${e.runId}, attempt ${e.attempt}${e.resume ? ", resuming" : ""}`;
|
|
320
|
+
case "settled":
|
|
321
|
+
return `${at(e.job, e.commit, e.pr)} ${e.status === "ok" ? "passed" : `failed${e.failure ? `: ${e.failure}` : ""}`}${e.report ? `; report ${e.report}` : ""}`;
|
|
322
|
+
case "error":
|
|
323
|
+
return `error: ${e.message}`;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
// ── The command ──────────────────────────────────────────────────────────────
|
|
327
|
+
const USAGE = "chant ci serve --forge forgejo|github --repo <owner/repo> --env <env> [--interval <s>] [--max-jobs <n>] [--state <dir>] " +
|
|
328
|
+
"[--author <login>]... [--once] [--rerun-failed] [--gate <name>] [--branch <name>] [--events-json] [--report-url <url>] " +
|
|
329
|
+
"[--image <image>] [--before-script <line>]... [--pr-build] [--pr-build-command <line>] [--chant <command>] [--pass-env <NAME>]... [--key <runner key.pem>]";
|
|
330
|
+
const ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
331
|
+
/** `--interval`: seconds, or a duration such as `30s` or `2m`. Default 30 seconds. */
|
|
332
|
+
export function ciServeInterval(value) {
|
|
333
|
+
if (value === undefined)
|
|
334
|
+
return 30000;
|
|
335
|
+
const ms = /^\d+$/.test(value) ? Number(value) * 1000 : parseDuration(value);
|
|
336
|
+
if (!(ms >= 1000))
|
|
337
|
+
throw new CiRunError(`--interval takes seconds or a duration of a second or more, not ${JSON.stringify(value)}`);
|
|
338
|
+
return ms;
|
|
339
|
+
}
|
|
340
|
+
/** `chant ci serve` (#4095). */
|
|
341
|
+
export async function runCiServe(ctx) {
|
|
342
|
+
const { args } = ctx;
|
|
343
|
+
try {
|
|
344
|
+
const forge = args.forge;
|
|
345
|
+
if (forge !== "forgejo" && forge !== "github")
|
|
346
|
+
throw new CiRunError(`--forge names the forge ci serve polls: --forge forgejo|github${forge ? `, not ${JSON.stringify(forge)}` : ""}`);
|
|
347
|
+
if (!args.ciRepo)
|
|
348
|
+
throw new CiRunError("--repo names the repository whose pull requests ci serve polls: --repo <owner/repo>");
|
|
349
|
+
if (!args.env)
|
|
350
|
+
throw new CiRunError("--env names the environment the pipeline is for: --env <env>");
|
|
351
|
+
for (const name of args.passEnv ?? [])
|
|
352
|
+
if (!ENV_NAME.test(name))
|
|
353
|
+
throw new CiRunError(`--pass-env takes a variable's name, not ${JSON.stringify(name)}`);
|
|
354
|
+
const intervalMs = ciServeInterval(args.interval);
|
|
355
|
+
const fromFlag = args.key !== undefined;
|
|
356
|
+
const runnerKey = fromFlag ? readFileSync(resolve(args.key), "utf-8") : process.env[RUNNER_KEY_ENV] || undefined;
|
|
357
|
+
const hostEnv = { ...process.env, GITHUB_REPOSITORY: args.ciRepo };
|
|
358
|
+
const client = forgeFromEnv(forge, hostEnv);
|
|
359
|
+
if (!client.openPullRequests || !client.branchHead)
|
|
360
|
+
throw new CiRunError(`the ${forge} client cannot list pull requests`);
|
|
361
|
+
const opts = {
|
|
362
|
+
cwd: process.cwd(),
|
|
363
|
+
forge,
|
|
364
|
+
repo: args.ciRepo,
|
|
365
|
+
env: args.env,
|
|
366
|
+
client: { openPullRequests: client.openPullRequests.bind(client), branchHead: client.branchHead.bind(client) },
|
|
367
|
+
...(args.statePath ? { stateDir: isAbsolute(args.statePath) ? args.statePath : resolve(args.statePath) } : {}),
|
|
368
|
+
...(args.maxJobs ? { maxJobs: args.maxJobs } : {}),
|
|
369
|
+
...(args.ciAuthors?.length ? { authors: args.ciAuthors } : {}),
|
|
370
|
+
...(args.rerunFailed ? { rerunFailed: true } : {}),
|
|
371
|
+
job: {
|
|
372
|
+
loop: {
|
|
373
|
+
...(args.gate ? { gate: args.gate } : {}),
|
|
374
|
+
...(args.branch ? { branch: args.branch } : {}),
|
|
375
|
+
...(args.eventsJson ? { events: true } : {}),
|
|
376
|
+
...(args.reportUrl ? { reportUrl: args.reportUrl } : {}),
|
|
377
|
+
...(args.prBuild ? { build: true } : {}),
|
|
378
|
+
...(args.prBuildCommand ? { buildCommand: args.prBuildCommand } : {}),
|
|
379
|
+
},
|
|
380
|
+
...(args.image ? { image: args.image } : {}),
|
|
381
|
+
...(args.beforeScript?.length ? { beforeScript: args.beforeScript } : {}),
|
|
382
|
+
...(args.ciChant ? { chant: args.ciChant } : {}),
|
|
383
|
+
...(args.passEnv?.length ? { passEnv: args.passEnv } : {}),
|
|
384
|
+
...(runnerKey !== undefined ? { runnerKey, runnerKeyFromEnv: !fromFlag } : {}),
|
|
385
|
+
...(args.eventsJson ? { runEvents: (line) => void process.stdout.write(line) } : {}),
|
|
386
|
+
hostEnv,
|
|
387
|
+
stepOutput: (line) => void process.stderr.write(`${line}\n`),
|
|
388
|
+
},
|
|
389
|
+
log: (e) => console.error(e.type === "error" ? formatWarning({ message: formatCiServeEvent(e) }) : `ci serve: ${formatCiServeEvent(e)}`),
|
|
390
|
+
};
|
|
391
|
+
if (args.once) {
|
|
392
|
+
const pass = await ciServePass(opts);
|
|
393
|
+
return pass.jobs.some((j) => j.status !== "ok") ? 1 : 0;
|
|
394
|
+
}
|
|
395
|
+
const stop = new AbortController();
|
|
396
|
+
const onSignal = () => stop.abort();
|
|
397
|
+
process.once("SIGINT", onSignal);
|
|
398
|
+
process.once("SIGTERM", onSignal);
|
|
399
|
+
try {
|
|
400
|
+
await ciServeLoop({ ...opts, intervalMs, signal: stop.signal });
|
|
401
|
+
}
|
|
402
|
+
finally {
|
|
403
|
+
process.off("SIGINT", onSignal);
|
|
404
|
+
process.off("SIGTERM", onSignal);
|
|
405
|
+
}
|
|
406
|
+
return 0;
|
|
407
|
+
}
|
|
408
|
+
catch (err) {
|
|
409
|
+
console.error(formatError({ message: `chant ci serve: ${message(err)}`, hint: USAGE }));
|
|
410
|
+
return 1;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
@@ -49,6 +49,11 @@
|
|
|
49
49
|
"applied": { "type": "array", "items": { "type": "string" }, "description": "Components the earlier attempt applied, which this run did not run again." }
|
|
50
50
|
}
|
|
51
51
|
},
|
|
52
|
+
"deployedOutputs": {
|
|
53
|
+
"type": "object",
|
|
54
|
+
"description": "Added within contract version 1 by #4104, written by chant 0.124.30 and newer. Per dependency a member was planned against, the names of the outputs read from the deployed estate through its capability's outputs, sorted. A dependency outside the change is listed here too, and one whose stack is not deployed yet lists []. Outputs given with --seed-outputs, or carried from an earlier attempt's record, are not listed. Absent when no dependency was read, and on a resumed apply.",
|
|
55
|
+
"additionalProperties": { "type": "array", "items": { "type": "string" } }
|
|
56
|
+
},
|
|
52
57
|
"approval": {
|
|
53
58
|
"type": "object",
|
|
54
59
|
"required": ["status"],
|
|
@@ -50,8 +50,8 @@
|
|
|
50
50
|
"required": ["forge"],
|
|
51
51
|
"properties": {
|
|
52
52
|
"forge": {
|
|
53
|
-
"enum": ["github", "gitlab", "op", "local"],
|
|
54
|
-
"description": "github: a GitHub Actions run, also the spelling Forgejo Actions uses. gitlab: a CI pipeline. op: a steward's run, named by its Op run id. local: a run on the machine that started it, outside CI."
|
|
53
|
+
"enum": ["github", "gitlab", "op", "local", "chant"],
|
|
54
|
+
"description": "github: a GitHub Actions run, also the spelling Forgejo Actions uses. gitlab: a CI pipeline. op: a steward's run, named by its Op run id. local: a run on the machine that started it, outside CI. chant: a pull-request job the chant runner ran (chant ci run, #4094), named by its Op run id; added within contract version 1 and written by chant 0.124.30 and newer, so a reader that switches on forge keeps a case for a value it does not know."
|
|
55
55
|
},
|
|
56
56
|
"repo": { "type": "string", "description": "The repository or project slug on the forge, when the environment named one." },
|
|
57
57
|
"url": { "type": "string", "description": "A link to the run, when the environment gave enough to build one." }
|
|
@@ -95,7 +95,18 @@
|
|
|
95
95
|
"type": { "const": "run-settle" },
|
|
96
96
|
"status": { "$ref": "#/$defs/settleStatus" },
|
|
97
97
|
"durationMs": { "type": ["integer", "null"], "minimum": 0, "description": "From run-start to now, or null when the writer did not time it." },
|
|
98
|
-
"error": { "type": "string", "description": "With status failed, what failed, when the writer knows." }
|
|
98
|
+
"error": { "type": "string", "description": "With status failed, what failed, when the writer knows." },
|
|
99
|
+
"failure": {
|
|
100
|
+
"type": "object",
|
|
101
|
+
"required": ["code", "reason"],
|
|
102
|
+
"description": "Added within contract version 1 by #4094, written by chant 0.124.30 and newer. With status failed: why, as the run record's failure says. code is a pull-request report's refusal or status (not-approved, plan-changed, not-a-reviewer, no-pull-request, plan-failed, failed, refused) or command-failed, setup-failed or build-failed, and a reader keeps a case for a code it does not know. reason is one line for a person, phase the phase that failed, exitCode the failed command's exit code. chant ci run writes it on every failed job.",
|
|
103
|
+
"properties": {
|
|
104
|
+
"code": { "type": "string", "minLength": 1 },
|
|
105
|
+
"reason": { "type": "string" },
|
|
106
|
+
"phase": { "type": "string" },
|
|
107
|
+
"exitCode": { "type": "integer" }
|
|
108
|
+
}
|
|
109
|
+
}
|
|
99
110
|
}
|
|
100
111
|
}
|
|
101
112
|
]
|
|
@@ -61,6 +61,8 @@ export interface StatusStewardRun {
|
|
|
61
61
|
gitSha?: string;
|
|
62
62
|
/** The CI run the Op ran in (#4020), when it ran in CI: the shape a release's `runOrigin` has. */
|
|
63
63
|
runOrigin?: OpRunRecord["runOrigin"];
|
|
64
|
+
/** Why the run failed (#4094), for a failed run whose record says. Absent otherwise, and on a record written before chant 0.124.30. */
|
|
65
|
+
failure?: OpRunRecord["failure"];
|
|
64
66
|
/**
|
|
65
67
|
* The gate the run stopped at, for a `gated` run: its name, when the run
|
|
66
68
|
* stopped there, the op it is recorded under (the Op's own, or the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status-stewards.d.ts","sourceRoot":"","sources":["../../src/workspace/status-stewards.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"status-stewards.d.ts","sourceRoot":"","sources":["../../src/workspace/status-stewards.ts"],"names":[],"mappings":"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"}
|
|
@@ -230,6 +230,7 @@ export async function readMemberStewards(memberDir, env, now, kind = "chant", bo
|
|
|
230
230
|
ended: newest.ended,
|
|
231
231
|
...(newest.gitSha ? { gitSha: newest.gitSha } : {}),
|
|
232
232
|
...(newest.runOrigin ? { runOrigin: newest.runOrigin } : {}),
|
|
233
|
+
...(newest.failure ? { failure: newest.failure } : {}),
|
|
233
234
|
gate: newest.gate ? gateOf(newest.gate, op.name) : null,
|
|
234
235
|
point: point?.wait ?? null,
|
|
235
236
|
phases: newest.phases.map((p) => ({
|
|
@@ -449,11 +449,22 @@
|
|
|
449
449
|
"required": ["forge"],
|
|
450
450
|
"description": "Added in contract 1 by #4020, written by chant 0.124.28 and newer. The CI run the Op ran in, the shape a release's runOrigin has: the forge (github for GitHub and Forgejo, gitlab), the repo or project, and a link to the run. Absent outside CI.",
|
|
451
451
|
"properties": {
|
|
452
|
-
"forge": { "enum": ["github", "gitlab", "op", "local"] },
|
|
452
|
+
"forge": { "enum": ["github", "gitlab", "op", "local", "chant"], "description": "chant: a pull-request job the chant runner ran (chant ci run, #4094), added within contract 1 and written by chant 0.124.30 and newer." },
|
|
453
453
|
"repo": { "type": "string" },
|
|
454
454
|
"url": { "type": "string" }
|
|
455
455
|
}
|
|
456
456
|
},
|
|
457
|
+
"failure": {
|
|
458
|
+
"type": "object",
|
|
459
|
+
"required": ["code", "reason"],
|
|
460
|
+
"description": "Added in contract 1 by #4094, written by chant 0.124.30 and newer. Why a failed run failed: code is a pull-request report's refusal or status (not-approved, plan-changed, not-a-reviewer, no-pull-request, plan-failed, failed, refused) or command-failed, setup-failed or build-failed, and a reader keeps a case for a code it does not know. reason is one line for a person, phase the phase that failed, exitCode the failed command's exit code. chant ci run writes it on every failed job; absent otherwise.",
|
|
461
|
+
"properties": {
|
|
462
|
+
"code": { "type": "string", "minLength": 1 },
|
|
463
|
+
"reason": { "type": "string" },
|
|
464
|
+
"phase": { "type": "string" },
|
|
465
|
+
"exitCode": { "type": "integer" }
|
|
466
|
+
}
|
|
467
|
+
},
|
|
457
468
|
"gate": {
|
|
458
469
|
"oneOf": [
|
|
459
470
|
{ "type": "null" },
|
package/package.json
CHANGED
|
@@ -148,6 +148,21 @@ describe("runBuild --components --generate (chant #1108 build-time parameters)",
|
|
|
148
148
|
vi.restoreAllMocks();
|
|
149
149
|
});
|
|
150
150
|
|
|
151
|
+
test("--pr-build and --pr-build-command become the prLoop build options (#4088)", async () => {
|
|
152
|
+
generateComponentsPipelineMock.mockResolvedValue({ success: true, yaml: "jobs: {}", stages: [], jobs: [] });
|
|
153
|
+
vi.spyOn(console, "log").mockImplementation(() => {});
|
|
154
|
+
|
|
155
|
+
const exit = await runBuild({
|
|
156
|
+
args: makeArgs({ generate: "github", prLoop: true, prBuild: true, prBuildCommand: "npm run build" }),
|
|
157
|
+
plugins: [],
|
|
158
|
+
serializers: [],
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
expect(exit).toBe(0);
|
|
162
|
+
expect(generateComponentsPipelineMock).toHaveBeenCalledWith(".", "github", { env: undefined, prLoop: { build: true, buildCommand: "npm run build" } }, undefined, []);
|
|
163
|
+
vi.restoreAllMocks();
|
|
164
|
+
});
|
|
165
|
+
|
|
151
166
|
test("chant.config.ts's declared buildParams resolve, log, and are forwarded to generateComponentsPipeline", async () => {
|
|
152
167
|
loadChantConfigUpwardMock.mockResolvedValue({
|
|
153
168
|
config: { buildParams: { tier: { type: "string", default: "light" } } },
|
|
@@ -13,7 +13,8 @@ import type { PrLoopPipelineOptions } from "../../components/pr-pipeline";
|
|
|
13
13
|
/**
|
|
14
14
|
* The `prLoop` generator option from `--pr-loop`'s flags (#3183): the gate
|
|
15
15
|
* and the branch, and with `--events-json` and `--report-url` (#4007) the
|
|
16
|
-
* flags the generated jobs pass to pr-plan and pr-apply.
|
|
16
|
+
* flags the generated jobs pass to pr-plan and pr-apply. `--pr-build` and
|
|
17
|
+
* `--pr-build-command` (#4088) add the build and lint steps before both.
|
|
17
18
|
*/
|
|
18
19
|
function prLoopOption(args: CommandContext["args"]): PrLoopPipelineOptions {
|
|
19
20
|
return {
|
|
@@ -21,6 +22,8 @@ function prLoopOption(args: CommandContext["args"]): PrLoopPipelineOptions {
|
|
|
21
22
|
...(args.branch ? { branch: args.branch } : {}),
|
|
22
23
|
...(args.eventsJson ? { events: true } : {}),
|
|
23
24
|
...(args.reportUrl ? { reportUrl: args.reportUrl } : {}),
|
|
25
|
+
...(args.prBuild ? { build: true } : {}),
|
|
26
|
+
...(args.prBuildCommand ? { buildCommand: args.prBuildCommand } : {}),
|
|
24
27
|
};
|
|
25
28
|
}
|
|
26
29
|
|