@intentius/chant 0.124.31 → 0.124.33
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/ci-jobs.d.ts +4 -0
- package/dist/ci-jobs.d.ts.map +1 -1
- package/dist/ci-jobs.js +9 -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 +38 -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/lifecycle-health.d.ts +16 -0
- package/dist/cli/handlers/lifecycle-health.d.ts.map +1 -0
- package/dist/cli/handlers/lifecycle-health.js +150 -0
- package/dist/cli/handlers/lifecycle.d.ts +26 -0
- package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
- package/dist/cli/handlers/lifecycle.js +1 -1
- 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 +16 -0
- package/dist/cli/handlers/pr.d.ts.map +1 -1
- package/dist/cli/handlers/pr.js +610 -32
- package/dist/cli/handlers/promote.d.ts.map +1 -1
- package/dist/cli/handlers/promote.js +19 -2
- package/dist/cli/handlers/release.d.ts +16 -1
- package/dist/cli/handlers/release.d.ts.map +1 -1
- package/dist/cli/handlers/release.js +83 -11
- 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 +121 -33
- package/dist/cli/parse-args.d.ts.map +1 -1
- package/dist/cli/parse-args.js +37 -0
- package/dist/cli/registry.d.ts +29 -6
- 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/deploy-inputs.d.ts +91 -0
- package/dist/components/deploy-inputs.d.ts.map +1 -0
- package/dist/components/deploy-inputs.js +184 -0
- package/dist/components/driver.d.ts +38 -0
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/driver.js +56 -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/gate-plan.d.ts +8 -0
- package/dist/components/gate-plan.d.ts.map +1 -1
- package/dist/components/gate-plan.js +6 -0
- package/dist/components/pr-pipeline.d.ts +98 -12
- package/dist/components/pr-pipeline.d.ts.map +1 -1
- package/dist/components/pr-pipeline.js +146 -23
- package/dist/components/pr-run.d.ts +128 -30
- package/dist/components/pr-run.d.ts.map +1 -1
- package/dist/components/pr-run.js +290 -70
- package/dist/components/release-compile.d.ts +37 -2
- package/dist/components/release-compile.d.ts.map +1 -1
- package/dist/components/release-compile.js +64 -8
- package/dist/components/release-promote.d.ts +17 -3
- package/dist/components/release-promote.d.ts.map +1 -1
- package/dist/components/release-promote.js +79 -18
- package/dist/components/verbs/bom-writer.d.ts +1 -1
- package/dist/components/verbs/bom-writer.d.ts.map +1 -1
- package/dist/components/verbs/lockfile-sbom-generator.d.ts +20 -0
- package/dist/components/verbs/lockfile-sbom-generator.d.ts.map +1 -1
- package/dist/components/verbs/lockfile-sbom-generator.js +41 -4
- package/dist/components/wave-plan.d.ts +15 -2
- package/dist/components/wave-plan.d.ts.map +1 -1
- package/dist/components/wave-plan.js +44 -5
- 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/graph-detail.d.ts.map +1 -1
- package/dist/graph-detail.js +32 -7
- package/dist/health.d.ts +110 -0
- package/dist/health.d.ts.map +1 -0
- package/dist/health.js +105 -0
- package/dist/health.schema.json +191 -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 +29 -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/merge-record.d.ts +104 -0
- package/dist/lifecycle/merge-record.d.ts.map +1 -0
- package/dist/lifecycle/merge-record.js +102 -0
- package/dist/lifecycle/publish-attachments.d.ts +8 -5
- package/dist/lifecycle/publish-attachments.d.ts.map +1 -1
- package/dist/lifecycle/publish-attachments.js +27 -13
- package/dist/lifecycle/publish-npm.d.ts +3 -2
- package/dist/lifecycle/publish-npm.d.ts.map +1 -1
- package/dist/lifecycle/publish-npm.js +4 -3
- package/dist/lifecycle/release-at.d.ts +40 -0
- package/dist/lifecycle/release-at.d.ts.map +1 -0
- package/dist/lifecycle/release-at.js +83 -0
- package/dist/lifecycle/release-cut.d.ts.map +1 -1
- package/dist/lifecycle/release-cut.js +23 -12
- 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/release-publish.d.ts +28 -12
- package/dist/lifecycle/release-publish.d.ts.map +1 -1
- package/dist/lifecycle/release-publish.js +29 -17
- package/dist/lifecycle/release-store.d.ts +25 -2
- package/dist/lifecycle/release-store.d.ts.map +1 -1
- package/dist/lifecycle/release-store.js +40 -13
- package/dist/lifecycle/run-ledger.d.ts.map +1 -1
- package/dist/lifecycle/run-ledger.js +1 -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/lint/rules/op/index.d.ts +2 -1
- package/dist/lint/rules/op/index.d.ts.map +1 -1
- package/dist/lint/rules/op/index.js +4 -2
- package/dist/lint/rules/op/ops018-shell-image-digest.d.ts +10 -0
- package/dist/lint/rules/op/ops018-shell-image-digest.d.ts.map +1 -0
- package/dist/lint/rules/op/ops018-shell-image-digest.js +38 -0
- 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/activity-contracts.d.ts +5 -0
- package/dist/op/activities/activity-contracts.d.ts.map +1 -1
- package/dist/op/activities/activity-contracts.js +3 -0
- package/dist/op/activities/factory.js +1 -1
- package/dist/op/activities/shell.d.ts +38 -0
- package/dist/op/activities/shell.d.ts.map +1 -1
- package/dist/op/activities/shell.js +89 -3
- package/dist/op/builders.d.ts +7 -0
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/builders.js +7 -0
- 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/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/runtime.d.ts +2 -0
- package/dist/op/runtime.d.ts.map +1 -1
- 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 +10 -0
- package/dist/pr-forge.d.ts.map +1 -1
- package/dist/pr-forge.js +39 -0
- package/dist/pr-loop.d.ts +155 -7
- package/dist/pr-loop.d.ts.map +1 -1
- package/dist/pr-loop.js +137 -11
- package/dist/pr-report-url.d.ts +4 -4
- package/dist/pr-report-url.d.ts.map +1 -1
- package/dist/pr-report-url.js +5 -5
- package/dist/runner-start.d.ts +179 -0
- package/dist/runner-start.d.ts.map +1 -0
- package/dist/runner-start.js +277 -0
- 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 +238 -231
- 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/check.schema.json +70 -2
- package/dist/workspace/checks/boxes.d.ts +6 -6
- package/dist/workspace/checks/boxes.js +9 -9
- package/dist/workspace/checks/security.d.ts +35 -0
- package/dist/workspace/checks/security.d.ts.map +1 -0
- package/dist/workspace/checks/security.js +305 -0
- package/dist/workspace/checks.d.ts +2 -0
- package/dist/workspace/checks.d.ts.map +1 -1
- package/dist/workspace/checks.js +5 -0
- package/dist/workspace/ci-builds.d.ts +163 -0
- package/dist/workspace/ci-builds.d.ts.map +1 -0
- package/dist/workspace/ci-builds.js +315 -0
- package/dist/workspace/ci-green-cli.d.ts +2 -1
- package/dist/workspace/ci-green-cli.d.ts.map +1 -1
- package/dist/workspace/ci-green-cli.js +25 -5
- package/dist/workspace/ci-green-forge.d.ts +18 -4
- package/dist/workspace/ci-green-forge.d.ts.map +1 -1
- package/dist/workspace/ci-green-forge.js +12 -0
- package/dist/workspace/ci-green-workflow.d.ts +55 -1
- package/dist/workspace/ci-green-workflow.d.ts.map +1 -1
- package/dist/workspace/ci-green-workflow.js +128 -1
- package/dist/workspace/ci-green.d.ts +117 -16
- package/dist/workspace/ci-green.d.ts.map +1 -1
- package/dist/workspace/ci-green.js +358 -43
- package/dist/workspace/ci-last-green.schema.json +49 -0
- package/dist/workspace/ci-list.schema.json +47 -7
- 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 +13 -1
- package/dist/workspace/ci-run-index.d.ts.map +1 -1
- package/dist/workspace/ci-run-index.js +6 -4
- package/dist/workspace/ci-run-index.schema.json +6 -4
- package/dist/workspace/ci-run.d.ts +85 -6
- package/dist/workspace/ci-run.d.ts.map +1 -1
- package/dist/workspace/ci-run.js +262 -64
- package/dist/workspace/ci-runner-key.d.ts +16 -3
- package/dist/workspace/ci-runner-key.d.ts.map +1 -1
- package/dist/workspace/ci-runner-key.js +30 -10
- package/dist/workspace/ci-runner-start.d.ts +77 -0
- package/dist/workspace/ci-runner-start.d.ts.map +1 -0
- package/dist/workspace/ci-runner-start.js +185 -0
- package/dist/workspace/ci-serve.d.ts +130 -11
- package/dist/workspace/ci-serve.d.ts.map +1 -1
- package/dist/workspace/ci-serve.js +323 -40
- package/dist/workspace/declaration.d.ts +25 -0
- package/dist/workspace/declaration.d.ts.map +1 -1
- package/dist/workspace/declaration.js +14 -2
- package/dist/workspace/declaration.schema.json +30 -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 +8 -1
- package/dist/workspace/ls.d.ts.map +1 -1
- package/dist/workspace/ls.js +2 -1
- package/dist/workspace/ls.schema.json +9 -2
- package/dist/workspace/member-pipeline.d.ts +1 -0
- package/dist/workspace/member-pipeline.d.ts.map +1 -1
- package/dist/workspace/member-pipeline.js +2 -0
- package/dist/workspace/merge-record.schema.json +49 -0
- 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 +75 -8
- package/dist/workspace/reason-codes.d.ts +18 -1
- package/dist/workspace/reason-codes.d.ts.map +1 -1
- package/dist/workspace/reason-codes.js +20 -2
- package/dist/workspace/release-candidates.d.ts +129 -0
- package/dist/workspace/release-candidates.d.ts.map +1 -0
- package/dist/workspace/release-candidates.js +233 -0
- package/dist/workspace/release-candidates.schema.json +353 -0
- package/dist/workspace/run-event.schema.json +3 -1
- package/dist/workspace/security.d.ts +40 -0
- package/dist/workspace/security.d.ts.map +1 -0
- package/dist/workspace/security.js +99 -0
- package/dist/workspace/status.schema.json +3 -1
- 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 +8 -1
- package/src/__fixtures__/pr-loop/pr-apply-wave-waiting.note.golden.md +48 -0
- package/src/__fixtures__/pr-loop/pr-plan.note.golden.md +1 -1
- package/src/ci-jobs.ts +11 -2
- 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 +105 -0
- package/src/cli/handlers/build.ts +35 -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/lifecycle-health.test.ts +123 -0
- package/src/cli/handlers/lifecycle-health.ts +157 -0
- package/src/cli/handlers/lifecycle.ts +1 -1
- 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-deploy-inputs.test.ts +209 -0
- package/src/cli/handlers/pr-record.test.ts +201 -0
- package/src/cli/handlers/pr-waves.test.ts +449 -0
- package/src/cli/handlers/pr.test.ts +156 -0
- package/src/cli/handlers/pr.ts +648 -33
- package/src/cli/handlers/promote.test.ts +43 -1
- package/src/cli/handlers/promote.ts +19 -3
- package/src/cli/handlers/release-cut-at.e2e.test.ts +115 -0
- package/src/cli/handlers/release-publish-targets.e2e.test.ts +2 -2
- package/src/cli/handlers/release-verify.e2e.test.ts +12 -10
- package/src/cli/handlers/release.e2e.test.ts +19 -28
- package/src/cli/handlers/release.ts +81 -11
- 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 +18 -0
- package/src/cli/main.ts +120 -33
- package/src/cli/parse-args.ts +28 -0
- package/src/cli/registry.ts +35 -8
- 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/deploy-inputs.test.ts +108 -0
- package/src/components/deploy-inputs.ts +225 -0
- package/src/components/driver.test.ts +36 -1
- package/src/components/driver.ts +87 -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/gate-plan.ts +9 -0
- package/src/components/pr-pipeline.test.ts +100 -0
- package/src/components/pr-pipeline.ts +184 -28
- package/src/components/pr-run.test.ts +323 -18
- package/src/components/pr-run.ts +355 -76
- package/src/components/release-compile.test.ts +34 -0
- package/src/components/release-compile.ts +89 -8
- package/src/components/release-promote.test.ts +55 -2
- package/src/components/release-promote.ts +93 -23
- package/src/components/verbs/bom-writer.ts +1 -1
- package/src/components/verbs/lockfile-sbom-generator.test.ts +36 -0
- package/src/components/verbs/lockfile-sbom-generator.ts +43 -5
- package/src/components/wave-plan.ts +48 -8
- 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/graph-detail.test.ts +57 -0
- package/src/graph-detail.ts +33 -7
- package/src/health.schema.json +191 -0
- package/src/health.test.ts +62 -0
- package/src/health.ts +178 -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 +43 -1
- package/src/lifecycle/affected.test.ts +7 -0
- package/src/lifecycle/affected.ts +6 -1
- package/src/lifecycle/merge-record.test.ts +111 -0
- package/src/lifecycle/merge-record.ts +154 -0
- package/src/lifecycle/publish-attachments.ts +25 -13
- package/src/lifecycle/publish-npm.ts +4 -3
- package/src/lifecycle/publish-targets.test.ts +34 -4
- package/src/lifecycle/release-at.test.ts +48 -0
- package/src/lifecycle/release-at.ts +100 -0
- package/src/lifecycle/release-cut.test.ts +41 -0
- package/src/lifecycle/release-cut.ts +22 -11
- package/src/lifecycle/release-ledger.ts +34 -0
- package/src/lifecycle/release-publish.test.ts +43 -13
- package/src/lifecycle/release-publish.ts +38 -18
- package/src/lifecycle/release-store.ts +57 -13
- package/src/lifecycle/run-ledger.test.ts +13 -0
- package/src/lifecycle/run-ledger.ts +1 -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/lint/rules/op/index.ts +4 -2
- package/src/lint/rules/op/ops018-shell-image-digest.test.ts +60 -0
- package/src/lint/rules/op/ops018-shell-image-digest.ts +48 -0
- package/src/module-source.test.ts +85 -0
- package/src/module-source.ts +112 -0
- package/src/op/activities/activity-contracts.ts +3 -0
- package/src/op/activities/factory.ts +1 -1
- package/src/op/activities/shell-container.e2e.test.ts +67 -0
- package/src/op/activities/shell.test.ts +44 -1
- package/src/op/activities/shell.ts +110 -3
- package/src/op/builders.ts +7 -0
- 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/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/runtime.ts +2 -0
- package/src/op/step-console.test.ts +4 -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 +42 -0
- package/src/pr-forge.ts +40 -0
- package/src/pr-loop-bundle.test.ts +2 -1
- package/src/pr-loop.test.ts +146 -1
- package/src/pr-loop.ts +278 -17
- package/src/pr-report-url.ts +7 -7
- package/src/runner-start-bundle.test.ts +29 -0
- package/src/runner-start.test.ts +179 -0
- package/src/runner-start.ts +329 -0
- 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/check-contract.test.ts +3 -2
- package/src/workspace/check.schema.json +70 -2
- package/src/workspace/checks/boxes.ts +9 -9
- package/src/workspace/checks/security.test.ts +138 -0
- package/src/workspace/checks/security.ts +305 -0
- package/src/workspace/checks.ts +5 -0
- package/src/workspace/ci-builds.e2e.test.ts +208 -0
- package/src/workspace/ci-builds.test.ts +174 -0
- package/src/workspace/ci-builds.ts +385 -0
- package/src/workspace/ci-green-builds.test.ts +180 -0
- package/src/workspace/ci-green-cli.test.ts +54 -0
- package/src/workspace/ci-green-cli.ts +26 -5
- package/src/workspace/ci-green-forge.ts +30 -4
- package/src/workspace/ci-green-runs.test.ts +53 -11
- package/src/workspace/ci-green-workflow.test.ts +84 -1
- package/src/workspace/ci-green-workflow.ts +139 -2
- package/src/workspace/ci-green.test.ts +6 -3
- package/src/workspace/ci-green.ts +408 -48
- package/src/workspace/ci-last-green.schema.json +49 -0
- package/src/workspace/ci-list.schema.json +47 -7
- 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 +6 -4
- package/src/workspace/ci-run-index.test.ts +42 -3
- package/src/workspace/ci-run-index.ts +19 -5
- package/src/workspace/ci-run.test.ts +203 -8
- package/src/workspace/ci-run.ts +295 -63
- package/src/workspace/ci-runner-key.test.ts +55 -17
- package/src/workspace/ci-runner-key.ts +36 -11
- package/src/workspace/ci-runner-start.test.ts +151 -0
- package/src/workspace/ci-runner-start.ts +193 -0
- package/src/workspace/ci-serve-builds.test.ts +86 -0
- package/src/workspace/ci-serve.test.ts +209 -6
- package/src/workspace/ci-serve.ts +341 -42
- package/src/workspace/declaration.schema.json +30 -2
- package/src/workspace/declaration.test.ts +40 -0
- package/src/workspace/declaration.ts +40 -3
- package/src/workspace/export.ts +6 -3
- package/src/workspace/ls.schema.json +9 -2
- package/src/workspace/ls.ts +10 -4
- package/src/workspace/member-pipeline.ts +2 -1
- package/src/workspace/merge-record.schema.json +49 -0
- package/src/workspace/pin-integrity.test.ts +5 -0
- package/src/workspace/pin-integrity.ts +3 -2
- package/src/workspace/pr-report.schema.json +75 -8
- package/src/workspace/reason-codes.test.ts +2 -0
- package/src/workspace/reason-codes.ts +20 -2
- package/src/workspace/release-candidates.schema.json +353 -0
- package/src/workspace/release-candidates.test.ts +106 -0
- package/src/workspace/release-candidates.ts +315 -0
- package/src/workspace/run-event.schema.json +3 -1
- package/src/workspace/security.test.ts +70 -0
- package/src/workspace/security.ts +118 -0
- package/src/workspace/status.schema.json +3 -1
- package/src/workspace/write-scope.test.ts +29 -1
- package/src/workspace/write-scope.ts +12 -1
package/src/workspace/ci-run.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `chant ci run plan|apply` (#4094, epic #4101): run one pull-request job as
|
|
2
|
+
* `chant ci run plan|record|apply` (#4094, epic #4101, record #4168): run one pull-request job as
|
|
3
3
|
* a pipeline Op, the first slice of the chant runner.
|
|
4
4
|
*
|
|
5
5
|
* The job is the typed value `prLoopJobs` (../components/pr-pipeline.ts)
|
|
@@ -44,6 +44,30 @@
|
|
|
44
44
|
* With a forge client (#4097) the job also sets a commit status at its
|
|
45
45
|
* commit: `pending` when it starts, `success` or `failure` when it settles.
|
|
46
46
|
* A status the forge refuses is a warning and never fails the job.
|
|
47
|
+
*
|
|
48
|
+
* Signing is opt-in (#4156). With no runner key the record is unsigned, and
|
|
49
|
+
* a reader counts it with no signer. A key `.chant/trust.json` does not list
|
|
50
|
+
* leaves it unsigned with a note `--verbose` prints, unless the declaration
|
|
51
|
+
* sets `ci.green.signedSince`; then a run left unsigned is a warning.
|
|
52
|
+
*
|
|
53
|
+
* In place (`--in-place`, #4156) the job runs in the checkout it is started
|
|
54
|
+
* in, as a generated forge job does: no worktree, no setup phase and no
|
|
55
|
+
* commit status of its own (the forge shows the job). The steps get the
|
|
56
|
+
* job's whole environment less `CHANT_RUNNER_KEY`, since the forge job is
|
|
57
|
+
* already the boundary, and the record's `runOrigin` names the forge's run,
|
|
58
|
+
* job and attempt (`resolveCiJob`).
|
|
59
|
+
*
|
|
60
|
+
* Local (`--local`, #4161) runs the job the same way on this machine and
|
|
61
|
+
* leaves nothing outside it. It implies `--no-push` and `--no-status`, and
|
|
62
|
+
* writes nothing under a report URL, given or declared: the command gets no
|
|
63
|
+
* `--report-url`, and gets `--no-status`, so pr-plan and pr-apply post no
|
|
64
|
+
* status or note either. The record is still written to the local
|
|
65
|
+
* `chant/lifecycle`, where a reader on this machine finds it beside CI's for
|
|
66
|
+
* the same commit. It says `runOrigin: { forge: "local" }` and its events say
|
|
67
|
+
* `runtime: "local"`. `ci tick --source runs` and `ci list` never count it.
|
|
68
|
+
* A pr-apply still pushes its own release records and gate facts, as the
|
|
69
|
+
* command always does, since a local apply changes the same infrastructure
|
|
70
|
+
* a CI one does.
|
|
47
71
|
*/
|
|
48
72
|
|
|
49
73
|
import { execFileSync } from "node:child_process";
|
|
@@ -55,8 +79,8 @@ import { detectForge, ForgeEnvironmentError, forgeFromEnv, FORGE_KINDS, type Com
|
|
|
55
79
|
import { PR_APPLY_GATE } from "../pr-loop";
|
|
56
80
|
import type { CommandContext } from "../cli/registry";
|
|
57
81
|
import { formatError, formatWarning } from "../cli/format";
|
|
58
|
-
import type
|
|
59
|
-
import { pushLifecycleReport } from "../lifecycle/git";
|
|
82
|
+
import { resolveCiJob, type RunOrigin } from "../lifecycle/release-ledger";
|
|
83
|
+
import { fetchLifecycleStatus, pushLifecycleReport } from "../lifecycle/git";
|
|
60
84
|
import { ACTIVITY_PROFILES } from "../op/activity-profiles";
|
|
61
85
|
import type { ActivityFn, ActivityProfile } from "../op/activity-registry";
|
|
62
86
|
import { shellCmd } from "../op/activities/shell";
|
|
@@ -66,24 +90,38 @@ import type { ActivityStep, OpConfig, PhaseDefinition } from "../op/types";
|
|
|
66
90
|
import { redactText, type Redact } from "../op/redact";
|
|
67
91
|
import { findWorkspaceRoot } from "../project-root";
|
|
68
92
|
import { parseReportUrl, reportKey } from "../pr-report-url";
|
|
69
|
-
import {
|
|
93
|
+
import { reportUrlOf } from "./ci-report-url";
|
|
94
|
+
import { ciTagSigner, RUNNER_KEY_ENV, signedRunsRequired } from "./ci-green";
|
|
95
|
+
import { loadRunnerKey } from "./trust/dsse";
|
|
70
96
|
import { ciRedactor, ciSecretsFor, CI_SECRETS_ENV, readCiSecrets, type CiSecrets } from "./ci-secrets";
|
|
71
97
|
import { updateCiRunIndex, type CiRunIndexEntry } from "./ci-run-index";
|
|
72
98
|
import { resolveMemberContext } from "./member-pipeline";
|
|
73
99
|
import { signOpRunRecord } from "./trust/op-run-statement";
|
|
74
100
|
import { gitTop } from "./tree";
|
|
75
101
|
import { hostRunnerKey } from "./ci-runner-key";
|
|
102
|
+
import { requireRunnerStart } from "./ci-runner-start";
|
|
103
|
+
import { securityGroupsAt } from "./security";
|
|
76
104
|
|
|
77
|
-
/** The
|
|
105
|
+
/** The jobs a pull-request pipeline has: plan, and on merge record (#4168) or, opted in, apply. */
|
|
78
106
|
export type CiJobName = PrLoopJob["jobName"];
|
|
79
|
-
export const CI_JOB_NAMES: readonly CiJobName[] = ["plan", "apply"];
|
|
107
|
+
export const CI_JOB_NAMES: readonly CiJobName[] = ["plan", "apply", "record"];
|
|
80
108
|
|
|
81
109
|
/** The Op each job is recorded as, which `ci.green` phases match. */
|
|
82
|
-
export const CI_JOB_OPS: Record<CiJobName, string> = { plan: "pr-plan", apply: "pr-apply" };
|
|
110
|
+
export const CI_JOB_OPS: Record<CiJobName, string> = { plan: "pr-plan", apply: "pr-apply", record: "pr-record" };
|
|
111
|
+
|
|
112
|
+
/** What each job's Op says it does. */
|
|
113
|
+
const CI_JOB_OVERVIEWS: Record<CiJobName, string> = {
|
|
114
|
+
plan: "Plan the members this pull request reaches",
|
|
115
|
+
apply: "Apply the plan a reviewer approved",
|
|
116
|
+
record: "Record the plan on the merged commit; nothing applies",
|
|
117
|
+
};
|
|
83
118
|
|
|
84
119
|
/** Where a job the chant runner ran says it ran (#4094). */
|
|
85
120
|
export const CHANT_RUNNER_ORIGIN: RunOrigin = { forge: "chant" };
|
|
86
121
|
|
|
122
|
+
/** Where a job `chant ci run --local` ran says it ran (#4161): this machine, outside CI. */
|
|
123
|
+
export const CHANT_LOCAL_ORIGIN: RunOrigin = { forge: "local" };
|
|
124
|
+
|
|
87
125
|
/** The runner's variables every job gets, when the runner has them. */
|
|
88
126
|
export const CI_RUN_BASE_ENV = ["PATH", "HOME", "USER", "LOGNAME", "SHELL", "LANG", "LC_ALL", "LC_CTYPE", "TMPDIR", "TZ"] as const;
|
|
89
127
|
|
|
@@ -226,7 +264,7 @@ export function ciJobOp(input: CiJobOpInput): OpConfig {
|
|
|
226
264
|
const op = CI_JOB_OPS[input.job.jobName];
|
|
227
265
|
return {
|
|
228
266
|
name: op,
|
|
229
|
-
overview: input.job.jobName
|
|
267
|
+
overview: CI_JOB_OVERVIEWS[input.job.jobName],
|
|
230
268
|
labels: { Env: input.env, Pipeline: "pr", Job: input.job.jobName },
|
|
231
269
|
phases,
|
|
232
270
|
};
|
|
@@ -241,6 +279,17 @@ function exitCodeOf(error: string | undefined): number | undefined {
|
|
|
241
279
|
return m ? Number(m[1]) : undefined;
|
|
242
280
|
}
|
|
243
281
|
|
|
282
|
+
/**
|
|
283
|
+
* The code `chant ci run` exits with for a settled job: 0 when it passed,
|
|
284
|
+
* else its command's own code when that is 1 to 255, such as 3 for a moved
|
|
285
|
+
* plan or a waiting wave (#4156), else 1. The run index records the same
|
|
286
|
+
* code (#4165).
|
|
287
|
+
*/
|
|
288
|
+
export function ciJobExitCode(result: { status: OpRunResult["status"]; exitCode?: number }): number {
|
|
289
|
+
if (result.status === "ok") return 0;
|
|
290
|
+
return result.exitCode && result.exitCode > 0 && result.exitCode < 256 ? result.exitCode : 1;
|
|
291
|
+
}
|
|
292
|
+
|
|
244
293
|
/** The first line of a step's error, for a reason. */
|
|
245
294
|
const firstLine = (text: string): string => text.split("\n").find((l) => l.trim() !== "")?.trim() ?? text;
|
|
246
295
|
|
|
@@ -313,12 +362,12 @@ const STATUS_DESCRIPTION = 140;
|
|
|
313
362
|
const cut = (text: string, max = STATUS_DESCRIPTION): string => (text.length > max ? `${text.slice(0, max - 3)}...` : text);
|
|
314
363
|
|
|
315
364
|
/**
|
|
316
|
-
* A job's status context: `chant/pr-plan` for the plan, and for the apply
|
|
365
|
+
* A job's status context: `chant/pr-plan` for the plan, `chant/pr-record` for the record (#4168), and for the apply
|
|
317
366
|
* `chant/<gate>`, which is `chant/pr-apply` unless `--gate` renamed the gate.
|
|
318
367
|
* pr-plan's own status is `chant/plan` (../pr-loop.ts), a different context.
|
|
319
368
|
*/
|
|
320
369
|
export function ciStatusContext(job: CiJobName, gate?: string): string {
|
|
321
|
-
return job === "apply" ? `chant/${gate ?? PR_APPLY_GATE}` : `chant/${CI_JOB_OPS
|
|
370
|
+
return job === "apply" ? `chant/${gate ?? PR_APPLY_GATE}` : `chant/${CI_JOB_OPS[job]}`;
|
|
322
371
|
}
|
|
323
372
|
|
|
324
373
|
/**
|
|
@@ -378,7 +427,12 @@ export interface CiRunRequest {
|
|
|
378
427
|
base?: string;
|
|
379
428
|
pr?: number;
|
|
380
429
|
commit?: string;
|
|
381
|
-
/**
|
|
430
|
+
/**
|
|
431
|
+
* The generator's options: `--gate`, `--branch`, `--events-json`,
|
|
432
|
+
* `--report-url`, `--pr-build` and `--pr-build-command`, and `--wave-gate`
|
|
433
|
+
* (#4003), with which the apply job runs the waves in order and stops at
|
|
434
|
+
* the first whose moved plan waits on its own gate.
|
|
435
|
+
*/
|
|
382
436
|
loop?: PrLoopPipelineOptions;
|
|
383
437
|
/** `--image`: the image a generated pipeline names. Only the default gets setup lines. */
|
|
384
438
|
image?: string;
|
|
@@ -425,6 +479,30 @@ export interface CiRunRequest {
|
|
|
425
479
|
resumeRecord?: string;
|
|
426
480
|
/** Set a commit status at the job's commit (#4097). Absent: none is set. `chant ci run` builds it from the environment. */
|
|
427
481
|
status?: CiStatusConfig;
|
|
482
|
+
/**
|
|
483
|
+
* `--in-place` (#4156): run in the checkout `cwd` is in, at its `HEAD`, as
|
|
484
|
+
* a generated forge job does, with the runner's whole environment less
|
|
485
|
+
* `CHANT_RUNNER_KEY`, no setup phase, and the forge's run as `runOrigin`.
|
|
486
|
+
*/
|
|
487
|
+
inPlace?: boolean;
|
|
488
|
+
/**
|
|
489
|
+
* `--local` (#4161): run on this machine and write nothing beyond it. It
|
|
490
|
+
* implies `push: false` and no status (`status` is ignored), writes
|
|
491
|
+
* nothing under `loop.reportUrl`, and the record and events say
|
|
492
|
+
* `runOrigin: { forge: "local" }` and `runtime: "local"`.
|
|
493
|
+
*/
|
|
494
|
+
local?: boolean;
|
|
495
|
+
/**
|
|
496
|
+
* `--require-runner-start` (#4147): refuse the job before its first step
|
|
497
|
+
* unless a runner-start statement, signed by a runner key
|
|
498
|
+
* `.chant/trust.json` at `base` lists, names this forge job.
|
|
499
|
+
*/
|
|
500
|
+
requireRunnerStart?: boolean;
|
|
501
|
+
/**
|
|
502
|
+
* `--wave <k>` (#4003, #4156): the one wave a generated apply job runs, as
|
|
503
|
+
* `pr-apply --wave <k>`. Needs `--wave-gate`.
|
|
504
|
+
*/
|
|
505
|
+
wave?: number;
|
|
428
506
|
signal?: AbortSignal;
|
|
429
507
|
}
|
|
430
508
|
|
|
@@ -443,8 +521,14 @@ export interface CiRunResult {
|
|
|
443
521
|
pushWarning?: string;
|
|
444
522
|
/** What went wrong beside the job, such as a record the key could not sign. */
|
|
445
523
|
warnings: string[];
|
|
524
|
+
/** What `--verbose` prints: such as a run left unsigned when nothing asks for a signature (#4156). */
|
|
525
|
+
notes: string[];
|
|
526
|
+
/** The exit code of the job's command when it failed with one, such as pr-apply's 3 for a moved plan. */
|
|
527
|
+
exitCode?: number;
|
|
446
528
|
/** The checkout the job ran in, removed by now. */
|
|
447
529
|
checkout: string;
|
|
530
|
+
/** The job ran with `local` (#4161): its record stays on this machine. */
|
|
531
|
+
local?: true;
|
|
448
532
|
}
|
|
449
533
|
|
|
450
534
|
const message = (err: unknown): string => (err instanceof Error ? err.message : String(err));
|
|
@@ -516,6 +600,11 @@ async function recordInIndex(input: {
|
|
|
516
600
|
member?: string;
|
|
517
601
|
pr?: number;
|
|
518
602
|
record: OpRunRecord;
|
|
603
|
+
runOrigin: RunOrigin;
|
|
604
|
+
/** The runner that signed the record, or null (#4156). */
|
|
605
|
+
signer: string | null;
|
|
606
|
+
/** The code `chant ci run` exits with for the job (#4165). */
|
|
607
|
+
exitCode: number;
|
|
519
608
|
reportDir: string;
|
|
520
609
|
limit?: number;
|
|
521
610
|
/** The run's redactor (#4096): every string written to the index goes through it, as the copied report does. */
|
|
@@ -547,7 +636,9 @@ async function recordInIndex(input: {
|
|
|
547
636
|
ended: input.record.ended,
|
|
548
637
|
runId: clean(input.record.id),
|
|
549
638
|
key: clean(reportKey(pr, input.commit, input.member)),
|
|
550
|
-
runOrigin:
|
|
639
|
+
runOrigin: input.runOrigin,
|
|
640
|
+
signer: input.signer,
|
|
641
|
+
exitCode: input.exitCode,
|
|
551
642
|
};
|
|
552
643
|
await updateCiRunIndex({ target, entry, ...(input.limit ? { limit: input.limit } : {}), warn: input.warn });
|
|
553
644
|
}
|
|
@@ -565,11 +656,21 @@ export async function ciRun(req: CiRunRequest): Promise<CiRunResult> {
|
|
|
565
656
|
const top = gitTop(cwd);
|
|
566
657
|
if (!top) throw new CiRunError("a job runs in a fresh checkout of a commit, and this directory is not in a git repository");
|
|
567
658
|
const commit = resolveJobCommit(top, req.commit ?? "HEAD");
|
|
659
|
+
if (req.inPlace && commit !== resolveJobCommit(top, "HEAD")) throw new CiRunError(`--in-place runs the checkout's HEAD, and --commit names ${commit.slice(0, 12)}`);
|
|
660
|
+
if (req.local && req.inPlace) throw new CiRunError("--in-place runs a forge job in the forge's checkout, and --local runs one on this machine; pass one of them");
|
|
568
661
|
const place = ciJobPlace(cwd, top);
|
|
569
|
-
const jobs = prLoopJobs(req.forge, req.env, req.loop ?? {}, place.member);
|
|
570
|
-
const
|
|
571
|
-
if (!
|
|
572
|
-
|
|
662
|
+
const jobs = prLoopJobs(req.forge, req.env, req.local ? localLoop(req.loop) : (req.loop ?? {}), place.member);
|
|
663
|
+
const found = jobs.find((j) => j.jobName === req.job);
|
|
664
|
+
if (!found) throw new CiRunError(`the pull-request pipeline has no ${req.job} job; it has ${jobs.map((j) => j.jobName).join(" and ")}`);
|
|
665
|
+
if (req.wave !== undefined && (req.job !== "apply" || !req.loop?.waveGate)) throw new CiRunError("--wave names the one wave an apply runs, and takes --wave-gate: ci run apply --wave-gate <gate> --wave <k>");
|
|
666
|
+
// #4147: before anything runs or any secret reaches a step, the provisioner's word that this runner was started for this job.
|
|
667
|
+
// #4168: under the isolated-runners security group an apply job requires the statement too, unless it runs on this machine.
|
|
668
|
+
const isolated = !req.requireRunnerStart && !req.local && req.job === "apply" && securityGroupsAt(cwd).has("isolated-runners");
|
|
669
|
+
const started = req.requireRunnerStart || isolated ? runnerStartFor(req, { top, commit, hostEnv }) : undefined;
|
|
670
|
+
// A generated wave job's command, as prLoopWaveJobs writes it. #4161: a local job's command posts no status or note.
|
|
671
|
+
const command = `${found.command}${req.wave !== undefined ? ` --wave ${req.wave}` : ""}${req.local ? " --no-status" : ""}`;
|
|
672
|
+
const job = { ...found, command, ...(req.wave !== undefined ? { wave: req.wave } : {}) };
|
|
673
|
+
const own = ciJobEnv(job, {
|
|
573
674
|
forge: req.forge,
|
|
574
675
|
env: req.env,
|
|
575
676
|
values: { base: req.base, pr: req.pr, commit },
|
|
@@ -577,37 +678,107 @@ export async function ciRun(req: CiRunRequest): Promise<CiRunResult> {
|
|
|
577
678
|
passEnv: req.passEnv,
|
|
578
679
|
secrets: ciSecretsFor(req.secrets, req.job),
|
|
579
680
|
});
|
|
681
|
+
// #4156: in place, the forge job's environment is the job's, less the runner key.
|
|
682
|
+
const jobEnv = req.inPlace ? { ...definedEnv(hostEnv), ...own } : own;
|
|
683
|
+
delete jobEnv[RUNNER_KEY_ENV];
|
|
580
684
|
// #4096: the secrets and the job's secret-looking variables, redacted from everything the run writes and returns.
|
|
581
|
-
|
|
685
|
+
// In place the forge's own variables come too; one whose value is short, such as a flag, is left out, so it can't blank common words.
|
|
686
|
+
const redact = ciRedactor(req.inPlace ? { ...longValues(jobEnv), ...own } : jobEnv, req.secrets);
|
|
582
687
|
try {
|
|
583
|
-
const
|
|
584
|
-
|
|
688
|
+
const ran = await runCiJob(req, { cwd, top, commit, place, job, jobEnv, ...(redact ? { redact } : {}) });
|
|
689
|
+
const result = started ? { ...ran, notes: [started, ...ran.notes] } : ran;
|
|
690
|
+
return redact ? { ...result, warnings: result.warnings.map(redact), notes: result.notes.map(redact), ...(result.pushWarning ? { pushWarning: redact(result.pushWarning) } : {}) } : result;
|
|
585
691
|
} catch (err) {
|
|
586
692
|
if (redact && err instanceof Error) err.message = redact(err.message);
|
|
587
693
|
throw err;
|
|
588
694
|
}
|
|
589
695
|
}
|
|
590
696
|
|
|
697
|
+
/**
|
|
698
|
+
* `--require-runner-start` (#4147): the runner-start statement for this
|
|
699
|
+
* forge job, checked against `.chant/trust.json` at `--base` (the commit
|
|
700
|
+
* before the change, as a push's `before` is), or at the job's commit
|
|
701
|
+
* without one. Throws {@link CiRunError} unless it verifies.
|
|
702
|
+
*/
|
|
703
|
+
function runnerStartFor(req: CiRunRequest, at: { top: string; commit: string; hostEnv: Record<string, string | undefined> }): string {
|
|
704
|
+
if (req.local) throw new CiRunError("--require-runner-start checks a forge job's runner, and --local runs the job on this machine");
|
|
705
|
+
const base = req.base ? resolveJobCommit(at.top, req.base) : at.commit;
|
|
706
|
+
try {
|
|
707
|
+
return requireRunnerStart({ top: at.top, base, commit: at.commit, env: at.hostEnv }).reason;
|
|
708
|
+
} catch (err) {
|
|
709
|
+
throw new CiRunError(message(err));
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
/** The generator's options for a `--local` job (#4161): the same, with no report URL. */
|
|
714
|
+
function localLoop(loop: PrLoopPipelineOptions | undefined): PrLoopPipelineOptions {
|
|
715
|
+
const { reportUrl: _dropped, ...rest } = loop ?? {};
|
|
716
|
+
return rest;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
/** The variables of `env` whose value is long enough to be a credential, 8 characters or more. */
|
|
720
|
+
function longValues(env: Record<string, string>): Record<string, string> {
|
|
721
|
+
return Object.fromEntries(Object.entries(env).filter(([, value]) => value.length >= 8));
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
/** The variables of `env` that have a value. */
|
|
725
|
+
function definedEnv(env: Record<string, string | undefined>): Record<string, string> {
|
|
726
|
+
const out: Record<string, string> = {};
|
|
727
|
+
for (const [name, value] of Object.entries(env)) if (value !== undefined) out[name] = value;
|
|
728
|
+
return out;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
/**
|
|
732
|
+
* Who signs the run (#4156): the runner key, checked against
|
|
733
|
+
* `.chant/trust.json` at the commit. A key that isn't an Ed25519 PEM is an
|
|
734
|
+
* error, and so is a `--key` the file does not list. A key from the
|
|
735
|
+
* environment that it does not list, and no key at all, leave the run
|
|
736
|
+
* unsigned: a warning when the declaration's `ci.green.signedSince` asks
|
|
737
|
+
* for signed runs, a note for `--verbose` otherwise.
|
|
738
|
+
*/
|
|
739
|
+
function ciRunSigner(req: CiRunRequest, at: { cwd: string; top: string; commit: string }): { signer?: ReturnType<typeof ciTagSigner>; warnings: string[]; notes: string[] } {
|
|
740
|
+
// #4161: a local run never counts, signed or not, so nothing about its signature warns.
|
|
741
|
+
const required = req.local ? null : signedRunsRequired(at.cwd);
|
|
742
|
+
const say = (text: string) => (required ? { warnings: [`${text}, and ci.green.signedSince is ${required}, so it will not count`], notes: [] } : { warnings: [], notes: [text] });
|
|
743
|
+
if (req.runnerKey === undefined) return say("there is no runner key, so the run's record is unsigned");
|
|
744
|
+
try {
|
|
745
|
+
loadRunnerKey(req.runnerKey);
|
|
746
|
+
} catch (err) {
|
|
747
|
+
throw new CiRunError(`the runner key${req.runnerKeyFromEnv ? ` in ${RUNNER_KEY_ENV}` : ""} is not an Ed25519 private key in PEM: ${message(err)}`);
|
|
748
|
+
}
|
|
749
|
+
try {
|
|
750
|
+
return { signer: ciTagSigner(at.top, at.commit, req.runnerKey, "the runs it signed"), warnings: [], notes: [] };
|
|
751
|
+
} catch (err) {
|
|
752
|
+
if (!req.runnerKeyFromEnv) throw new CiRunError(`the run would not be signed: ${message(err)}`);
|
|
753
|
+
return say(`${RUNNER_KEY_ENV} is set, and the run will not be signed: ${message(err)}`);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
/** Where the job runs: a fresh worktree of the commit, or with `inPlace` the checkout itself, which is left as it is. */
|
|
758
|
+
function jobCheckout(top: string, commit: string, inPlace?: boolean): { dir: string; remove(): void } {
|
|
759
|
+
return inPlace ? { dir: top, remove() {} } : freshCheckout(top, commit);
|
|
760
|
+
}
|
|
761
|
+
|
|
591
762
|
/** {@link ciRun} once the job and its environment are known. */
|
|
592
763
|
async function runCiJob(
|
|
593
764
|
req: CiRunRequest,
|
|
594
765
|
at: { cwd: string; top: string; commit: string; place: { member?: string; dir: string }; job: PrLoopJob; jobEnv: Record<string, string>; redact?: Redact },
|
|
595
766
|
): Promise<CiRunResult> {
|
|
596
767
|
const { cwd, top, commit, place, job, jobEnv, redact } = at;
|
|
768
|
+
const local = req.local === true;
|
|
769
|
+
const status = local ? undefined : req.status;
|
|
770
|
+
const reportUrl = local ? undefined : req.loop?.reportUrl;
|
|
597
771
|
|
|
598
|
-
// The record is signed against .chant/trust.json at the commit the job runs, so a key that commit does not list is refused before anything runs.
|
|
599
|
-
|
|
600
|
-
const
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
early.push(`${RUNNER_KEY_ENV} is set, and the run will not be signed: ${message(err)}`);
|
|
607
|
-
}
|
|
608
|
-
}
|
|
772
|
+
// The record is signed against .chant/trust.json at the commit the job runs, so a --key that commit does not list is refused before anything runs.
|
|
773
|
+
const signing = ciRunSigner(req, { cwd, top, commit });
|
|
774
|
+
const signer = signing.signer;
|
|
775
|
+
const early = signing.warnings;
|
|
776
|
+
const notes = signing.notes;
|
|
777
|
+
const origin: RunOrigin = local ? CHANT_LOCAL_ORIGIN : req.inPlace ? (resolveCiJob(req.hostEnv ?? process.env)?.runOrigin ?? CHANT_RUNNER_ORIGIN) : CHANT_RUNNER_ORIGIN;
|
|
778
|
+
// In place, the job writes its record on the checkout's chant/lifecycle, which a forge checkout may not have fetched.
|
|
779
|
+
if (req.inPlace && req.push !== false) await fetchLifecycleStatus({ cwd: top }).catch(() => undefined);
|
|
609
780
|
|
|
610
|
-
const checkout =
|
|
781
|
+
const checkout = jobCheckout(top, commit, req.inPlace);
|
|
611
782
|
try {
|
|
612
783
|
const jobDir = place.dir === "." ? checkout.dir : join(checkout.dir, place.dir);
|
|
613
784
|
const op = ciJobOp({
|
|
@@ -615,7 +786,7 @@ async function runCiJob(
|
|
|
615
786
|
env: req.env,
|
|
616
787
|
cwd: jobDir,
|
|
617
788
|
jobEnv,
|
|
618
|
-
setup: prLoopSetup(req.image ?? PR_LOOP_IMAGE),
|
|
789
|
+
setup: req.inPlace ? [] : prLoopSetup(req.image ?? PR_LOOP_IMAGE),
|
|
619
790
|
build: [...(req.beforeScript ?? []), ...(job.build ?? [])],
|
|
620
791
|
...(req.chant ? { chant: req.chant } : {}),
|
|
621
792
|
});
|
|
@@ -627,13 +798,13 @@ async function runCiJob(
|
|
|
627
798
|
copyFileSync(resume.host, resume.job);
|
|
628
799
|
}
|
|
629
800
|
const statusContext = ciStatusContext(req.job, req.loop?.gate);
|
|
630
|
-
const statusUrl =
|
|
631
|
-
? ciStatusUrl({ ...(
|
|
801
|
+
const statusUrl = status
|
|
802
|
+
? ciStatusUrl({ ...(status.urlTemplate ? { urlTemplate: status.urlTemplate } : {}), ...(reportUrl ? { reportUrl } : {}), ...(req.pr !== undefined ? { pr: req.pr } : {}), commit, ...(place.member ? { member: place.member } : {}) })
|
|
632
803
|
: undefined;
|
|
633
804
|
const postStatus = async (state: CommitStatus["state"], description: string): Promise<void> => {
|
|
634
|
-
if (!
|
|
805
|
+
if (!status) return;
|
|
635
806
|
try {
|
|
636
|
-
await
|
|
807
|
+
await status.client.setCommitStatus(commit, { context: statusContext, state, description: cut(redact ? redact(description) : description), ...(statusUrl ? { targetUrl: statusUrl } : {}) });
|
|
637
808
|
} catch (err) {
|
|
638
809
|
warnings.push(`could not set the ${statusContext} status: ${message(err)}`);
|
|
639
810
|
}
|
|
@@ -649,7 +820,7 @@ async function runCiJob(
|
|
|
649
820
|
cwd: jobDir,
|
|
650
821
|
commit,
|
|
651
822
|
ledger: { cwd: jobDir },
|
|
652
|
-
runner: { kind: "pipeline", runtime: "ci", runOrigin:
|
|
823
|
+
runner: { kind: "pipeline", runtime: local ? "local" : "ci", runOrigin: origin },
|
|
653
824
|
describeFailure: (records) => ciJobFailure({ job: req.job, op, records, reportDir: join(jobDir, PR_LOOP_REPORT_DIR) }),
|
|
654
825
|
...(req.runEvents ? { runEvents: { write: req.runEvents } } : {}),
|
|
655
826
|
...(req.stepOutput ? { stepOutput: req.stepOutput } : {}),
|
|
@@ -687,26 +858,37 @@ async function runCiJob(
|
|
|
687
858
|
let report: string | null = null;
|
|
688
859
|
if (existsSync(written)) {
|
|
689
860
|
report = resolve(cwd, req.output ?? PR_LOOP_REPORT_DIR);
|
|
690
|
-
|
|
691
|
-
if (
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
861
|
+
// In place the report is already where the forge keeps it, and stays as the command wrote it.
|
|
862
|
+
if (!(existsSync(report) && realpathSync(report) === realpathSync(written))) {
|
|
863
|
+
cpSync(written, report, { recursive: true });
|
|
864
|
+
if (redact) redactTree(report, redact);
|
|
865
|
+
}
|
|
695
866
|
}
|
|
696
|
-
if (ledgerError) throw new CiRunError(ledgerError);
|
|
697
|
-
const pushed: { pushed: boolean; pushWarning?: string } = req.push === false ? { pushed: false, pushWarning: "chant/lifecycle was not pushed" } : await pushLifecycleReport({ cwd: top });
|
|
698
867
|
const failed = result.records.find((r) => r.status === "fail");
|
|
868
|
+
const exitCode = failed?.phase === req.job ? exitCodeOf(failed.error) : undefined;
|
|
869
|
+
if (reportUrl) {
|
|
870
|
+
await recordInIndex({ url: reportUrl, job: req.job, commit, member: place.member, pr: req.pr, record: result.record, runOrigin: origin, signer: result.record.statement && signer ? signer.principal : null, exitCode: ciJobExitCode({ status: result.status, ...(exitCode !== undefined ? { exitCode } : {}) }), reportDir: written, limit: req.runIndexLimit, ...(redact ? { redact } : {}), warn: (w) => warnings.push(w) });
|
|
871
|
+
}
|
|
872
|
+
// In place the forge job's outcome is the command's, so a record that could not be written is a warning there.
|
|
873
|
+
if (ledgerError && req.inPlace) warnings.push(ledgerError);
|
|
874
|
+
else if (ledgerError) throw new CiRunError(ledgerError);
|
|
875
|
+
const pushed: { pushed: boolean; pushWarning?: string } = local
|
|
876
|
+
? { pushed: false }
|
|
877
|
+
: req.push === false ? { pushed: false, pushWarning: "chant/lifecycle was not pushed" } : await pushLifecycleReport({ cwd: top });
|
|
699
878
|
return {
|
|
700
879
|
op: op.name,
|
|
701
880
|
status: result.status,
|
|
702
881
|
record: result.record,
|
|
703
882
|
...(failed ? { failure: { phase: failed.phase, error: failed.error ?? "the step failed" } } : {}),
|
|
883
|
+
...(exitCode !== undefined ? { exitCode } : {}),
|
|
704
884
|
report,
|
|
705
|
-
signer: signer
|
|
885
|
+
signer: result.record.statement && signer ? signer.principal : null,
|
|
706
886
|
pushed: pushed.pushed,
|
|
707
887
|
...(pushed.pushWarning ? { pushWarning: pushed.pushWarning } : {}),
|
|
708
888
|
warnings,
|
|
889
|
+
notes,
|
|
709
890
|
checkout: checkout.dir,
|
|
891
|
+
...(local ? { local: true as const } : {}),
|
|
710
892
|
};
|
|
711
893
|
} finally {
|
|
712
894
|
checkout.remove();
|
|
@@ -740,19 +922,40 @@ export function formatCiRun(r: CiRunResult): string {
|
|
|
740
922
|
const why = r.record.failure;
|
|
741
923
|
if (why) lines.push(` failure: ${why.code}${why.phase ? ` in ${why.phase}` : ""}${why.exitCode !== undefined ? `, exit ${why.exitCode}` : ""}: ${why.reason}`);
|
|
742
924
|
else if (r.failure) lines.push(` ${r.failure.phase}: ${r.failure.error}`);
|
|
743
|
-
lines.push(` record: ${r.record.env}/runs__${r.op}.jsonl on chant/lifecycle, ${r.signer ? `signed by ${r.signer}` : "unsigned
|
|
925
|
+
lines.push(` record: ${r.record.env}/runs__${r.op}.jsonl on chant/lifecycle, ${r.signer ? `signed by ${r.signer}` : "unsigned"}`);
|
|
744
926
|
if (r.report) lines.push(` report: ${r.report}`);
|
|
745
|
-
if (
|
|
927
|
+
if (r.local) lines.push(" local run: the record stays on this machine, with no push, commit status or report upload");
|
|
928
|
+
else if (!r.pushed) lines.push(` ${r.pushWarning ?? "chant/lifecycle was not pushed"}`);
|
|
746
929
|
return lines.join("\n");
|
|
747
930
|
}
|
|
748
931
|
|
|
749
932
|
// ── The command ──────────────────────────────────────────────────────────────
|
|
750
933
|
|
|
934
|
+
/**
|
|
935
|
+
* The generator's options from `ci run`'s and `ci serve`'s flags, as `chant
|
|
936
|
+
* build --components --generate <lexicon> --pr-loop` takes them: `--gate`,
|
|
937
|
+
* `--branch`, `--events-json`, `--report-url`, `--pr-build`,
|
|
938
|
+
* `--pr-build-command`, `--wave-gate` (#4003) and `--require-review`
|
|
939
|
+
* (#4168; `--no-require-review`, the default, is still accepted).
|
|
940
|
+
*/
|
|
941
|
+
export function ciLoopOptions(args: CommandContext["args"]): PrLoopPipelineOptions {
|
|
942
|
+
return {
|
|
943
|
+
...(args.gate ? { gate: args.gate } : {}),
|
|
944
|
+
...(args.branch ? { branch: args.branch } : {}),
|
|
945
|
+
...(args.eventsJson ? { events: true } : {}),
|
|
946
|
+
...(args.reportUrl ? { reportUrl: args.reportUrl } : {}),
|
|
947
|
+
...(args.prBuild ? { build: true } : {}),
|
|
948
|
+
...(args.prBuildCommand ? { buildCommand: args.prBuildCommand } : {}),
|
|
949
|
+
...(args.waveGate ? { waveGate: args.waveGate } : {}),
|
|
950
|
+
...(args.requireReview === true ? { requireReview: true } : {}),
|
|
951
|
+
};
|
|
952
|
+
}
|
|
953
|
+
|
|
751
954
|
const USAGE =
|
|
752
|
-
"chant ci run plan|apply --env <env> --base <sha> [--pr <n>] [--commit <sha>] [--forge github|gitlab|forgejo] " +
|
|
753
|
-
"[--gate <name>] [--branch <name>] [--events-json] [--report-url <url>] [--run-index-limit <n>] [--image <image>] [--before-script <line>]... " +
|
|
754
|
-
"[--pr-build] [--pr-build-command <line>] [--no-status] [--status-url <url template>] " +
|
|
755
|
-
"[--chant <command>] [--pass-env <NAME>]... [--secrets <file>] [--key <runner key.pem>] [-o <dir>] | chant ci run --setup-key [--trust [--principal <name>]] [--state <dir>] [--branch <name>]";
|
|
955
|
+
"chant ci run plan|record|apply --env <env> --base <sha> [--pr <n>] [--commit <sha>] [--forge github|gitlab|forgejo] " +
|
|
956
|
+
"[--gate <name>] [--wave-gate <name>] [--wave <k>] [--branch <name>] [--events-json] [--report-url <url>] [--run-index-limit <n>] [--image <image>] [--before-script <line>]... " +
|
|
957
|
+
"[--pr-build] [--pr-build-command <line>] [--require-review] [--no-status] [--status-url <url template>] " +
|
|
958
|
+
"[--chant <command>] [--pass-env <NAME>]... [--secrets <file>] [--key <runner key.pem>] [-o <dir>] [--in-place | --local] [--no-push] [--verbose] | chant ci run --at <sha> | chant ci run --setup-key [--trust [--principal <name>]] [--state <dir>] [--branch <name>]";
|
|
756
959
|
|
|
757
960
|
const ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
758
961
|
|
|
@@ -775,13 +978,38 @@ export function ciSecretsOf(flag: string | undefined, env: Record<string, string
|
|
|
775
978
|
return file === undefined ? undefined : readCiSecrets(resolve(file));
|
|
776
979
|
}
|
|
777
980
|
|
|
778
|
-
/**
|
|
981
|
+
/**
|
|
982
|
+
* `chant ci run --at <sha>` (#4169): ask for every required phase to be built
|
|
983
|
+
* at a commit of the green branch. On GitHub, with a token in the
|
|
984
|
+
* environment, the workflows holding the phases start at once.
|
|
985
|
+
*/
|
|
986
|
+
async function requestBuildCommand(at: string): Promise<number> {
|
|
987
|
+
const { requestBuild } = await import("./ci-green");
|
|
988
|
+
const { ciForgeFromEnv } = await import("./ci-green-forge");
|
|
989
|
+
let forge: Awaited<ReturnType<typeof ciForgeFromEnv>> | undefined;
|
|
990
|
+
try {
|
|
991
|
+
forge = process.env.GITHUB_REPOSITORY ? ciForgeFromEnv("github") : undefined;
|
|
992
|
+
} catch {
|
|
993
|
+
forge = undefined;
|
|
994
|
+
}
|
|
995
|
+
const r = await requestBuild({ cwd: process.cwd(), at, ...(forge ? { forge } : {}) });
|
|
996
|
+
for (const w of r.warnings) console.error(formatWarning({ message: w }));
|
|
997
|
+
const what = `${r.request.phases.join(", ")} at ${r.request.commit.slice(0, 12)}`;
|
|
998
|
+
console.log(
|
|
999
|
+
`${r.existed ? `${r.request.tag} already asks for a build` : `Asked for ${what}: ${r.request.tag}`}. ` +
|
|
1000
|
+
(r.dispatched.length > 0 ? `Started ${r.dispatched.join(", ")}.` : "The next ci tick starts it on GitHub, and ci serve --build-command serves it for chant runs."),
|
|
1001
|
+
);
|
|
1002
|
+
return 0;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
/** `chant ci run plan|record|apply` (#4094, #4168). */
|
|
779
1006
|
export async function runCiRun(ctx: CommandContext): Promise<number> {
|
|
780
1007
|
const { args } = ctx;
|
|
781
1008
|
try {
|
|
782
1009
|
if (args.setupKey) return (await import("./ci-serve")).runnerKeySetupCommand(ctx);
|
|
1010
|
+
if (args.at !== undefined && args.extraPositional === undefined) return await requestBuildCommand(args.at);
|
|
783
1011
|
const job = args.extraPositional;
|
|
784
|
-
if (job !== "plan" && job !== "apply") throw new CiRunError(`ci run takes the job to run, plan or apply${job ? `, not ${JSON.stringify(job)}` : ""}`);
|
|
1012
|
+
if (job !== "plan" && job !== "apply" && job !== "record") throw new CiRunError(`ci run takes the job to run, plan, record or apply${job ? `, not ${JSON.stringify(job)}` : ""}`);
|
|
785
1013
|
if (!args.env) throw new CiRunError("--env names the environment the pipeline is for, as chant build --components --generate <lexicon> --pr-loop took it: --env <env>");
|
|
786
1014
|
const forge = args.forge ?? detectForge(process.env);
|
|
787
1015
|
if (!forge) throw new CiRunError("--forge names the forge the job posts to: --forge github|gitlab|forgejo");
|
|
@@ -792,9 +1020,13 @@ export async function runCiRun(ctx: CommandContext): Promise<number> {
|
|
|
792
1020
|
const hostKey = fromFlag || process.env[RUNNER_KEY_ENV] ? undefined : hostRunnerKeyAt(process.cwd(), args.statePath);
|
|
793
1021
|
const runnerKey = fromFlag ? readFileSync(resolve(args.key!), "utf-8") : process.env[RUNNER_KEY_ENV] || hostKey?.pem;
|
|
794
1022
|
const hostEnv = process.env;
|
|
795
|
-
|
|
1023
|
+
// #4156: in place the forge shows the job, so ci run sets no status of its own.
|
|
1024
|
+
// #4161: a local run sets no status, so it builds no client and warns about none.
|
|
1025
|
+
const { status, warning } = ciStatusFromEnv({ forge: forge as ForgeKind, hostEnv, noStatus: args.noStatus || args.ciInPlace || args.local, statusUrl: args.statusUrl });
|
|
796
1026
|
if (warning) console.error(formatWarning({ message: warning }));
|
|
797
1027
|
const secrets = ciSecretsOf(args.ciSecrets);
|
|
1028
|
+
// #4160: without --report-url, the declaration's ci.reportUrl.
|
|
1029
|
+
const reportUrl = await reportUrlOf(args.reportUrl, process.cwd());
|
|
798
1030
|
const result = await ciRun({
|
|
799
1031
|
cwd: process.cwd(),
|
|
800
1032
|
...(status ? { status } : {}),
|
|
@@ -804,14 +1036,12 @@ export async function runCiRun(ctx: CommandContext): Promise<number> {
|
|
|
804
1036
|
...(args.base ? { base: args.base } : {}),
|
|
805
1037
|
...(args.pr !== undefined ? { pr: args.pr } : {}),
|
|
806
1038
|
...(args.commit ? { commit: args.commit } : {}),
|
|
807
|
-
loop: {
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
...(args.prBuildCommand ? { buildCommand: args.prBuildCommand } : {}),
|
|
814
|
-
},
|
|
1039
|
+
loop: ciLoopOptions(reportUrl ? { ...args, reportUrl } : args),
|
|
1040
|
+
...(args.ciInPlace ? { inPlace: true } : {}),
|
|
1041
|
+
...(args.local ? { local: true } : {}),
|
|
1042
|
+
...(args.noPush ? { push: false } : {}),
|
|
1043
|
+
...(args.wave !== undefined ? { wave: args.wave } : {}),
|
|
1044
|
+
...(args.requireRunnerStart ? { requireRunnerStart: true } : {}),
|
|
815
1045
|
...(args.runIndexLimit ? { runIndexLimit: args.runIndexLimit } : {}),
|
|
816
1046
|
...(args.image ? { image: args.image } : {}),
|
|
817
1047
|
...(args.beforeScript?.length ? { beforeScript: args.beforeScript } : {}),
|
|
@@ -824,8 +1054,10 @@ export async function runCiRun(ctx: CommandContext): Promise<number> {
|
|
|
824
1054
|
stepOutput: (line) => void process.stderr.write(`${line}\n`),
|
|
825
1055
|
});
|
|
826
1056
|
for (const w of result.warnings) console.error(formatWarning({ message: w }));
|
|
1057
|
+
if (args.verbose) for (const n of result.notes) console.error(`ci run: ${n}`);
|
|
827
1058
|
console.error(formatCiRun(result));
|
|
828
|
-
|
|
1059
|
+
// #4156: a failed command's own exit code, such as 3 for a moved plan, is the job's, as it was before the job ran through ci run.
|
|
1060
|
+
return ciJobExitCode(result);
|
|
829
1061
|
} catch (err) {
|
|
830
1062
|
console.error(formatError({ message: `chant ci run: ${message(err)}`, hint: USAGE }));
|
|
831
1063
|
return 1;
|