@intentius/chant 0.124.30 → 0.124.32
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/bin/chant +7 -2
- package/dist/cli/commands/check-lexicon-plugin.d.ts +7 -4
- package/dist/cli/commands/check-lexicon-plugin.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon-plugin.js +10 -7
- package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon.js +18 -12
- package/dist/cli/commands/import.d.ts +10 -0
- package/dist/cli/commands/import.d.ts.map +1 -1
- package/dist/cli/commands/import.js +37 -0
- package/dist/cli/commands/init-lexicon/templates/project.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon/templates/project.js +4 -3
- package/dist/cli/commands/onboard.d.ts.map +1 -1
- package/dist/cli/commands/onboard.js +8 -4
- package/dist/cli/commands/update.d.ts.map +1 -1
- package/dist/cli/commands/update.js +2 -1
- package/dist/cli/dependencies.d.ts +18 -0
- package/dist/cli/dependencies.d.ts.map +1 -0
- package/dist/cli/dependencies.js +120 -0
- package/dist/cli/handlers/build.d.ts.map +1 -1
- package/dist/cli/handlers/build.js +23 -4
- package/dist/cli/handlers/fan-out.d.ts.map +1 -1
- package/dist/cli/handlers/fan-out.js +12 -4
- package/dist/cli/handlers/graph.d.ts.map +1 -1
- package/dist/cli/handlers/graph.js +16 -6
- package/dist/cli/handlers/lint.d.ts.map +1 -1
- package/dist/cli/handlers/lint.js +6 -0
- package/dist/cli/handlers/operator.d.ts +2 -2
- package/dist/cli/handlers/operator.js +3 -3
- package/dist/cli/handlers/pr.d.ts +14 -0
- package/dist/cli/handlers/pr.d.ts.map +1 -1
- package/dist/cli/handlers/pr.js +488 -32
- package/dist/cli/handlers/promote.d.ts.map +1 -1
- package/dist/cli/handlers/promote.js +3 -1
- package/dist/cli/handlers/run.d.ts +13 -1
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/handlers/run.js +38 -15
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +74 -12
- package/dist/cli/parse-args.d.ts.map +1 -1
- package/dist/cli/parse-args.js +65 -0
- package/dist/cli/registry.d.ts +29 -2
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/cli/registry.js +6 -2
- package/dist/codegen/generate-post-synth-barrel.js +2 -2
- package/dist/codegen/lexicon-regen.d.ts +4 -0
- package/dist/codegen/lexicon-regen.d.ts.map +1 -1
- package/dist/codegen/lexicon-regen.js +1 -1
- package/dist/codegen/pinned-upgrade.js +2 -2
- package/dist/components/capability.d.ts +44 -3
- package/dist/components/capability.d.ts.map +1 -1
- package/dist/components/capability.js +21 -0
- package/dist/components/changed-files.d.ts +7 -1
- package/dist/components/changed-files.d.ts.map +1 -1
- package/dist/components/changed-files.js +9 -1
- package/dist/components/driver.d.ts +38 -0
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/driver.js +47 -6
- package/dist/components/fan-out-record.d.ts +6 -1
- package/dist/components/fan-out-record.d.ts.map +1 -1
- package/dist/components/fan-out-record.js +24 -0
- package/dist/components/fan-out-run.d.ts +20 -0
- package/dist/components/fan-out-run.d.ts.map +1 -1
- package/dist/components/fan-out-run.js +21 -1
- package/dist/components/pr-pipeline.d.ts +65 -2
- package/dist/components/pr-pipeline.d.ts.map +1 -1
- package/dist/components/pr-pipeline.js +107 -15
- package/dist/components/pr-run.d.ts +127 -29
- package/dist/components/pr-run.d.ts.map +1 -1
- package/dist/components/pr-run.js +290 -70
- package/dist/components/wave-plan.d.ts +5 -2
- package/dist/components/wave-plan.d.ts.map +1 -1
- package/dist/components/wave-plan.js +12 -1
- package/dist/discovery/fold-import.d.ts.map +1 -1
- package/dist/discovery/fold-import.js +16 -6
- package/dist/discovery/sandbox/bundle.d.ts.map +1 -1
- package/dist/discovery/sandbox/bundle.js +6 -0
- package/dist/discovery/specifier-resolve.d.ts.map +1 -1
- package/dist/discovery/specifier-resolve.js +8 -2
- package/dist/fold/fold.d.ts.map +1 -1
- package/dist/fold/fold.js +68 -1
- package/dist/fold/subset.d.ts +37 -0
- package/dist/fold/subset.d.ts.map +1 -1
- package/dist/fold/subset.js +88 -0
- package/dist/lexicon-module.d.ts +10 -0
- package/dist/lexicon-module.d.ts.map +1 -1
- package/dist/lexicon-module.js +53 -8
- package/dist/lexicon-plugin-helpers.d.ts.map +1 -1
- package/dist/lexicon-plugin-helpers.js +6 -4
- package/dist/lexicon.d.ts +2 -0
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/affected.d.ts.map +1 -1
- package/dist/lifecycle/affected.js +7 -1
- package/dist/lifecycle/release-ledger.d.ts +21 -0
- package/dist/lifecycle/release-ledger.d.ts.map +1 -1
- package/dist/lifecycle/release-ledger.js +24 -0
- package/dist/lifecycle/work-dir.d.ts +45 -0
- package/dist/lifecycle/work-dir.d.ts.map +1 -0
- package/dist/lifecycle/work-dir.js +78 -0
- package/dist/lint/discover.d.ts +17 -9
- package/dist/lint/discover.d.ts.map +1 -1
- package/dist/lint/discover.js +62 -54
- package/dist/module-source.d.ts +57 -0
- package/dist/module-source.d.ts.map +1 -0
- package/dist/module-source.js +104 -0
- package/dist/op/activities/factory.js +1 -1
- package/dist/op/discover.d.ts.map +1 -1
- package/dist/op/discover.js +13 -3
- package/dist/op/gate.d.ts.map +1 -1
- package/dist/op/gate.js +3 -0
- package/dist/op/local-executor.d.ts +12 -0
- package/dist/op/local-executor.d.ts.map +1 -1
- package/dist/op/local-executor.js +22 -3
- package/dist/op/op-waves-run.d.ts.map +1 -1
- package/dist/op/op-waves-run.js +20 -5
- package/dist/op/operator.d.ts +2 -2
- package/dist/op/operator.js +2 -2
- package/dist/op/redact.d.ts +34 -0
- package/dist/op/redact.d.ts.map +1 -0
- package/dist/op/redact.js +94 -0
- package/dist/op/step-console.d.ts +2 -0
- package/dist/op/step-console.d.ts.map +1 -1
- package/dist/op/step-console.js +5 -2
- package/dist/op/steward.d.ts +6 -4
- package/dist/op/steward.d.ts.map +1 -1
- package/dist/op/steward.js +5 -3
- package/dist/op/work-lease-run.d.ts +20 -7
- package/dist/op/work-lease-run.d.ts.map +1 -1
- package/dist/op/work-lease-run.js +56 -12
- package/dist/pr-forge.d.ts +27 -0
- package/dist/pr-forge.d.ts.map +1 -1
- package/dist/pr-forge.js +51 -6
- package/dist/pr-loop.d.ts +141 -4
- package/dist/pr-loop.d.ts.map +1 -1
- package/dist/pr-loop.js +122 -6
- package/dist/pr-report-url.d.ts +10 -2
- package/dist/pr-report-url.d.ts.map +1 -1
- package/dist/pr-report-url.js +52 -6
- package/dist/ts-loader.d.ts +38 -4
- package/dist/ts-loader.d.ts.map +1 -1
- package/dist/ts-loader.js +190 -16
- package/dist/wave-runtime.mjs +208 -208
- package/dist/workspace/chant-migrations/fountain-retired-kinds.d.ts +34 -0
- package/dist/workspace/chant-migrations/fountain-retired-kinds.d.ts.map +1 -0
- package/dist/workspace/chant-migrations/fountain-retired-kinds.js +176 -0
- package/dist/workspace/chant-migrations.d.ts.map +1 -1
- package/dist/workspace/chant-migrations.js +2 -0
- package/dist/workspace/checks/boxes.d.ts +6 -6
- package/dist/workspace/checks/boxes.js +9 -9
- package/dist/workspace/ci-green-forge.d.ts +6 -4
- package/dist/workspace/ci-green-forge.d.ts.map +1 -1
- package/dist/workspace/ci-green.d.ts +28 -12
- package/dist/workspace/ci-green.d.ts.map +1 -1
- package/dist/workspace/ci-green.js +49 -21
- package/dist/workspace/ci-list.schema.json +12 -6
- package/dist/workspace/ci-report-url.d.ts +18 -0
- package/dist/workspace/ci-report-url.d.ts.map +1 -0
- package/dist/workspace/ci-report-url.js +33 -0
- package/dist/workspace/ci-run-index.d.ts +108 -0
- package/dist/workspace/ci-run-index.d.ts.map +1 -0
- package/dist/workspace/ci-run-index.js +164 -0
- package/dist/workspace/ci-run-index.schema.json +52 -0
- package/dist/workspace/ci-run.d.ts +159 -9
- package/dist/workspace/ci-run.d.ts.map +1 -1
- package/dist/workspace/ci-run.js +419 -50
- package/dist/workspace/ci-runner-key.d.ts +133 -0
- package/dist/workspace/ci-runner-key.d.ts.map +1 -0
- package/dist/workspace/ci-runner-key.js +237 -0
- package/dist/workspace/ci-secrets.d.ts +65 -0
- package/dist/workspace/ci-secrets.d.ts.map +1 -0
- package/dist/workspace/ci-secrets.js +211 -0
- package/dist/workspace/ci-serve.d.ts +67 -4
- package/dist/workspace/ci-serve.d.ts.map +1 -1
- package/dist/workspace/ci-serve.js +240 -35
- package/dist/workspace/declaration.d.ts +8 -0
- package/dist/workspace/declaration.d.ts.map +1 -1
- package/dist/workspace/declaration.js +11 -2
- package/dist/workspace/declaration.schema.json +7 -2
- package/dist/workspace/export.d.ts +1 -1
- package/dist/workspace/export.d.ts.map +1 -1
- package/dist/workspace/export.js +7 -3
- package/dist/workspace/ls.d.ts +6 -1
- package/dist/workspace/ls.d.ts.map +1 -1
- package/dist/workspace/ls.js +1 -0
- package/dist/workspace/ls.schema.json +7 -1
- package/dist/workspace/pin-integrity.d.ts.map +1 -1
- package/dist/workspace/pin-integrity.js +3 -2
- package/dist/workspace/pr-report.schema.json +74 -7
- package/dist/workspace/reason-codes.d.ts +7 -3
- package/dist/workspace/reason-codes.d.ts.map +1 -1
- package/dist/workspace/reason-codes.js +9 -4
- package/dist/workspace/run-event.schema.json +3 -1
- package/dist/workspace/status.schema.json +3 -1
- package/dist/workspace/trust/trust-write.d.ts +109 -0
- package/dist/workspace/trust/trust-write.d.ts.map +1 -0
- package/dist/workspace/trust/trust-write.js +320 -0
- package/dist/workspace/trust-write.schema.json +265 -0
- package/dist/workspace/write-scope.d.ts +9 -0
- package/dist/workspace/write-scope.d.ts.map +1 -1
- package/dist/workspace/write-scope.js +11 -1
- package/package.json +1 -1
- package/src/__fixtures__/pr-loop/pr-apply-wave-waiting.note.golden.md +48 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +3 -3
- package/src/cli/commands/audit.test.ts +2 -2
- package/src/cli/commands/check-lexicon-plugin.test.ts +9 -0
- package/src/cli/commands/check-lexicon-plugin.ts +11 -8
- package/src/cli/commands/check-lexicon.test.ts +1 -1
- package/src/cli/commands/check-lexicon.ts +16 -11
- package/src/cli/commands/import.ts +40 -0
- package/src/cli/commands/init-lexicon/templates/project.ts +4 -3
- package/src/cli/commands/init-lexicon.test.ts +8 -5
- package/src/cli/commands/onboard.test.ts +45 -0
- package/src/cli/commands/onboard.ts +8 -4
- package/src/cli/commands/update.test.ts +6 -0
- package/src/cli/commands/update.ts +4 -1
- package/src/cli/compiled-cli.e2e.test.ts +76 -11
- package/src/cli/dependencies.e2e.test.ts +101 -0
- package/src/cli/dependencies.test.ts +93 -0
- package/src/cli/dependencies.ts +122 -0
- package/src/cli/handlers/build.test.ts +69 -0
- package/src/cli/handlers/build.ts +20 -4
- package/src/cli/handlers/fan-out.test.ts +73 -0
- package/src/cli/handlers/fan-out.ts +11 -4
- package/src/cli/handlers/graph.test.ts +76 -0
- package/src/cli/handlers/graph.ts +19 -12
- package/src/cli/handlers/lint.test.ts +42 -0
- package/src/cli/handlers/lint.ts +6 -0
- package/src/cli/handlers/operator.ts +3 -3
- package/src/cli/handlers/pr-waves.test.ts +449 -0
- package/src/cli/handlers/pr.test.ts +134 -0
- package/src/cli/handlers/pr.ts +523 -31
- package/src/cli/handlers/promote.test.ts +26 -1
- package/src/cli/handlers/promote.ts +3 -2
- package/src/cli/handlers/run-components-exit.test.ts +99 -0
- package/src/cli/handlers/run-signer.test.ts +79 -0
- package/src/cli/handlers/run.ts +34 -16
- package/src/cli/main.test.ts +19 -0
- package/src/cli/main.ts +73 -12
- package/src/cli/parse-args.ts +48 -0
- package/src/cli/registry.ts +35 -4
- package/src/codegen/generate-post-synth-barrel.ts +2 -2
- package/src/codegen/lexicon-regen.ts +1 -1
- package/src/codegen/pinned-upgrade.ts +2 -2
- package/src/codegen/post-synth-barrel-guards.test.ts +6 -11
- package/src/components/capability.ts +51 -3
- package/src/components/changed-files.test.ts +16 -1
- package/src/components/changed-files.ts +9 -1
- package/src/components/driver.test.ts +36 -1
- package/src/components/driver.ts +76 -4
- package/src/components/fan-out-record.ts +29 -1
- package/src/components/fan-out-run.test.ts +35 -0
- package/src/components/fan-out-run.ts +40 -1
- package/src/components/pr-pipeline.test.ts +100 -0
- package/src/components/pr-pipeline.ts +132 -17
- package/src/components/pr-run.test.ts +323 -18
- package/src/components/pr-run.ts +354 -75
- package/src/components/wave-plan.ts +16 -4
- package/src/discovery/fold-host-method.test.ts +87 -0
- package/src/discovery/fold-import.ts +15 -5
- package/src/discovery/fold-package-composite.test.ts +27 -0
- package/src/discovery/fold-specifiers.test.ts +8 -0
- package/src/discovery/sandbox/bundle.ts +6 -0
- package/src/discovery/specifier-resolve.ts +8 -2
- package/src/fold/fold.test.ts +72 -0
- package/src/fold/fold.ts +71 -0
- package/src/fold/subset.test.ts +31 -0
- package/src/fold/subset.ts +99 -0
- package/src/lexicon-dist.e2e.test.ts +254 -0
- package/src/lexicon-module.test.ts +47 -0
- package/src/lexicon-module.ts +49 -7
- package/src/lexicon-plugin-helpers.ts +6 -4
- package/src/lexicon.ts +2 -0
- package/src/lifecycle/affected.test.ts +7 -0
- package/src/lifecycle/affected.ts +6 -1
- package/src/lifecycle/release-ledger.ts +34 -0
- package/src/lifecycle/work-dir.test.ts +77 -0
- package/src/lifecycle/work-dir.ts +82 -0
- package/src/lint/discover.test.ts +46 -2
- package/src/lint/discover.ts +55 -49
- package/src/module-source.test.ts +85 -0
- package/src/module-source.ts +112 -0
- package/src/op/activities/factory.ts +1 -1
- package/src/op/discover-root.test.ts +31 -2
- package/src/op/discover.ts +14 -4
- package/src/op/gate.test.ts +30 -0
- package/src/op/gate.ts +3 -0
- package/src/op/local-executor.ts +31 -3
- package/src/op/op-waves-run.ts +20 -5
- package/src/op/op-waves.test.ts +49 -0
- package/src/op/operator.ts +2 -2
- package/src/op/redact.ts +93 -0
- package/src/op/step-console.ts +7 -2
- package/src/op/steward.ts +6 -4
- package/src/op/work-lease-run.test.ts +88 -2
- package/src/op/work-lease-run.ts +52 -12
- package/src/pr-forge-bundle.test.ts +2 -2
- package/src/pr-forge.test.ts +71 -0
- package/src/pr-forge.ts +70 -6
- package/src/pr-loop-bundle.test.ts +2 -1
- package/src/pr-loop.test.ts +117 -1
- package/src/pr-loop.ts +252 -10
- package/src/pr-report-url.ts +58 -6
- package/src/terraform/__fixtures__/advise.test.ts +21 -2
- package/src/ts-loader.test.ts +89 -1
- package/src/ts-loader.ts +180 -13
- package/src/workspace/changes.test.ts +1 -1
- package/src/workspace/chant-migrations/fountain-retired-kinds.test.ts +33 -0
- package/src/workspace/chant-migrations/fountain-retired-kinds.ts +190 -0
- package/src/workspace/chant-migrations.e2e.test.ts +5 -0
- package/src/workspace/chant-migrations.ts +2 -0
- package/src/workspace/checks/boxes.ts +9 -9
- package/src/workspace/ci-green-forge.ts +6 -4
- package/src/workspace/ci-green-runs.test.ts +53 -11
- package/src/workspace/ci-green.test.ts +1 -1
- package/src/workspace/ci-green.ts +50 -22
- package/src/workspace/ci-list.schema.json +12 -6
- package/src/workspace/ci-report-url.test.ts +220 -0
- package/src/workspace/ci-report-url.ts +33 -0
- package/src/workspace/ci-run-index.schema.json +52 -0
- package/src/workspace/ci-run-index.test.ts +392 -0
- package/src/workspace/ci-run-index.ts +206 -0
- package/src/workspace/ci-run.test.ts +520 -42
- package/src/workspace/ci-run.ts +483 -51
- package/src/workspace/ci-runner-key.test.ts +204 -0
- package/src/workspace/ci-runner-key.ts +275 -0
- package/src/workspace/ci-secrets.test.ts +106 -0
- package/src/workspace/ci-secrets.ts +213 -0
- package/src/workspace/ci-serve.test.ts +282 -39
- package/src/workspace/ci-serve.ts +231 -34
- package/src/workspace/declaration.schema.json +7 -2
- package/src/workspace/declaration.test.ts +23 -0
- package/src/workspace/declaration.ts +19 -3
- package/src/workspace/export.ts +6 -3
- package/src/workspace/ls.schema.json +7 -1
- package/src/workspace/ls.ts +7 -2
- package/src/workspace/pin-integrity.test.ts +5 -0
- package/src/workspace/pin-integrity.ts +3 -2
- package/src/workspace/pr-report.schema.json +74 -7
- package/src/workspace/reason-codes.test.ts +2 -0
- package/src/workspace/reason-codes.ts +9 -4
- package/src/workspace/run-event.schema.json +3 -1
- package/src/workspace/status.schema.json +3 -1
- package/src/workspace/trust/trust-write.test.ts +179 -0
- package/src/workspace/trust/trust-write.ts +377 -0
- package/src/workspace/trust-write.schema.json +265 -0
- package/src/workspace/write-scope.test.ts +29 -1
- package/src/workspace/write-scope.ts +12 -1
|
@@ -15,12 +15,34 @@
|
|
|
15
15
|
* the one `chant operator` holds) named for `prApplyGroup`, renews it while
|
|
16
16
|
* it runs and releases it after. An apply that finds it held waits for a
|
|
17
17
|
* later poll, as a forge's concurrency group queues it.
|
|
18
|
+
* - Merged pull request. An apply asks the forge for the pull request whose
|
|
19
|
+
* merge commit the new head is (`pullRequestFor`, as pr-apply does) and
|
|
20
|
+
* passes it as `--pr`, so its commit status link and run index use
|
|
21
|
+
* `<pr>/<commit>`. With none found it runs without `--pr`.
|
|
18
22
|
* - Resume records. Each apply gets `<state>/resume/<prApplyRecordKey>.json`
|
|
19
23
|
* as its `--resume` record, so a re-run of a failed apply at the same
|
|
20
24
|
* commit finishes under the approval it has. This replaces the forge's CI
|
|
21
25
|
* cache.
|
|
26
|
+
* - A gate per wave (#4003). With `--wave-gate` the apply job runs
|
|
27
|
+
* `pr-apply --wave-gate`, which applies the waves in order and stops at
|
|
28
|
+
* the first whose moved plan waits on its own gate. The job fails, and the
|
|
29
|
+
* resume record keeps the waves that applied; once the wave's plan is
|
|
30
|
+
* approved, `rerunFailed` runs the apply again and it carries on from
|
|
31
|
+
* that wave.
|
|
22
32
|
* - Capacity. At most `maxJobs` jobs run at once. A job over the limit is not
|
|
23
33
|
* recorded, so a later poll starts it.
|
|
34
|
+
* - Fast-forwards only (#4122). An apply runs only when the target's new head
|
|
35
|
+
* descends from the head seen before it. Any other move, such as a force
|
|
36
|
+
* push back to an older commit, is recorded as seen and not applied.
|
|
37
|
+
* - `[skip ci]` (#4122). A target head or pull request head whose commit
|
|
38
|
+
* message says `[skip ci]` or `[ci skip]` is recorded as seen and not run,
|
|
39
|
+
* as Actions does.
|
|
40
|
+
* - The forge's ledger (#4121). Before each job, when no other job of this
|
|
41
|
+
* serve runs, the clone's `chant/lifecycle` follows the forge's: it is
|
|
42
|
+
* deleted when the forge has none, and reset to the forge's when neither
|
|
43
|
+
* contains the other. Each is a warning. A local branch ahead of the
|
|
44
|
+
* forge's keeps its facts, and the job's push sends them. Nothing here
|
|
45
|
+
* pushes the ledger.
|
|
24
46
|
*
|
|
25
47
|
* Host mode only: each job runs in a fresh worktree on this host as this
|
|
26
48
|
* user, with the clean environment `ciRun` gives it. A pull request from a
|
|
@@ -40,6 +62,8 @@ export type CiServeForgeKind = "github" | "forgejo";
|
|
|
40
62
|
export interface CiServeForge {
|
|
41
63
|
openPullRequests(base: string): Promise<OpenPullRequest[]>;
|
|
42
64
|
branchHead(branch: string): Promise<string | undefined>;
|
|
65
|
+
/** The merged pull request that produced a commit, as pr-apply finds it (`pullRequestFor`). Without it an apply gets no `--pr`. */
|
|
66
|
+
pullRequestFor?(sha: string): Promise<number | null>;
|
|
43
67
|
}
|
|
44
68
|
/** A job the forge's state calls for: the plan of a pull request's head, or the apply of a target-branch commit. */
|
|
45
69
|
export type CiServeTrigger = {
|
|
@@ -79,9 +103,11 @@ export interface CiServeState {
|
|
|
79
103
|
env: string;
|
|
80
104
|
branch: string;
|
|
81
105
|
member?: string;
|
|
82
|
-
/** The target branch's head the last apply was measured to, or the head
|
|
106
|
+
/** The target branch's head the last apply was measured to, or the last head seen and not applied. */
|
|
83
107
|
target?: string;
|
|
84
108
|
jobs: Record<string, CiServeJobState>;
|
|
109
|
+
/** Plans seen and not run, by state key, with why (#4122). */
|
|
110
|
+
skipped?: Record<string, "skip-ci">;
|
|
85
111
|
}
|
|
86
112
|
/** What a pass did, in order, for the log. */
|
|
87
113
|
export type CiServeEvent = {
|
|
@@ -119,6 +145,19 @@ export type CiServeEvent = {
|
|
|
119
145
|
status: "ok" | "fail";
|
|
120
146
|
failure?: string;
|
|
121
147
|
report?: string;
|
|
148
|
+
} | {
|
|
149
|
+
type: "not-run";
|
|
150
|
+
job: CiJobName;
|
|
151
|
+
commit: string;
|
|
152
|
+
pr?: number;
|
|
153
|
+
reason: "not-fast-forward" | "skip-ci";
|
|
154
|
+
branch?: string;
|
|
155
|
+
from?: string;
|
|
156
|
+
} | {
|
|
157
|
+
type: "ledger";
|
|
158
|
+
action: "deleted" | "reset";
|
|
159
|
+
local: string;
|
|
160
|
+
forge?: string;
|
|
122
161
|
} | {
|
|
123
162
|
type: "error";
|
|
124
163
|
message: string;
|
|
@@ -162,17 +201,34 @@ export declare function ciServeKey(t: {
|
|
|
162
201
|
commit: string;
|
|
163
202
|
pr?: number;
|
|
164
203
|
}): string;
|
|
204
|
+
/**
|
|
205
|
+
* Make the clone's `chant/lifecycle` follow the forge's (#4121). The clone's
|
|
206
|
+
* branch outlives the forge's, so a ledger the forge deleted or rewrote would
|
|
207
|
+
* make the next pr-apply find the two diverged and stall.
|
|
208
|
+
*
|
|
209
|
+
* - The forge has none: the local branch and its remote-tracking ref go.
|
|
210
|
+
* - Neither contains the other: the local branch and its remote-tracking ref
|
|
211
|
+
* are reset to the forge's tip.
|
|
212
|
+
* - The local branch is ahead of the forge's, or behind it, or the same: it
|
|
213
|
+
* is left, and an apply's push sends what it holds that the forge lacks.
|
|
214
|
+
*
|
|
215
|
+
* Nothing is pushed, so a rewritten ledger never goes back to the forge. A
|
|
216
|
+
* forge that can't be reached leaves everything as it is; the job's own
|
|
217
|
+
* fetch says why.
|
|
218
|
+
*/
|
|
219
|
+
export declare function reconcileCiServeLedger(top: string): CiServeEvent | undefined;
|
|
165
220
|
/** Where a serve keeps its state when `--state` names nowhere: beside the run events, in the repository's common git directory. */
|
|
166
221
|
export declare function defaultCiServeStateDir(cwd: string): string;
|
|
167
222
|
/** The state file, or a new one. */
|
|
168
223
|
export declare function readCiServeState(file: string, fresh: Omit<CiServeState, "schema" | "jobs">): CiServeState;
|
|
169
224
|
/**
|
|
170
225
|
* One poll of the forge, as triggers: an apply when the target's head moved
|
|
171
|
-
* since the last apply (none on the first poll, which only
|
|
226
|
+
* since the last apply by a fast-forward (none on the first poll, which only
|
|
227
|
+
* notes the head, and none for a head whose message says `[skip ci]`),
|
|
172
228
|
* then a plan for each open pull request head not yet planned, oldest pull
|
|
173
229
|
* request first. A job already in the state file is left out unless it
|
|
174
|
-
* failed and `rerunFailed` is set. The first poll's head
|
|
175
|
-
* state file.
|
|
230
|
+
* failed and `rerunFailed` is set. The first poll's head, and a head seen
|
|
231
|
+
* and not applied, are written to the state file.
|
|
176
232
|
*/
|
|
177
233
|
export declare function ciServeObserve(opts: CiServeOptions, rt?: CiServeRuntime): Promise<{
|
|
178
234
|
triggers: CiServeTrigger[];
|
|
@@ -207,6 +263,13 @@ export declare function ciServeLoop(opts: CiServeOptions & {
|
|
|
207
263
|
}): Promise<void>;
|
|
208
264
|
/** One line for an event, as `ci serve` prints it. */
|
|
209
265
|
export declare function formatCiServeEvent(e: CiServeEvent): string;
|
|
266
|
+
/**
|
|
267
|
+
* `chant ci serve|run --setup-key [--trust [--principal <name>]] [--state <dir>] [--branch <name>]` (#4099):
|
|
268
|
+
* make the host's runner key when there is none, print its public half on
|
|
269
|
+
* stdout, and say whether the target's head lists it. With --trust, commit
|
|
270
|
+
* the runner entry on a branch of its own and push it for review.
|
|
271
|
+
*/
|
|
272
|
+
export declare function runnerKeySetupCommand(ctx: CommandContext): number;
|
|
210
273
|
/** `--interval`: seconds, or a duration such as `30s` or `2m`. Default 30 seconds. */
|
|
211
274
|
export declare function ciServeInterval(value: string | undefined): number;
|
|
212
275
|
/** `chant ci serve` (#4095). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ci-serve.d.ts","sourceRoot":"","sources":["../../src/workspace/ci-serve.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"ci-serve.d.ts","sourceRoot":"","sources":["../../src/workspace/ci-serve.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,12 +15,34 @@
|
|
|
15
15
|
* the one `chant operator` holds) named for `prApplyGroup`, renews it while
|
|
16
16
|
* it runs and releases it after. An apply that finds it held waits for a
|
|
17
17
|
* later poll, as a forge's concurrency group queues it.
|
|
18
|
+
* - Merged pull request. An apply asks the forge for the pull request whose
|
|
19
|
+
* merge commit the new head is (`pullRequestFor`, as pr-apply does) and
|
|
20
|
+
* passes it as `--pr`, so its commit status link and run index use
|
|
21
|
+
* `<pr>/<commit>`. With none found it runs without `--pr`.
|
|
18
22
|
* - Resume records. Each apply gets `<state>/resume/<prApplyRecordKey>.json`
|
|
19
23
|
* as its `--resume` record, so a re-run of a failed apply at the same
|
|
20
24
|
* commit finishes under the approval it has. This replaces the forge's CI
|
|
21
25
|
* cache.
|
|
26
|
+
* - A gate per wave (#4003). With `--wave-gate` the apply job runs
|
|
27
|
+
* `pr-apply --wave-gate`, which applies the waves in order and stops at
|
|
28
|
+
* the first whose moved plan waits on its own gate. The job fails, and the
|
|
29
|
+
* resume record keeps the waves that applied; once the wave's plan is
|
|
30
|
+
* approved, `rerunFailed` runs the apply again and it carries on from
|
|
31
|
+
* that wave.
|
|
22
32
|
* - Capacity. At most `maxJobs` jobs run at once. A job over the limit is not
|
|
23
33
|
* recorded, so a later poll starts it.
|
|
34
|
+
* - Fast-forwards only (#4122). An apply runs only when the target's new head
|
|
35
|
+
* descends from the head seen before it. Any other move, such as a force
|
|
36
|
+
* push back to an older commit, is recorded as seen and not applied.
|
|
37
|
+
* - `[skip ci]` (#4122). A target head or pull request head whose commit
|
|
38
|
+
* message says `[skip ci]` or `[ci skip]` is recorded as seen and not run,
|
|
39
|
+
* as Actions does.
|
|
40
|
+
* - The forge's ledger (#4121). Before each job, when no other job of this
|
|
41
|
+
* serve runs, the clone's `chant/lifecycle` follows the forge's: it is
|
|
42
|
+
* deleted when the forge has none, and reset to the forge's when neither
|
|
43
|
+
* contains the other. Each is a warning. A local branch ahead of the
|
|
44
|
+
* forge's keeps its facts, and the job's push sends them. Nothing here
|
|
45
|
+
* pushes the ledger.
|
|
24
46
|
*
|
|
25
47
|
* Host mode only: each job runs in a fresh worktree on this host as this
|
|
26
48
|
* user, with the clean environment `ciRun` gives it. A pull request from a
|
|
@@ -31,17 +53,19 @@
|
|
|
31
53
|
* {@link ciServeObserve} is the poll that makes them; a webhook handler would
|
|
32
54
|
* turn a checked payload into the same triggers and schedule them.
|
|
33
55
|
*/
|
|
34
|
-
import { execFileSync } from "node:child_process";
|
|
56
|
+
import { execFileSync, spawnSync } from "node:child_process";
|
|
35
57
|
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
36
|
-
import {
|
|
58
|
+
import { join, resolve } from "node:path";
|
|
37
59
|
import { prApplyGroup, prApplyRecordKey } from "../components/pr-pipeline.js";
|
|
38
60
|
import { forgeFromEnv } from "../pr-forge.js";
|
|
39
61
|
import { formatError, formatWarning } from "../cli/format.js";
|
|
40
62
|
import { acquireLease, currentHolderId, releaseLease, DEFAULT_LEASE_TTL_MS } from "../lifecycle/lease.js";
|
|
41
63
|
import { parseDuration } from "../op/duration.js";
|
|
42
|
-
import {
|
|
43
|
-
import {
|
|
64
|
+
import { reportUrlOf } from "./ci-report-url.js";
|
|
65
|
+
import { CI_JOB_OPS, ciJobPlace, ciLoopOptions, ciSecretsOf, ciRun, ciStatusFromEnv, CiRunError } from "./ci-run.js";
|
|
66
|
+
import { RUNNER_KEY_ENV, signedRunsRequired } from "./ci-green.js";
|
|
44
67
|
import { gitTop } from "./tree.js";
|
|
68
|
+
import { ciServeRunnerKey, formatRunnerKeySetup, setupRunnerKey } from "./ci-runner-key.js";
|
|
45
69
|
export const newCiServeRuntime = () => ({ inflight: new Map() });
|
|
46
70
|
/** The state key of a job. */
|
|
47
71
|
export function ciServeKey(t) {
|
|
@@ -56,6 +80,79 @@ function tryGit(cwd, args) {
|
|
|
56
80
|
return undefined;
|
|
57
81
|
}
|
|
58
82
|
}
|
|
83
|
+
const LEDGER = "chant/lifecycle";
|
|
84
|
+
/** Where the forge's ledger tip is fetched to, a ref only this module writes. */
|
|
85
|
+
const FORGE_LEDGER = "refs/chant/ci-serve/forge-ledger";
|
|
86
|
+
/** `git` with its exit status, for the calls whose answer is the status. */
|
|
87
|
+
function gitStatus(cwd, args) {
|
|
88
|
+
const r = spawnSync("git", args, { cwd, encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"], env: { ...process.env, LC_ALL: "C" } });
|
|
89
|
+
return { code: r.status ?? -1, out: (r.stdout ?? "").trim() };
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Make the clone's `chant/lifecycle` follow the forge's (#4121). The clone's
|
|
93
|
+
* branch outlives the forge's, so a ledger the forge deleted or rewrote would
|
|
94
|
+
* make the next pr-apply find the two diverged and stall.
|
|
95
|
+
*
|
|
96
|
+
* - The forge has none: the local branch and its remote-tracking ref go.
|
|
97
|
+
* - Neither contains the other: the local branch and its remote-tracking ref
|
|
98
|
+
* are reset to the forge's tip.
|
|
99
|
+
* - The local branch is ahead of the forge's, or behind it, or the same: it
|
|
100
|
+
* is left, and an apply's push sends what it holds that the forge lacks.
|
|
101
|
+
*
|
|
102
|
+
* Nothing is pushed, so a rewritten ledger never goes back to the forge. A
|
|
103
|
+
* forge that can't be reached leaves everything as it is; the job's own
|
|
104
|
+
* fetch says why.
|
|
105
|
+
*/
|
|
106
|
+
export function reconcileCiServeLedger(top) {
|
|
107
|
+
const local = tryGit(top, ["rev-parse", "--verify", "--quiet", `refs/heads/${LEDGER}^{commit}`]);
|
|
108
|
+
const listed = gitStatus(top, ["ls-remote", "--exit-code", "origin", `refs/heads/${LEDGER}`]);
|
|
109
|
+
if (listed.code === 2) {
|
|
110
|
+
// A remote-tracking ref left from a deleted branch would be the next push's lease, and refuse it.
|
|
111
|
+
tryGit(top, ["update-ref", "-d", `refs/remotes/origin/${LEDGER}`]);
|
|
112
|
+
if (!local)
|
|
113
|
+
return undefined;
|
|
114
|
+
tryGit(top, ["update-ref", "-d", `refs/heads/${LEDGER}`, local]);
|
|
115
|
+
return { type: "ledger", action: "deleted", local };
|
|
116
|
+
}
|
|
117
|
+
if (listed.code !== 0 || !local)
|
|
118
|
+
return undefined;
|
|
119
|
+
const forge = listed.out.split(/\s+/)[0];
|
|
120
|
+
if (!forge || forge === local)
|
|
121
|
+
return undefined;
|
|
122
|
+
if (gitStatus(top, ["fetch", "--quiet", "--no-tags", "origin", `+refs/heads/${LEDGER}:${FORGE_LEDGER}`]).code !== 0)
|
|
123
|
+
return undefined;
|
|
124
|
+
try {
|
|
125
|
+
const ahead = gitStatus(top, ["merge-base", "--is-ancestor", forge, local]).code === 0;
|
|
126
|
+
const behind = gitStatus(top, ["merge-base", "--is-ancestor", local, forge]).code === 0;
|
|
127
|
+
if (ahead || behind)
|
|
128
|
+
return undefined;
|
|
129
|
+
tryGit(top, ["update-ref", `refs/heads/${LEDGER}`, forge, local]);
|
|
130
|
+
tryGit(top, ["update-ref", `refs/remotes/origin/${LEDGER}`, forge]);
|
|
131
|
+
return { type: "ledger", action: "reset", local, forge };
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
|
+
tryGit(top, ["update-ref", "-d", FORGE_LEDGER]);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/** A commit message that asks for no CI run, as Actions and GitLab read it. */
|
|
138
|
+
const SKIP_CI = /\[(?:skip ci|ci skip)\]/i;
|
|
139
|
+
/** Whether `commit`'s message asks for no CI run. A commit this clone can't read is not skipped. */
|
|
140
|
+
function skipsCi(top, commit) {
|
|
141
|
+
const body = tryGit(top, ["log", "-1", "--format=%B", commit]);
|
|
142
|
+
return body !== undefined && SKIP_CI.test(body);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* How the target branch moved from `from` to `head` (#4122): `fast-forward`
|
|
146
|
+
* when `head` descends from `from`, `other` when it does not, and `unknown`
|
|
147
|
+
* when `head` could not be fetched. Once `head` is here its history is too,
|
|
148
|
+
* so a `from` this clone lacks is not in that history.
|
|
149
|
+
*/
|
|
150
|
+
function targetMove(top, branch, from, head) {
|
|
151
|
+
tryGit(top, ["fetch", "--quiet", "--no-tags", "origin", branch]);
|
|
152
|
+
if (gitStatus(top, ["cat-file", "-e", `${head}^{commit}`]).code !== 0)
|
|
153
|
+
return "unknown";
|
|
154
|
+
return gitStatus(top, ["merge-base", "--is-ancestor", from, head]).code === 0 ? "fast-forward" : "other";
|
|
155
|
+
}
|
|
59
156
|
/** Where a serve keeps its state when `--state` names nowhere: beside the run events, in the repository's common git directory. */
|
|
60
157
|
export function defaultCiServeStateDir(cwd) {
|
|
61
158
|
const common = tryGit(cwd, ["rev-parse", "--path-format=absolute", "--git-common-dir"]);
|
|
@@ -93,15 +190,23 @@ function writeState(file, state) {
|
|
|
93
190
|
const failedEntry = (entry, key, rt) => !!entry && (entry.status === "fail" || (entry.status === "running" && !rt.inflight.has(key)));
|
|
94
191
|
/**
|
|
95
192
|
* 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
|
|
193
|
+
* since the last apply by a fast-forward (none on the first poll, which only
|
|
194
|
+
* notes the head, and none for a head whose message says `[skip ci]`),
|
|
97
195
|
* then a plan for each open pull request head not yet planned, oldest pull
|
|
98
196
|
* 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
|
|
100
|
-
* state file.
|
|
197
|
+
* failed and `rerunFailed` is set. The first poll's head, and a head seen
|
|
198
|
+
* and not applied, are written to the state file.
|
|
101
199
|
*/
|
|
102
200
|
export async function ciServeObserve(opts, rt = newCiServeRuntime()) {
|
|
103
201
|
const place = servePlace(opts);
|
|
104
|
-
const
|
|
202
|
+
const fresh = { forge: opts.forge, repo: opts.repo, env: opts.env, branch: place.branch, ...(place.member ? { member: place.member } : {}) };
|
|
203
|
+
const state = readCiServeState(place.stateFile, fresh);
|
|
204
|
+
// Read again at the write: a job of this serve may have settled while the forge answered.
|
|
205
|
+
const update = (fn) => {
|
|
206
|
+
const s = readCiServeState(place.stateFile, fresh);
|
|
207
|
+
fn(s);
|
|
208
|
+
writeState(place.stateFile, s);
|
|
209
|
+
};
|
|
105
210
|
const triggers = [];
|
|
106
211
|
const events = [];
|
|
107
212
|
const [head, prs] = await Promise.all([opts.client.branchHead(place.branch), opts.client.openPullRequests(place.branch)]);
|
|
@@ -110,14 +215,27 @@ export async function ciServeObserve(opts, rt = newCiServeRuntime()) {
|
|
|
110
215
|
}
|
|
111
216
|
else if (state.target === undefined) {
|
|
112
217
|
// What the branch held before this runner watched it was applied by whatever ran then.
|
|
113
|
-
|
|
114
|
-
|
|
218
|
+
update((s) => {
|
|
219
|
+
s.target = head;
|
|
220
|
+
});
|
|
115
221
|
events.push({ type: "baseline", commit: head });
|
|
116
222
|
}
|
|
117
223
|
else if (head !== state.target) {
|
|
224
|
+
const from = state.target;
|
|
225
|
+
const move = targetMove(place.top, place.branch, from, head);
|
|
118
226
|
const entry = state.jobs[ciServeKey({ job: "apply", commit: head })];
|
|
119
|
-
if (
|
|
120
|
-
|
|
227
|
+
if (move === "unknown") {
|
|
228
|
+
events.push({ type: "error", message: `${place.branch} is at ${head.slice(0, 12)} on the forge, and that commit could not be fetched; the next poll tries again` });
|
|
229
|
+
}
|
|
230
|
+
else if (move === "other" || (!entry && skipsCi(place.top, head))) {
|
|
231
|
+
// #4122: a move that is not a fast-forward, or a head that asks for no run, is seen and not applied.
|
|
232
|
+
update((s) => {
|
|
233
|
+
s.target = head;
|
|
234
|
+
});
|
|
235
|
+
events.push({ type: "not-run", job: "apply", commit: head, reason: move === "other" ? "not-fast-forward" : "skip-ci", ...(move === "other" ? { branch: place.branch, from } : {}) });
|
|
236
|
+
}
|
|
237
|
+
else if (!entry)
|
|
238
|
+
triggers.push({ job: "apply", commit: head, base: from });
|
|
121
239
|
else if (opts.rerunFailed && failedEntry(entry, ciServeKey(entry), rt))
|
|
122
240
|
triggers.push({ job: "apply", commit: head, base: entry.base, rerun: true });
|
|
123
241
|
}
|
|
@@ -140,10 +258,21 @@ export async function ciServeObserve(opts, rt = newCiServeRuntime()) {
|
|
|
140
258
|
const key = ciServeKey({ job: "plan", commit: pr.headSha, pr: pr.number });
|
|
141
259
|
const entry = state.jobs[key];
|
|
142
260
|
const base = pr.baseSha ?? head;
|
|
143
|
-
if (!base)
|
|
261
|
+
if (!base || state.skipped?.[key])
|
|
144
262
|
continue;
|
|
145
|
-
if (!entry)
|
|
146
|
-
|
|
263
|
+
if (!entry) {
|
|
264
|
+
// #4122: a head whose message asks for no run is seen and not planned.
|
|
265
|
+
if (gitStatus(place.top, ["cat-file", "-e", `${pr.headSha}^{commit}`]).code !== 0)
|
|
266
|
+
tryGit(place.top, ["fetch", "--quiet", "--no-tags", "origin", `refs/pull/${pr.number}/head`]);
|
|
267
|
+
if (skipsCi(place.top, pr.headSha)) {
|
|
268
|
+
update((s) => {
|
|
269
|
+
s.skipped = { ...s.skipped, [key]: "skip-ci" };
|
|
270
|
+
});
|
|
271
|
+
events.push({ type: "not-run", job: "plan", commit: pr.headSha, pr: pr.number, reason: "skip-ci" });
|
|
272
|
+
}
|
|
273
|
+
else
|
|
274
|
+
triggers.push({ job: "plan", commit: pr.headSha, base, pr: pr.number });
|
|
275
|
+
}
|
|
147
276
|
else if (opts.rerunFailed && failedEntry(entry, key, rt))
|
|
148
277
|
triggers.push({ job: "plan", commit: pr.headSha, base: entry.base, pr: pr.number, rerun: true });
|
|
149
278
|
}
|
|
@@ -199,6 +328,12 @@ export async function ciServeSchedule(opts, triggers, rt = newCiServeRuntime())
|
|
|
199
328
|
}
|
|
200
329
|
lease = got.lease;
|
|
201
330
|
}
|
|
331
|
+
// #4121: with no other job of this serve writing it, the clone's ledger follows the forge's.
|
|
332
|
+
if (rt.inflight.size === 0) {
|
|
333
|
+
const ledger = reconcileCiServeLedger(place.top);
|
|
334
|
+
if (ledger)
|
|
335
|
+
emit(ledger);
|
|
336
|
+
}
|
|
202
337
|
const previous = readCiServeState(place.stateFile, fresh).jobs[key];
|
|
203
338
|
const attempt = (previous?.attempts ?? 0) + 1;
|
|
204
339
|
const runId = `chant-serve-${now().getTime()}-${t.job}-${t.commit.slice(0, 8)}`;
|
|
@@ -238,10 +373,14 @@ async function runJob(opts, place, t, paths, held) {
|
|
|
238
373
|
}, Math.max(1000, Math.floor(held.ttlMs / 3)))
|
|
239
374
|
: undefined;
|
|
240
375
|
renew?.unref?.();
|
|
376
|
+
let merged;
|
|
241
377
|
try {
|
|
242
378
|
// The pull request's head is on the forge's refs/pull/<n>/head, the target's on the branch.
|
|
243
379
|
tryGit(place.top, ["fetch", "--quiet", "--no-tags", "origin", t.job === "plan" ? `refs/pull/${t.pr}/head` : place.branch]);
|
|
244
380
|
const hostEnv = { ...(opts.job?.hostEnv ?? process.env), GITHUB_REPOSITORY: opts.repo };
|
|
381
|
+
// An apply is for a merge: pass the pull request whose merge commit it is, so the commit status link and the run index use `<pr>/<commit>`. None found, or a forge that errs, is today's behaviour.
|
|
382
|
+
if (t.job === "apply" && opts.client.pullRequestFor)
|
|
383
|
+
merged = (await opts.client.pullRequestFor(t.commit).catch(() => null)) ?? undefined;
|
|
245
384
|
const run = opts.run ?? ciRun;
|
|
246
385
|
const r = await run({
|
|
247
386
|
...opts.job,
|
|
@@ -251,17 +390,17 @@ async function runJob(opts, place, t, paths, held) {
|
|
|
251
390
|
env: opts.env,
|
|
252
391
|
forge: opts.forge,
|
|
253
392
|
base: t.base,
|
|
254
|
-
...(t.job === "plan" ? { pr: t.pr } : {}),
|
|
393
|
+
...(t.job === "plan" ? { pr: t.pr } : merged !== undefined ? { pr: merged } : {}),
|
|
255
394
|
commit: t.commit,
|
|
256
395
|
output: paths.report,
|
|
257
396
|
runId: paths.runId,
|
|
258
397
|
...(paths.resume ? { resumeRecord: paths.resume } : {}),
|
|
259
398
|
});
|
|
260
399
|
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 } : {}) };
|
|
400
|
+
return { status: r.status === "ok" ? "ok" : "fail", ...(merged !== undefined ? { pr: merged } : {}), ...(why && r.status !== "ok" ? { failure: why } : {}), ...(r.report ? { report: r.report } : {}) };
|
|
262
401
|
}
|
|
263
402
|
catch (err) {
|
|
264
|
-
return { status: "fail", failure: message(err) };
|
|
403
|
+
return { status: "fail", ...(merged !== undefined ? { pr: merged } : {}), failure: message(err) };
|
|
265
404
|
}
|
|
266
405
|
finally {
|
|
267
406
|
if (renew)
|
|
@@ -319,14 +458,50 @@ export function formatCiServeEvent(e) {
|
|
|
319
458
|
return `${at(e.job, e.commit, e.pr)} started, run ${e.runId}, attempt ${e.attempt}${e.resume ? ", resuming" : ""}`;
|
|
320
459
|
case "settled":
|
|
321
460
|
return `${at(e.job, e.commit, e.pr)} ${e.status === "ok" ? "passed" : `failed${e.failure ? `: ${e.failure}` : ""}`}${e.report ? `; report ${e.report}` : ""}`;
|
|
461
|
+
case "not-run":
|
|
462
|
+
return e.reason === "skip-ci"
|
|
463
|
+
? `${at(e.job, e.commit, e.pr)} is not run: its commit message says [skip ci]`
|
|
464
|
+
: `${e.branch ?? "the target branch"} moved from ${e.from?.slice(0, 12) ?? "a commit"} to ${e.commit.slice(0, 12)}, which is not a fast-forward, so ${e.commit.slice(0, 12)} is recorded as seen and not applied`;
|
|
465
|
+
case "ledger":
|
|
466
|
+
return e.action === "deleted"
|
|
467
|
+
? `the forge has no ${LEDGER}, so this clone's, at ${e.local.slice(0, 12)}, was deleted`
|
|
468
|
+
: `the forge's ${LEDGER} at ${e.forge.slice(0, 12)} does not contain this clone's at ${e.local.slice(0, 12)}, so this clone's was reset to the forge's and not pushed`;
|
|
322
469
|
case "error":
|
|
323
470
|
return `error: ${e.message}`;
|
|
324
471
|
}
|
|
325
472
|
}
|
|
326
473
|
// ── The command ──────────────────────────────────────────────────────────────
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
474
|
+
/**
|
|
475
|
+
* `chant ci serve|run --setup-key [--trust [--principal <name>]] [--state <dir>] [--branch <name>]` (#4099):
|
|
476
|
+
* make the host's runner key when there is none, print its public half on
|
|
477
|
+
* stdout, and say whether the target's head lists it. With --trust, commit
|
|
478
|
+
* the runner entry on a branch of its own and push it for review.
|
|
479
|
+
*/
|
|
480
|
+
export function runnerKeySetupCommand(ctx) {
|
|
481
|
+
const { args } = ctx;
|
|
482
|
+
const cwd = process.cwd();
|
|
483
|
+
const top = gitTop(cwd);
|
|
484
|
+
if (!top)
|
|
485
|
+
throw new CiRunError("the runner key is kept in the repository's git directory, and this directory is not in a git repository");
|
|
486
|
+
if (args.ciPrincipal !== undefined && !args.trustKey)
|
|
487
|
+
throw new CiRunError("--principal names who --trust lists the key for; give --trust with it");
|
|
488
|
+
const branch = args.branch ?? "main";
|
|
489
|
+
const setup = setupRunnerKey({
|
|
490
|
+
top,
|
|
491
|
+
stateDir: args.statePath ? resolve(args.statePath) : defaultCiServeStateDir(cwd),
|
|
492
|
+
branch,
|
|
493
|
+
...(args.ciPrincipal ? { principal: args.ciPrincipal } : {}),
|
|
494
|
+
...(args.trustKey ? { trust: true } : {}),
|
|
495
|
+
...(args.by ? { by: args.by } : {}),
|
|
496
|
+
});
|
|
497
|
+
console.log(setup.key.publicKey);
|
|
498
|
+
console.error(formatRunnerKeySetup(setup, branch));
|
|
499
|
+
return 0;
|
|
500
|
+
}
|
|
501
|
+
const USAGE = "chant ci serve --setup-key [--trust [--principal <name>]] [--state <dir>] [--branch <name>] | " +
|
|
502
|
+
"chant ci serve --forge forgejo|github --repo <owner/repo> --env <env> [--interval <s>] [--max-jobs <n>] [--state <dir>] " +
|
|
503
|
+
"[--author <login>]... [--once] [--rerun-failed] [--gate <name>] [--wave-gate <name>] [--branch <name>] [--events-json] [--report-url <url>] [--no-status] [--status-url <url template>] " +
|
|
504
|
+
"[--image <image>] [--before-script <line>]... [--pr-build] [--pr-build-command <line>] [--chant <command>] [--pass-env <NAME>]... [--secrets <file>] [--key <runner key.pem>] [--unsigned]";
|
|
330
505
|
const ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
331
506
|
/** `--interval`: seconds, or a duration such as `30s` or `2m`. Default 30 seconds. */
|
|
332
507
|
export function ciServeInterval(value) {
|
|
@@ -341,6 +516,8 @@ export function ciServeInterval(value) {
|
|
|
341
516
|
export async function runCiServe(ctx) {
|
|
342
517
|
const { args } = ctx;
|
|
343
518
|
try {
|
|
519
|
+
if (args.setupKey)
|
|
520
|
+
return runnerKeySetupCommand(ctx);
|
|
344
521
|
const forge = args.forge;
|
|
345
522
|
if (forge !== "forgejo" && forge !== "github")
|
|
346
523
|
throw new CiRunError(`--forge names the forge ci serve polls: --forge forgejo|github${forge ? `, not ${JSON.stringify(forge)}` : ""}`);
|
|
@@ -352,41 +529,69 @@ export async function runCiServe(ctx) {
|
|
|
352
529
|
if (!ENV_NAME.test(name))
|
|
353
530
|
throw new CiRunError(`--pass-env takes a variable's name, not ${JSON.stringify(name)}`);
|
|
354
531
|
const intervalMs = ciServeInterval(args.interval);
|
|
355
|
-
const
|
|
356
|
-
const
|
|
532
|
+
const cwd = process.cwd();
|
|
533
|
+
const top = gitTop(cwd);
|
|
534
|
+
if (!top)
|
|
535
|
+
throw new CiRunError("ci serve runs in a clone of the repository it serves, and this directory is not in a git repository");
|
|
536
|
+
const stateDir = args.statePath ? resolve(args.statePath) : defaultCiServeStateDir(cwd);
|
|
537
|
+
const branch = args.branch ?? "main";
|
|
538
|
+
// #4099: the host's key, checked against .chant/trust.json at the target's head before the first poll.
|
|
539
|
+
// #4156: signing is opt-in. Without ci.green.signedSince no key is quiet, and an untrusted one warns once and serves unsigned.
|
|
540
|
+
const keyed = ciServeRunnerKey({
|
|
541
|
+
top,
|
|
542
|
+
stateDir,
|
|
543
|
+
branch,
|
|
544
|
+
...(args.key !== undefined ? { keyFile: resolve(args.key) } : {}),
|
|
545
|
+
envKey: process.env[RUNNER_KEY_ENV] || undefined,
|
|
546
|
+
unsigned: args.unsigned,
|
|
547
|
+
required: signedRunsRequired(cwd),
|
|
548
|
+
});
|
|
549
|
+
const fromFlag = keyed.fromFlag;
|
|
550
|
+
const runnerKey = keyed.pem;
|
|
551
|
+
if (keyed.warning)
|
|
552
|
+
console.error(formatWarning({ message: keyed.warning }));
|
|
553
|
+
if (runnerKey !== undefined)
|
|
554
|
+
console.error(`ci serve: signing runs with the runner key from ${keyed.source}`);
|
|
555
|
+
else if (keyed.note && args.verbose)
|
|
556
|
+
console.error(`ci serve: ${keyed.note}`);
|
|
557
|
+
// #4096: read once, so a loose or broken secrets file stops the serve before its first poll.
|
|
558
|
+
const secrets = ciSecretsOf(args.ciSecrets);
|
|
559
|
+
// #4160: without --report-url, the declaration's ci.reportUrl.
|
|
560
|
+
const reportUrl = await reportUrlOf(args.reportUrl, cwd);
|
|
561
|
+
if (reportUrl && !args.reportUrl)
|
|
562
|
+
console.error(`ci serve: reports and the run index go to ${reportUrl}, the declaration's ci.reportUrl`);
|
|
357
563
|
const hostEnv = { ...process.env, GITHUB_REPOSITORY: args.ciRepo };
|
|
358
564
|
const client = forgeFromEnv(forge, hostEnv);
|
|
565
|
+
const { status, warning } = ciStatusFromEnv({ forge, hostEnv, noStatus: args.noStatus, statusUrl: args.statusUrl });
|
|
566
|
+
if (warning)
|
|
567
|
+
console.error(formatWarning({ message: warning }));
|
|
359
568
|
if (!client.openPullRequests || !client.branchHead)
|
|
360
569
|
throw new CiRunError(`the ${forge} client cannot list pull requests`);
|
|
361
570
|
const opts = {
|
|
362
|
-
cwd
|
|
571
|
+
cwd,
|
|
363
572
|
forge,
|
|
364
573
|
repo: args.ciRepo,
|
|
365
574
|
env: args.env,
|
|
366
|
-
client: { openPullRequests: client.openPullRequests.bind(client), branchHead: client.branchHead.bind(client) },
|
|
367
|
-
|
|
575
|
+
client: { openPullRequests: client.openPullRequests.bind(client), branchHead: client.branchHead.bind(client), pullRequestFor: client.pullRequestFor.bind(client) },
|
|
576
|
+
stateDir,
|
|
368
577
|
...(args.maxJobs ? { maxJobs: args.maxJobs } : {}),
|
|
369
578
|
...(args.ciAuthors?.length ? { authors: args.ciAuthors } : {}),
|
|
370
579
|
...(args.rerunFailed ? { rerunFailed: true } : {}),
|
|
371
580
|
job: {
|
|
372
|
-
loop: {
|
|
373
|
-
|
|
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
|
-
},
|
|
581
|
+
loop: ciLoopOptions(reportUrl ? { ...args, reportUrl } : args),
|
|
582
|
+
...(args.runIndexLimit ? { runIndexLimit: args.runIndexLimit } : {}),
|
|
380
583
|
...(args.image ? { image: args.image } : {}),
|
|
381
584
|
...(args.beforeScript?.length ? { beforeScript: args.beforeScript } : {}),
|
|
382
585
|
...(args.ciChant ? { chant: args.ciChant } : {}),
|
|
383
586
|
...(args.passEnv?.length ? { passEnv: args.passEnv } : {}),
|
|
587
|
+
...(status ? { status } : {}),
|
|
588
|
+
...(secrets ? { secrets } : {}),
|
|
384
589
|
...(runnerKey !== undefined ? { runnerKey, runnerKeyFromEnv: !fromFlag } : {}),
|
|
385
590
|
...(args.eventsJson ? { runEvents: (line) => void process.stdout.write(line) } : {}),
|
|
386
591
|
hostEnv,
|
|
387
592
|
stepOutput: (line) => void process.stderr.write(`${line}\n`),
|
|
388
593
|
},
|
|
389
|
-
log: (e) => console.error(e.type === "error" ? formatWarning({ message: formatCiServeEvent(e) }) : `ci serve: ${formatCiServeEvent(e)}`),
|
|
594
|
+
log: (e) => console.error(e.type === "error" || e.type === "ledger" ? formatWarning({ message: formatCiServeEvent(e) }) : `ci serve: ${formatCiServeEvent(e)}`),
|
|
390
595
|
};
|
|
391
596
|
if (args.once) {
|
|
392
597
|
const pass = await ciServePass(opts);
|
|
@@ -171,6 +171,14 @@ export type CiSource = "checks" | "runs";
|
|
|
171
171
|
/** The declaration's `ci` block (#3573). */
|
|
172
172
|
export interface CiDeclaration {
|
|
173
173
|
green: CiGreen | null;
|
|
174
|
+
/**
|
|
175
|
+
* `ci.reportUrl` (#4160): where the pull-request jobs copy their reports
|
|
176
|
+
* and `chant ci run` keeps the run index, `<reportUrl>/runs/index.json`.
|
|
177
|
+
* An `s3://` or `file://` URL, as `--report-url` takes, without a trailing
|
|
178
|
+
* slash. The commands that take `--report-url` default to it. Null when
|
|
179
|
+
* the declaration sets none.
|
|
180
|
+
*/
|
|
181
|
+
reportUrl: string | null;
|
|
174
182
|
}
|
|
175
183
|
export interface MemberRole {
|
|
176
184
|
name: string;
|