@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
|
@@ -3,11 +3,15 @@
|
|
|
3
3
|
* host. It polls the forge for the open pull requests into the target branch
|
|
4
4
|
* and for the branch's head, and runs the pull-request jobs with
|
|
5
5
|
* {@link ciRun} (./ci-run.ts): `plan` for each new pull request head, and
|
|
6
|
-
* `
|
|
7
|
-
* the previous poll saw (the push's `before`).
|
|
6
|
+
* `record` for each new commit on the target branch (#4168), measured from
|
|
7
|
+
* the head the previous poll saw (the push's `before`). The record applies
|
|
8
|
+
* nothing; with `applyOnMerge` (`--apply-on-merge`) the commit gets `apply`
|
|
9
|
+
* in its place, as before #4168. After each job settles it runs `ci tick`
|
|
10
|
+
* from the runs the jobs recorded, when the declaration has `ci.green`.
|
|
11
|
+
* What the list below says of the apply holds for it under `applyOnMerge`.
|
|
8
12
|
*
|
|
9
13
|
* - Dedupe. A state file in the state directory keeps every job it started,
|
|
10
|
-
* keyed by job and commit (`plan:<pr>:<sha>`, `apply:<sha>`), with how it
|
|
14
|
+
* keyed by job and commit (`plan:<pr>:<sha>`, `record:<sha>`, `apply:<sha>`), with how it
|
|
11
15
|
* ended, and the target head the last apply was measured to. A job already
|
|
12
16
|
* in it is not started again, unless it failed and `rerunFailed` asks for
|
|
13
17
|
* it: the forge's "re-run failed jobs".
|
|
@@ -23,8 +27,34 @@
|
|
|
23
27
|
* as its `--resume` record, so a re-run of a failed apply at the same
|
|
24
28
|
* commit finishes under the approval it has. This replaces the forge's CI
|
|
25
29
|
* cache.
|
|
30
|
+
* - A gate per wave (#4003). With `--wave-gate` the apply job runs
|
|
31
|
+
* `pr-apply --wave-gate`, which applies the waves in order and stops at
|
|
32
|
+
* the first whose moved plan waits on its own gate. The job fails, and the
|
|
33
|
+
* resume record keeps the waves that applied; once the wave's plan is
|
|
34
|
+
* approved, `rerunFailed` runs the apply again and it carries on from
|
|
35
|
+
* that wave.
|
|
26
36
|
* - Capacity. At most `maxJobs` jobs run at once. A job over the limit is not
|
|
27
37
|
* recorded, so a later poll starts it.
|
|
38
|
+
* - Fast-forwards only (#4122). An apply runs only when the target's new head
|
|
39
|
+
* descends from the head seen before it. Any other move, such as a force
|
|
40
|
+
* push back to an older commit, is recorded as seen and not applied.
|
|
41
|
+
* - `[skip ci]` (#4122). A target head or pull request head whose commit
|
|
42
|
+
* message says `[skip ci]` or `[ci skip]` is recorded as seen and not run,
|
|
43
|
+
* as Actions does.
|
|
44
|
+
* - Build requests (#4169). With `buildCommand`, each `ci/build/<sha>`
|
|
45
|
+
* tag the tick or `ci run --at` pushed is served once: the command runs
|
|
46
|
+
* in a fresh detached worktree of the commit, with `CHANT_BUILD_COMMIT`,
|
|
47
|
+
* `CHANT_BUILD_PHASES` (comma-separated) and `CHANT_BUILD_REASON` set,
|
|
48
|
+
* and is expected to run the phases' Ops (`chant run <op>`), whose
|
|
49
|
+
* records the tick reads. A build counts against `maxJobs`, and the state
|
|
50
|
+
* file keeps it under `build:<sha>`. Without `buildCommand` the tags are
|
|
51
|
+
* left alone.
|
|
52
|
+
* - The forge's ledger (#4121). Before each job, when no other job of this
|
|
53
|
+
* serve runs, the clone's `chant/lifecycle` follows the forge's: it is
|
|
54
|
+
* deleted when the forge has none, and reset to the forge's when neither
|
|
55
|
+
* contains the other. Each is a warning. A local branch ahead of the
|
|
56
|
+
* forge's keeps its facts, and the job's push sends them. Nothing here
|
|
57
|
+
* pushes the ledger.
|
|
28
58
|
*
|
|
29
59
|
* Host mode only: each job runs in a fresh worktree on this host as this
|
|
30
60
|
* user, with the clean environment `ciRun` gives it. A pull request from a
|
|
@@ -35,22 +65,25 @@
|
|
|
35
65
|
* {@link ciServeObserve} is the poll that makes them; a webhook handler would
|
|
36
66
|
* turn a checked payload into the same triggers and schedule them.
|
|
37
67
|
*/
|
|
38
|
-
import { execFileSync } from "node:child_process";
|
|
39
|
-
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
68
|
+
import { execFileSync, spawn, spawnSync } from "node:child_process";
|
|
69
|
+
import { existsSync, mkdirSync, mkdtempSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
70
|
+
import { tmpdir } from "node:os";
|
|
40
71
|
import { join, resolve } from "node:path";
|
|
72
|
+
import { CI_BUILD_TAG_PREFIX, readBuildRequests } from "./ci-builds.js";
|
|
41
73
|
import { prApplyGroup, prApplyRecordKey } from "../components/pr-pipeline.js";
|
|
42
74
|
import { forgeFromEnv } from "../pr-forge.js";
|
|
43
75
|
import { formatError, formatWarning } from "../cli/format.js";
|
|
44
76
|
import { acquireLease, currentHolderId, releaseLease, DEFAULT_LEASE_TTL_MS } from "../lifecycle/lease.js";
|
|
45
77
|
import { parseDuration } from "../op/duration.js";
|
|
46
|
-
import {
|
|
47
|
-
import {
|
|
78
|
+
import { reportUrlOf } from "./ci-report-url.js";
|
|
79
|
+
import { CI_JOB_OPS, ciJobPlace, ciLoopOptions, ciSecretsOf, ciRun, ciStatusFromEnv, CiRunError } from "./ci-run.js";
|
|
80
|
+
import { CiGreenError, ciTick, RUNNER_KEY_ENV, signedRunsRequired } from "./ci-green.js";
|
|
48
81
|
import { gitTop } from "./tree.js";
|
|
49
82
|
import { ciServeRunnerKey, formatRunnerKeySetup, setupRunnerKey } from "./ci-runner-key.js";
|
|
50
83
|
export const newCiServeRuntime = () => ({ inflight: new Map() });
|
|
51
84
|
/** The state key of a job. */
|
|
52
85
|
export function ciServeKey(t) {
|
|
53
|
-
return t.job === "plan" ? `plan:${t.pr}:${t.commit}` :
|
|
86
|
+
return t.job === "plan" ? `plan:${t.pr}:${t.commit}` : `${t.job}:${t.commit}`;
|
|
54
87
|
}
|
|
55
88
|
const message = (err) => (err instanceof Error ? err.message : String(err));
|
|
56
89
|
function tryGit(cwd, args) {
|
|
@@ -61,6 +94,79 @@ function tryGit(cwd, args) {
|
|
|
61
94
|
return undefined;
|
|
62
95
|
}
|
|
63
96
|
}
|
|
97
|
+
const LEDGER = "chant/lifecycle";
|
|
98
|
+
/** Where the forge's ledger tip is fetched to, a ref only this module writes. */
|
|
99
|
+
const FORGE_LEDGER = "refs/chant/ci-serve/forge-ledger";
|
|
100
|
+
/** `git` with its exit status, for the calls whose answer is the status. */
|
|
101
|
+
function gitStatus(cwd, args) {
|
|
102
|
+
const r = spawnSync("git", args, { cwd, encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"], env: { ...process.env, LC_ALL: "C" } });
|
|
103
|
+
return { code: r.status ?? -1, out: (r.stdout ?? "").trim() };
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Make the clone's `chant/lifecycle` follow the forge's (#4121). The clone's
|
|
107
|
+
* branch outlives the forge's, so a ledger the forge deleted or rewrote would
|
|
108
|
+
* make the next pr-apply find the two diverged and stall.
|
|
109
|
+
*
|
|
110
|
+
* - The forge has none: the local branch and its remote-tracking ref go.
|
|
111
|
+
* - Neither contains the other: the local branch and its remote-tracking ref
|
|
112
|
+
* are reset to the forge's tip.
|
|
113
|
+
* - The local branch is ahead of the forge's, or behind it, or the same: it
|
|
114
|
+
* is left, and an apply's push sends what it holds that the forge lacks.
|
|
115
|
+
*
|
|
116
|
+
* Nothing is pushed, so a rewritten ledger never goes back to the forge. A
|
|
117
|
+
* forge that can't be reached leaves everything as it is; the job's own
|
|
118
|
+
* fetch says why.
|
|
119
|
+
*/
|
|
120
|
+
export function reconcileCiServeLedger(top) {
|
|
121
|
+
const local = tryGit(top, ["rev-parse", "--verify", "--quiet", `refs/heads/${LEDGER}^{commit}`]);
|
|
122
|
+
const listed = gitStatus(top, ["ls-remote", "--exit-code", "origin", `refs/heads/${LEDGER}`]);
|
|
123
|
+
if (listed.code === 2) {
|
|
124
|
+
// A remote-tracking ref left from a deleted branch would be the next push's lease, and refuse it.
|
|
125
|
+
tryGit(top, ["update-ref", "-d", `refs/remotes/origin/${LEDGER}`]);
|
|
126
|
+
if (!local)
|
|
127
|
+
return undefined;
|
|
128
|
+
tryGit(top, ["update-ref", "-d", `refs/heads/${LEDGER}`, local]);
|
|
129
|
+
return { type: "ledger", action: "deleted", local };
|
|
130
|
+
}
|
|
131
|
+
if (listed.code !== 0 || !local)
|
|
132
|
+
return undefined;
|
|
133
|
+
const forge = listed.out.split(/\s+/)[0];
|
|
134
|
+
if (!forge || forge === local)
|
|
135
|
+
return undefined;
|
|
136
|
+
if (gitStatus(top, ["fetch", "--quiet", "--no-tags", "origin", `+refs/heads/${LEDGER}:${FORGE_LEDGER}`]).code !== 0)
|
|
137
|
+
return undefined;
|
|
138
|
+
try {
|
|
139
|
+
const ahead = gitStatus(top, ["merge-base", "--is-ancestor", forge, local]).code === 0;
|
|
140
|
+
const behind = gitStatus(top, ["merge-base", "--is-ancestor", local, forge]).code === 0;
|
|
141
|
+
if (ahead || behind)
|
|
142
|
+
return undefined;
|
|
143
|
+
tryGit(top, ["update-ref", `refs/heads/${LEDGER}`, forge, local]);
|
|
144
|
+
tryGit(top, ["update-ref", `refs/remotes/origin/${LEDGER}`, forge]);
|
|
145
|
+
return { type: "ledger", action: "reset", local, forge };
|
|
146
|
+
}
|
|
147
|
+
finally {
|
|
148
|
+
tryGit(top, ["update-ref", "-d", FORGE_LEDGER]);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/** A commit message that asks for no CI run, as Actions and GitLab read it. */
|
|
152
|
+
const SKIP_CI = /\[(?:skip ci|ci skip)\]/i;
|
|
153
|
+
/** Whether `commit`'s message asks for no CI run. A commit this clone can't read is not skipped. */
|
|
154
|
+
function skipsCi(top, commit) {
|
|
155
|
+
const body = tryGit(top, ["log", "-1", "--format=%B", commit]);
|
|
156
|
+
return body !== undefined && SKIP_CI.test(body);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* How the target branch moved from `from` to `head` (#4122): `fast-forward`
|
|
160
|
+
* when `head` descends from `from`, `other` when it does not, and `unknown`
|
|
161
|
+
* when `head` could not be fetched. Once `head` is here its history is too,
|
|
162
|
+
* so a `from` this clone lacks is not in that history.
|
|
163
|
+
*/
|
|
164
|
+
function targetMove(top, branch, from, head) {
|
|
165
|
+
tryGit(top, ["fetch", "--quiet", "--no-tags", "origin", branch]);
|
|
166
|
+
if (gitStatus(top, ["cat-file", "-e", `${head}^{commit}`]).code !== 0)
|
|
167
|
+
return "unknown";
|
|
168
|
+
return gitStatus(top, ["merge-base", "--is-ancestor", from, head]).code === 0 ? "fast-forward" : "other";
|
|
169
|
+
}
|
|
64
170
|
/** Where a serve keeps its state when `--state` names nowhere: beside the run events, in the repository's common git directory. */
|
|
65
171
|
export function defaultCiServeStateDir(cwd) {
|
|
66
172
|
const common = tryGit(cwd, ["rev-parse", "--path-format=absolute", "--git-common-dir"]);
|
|
@@ -98,39 +204,62 @@ function writeState(file, state) {
|
|
|
98
204
|
const failedEntry = (entry, key, rt) => !!entry && (entry.status === "fail" || (entry.status === "running" && !rt.inflight.has(key)));
|
|
99
205
|
/**
|
|
100
206
|
* One poll of the forge, as triggers: an apply when the target's head moved
|
|
101
|
-
* since the last apply (none on the first poll, which only
|
|
207
|
+
* since the last apply by a fast-forward (none on the first poll, which only
|
|
208
|
+
* notes the head, and none for a head whose message says `[skip ci]`),
|
|
102
209
|
* then a plan for each open pull request head not yet planned, oldest pull
|
|
103
210
|
* request first. A job already in the state file is left out unless it
|
|
104
|
-
* failed and `rerunFailed` is set. The first poll's head
|
|
105
|
-
* state file.
|
|
211
|
+
* failed and `rerunFailed` is set. The first poll's head, and a head seen
|
|
212
|
+
* and not applied, are written to the state file.
|
|
106
213
|
*/
|
|
107
214
|
export async function ciServeObserve(opts, rt = newCiServeRuntime()) {
|
|
108
215
|
const place = servePlace(opts);
|
|
109
|
-
const
|
|
216
|
+
const fresh = { forge: opts.forge, repo: opts.repo, env: opts.env, branch: place.branch, ...(place.member ? { member: place.member } : {}) };
|
|
217
|
+
const state = readCiServeState(place.stateFile, fresh);
|
|
218
|
+
// Read again at the write: a job of this serve may have settled while the forge answered.
|
|
219
|
+
const update = (fn) => {
|
|
220
|
+
const s = readCiServeState(place.stateFile, fresh);
|
|
221
|
+
fn(s);
|
|
222
|
+
writeState(place.stateFile, s);
|
|
223
|
+
};
|
|
110
224
|
const triggers = [];
|
|
111
225
|
const events = [];
|
|
112
226
|
const [head, prs] = await Promise.all([opts.client.branchHead(place.branch), opts.client.openPullRequests(place.branch)]);
|
|
227
|
+
// #4168: a new target commit is recorded, and applied only with applyOnMerge.
|
|
228
|
+
const onMerge = opts.applyOnMerge ? "apply" : "record";
|
|
113
229
|
if (head === undefined) {
|
|
114
230
|
events.push({ type: "no-branch", branch: place.branch });
|
|
115
231
|
}
|
|
116
232
|
else if (state.target === undefined) {
|
|
117
233
|
// What the branch held before this runner watched it was applied by whatever ran then.
|
|
118
|
-
|
|
119
|
-
|
|
234
|
+
update((s) => {
|
|
235
|
+
s.target = head;
|
|
236
|
+
});
|
|
120
237
|
events.push({ type: "baseline", commit: head });
|
|
121
238
|
}
|
|
122
239
|
else if (head !== state.target) {
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
240
|
+
const from = state.target;
|
|
241
|
+
const move = targetMove(place.top, place.branch, from, head);
|
|
242
|
+
const entry = state.jobs[ciServeKey({ job: onMerge, commit: head })];
|
|
243
|
+
if (move === "unknown") {
|
|
244
|
+
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` });
|
|
245
|
+
}
|
|
246
|
+
else if (move === "other" || (!entry && skipsCi(place.top, head))) {
|
|
247
|
+
// #4122: a move that is not a fast-forward, or a head that asks for no run, is seen and not applied.
|
|
248
|
+
update((s) => {
|
|
249
|
+
s.target = head;
|
|
250
|
+
});
|
|
251
|
+
events.push({ type: "not-run", job: onMerge, commit: head, reason: move === "other" ? "not-fast-forward" : "skip-ci", ...(move === "other" ? { branch: place.branch, from } : {}) });
|
|
252
|
+
}
|
|
253
|
+
else if (!entry)
|
|
254
|
+
triggers.push({ job: onMerge, commit: head, base: from });
|
|
126
255
|
else if (opts.rerunFailed && failedEntry(entry, ciServeKey(entry), rt))
|
|
127
|
-
triggers.push({ job:
|
|
256
|
+
triggers.push({ job: onMerge, commit: head, base: entry.base, rerun: true });
|
|
128
257
|
}
|
|
129
258
|
else {
|
|
130
|
-
const key = ciServeKey({ job:
|
|
259
|
+
const key = ciServeKey({ job: onMerge, commit: head });
|
|
131
260
|
const entry = state.jobs[key];
|
|
132
261
|
if (opts.rerunFailed && failedEntry(entry, key, rt))
|
|
133
|
-
triggers.push({ job:
|
|
262
|
+
triggers.push({ job: onMerge, commit: head, base: entry.base, rerun: true });
|
|
134
263
|
}
|
|
135
264
|
const authors = opts.authors?.length ? new Set(opts.authors.map((a) => a.toLowerCase())) : undefined;
|
|
136
265
|
for (const pr of prs) {
|
|
@@ -145,10 +274,21 @@ export async function ciServeObserve(opts, rt = newCiServeRuntime()) {
|
|
|
145
274
|
const key = ciServeKey({ job: "plan", commit: pr.headSha, pr: pr.number });
|
|
146
275
|
const entry = state.jobs[key];
|
|
147
276
|
const base = pr.baseSha ?? head;
|
|
148
|
-
if (!base)
|
|
277
|
+
if (!base || state.skipped?.[key])
|
|
149
278
|
continue;
|
|
150
|
-
if (!entry)
|
|
151
|
-
|
|
279
|
+
if (!entry) {
|
|
280
|
+
// #4122: a head whose message asks for no run is seen and not planned.
|
|
281
|
+
if (gitStatus(place.top, ["cat-file", "-e", `${pr.headSha}^{commit}`]).code !== 0)
|
|
282
|
+
tryGit(place.top, ["fetch", "--quiet", "--no-tags", "origin", `refs/pull/${pr.number}/head`]);
|
|
283
|
+
if (skipsCi(place.top, pr.headSha)) {
|
|
284
|
+
update((s) => {
|
|
285
|
+
s.skipped = { ...s.skipped, [key]: "skip-ci" };
|
|
286
|
+
});
|
|
287
|
+
events.push({ type: "not-run", job: "plan", commit: pr.headSha, pr: pr.number, reason: "skip-ci" });
|
|
288
|
+
}
|
|
289
|
+
else
|
|
290
|
+
triggers.push({ job: "plan", commit: pr.headSha, base, pr: pr.number });
|
|
291
|
+
}
|
|
152
292
|
else if (opts.rerunFailed && failedEntry(entry, key, rt))
|
|
153
293
|
triggers.push({ job: "plan", commit: pr.headSha, base: entry.base, pr: pr.number, rerun: true });
|
|
154
294
|
}
|
|
@@ -204,6 +344,12 @@ export async function ciServeSchedule(opts, triggers, rt = newCiServeRuntime())
|
|
|
204
344
|
}
|
|
205
345
|
lease = got.lease;
|
|
206
346
|
}
|
|
347
|
+
// #4121: with no other job of this serve writing it, the clone's ledger follows the forge's.
|
|
348
|
+
if (rt.inflight.size === 0) {
|
|
349
|
+
const ledger = reconcileCiServeLedger(place.top);
|
|
350
|
+
if (ledger)
|
|
351
|
+
emit(ledger);
|
|
352
|
+
}
|
|
207
353
|
const previous = readCiServeState(place.stateFile, fresh).jobs[key];
|
|
208
354
|
const attempt = (previous?.attempts ?? 0) + 1;
|
|
209
355
|
const runId = `chant-serve-${now().getTime()}-${t.job}-${t.commit.slice(0, 8)}`;
|
|
@@ -212,7 +358,7 @@ export async function ciServeSchedule(opts, triggers, rt = newCiServeRuntime())
|
|
|
212
358
|
const entry = { job: t.job, commit: t.commit, base: t.base, ...pr, status: "running", runId, attempts: attempt, startedAt: now().toISOString() };
|
|
213
359
|
update((s) => {
|
|
214
360
|
s.jobs[key] = entry;
|
|
215
|
-
if (t.job
|
|
361
|
+
if (t.job !== "plan" && !t.rerun)
|
|
216
362
|
s.target = t.commit;
|
|
217
363
|
});
|
|
218
364
|
emit({ type: "started", job: t.job, commit: t.commit, ...pr, base: t.base, runId, attempt, ...(resume && existsSync(resume) ? { resume } : {}) });
|
|
@@ -228,7 +374,7 @@ export async function ciServeSchedule(opts, triggers, rt = newCiServeRuntime())
|
|
|
228
374
|
emit({ type: "error", message: `${key} settled, and the state file could not be written: ${message(err)}` });
|
|
229
375
|
}
|
|
230
376
|
emit({ type: "settled", job: t.job, commit: t.commit, ...pr, status: settled.status === "ok" ? "ok" : "fail", ...(settled.failure ? { failure: settled.failure } : {}), ...(settled.report ? { report: settled.report } : {}) });
|
|
231
|
-
return settled;
|
|
377
|
+
return serveTick(opts).then(() => settled);
|
|
232
378
|
});
|
|
233
379
|
rt.inflight.set(key, job);
|
|
234
380
|
started.push(job);
|
|
@@ -249,7 +395,7 @@ async function runJob(opts, place, t, paths, held) {
|
|
|
249
395
|
tryGit(place.top, ["fetch", "--quiet", "--no-tags", "origin", t.job === "plan" ? `refs/pull/${t.pr}/head` : place.branch]);
|
|
250
396
|
const hostEnv = { ...(opts.job?.hostEnv ?? process.env), GITHUB_REPOSITORY: opts.repo };
|
|
251
397
|
// 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.
|
|
252
|
-
if (t.job
|
|
398
|
+
if (t.job !== "plan" && opts.client.pullRequestFor)
|
|
253
399
|
merged = (await opts.client.pullRequestFor(t.commit).catch(() => null)) ?? undefined;
|
|
254
400
|
const run = opts.run ?? ciRun;
|
|
255
401
|
const r = await run({
|
|
@@ -279,14 +425,105 @@ async function runJob(opts, place, t, paths, held) {
|
|
|
279
425
|
await releaseLease(place.group, held.holder, held.lease.token, { cwd: opts.cwd }).catch(() => false);
|
|
280
426
|
}
|
|
281
427
|
}
|
|
282
|
-
/** One pass: observe, schedule, and with `wait` wait for the jobs it started. */
|
|
428
|
+
/** One pass: observe, schedule, serve build requests, and with `wait` wait for the jobs it started. */
|
|
283
429
|
export async function ciServePass(opts, rt = newCiServeRuntime(), wait = true) {
|
|
284
430
|
const observed = await ciServeObserve(opts, rt);
|
|
285
431
|
for (const e of observed.events)
|
|
286
432
|
opts.log?.(e);
|
|
287
433
|
const scheduled = await ciServeSchedule(opts, observed.triggers, rt);
|
|
434
|
+
const builds = opts.buildCommand ? ciServeBuilds(opts, rt) : { started: [], events: [] };
|
|
288
435
|
const jobs = wait ? await Promise.all(scheduled.started) : [];
|
|
289
|
-
|
|
436
|
+
if (wait)
|
|
437
|
+
await Promise.all(builds.started);
|
|
438
|
+
return { events: [...observed.events, ...scheduled.events, ...builds.events], jobs };
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Serve the build requests (#4169): fetch the `ci/build/*` tags, and start
|
|
442
|
+
* `buildCommand` for each one not in the state file yet, oldest first, while
|
|
443
|
+
* fewer than `maxJobs` jobs run. A build that fails is recorded and not run
|
|
444
|
+
* again; the tick decides what its phases say.
|
|
445
|
+
*/
|
|
446
|
+
export function ciServeBuilds(opts, rt) {
|
|
447
|
+
const place = servePlace(opts);
|
|
448
|
+
const fresh = { forge: opts.forge, repo: opts.repo, env: opts.env, branch: place.branch, ...(place.member ? { member: place.member } : {}) };
|
|
449
|
+
const update = (fn) => {
|
|
450
|
+
const st = readCiServeState(place.stateFile, fresh);
|
|
451
|
+
fn(st);
|
|
452
|
+
writeState(place.stateFile, st);
|
|
453
|
+
};
|
|
454
|
+
const events = [];
|
|
455
|
+
const started = [];
|
|
456
|
+
tryGit(place.top, ["fetch", "--quiet", "--prune", "origin", `+refs/tags/${CI_BUILD_TAG_PREFIX}*:refs/tags/${CI_BUILD_TAG_PREFIX}*`]);
|
|
457
|
+
const served = readCiServeState(place.stateFile, fresh).builds ?? {};
|
|
458
|
+
const max = opts.maxJobs ?? 1;
|
|
459
|
+
const now = opts.now ?? (() => new Date());
|
|
460
|
+
const requests = [...readBuildRequests(place.top).values()].sort((a, b) => a.at.localeCompare(b.at));
|
|
461
|
+
for (const request of requests) {
|
|
462
|
+
const key = `build:${request.commit}`;
|
|
463
|
+
if (served[key]?.tag === request.tag || rt.inflight.has(key))
|
|
464
|
+
continue;
|
|
465
|
+
const log = (e) => {
|
|
466
|
+
events.push(e);
|
|
467
|
+
opts.log?.(e);
|
|
468
|
+
};
|
|
469
|
+
if (rt.inflight.size >= max) {
|
|
470
|
+
log({ type: "build", commit: request.commit, phases: request.phases, status: "held" });
|
|
471
|
+
continue;
|
|
472
|
+
}
|
|
473
|
+
update((st) => {
|
|
474
|
+
st.builds = { ...st.builds, [key]: { tag: request.tag, status: "running", startedAt: now().toISOString() } };
|
|
475
|
+
});
|
|
476
|
+
log({ type: "build", commit: request.commit, phases: request.phases, status: "started" });
|
|
477
|
+
const build = opts.build ?? runBuild;
|
|
478
|
+
const job = build({ top: place.top, request, command: opts.buildCommand })
|
|
479
|
+
.catch(() => 1)
|
|
480
|
+
.then((code) => {
|
|
481
|
+
update((st) => {
|
|
482
|
+
st.builds = { ...st.builds, [key]: { tag: request.tag, status: code === 0 ? "ok" : "fail", startedAt: st.builds?.[key]?.startedAt ?? now().toISOString(), settledAt: now().toISOString() } };
|
|
483
|
+
});
|
|
484
|
+
opts.log?.({ type: "build", commit: request.commit, phases: request.phases, status: code === 0 ? "ok" : "fail", exitCode: code });
|
|
485
|
+
});
|
|
486
|
+
const tracked = job.finally(() => rt.inflight.delete(key));
|
|
487
|
+
rt.inflight.set(key, tracked);
|
|
488
|
+
started.push(tracked);
|
|
489
|
+
}
|
|
490
|
+
return { started, events };
|
|
491
|
+
}
|
|
492
|
+
/** `sh -c <command>` in a fresh detached worktree of the request's commit, removed after. Resolves to the exit code. */
|
|
493
|
+
async function runBuild(input) {
|
|
494
|
+
const dir = mkdtempSync(join(tmpdir(), "chant-ci-build-"));
|
|
495
|
+
try {
|
|
496
|
+
execFileSync("git", ["worktree", "add", "--quiet", "--detach", dir, input.request.commit], { cwd: input.top, stdio: ["ignore", "pipe", "pipe"] });
|
|
497
|
+
return await new Promise((done) => {
|
|
498
|
+
const child = spawn("sh", ["-c", input.command], {
|
|
499
|
+
cwd: dir,
|
|
500
|
+
stdio: ["ignore", "inherit", "inherit"],
|
|
501
|
+
env: { ...process.env, CHANT_BUILD_COMMIT: input.request.commit, CHANT_BUILD_PHASES: input.request.phases.join(","), CHANT_BUILD_REASON: input.request.reason },
|
|
502
|
+
});
|
|
503
|
+
child.on("error", () => done(127));
|
|
504
|
+
child.on("close", (code) => done(code ?? 1));
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
finally {
|
|
508
|
+
tryGit(input.top, ["worktree", "remove", "--force", dir]);
|
|
509
|
+
rmSync(dir, { recursive: true, force: true });
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
/** `ci tick` after a job settled (#4168), logged; a tick that fails is an error event and never fails the job. */
|
|
513
|
+
async function serveTick(opts) {
|
|
514
|
+
if (!opts.tick)
|
|
515
|
+
return undefined;
|
|
516
|
+
let event;
|
|
517
|
+
try {
|
|
518
|
+
const made = await opts.tick();
|
|
519
|
+
event = made === undefined ? undefined : { type: "tick", made };
|
|
520
|
+
}
|
|
521
|
+
catch (err) {
|
|
522
|
+
event = { type: "error", message: `ci tick after a job settled: ${message(err)}` };
|
|
523
|
+
}
|
|
524
|
+
if (event)
|
|
525
|
+
opts.log?.(event);
|
|
526
|
+
return event;
|
|
290
527
|
}
|
|
291
528
|
/**
|
|
292
529
|
* The loop: a pass every `intervalMs` until `signal` aborts, jobs running
|
|
@@ -328,6 +565,22 @@ export function formatCiServeEvent(e) {
|
|
|
328
565
|
return `${at(e.job, e.commit, e.pr)} started, run ${e.runId}, attempt ${e.attempt}${e.resume ? ", resuming" : ""}`;
|
|
329
566
|
case "settled":
|
|
330
567
|
return `${at(e.job, e.commit, e.pr)} ${e.status === "ok" ? "passed" : `failed${e.failure ? `: ${e.failure}` : ""}`}${e.report ? `; report ${e.report}` : ""}`;
|
|
568
|
+
case "not-run":
|
|
569
|
+
return e.reason === "skip-ci"
|
|
570
|
+
? `${at(e.job, e.commit, e.pr)} is not run: its commit message says [skip ci]`
|
|
571
|
+
: `${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`;
|
|
572
|
+
case "ledger":
|
|
573
|
+
return e.action === "deleted"
|
|
574
|
+
? `the forge has no ${LEDGER}, so this clone's, at ${e.local.slice(0, 12)}, was deleted`
|
|
575
|
+
: `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`;
|
|
576
|
+
case "build": {
|
|
577
|
+
const what = `the build of ${e.phases.join(", ")} at ${e.commit.slice(0, 12)}`;
|
|
578
|
+
if (e.status === "held")
|
|
579
|
+
return `${what} waits: --max-jobs jobs run`;
|
|
580
|
+
return e.status === "started" ? `${what} started` : e.status === "ok" ? `${what} passed` : `${what} failed${e.exitCode !== undefined ? ` with exit code ${e.exitCode}` : ""}`;
|
|
581
|
+
}
|
|
582
|
+
case "tick":
|
|
583
|
+
return e.made.length > 0 ? `ci tick made ${e.made.join(", ")}` : "ci tick: no tag due";
|
|
331
584
|
case "error":
|
|
332
585
|
return `error: ${e.message}`;
|
|
333
586
|
}
|
|
@@ -362,7 +615,7 @@ export function runnerKeySetupCommand(ctx) {
|
|
|
362
615
|
}
|
|
363
616
|
const USAGE = "chant ci serve --setup-key [--trust [--principal <name>]] [--state <dir>] [--branch <name>] | " +
|
|
364
617
|
"chant ci serve --forge forgejo|github --repo <owner/repo> --env <env> [--interval <s>] [--max-jobs <n>] [--state <dir>] " +
|
|
365
|
-
"[--author <login>]... [--once] [--rerun-failed] [--gate <name>] [--branch <name>] [--events-json] [--report-url <url>] [--no-status] [--status-url <url template>] " +
|
|
618
|
+
"[--author <login>]... [--once] [--rerun-failed] [--build-command <line>] [--gate <name>] [--wave-gate <name>] [--branch <name>] [--events-json] [--report-url <url>] [--no-status] [--status-url <url template>] " +
|
|
366
619
|
"[--image <image>] [--before-script <line>]... [--pr-build] [--pr-build-command <line>] [--chant <command>] [--pass-env <NAME>]... [--secrets <file>] [--key <runner key.pem>] [--unsigned]";
|
|
367
620
|
const ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
368
621
|
/** `--interval`: seconds, or a duration such as `30s` or `2m`. Default 30 seconds. */
|
|
@@ -390,6 +643,9 @@ export async function runCiServe(ctx) {
|
|
|
390
643
|
for (const name of args.passEnv ?? [])
|
|
391
644
|
if (!ENV_NAME.test(name))
|
|
392
645
|
throw new CiRunError(`--pass-env takes a variable's name, not ${JSON.stringify(name)}`);
|
|
646
|
+
// #4168: a gate per wave gates the apply on merge, which a merge runs only when opted in.
|
|
647
|
+
if (args.waveGate && !args.applyOnMerge)
|
|
648
|
+
throw new CiRunError("--wave-gate gates the apply on merge, so it needs --apply-on-merge (#4168); without it a merge gets the record job, which applies nothing");
|
|
393
649
|
const intervalMs = ciServeInterval(args.interval);
|
|
394
650
|
const cwd = process.cwd();
|
|
395
651
|
const top = gitTop(cwd);
|
|
@@ -398,12 +654,30 @@ export async function runCiServe(ctx) {
|
|
|
398
654
|
const stateDir = args.statePath ? resolve(args.statePath) : defaultCiServeStateDir(cwd);
|
|
399
655
|
const branch = args.branch ?? "main";
|
|
400
656
|
// #4099: the host's key, checked against .chant/trust.json at the target's head before the first poll.
|
|
401
|
-
|
|
657
|
+
// #4156: signing is opt-in. Without ci.green.signedSince no key is quiet, and an untrusted one warns once and serves unsigned.
|
|
658
|
+
const keyed = ciServeRunnerKey({
|
|
659
|
+
top,
|
|
660
|
+
stateDir,
|
|
661
|
+
branch,
|
|
662
|
+
...(args.key !== undefined ? { keyFile: resolve(args.key) } : {}),
|
|
663
|
+
envKey: process.env[RUNNER_KEY_ENV] || undefined,
|
|
664
|
+
unsigned: args.unsigned,
|
|
665
|
+
required: signedRunsRequired(cwd),
|
|
666
|
+
});
|
|
402
667
|
const fromFlag = keyed.fromFlag;
|
|
403
668
|
const runnerKey = keyed.pem;
|
|
404
|
-
|
|
669
|
+
if (keyed.warning)
|
|
670
|
+
console.error(formatWarning({ message: keyed.warning }));
|
|
671
|
+
if (runnerKey !== undefined)
|
|
672
|
+
console.error(`ci serve: signing runs with the runner key from ${keyed.source}`);
|
|
673
|
+
else if (keyed.note && args.verbose)
|
|
674
|
+
console.error(`ci serve: ${keyed.note}`);
|
|
405
675
|
// #4096: read once, so a loose or broken secrets file stops the serve before its first poll.
|
|
406
676
|
const secrets = ciSecretsOf(args.ciSecrets);
|
|
677
|
+
// #4160: without --report-url, the declaration's ci.reportUrl.
|
|
678
|
+
const reportUrl = await reportUrlOf(args.reportUrl, cwd);
|
|
679
|
+
if (reportUrl && !args.reportUrl)
|
|
680
|
+
console.error(`ci serve: reports and the run index go to ${reportUrl}, the declaration's ci.reportUrl`);
|
|
407
681
|
const hostEnv = { ...process.env, GITHUB_REPOSITORY: args.ciRepo };
|
|
408
682
|
const client = forgeFromEnv(forge, hostEnv);
|
|
409
683
|
const { status, warning } = ciStatusFromEnv({ forge, hostEnv, noStatus: args.noStatus, statusUrl: args.statusUrl });
|
|
@@ -411,6 +685,9 @@ export async function runCiServe(ctx) {
|
|
|
411
685
|
console.error(formatWarning({ message: warning }));
|
|
412
686
|
if (!client.openPullRequests || !client.branchHead)
|
|
413
687
|
throw new CiRunError(`the ${forge} client cannot list pull requests`);
|
|
688
|
+
// #4168: a host that applied each merge before the upgrade hears that it no longer does.
|
|
689
|
+
if (!args.applyOnMerge)
|
|
690
|
+
console.error("ci serve: each new commit on the target branch gets the record job, which applies nothing (#4168); --apply-on-merge applies it");
|
|
414
691
|
const opts = {
|
|
415
692
|
cwd,
|
|
416
693
|
forge,
|
|
@@ -421,15 +698,21 @@ export async function runCiServe(ctx) {
|
|
|
421
698
|
...(args.maxJobs ? { maxJobs: args.maxJobs } : {}),
|
|
422
699
|
...(args.ciAuthors?.length ? { authors: args.ciAuthors } : {}),
|
|
423
700
|
...(args.rerunFailed ? { rerunFailed: true } : {}),
|
|
701
|
+
...(args.ciBuildCommand ? { buildCommand: args.ciBuildCommand } : {}),
|
|
702
|
+
...(args.applyOnMerge ? { applyOnMerge: true } : {}),
|
|
703
|
+
// #4168: the tick from the runs the jobs recorded, signed with the runs' key. No ci.green, no tick.
|
|
704
|
+
tick: async () => {
|
|
705
|
+
try {
|
|
706
|
+
return (await ciTick({ cwd, source: "runs", ...(runnerKey !== undefined ? { runnerKey } : {}) })).made;
|
|
707
|
+
}
|
|
708
|
+
catch (err) {
|
|
709
|
+
if (err instanceof CiGreenError && err.code === "ci-green-undeclared")
|
|
710
|
+
return undefined;
|
|
711
|
+
throw err;
|
|
712
|
+
}
|
|
713
|
+
},
|
|
424
714
|
job: {
|
|
425
|
-
loop: {
|
|
426
|
-
...(args.gate ? { gate: args.gate } : {}),
|
|
427
|
-
...(args.branch ? { branch: args.branch } : {}),
|
|
428
|
-
...(args.eventsJson ? { events: true } : {}),
|
|
429
|
-
...(args.reportUrl ? { reportUrl: args.reportUrl } : {}),
|
|
430
|
-
...(args.prBuild ? { build: true } : {}),
|
|
431
|
-
...(args.prBuildCommand ? { buildCommand: args.prBuildCommand } : {}),
|
|
432
|
-
},
|
|
715
|
+
loop: ciLoopOptions(reportUrl ? { ...args, reportUrl } : args),
|
|
433
716
|
...(args.runIndexLimit ? { runIndexLimit: args.runIndexLimit } : {}),
|
|
434
717
|
...(args.image ? { image: args.image } : {}),
|
|
435
718
|
...(args.beforeScript?.length ? { beforeScript: args.beforeScript } : {}),
|
|
@@ -442,7 +725,7 @@ export async function runCiServe(ctx) {
|
|
|
442
725
|
hostEnv,
|
|
443
726
|
stepOutput: (line) => void process.stderr.write(`${line}\n`),
|
|
444
727
|
},
|
|
445
|
-
log: (e) => console.error(e.type === "error" ? formatWarning({ message: formatCiServeEvent(e) }) : `ci serve: ${formatCiServeEvent(e)}`),
|
|
728
|
+
log: (e) => console.error(e.type === "error" || e.type === "ledger" ? formatWarning({ message: formatCiServeEvent(e) }) : `ci serve: ${formatCiServeEvent(e)}`),
|
|
446
729
|
};
|
|
447
730
|
if (args.once) {
|
|
448
731
|
const pass = await ciServePass(opts);
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
import { type RetentionOverride } from "../lifecycle/retention-policy.js";
|
|
19
19
|
import { EXAMPLES_KIND } from "./kinds.js";
|
|
20
20
|
import { type TextLocation } from "./jsonc.js";
|
|
21
|
+
import type { SecurityGroup } from "./security.js";
|
|
21
22
|
import { type WorkspaceTree } from "./tree.js";
|
|
22
23
|
export declare const DECLARATION_SCHEMA_ID: string;
|
|
23
24
|
export declare const DECLARATION_FILES: readonly ["chant.workspace.json", "chant.workspace.jsonc"];
|
|
@@ -126,6 +127,12 @@ export interface AgentDeclaration {
|
|
|
126
127
|
}
|
|
127
128
|
/** What a check run that finished as skipped counts as in a CI phase (#3573). */
|
|
128
129
|
export type CiSkipped = "pass" | "fail";
|
|
130
|
+
/**
|
|
131
|
+
* Which commits a phase runs on (#4169): `every` first-parent commit of the
|
|
132
|
+
* branch, or only the `newest` one when a runner frees, the commits between
|
|
133
|
+
* left unbuilt and a red one bisected.
|
|
134
|
+
*/
|
|
135
|
+
export type CiBuild = "every" | "newest";
|
|
129
136
|
/** One phase of `ci.green`: the check runs that make it up (#3573, ws-103). */
|
|
130
137
|
export interface CiPhase {
|
|
131
138
|
name: string;
|
|
@@ -133,6 +140,12 @@ export interface CiPhase {
|
|
|
133
140
|
runs: string[];
|
|
134
141
|
/** `fail` (the default): a skipped run never passes. `pass`: it passes, for a job a path filter runs only on some commits. */
|
|
135
142
|
skipped: CiSkipped;
|
|
143
|
+
/**
|
|
144
|
+
* Which commits the phase runs on (#4169), when the declaration says.
|
|
145
|
+
* Absent means `every`, and `ci workflow` then leaves the phase's
|
|
146
|
+
* workflows as they are.
|
|
147
|
+
*/
|
|
148
|
+
build?: CiBuild;
|
|
136
149
|
pointer: string;
|
|
137
150
|
}
|
|
138
151
|
/** The default `ci.green.window`. */
|
|
@@ -171,6 +184,14 @@ export type CiSource = "checks" | "runs";
|
|
|
171
184
|
/** The declaration's `ci` block (#3573). */
|
|
172
185
|
export interface CiDeclaration {
|
|
173
186
|
green: CiGreen | null;
|
|
187
|
+
/**
|
|
188
|
+
* `ci.reportUrl` (#4160): where the pull-request jobs copy their reports
|
|
189
|
+
* and `chant ci run` keeps the run index, `<reportUrl>/runs/index.json`.
|
|
190
|
+
* An `s3://` or `file://` URL, as `--report-url` takes, without a trailing
|
|
191
|
+
* slash. The commands that take `--report-url` default to it. Null when
|
|
192
|
+
* the declaration sets none.
|
|
193
|
+
*/
|
|
194
|
+
reportUrl: string | null;
|
|
174
195
|
}
|
|
175
196
|
export interface MemberRole {
|
|
176
197
|
name: string;
|
|
@@ -470,6 +491,8 @@ export interface Member {
|
|
|
470
491
|
because: string | null;
|
|
471
492
|
/** Whether `chant workspace export` takes the member (#2552, D10). False when the entry does not say. */
|
|
472
493
|
travel: boolean;
|
|
494
|
+
/** The security groups this member adds to the declaration's top-level `security` (#4168 step 7), in file order; empty when it names none. */
|
|
495
|
+
security: SecurityGroup[];
|
|
473
496
|
suppress: Suppression[];
|
|
474
497
|
/** The entry's JSON Pointer in the file, for messages. */
|
|
475
498
|
pointer: string;
|
|
@@ -535,6 +558,8 @@ export interface Declaration {
|
|
|
535
558
|
metrics: {
|
|
536
559
|
failureWindowDays?: number;
|
|
537
560
|
} | null;
|
|
561
|
+
/** The security groups the workspace opts into (#4168 section 8, ./security.ts), in file order; empty when the declaration has no `security` key. */
|
|
562
|
+
security: SecurityGroup[];
|
|
538
563
|
/** The file, relative to the workspace root's tree (`chant.workspace.json` or `.jsonc`). */
|
|
539
564
|
file: string;
|
|
540
565
|
}
|