@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
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #4169 end to end: `chant ci tick` and `chant ci run --at`, as a process,
|
|
3
|
+
* against a bare git remote and a local server that answers GitHub's check
|
|
4
|
+
* run, re-run and workflow dispatch calls the way Actions would for a
|
|
5
|
+
* `suites` phase declared `build: "newest"`.
|
|
6
|
+
*
|
|
7
|
+
* Seven commits go to main at once: a green base, five commits the suites
|
|
8
|
+
* never ran on (GitHub dropped their waiting runs), and the newest, whose
|
|
9
|
+
* suites run fails. The fourth of the five broke the suites. The tick runs
|
|
10
|
+
* each failed job again once, then bisects: it halves the five, steps back
|
|
11
|
+
* from the red, and names the culprit, leaving the two commits below the
|
|
12
|
+
* green middle one unbuilt.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { spawn } from "node:child_process";
|
|
16
|
+
import { createServer, type IncomingMessage, type Server, type ServerResponse } from "node:http";
|
|
17
|
+
import type { AddressInfo } from "node:net";
|
|
18
|
+
import { join } from "node:path";
|
|
19
|
+
import { pathToFileURL } from "node:url";
|
|
20
|
+
import { afterAll, beforeAll, describe, expect, test } from "vitest";
|
|
21
|
+
import { cleanScratch, declaration, git, REPO, scratchDir, writeFiles } from "./__fixtures__/contract-repo";
|
|
22
|
+
|
|
23
|
+
afterAll(cleanScratch);
|
|
24
|
+
|
|
25
|
+
const GREEN = {
|
|
26
|
+
branch: "main",
|
|
27
|
+
phases: { check: { runs: ["check"], build: "every" }, suites: { runs: ["suites"], build: "newest" } },
|
|
28
|
+
require: ["check", "suites"],
|
|
29
|
+
};
|
|
30
|
+
const SUITES_WORKFLOW = "name: release-suites\non:\n push:\n branches: [main]\n workflow_dispatch: {}\njobs:\n suites:\n runs-on: ubuntu-latest\n steps:\n - run: true\n";
|
|
31
|
+
|
|
32
|
+
interface Run {
|
|
33
|
+
id: number;
|
|
34
|
+
name: string;
|
|
35
|
+
status: string;
|
|
36
|
+
conclusion: string | null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** The fake GitHub: runs per commit, and what dispatching the suites at a commit concludes. */
|
|
40
|
+
class FakeGithub {
|
|
41
|
+
runs = new Map<string, Run[]>();
|
|
42
|
+
dispatched: string[] = [];
|
|
43
|
+
reruns: number[] = [];
|
|
44
|
+
private id = 1;
|
|
45
|
+
server!: Server;
|
|
46
|
+
constructor(
|
|
47
|
+
readonly origin: string,
|
|
48
|
+
readonly suitesPass: (sha: string) => boolean,
|
|
49
|
+
) {}
|
|
50
|
+
|
|
51
|
+
add(sha: string, name: string, conclusion: string): void {
|
|
52
|
+
this.runs.set(sha, [...(this.runs.get(sha) ?? []), { id: this.id++, name, status: "completed", conclusion }]);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async listen(): Promise<string> {
|
|
56
|
+
this.server = createServer((req, res) => void this.handle(req, res));
|
|
57
|
+
await new Promise<void>((done) => this.server.listen(0, "127.0.0.1", done));
|
|
58
|
+
return `http://127.0.0.1:${(this.server.address() as AddressInfo).port}`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private async handle(req: IncomingMessage, res: ServerResponse): Promise<void> {
|
|
62
|
+
const body = await new Promise<string>((done) => {
|
|
63
|
+
let text = "";
|
|
64
|
+
req.on("data", (c) => (text += c));
|
|
65
|
+
req.on("end", () => done(text));
|
|
66
|
+
});
|
|
67
|
+
const url = new URL(req.url ?? "/", "http://x");
|
|
68
|
+
const send = (status: number, json?: unknown) => {
|
|
69
|
+
res.writeHead(status, { "Content-Type": "application/json" });
|
|
70
|
+
res.end(json === undefined ? "" : JSON.stringify(json));
|
|
71
|
+
};
|
|
72
|
+
let m = /^\/repos\/acme\/app\/commits\/([0-9a-f]+)\/check-runs$/.exec(url.pathname);
|
|
73
|
+
if (req.method === "GET" && m) {
|
|
74
|
+
const runs = this.runs.get(m[1]) ?? [];
|
|
75
|
+
return send(200, { total_count: runs.length, check_runs: runs.map((r) => ({ ...r, completed_at: null, html_url: null })) });
|
|
76
|
+
}
|
|
77
|
+
m = /^\/repos\/acme\/app\/actions\/jobs\/(\d+)\/rerun$/.exec(url.pathname);
|
|
78
|
+
if (req.method === "POST" && m) {
|
|
79
|
+
const id = Number(m[1]);
|
|
80
|
+
this.reruns.push(id);
|
|
81
|
+
// The job runs again and fails the same way.
|
|
82
|
+
for (const [sha, runs] of this.runs) {
|
|
83
|
+
const r = runs.find((x) => x.id === id);
|
|
84
|
+
if (r) this.add(sha, r.name, r.conclusion ?? "failure");
|
|
85
|
+
}
|
|
86
|
+
return send(201, {});
|
|
87
|
+
}
|
|
88
|
+
m = /^\/repos\/acme\/app\/actions\/workflows\/([^/]+)\/dispatches$/.exec(url.pathname);
|
|
89
|
+
if (req.method === "POST" && m) {
|
|
90
|
+
const ref = (JSON.parse(body) as { ref: string }).ref;
|
|
91
|
+
const sha = git(this.origin, "rev-parse", `refs/tags/${ref}^{commit}`);
|
|
92
|
+
this.dispatched.push(sha);
|
|
93
|
+
this.add(sha, "suites", this.suitesPass(sha) ? "success" : "failure");
|
|
94
|
+
return send(204);
|
|
95
|
+
}
|
|
96
|
+
send(404, { message: "not found" });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function chant(cwd: string, api: string, ...args: string[]): Promise<{ code: number; out: string; err: string }> {
|
|
101
|
+
return new Promise((done) => {
|
|
102
|
+
const child = spawn(process.execPath, ["--import", pathToFileURL(join(REPO, "node_modules/tsx/dist/loader.mjs")).href, join(REPO, "packages/core/src/cli/main.ts"), ...args], {
|
|
103
|
+
cwd,
|
|
104
|
+
env: { ...process.env, GITHUB_API_URL: api, GITHUB_REPOSITORY: "acme/app", GITHUB_TOKEN: "t", GIT_TERMINAL_PROMPT: "0", NO_COLOR: "1" },
|
|
105
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
106
|
+
});
|
|
107
|
+
let out = "";
|
|
108
|
+
let err = "";
|
|
109
|
+
child.stdout.on("data", (c) => (out += c));
|
|
110
|
+
child.stderr.on("data", (c) => (err += c));
|
|
111
|
+
child.on("close", (code) => done({ code: code ?? 1, out, err }));
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
describe("a newest phase, bisected end to end (#4169)", () => {
|
|
116
|
+
let root: string;
|
|
117
|
+
let origin: string;
|
|
118
|
+
let forge: FakeGithub;
|
|
119
|
+
let api: string;
|
|
120
|
+
const shas: Record<string, string> = {};
|
|
121
|
+
|
|
122
|
+
beforeAll(async () => {
|
|
123
|
+
origin = scratchDir("chant-builds-e2e-origin-");
|
|
124
|
+
git(origin, "init", "-q", "--bare");
|
|
125
|
+
root = scratchDir("chant-builds-e2e-work-");
|
|
126
|
+
git(root, "init", "-q");
|
|
127
|
+
git(root, "symbolic-ref", "HEAD", "refs/heads/main");
|
|
128
|
+
git(root, "config", "user.name", "t");
|
|
129
|
+
git(root, "config", "user.email", "t@example.com");
|
|
130
|
+
git(root, "remote", "add", "origin", origin);
|
|
131
|
+
writeFiles(root, {
|
|
132
|
+
"chant.workspace.json": declaration([{ name: "app", dir: "app", kind: "other", because: "the app" }], { ci: { green: GREEN } }),
|
|
133
|
+
".github/workflows/release-suites.yml": SUITES_WORKFLOW,
|
|
134
|
+
});
|
|
135
|
+
for (const name of ["base", "u1", "u2", "u3", "u4", "u5", "top"]) {
|
|
136
|
+
writeFiles(root, { [`app/${name}.txt`]: `${name}\n` });
|
|
137
|
+
git(root, "add", "-A");
|
|
138
|
+
git(root, "commit", "-q", "-m", name);
|
|
139
|
+
shas[name] = git(root, "rev-parse", "HEAD");
|
|
140
|
+
}
|
|
141
|
+
git(root, "push", "-q", "origin", "main");
|
|
142
|
+
const order = ["base", "u1", "u2", "u3", "u4", "u5", "top"].map((n) => shas[n]);
|
|
143
|
+
// u4 broke the suites: they pass below it.
|
|
144
|
+
forge = new FakeGithub(origin, (sha) => order.indexOf(sha) < order.indexOf(shas.u4));
|
|
145
|
+
for (const sha of order) forge.add(sha, "check", "success");
|
|
146
|
+
forge.add(shas.base, "suites", "success");
|
|
147
|
+
forge.add(shas.top, "suites", "failure");
|
|
148
|
+
api = await forge.listen();
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
afterAll(() => forge?.server.close());
|
|
152
|
+
|
|
153
|
+
const tags = () => git(origin, "for-each-ref", "--format=%(refname:lstrip=2)", "refs/tags/").split("\n").filter(Boolean).sort();
|
|
154
|
+
const record = (name: string) => JSON.parse(git(origin, "show", `refs/heads/chant/lifecycle:_ci/${shas[name]}.json`));
|
|
155
|
+
const tick = async () => {
|
|
156
|
+
const r = await chant(root, api, "ci", "tick");
|
|
157
|
+
expect(r.code, r.err).toBe(0);
|
|
158
|
+
return r.out;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
test("retries once, bisects to the culprit, and leaves the commits below the green one unbuilt", async () => {
|
|
162
|
+
// The failed suites run again once, and fail again.
|
|
163
|
+
expect(await tick()).toContain(`ran suites at ${shas.top.slice(0, 12)} again`);
|
|
164
|
+
expect(forge.reruns).toHaveLength(1);
|
|
165
|
+
expect(record("top")).toMatchObject({ state: "pending", phases: { suites: { reason: "retrying" } } });
|
|
166
|
+
|
|
167
|
+
// Red now: five unbuilt below it, so the middle one, u3.
|
|
168
|
+
await tick();
|
|
169
|
+
expect(forge.dispatched).toEqual([shas.u3]);
|
|
170
|
+
// u3 passes and goes green; then the step back from the red, u5, then u4,
|
|
171
|
+
// each red run of them run again once before the next step.
|
|
172
|
+
await tick();
|
|
173
|
+
expect(tags()).toContain(`ci/green/${shas.u3}`);
|
|
174
|
+
expect(forge.dispatched).toEqual([shas.u3, shas.u5]);
|
|
175
|
+
expect(await tick()).toContain(`ran suites at ${shas.u5.slice(0, 12)} again`);
|
|
176
|
+
await tick();
|
|
177
|
+
expect(forge.dispatched).toEqual([shas.u3, shas.u5, shas.u4]);
|
|
178
|
+
expect(await tick()).toContain(`ran suites at ${shas.u4.slice(0, 12)} again`);
|
|
179
|
+
await tick();
|
|
180
|
+
expect(forge.dispatched).toHaveLength(3);
|
|
181
|
+
expect(forge.reruns).toHaveLength(3);
|
|
182
|
+
|
|
183
|
+
for (const name of ["u4", "u5", "top"]) expect(record(name), name).toMatchObject({ state: "red", phases: { suites: { culprit: shas.u4 } } });
|
|
184
|
+
for (const name of ["u1", "u2"]) expect(record(name), name).toMatchObject({ state: "unbuilt", phases: { suites: { verdict: "unbuilt", reason: "superseded" } } });
|
|
185
|
+
expect(record("u3")).toMatchObject({ state: "green" });
|
|
186
|
+
expect(tags().filter((t) => t.startsWith("ci/build/"))).toEqual([]);
|
|
187
|
+
expect(tags()).toEqual([`ci/green/${shas.base}`, `ci/green/${shas.u3}`].sort());
|
|
188
|
+
|
|
189
|
+
const last = await chant(root, api, "ci", "last-green", "--json");
|
|
190
|
+
const doc = JSON.parse(last.out);
|
|
191
|
+
expect(doc.commit.sha).toBe(shas.u3);
|
|
192
|
+
expect(doc.newer.map((n: { sha: string; record: { state: string; culprit?: string } }) => [n.sha, n.record.state, n.record.culprit])).toEqual([
|
|
193
|
+
[shas.top, "red", shas.u4],
|
|
194
|
+
[shas.u5, "red", shas.u4],
|
|
195
|
+
[shas.u4, "red", shas.u4],
|
|
196
|
+
]);
|
|
197
|
+
}, 180_000);
|
|
198
|
+
|
|
199
|
+
test("ci run --at asks for a chosen commit and starts the suites there", async () => {
|
|
200
|
+
const r = await chant(root, api, "ci", "run", "--at", shas.u1);
|
|
201
|
+
expect(r.code, r.err).toBe(0);
|
|
202
|
+
expect(r.out).toContain(`Asked for check, suites at ${shas.u1.slice(0, 12)}: ci/build/${shas.u1}. Started release-suites.yml.`);
|
|
203
|
+
expect(tags()).toContain(`ci/build/${shas.u1}`);
|
|
204
|
+
await tick();
|
|
205
|
+
expect(tags()).toContain(`ci/green/${shas.u1}`);
|
|
206
|
+
expect(tags()).not.toContain(`ci/build/${shas.u1}`);
|
|
207
|
+
}, 60_000);
|
|
208
|
+
});
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #4169 — which commits get built: supersession, retries, requests and
|
|
3
|
+
* bisection over judged commits, and the records each commit gets.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, expect, test } from "vitest";
|
|
7
|
+
import { agedOut, BUILD_REQUEST_TTL_MS, planBuilds, recordOf, RETRY_TTL_MS, sameRecord, type BuildRequest, type CiRecord } from "./ci-builds";
|
|
8
|
+
import { evaluateCommit, type TickCommit } from "./ci-green";
|
|
9
|
+
import type { CheckRun } from "./ci-green-forge";
|
|
10
|
+
import type { CiGreen } from "./declaration";
|
|
11
|
+
|
|
12
|
+
const NOW = new Date("2026-10-20T12:00:00Z");
|
|
13
|
+
const ago = (ms: number) => new Date(NOW.getTime() - ms).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
14
|
+
|
|
15
|
+
const GREEN: CiGreen = {
|
|
16
|
+
branch: "main",
|
|
17
|
+
window: "24h",
|
|
18
|
+
phases: [
|
|
19
|
+
{ name: "check", runs: ["check"], skipped: "fail", build: "every", pointer: "/ci/green/phases/check" },
|
|
20
|
+
{ name: "suites", runs: ["suites"], skipped: "fail", build: "newest", pointer: "/ci/green/phases/suites" },
|
|
21
|
+
],
|
|
22
|
+
require: ["check", "suites"],
|
|
23
|
+
signedSince: null,
|
|
24
|
+
source: "checks",
|
|
25
|
+
pointer: "/ci/green",
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
let nextId = 1;
|
|
29
|
+
const run = (name: string, conclusion: string | null, status = "completed"): CheckRun => ({ id: nextId++, name, status, conclusion: status === "completed" ? conclusion : null, completedAt: null, url: null });
|
|
30
|
+
const sha = (n: number) => String(n).padStart(40, "0");
|
|
31
|
+
|
|
32
|
+
/** Commits newest first, each with its runs, judged as the tick judges them. */
|
|
33
|
+
function judged(runsPerCommit: CheckRun[][], before: TickCommit["before"][] = []): { commits: TickCommit[]; runs: Map<string, CheckRun[]> } {
|
|
34
|
+
const runs = new Map<string, CheckRun[]>();
|
|
35
|
+
const commits = runsPerCommit.map((r, i) => {
|
|
36
|
+
const s = sha(runsPerCommit.length - i);
|
|
37
|
+
runs.set(s, r);
|
|
38
|
+
return { sha: s, committed: NOW.toISOString(), before: before[i] ?? "none", verdict: evaluateCommit(GREEN, r), made: null } as TickCommit;
|
|
39
|
+
});
|
|
40
|
+
return { commits, runs };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const plan = (commits: TickCommit[], runs: Map<string, CheckRun[]>, extra: Partial<Parameters<typeof planBuilds>[0]> = {}) =>
|
|
44
|
+
planBuilds({ green: GREEN, commits, runs, requests: new Map(), records: new Map(), now: NOW, retryVia: null, ...extra });
|
|
45
|
+
|
|
46
|
+
const suites = (c: TickCommit) => c.verdict!.phases.find((p) => p.phase === "suites")!;
|
|
47
|
+
|
|
48
|
+
describe("supersession (#4169)", () => {
|
|
49
|
+
test("a newest phase with no run below a commit that has one is unbuilt, covered by it; the newest commit stays pending", () => {
|
|
50
|
+
const { commits, runs } = judged([[run("check", "success")], [run("check", "success"), run("suites", "success")], [run("check", "success")]]);
|
|
51
|
+
plan(commits, runs);
|
|
52
|
+
expect(commits.map((c) => c.verdict!.verdict)).toEqual(["pending", "pass", "unbuilt"]);
|
|
53
|
+
expect(suites(commits[2])).toMatchObject({ verdict: "unbuilt", reason: "superseded", coveredBy: commits[1].sha });
|
|
54
|
+
expect(suites(commits[0])).toMatchObject({ verdict: "pending" });
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test("an every phase is never superseded, and a cancelled run is unbuilt under either", () => {
|
|
58
|
+
const { commits, runs } = judged([[run("check", "success"), run("suites", "success")], [run("suites", "success")], [run("check", "cancelled"), run("suites", "success")]]);
|
|
59
|
+
plan(commits, runs);
|
|
60
|
+
expect(commits.map((c) => c.verdict!.verdict)).toEqual(["pass", "pending", "unbuilt"]);
|
|
61
|
+
expect(commits[2].verdict!.phases[0]).toMatchObject({ phase: "check", verdict: "unbuilt", reason: "cancelled" });
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe("bisect (#4169)", () => {
|
|
66
|
+
const green = () => [run("check", "success"), run("suites", "success")];
|
|
67
|
+
const red = () => [run("check", "success"), run("suites", "failure")];
|
|
68
|
+
const none = () => [run("check", "success")];
|
|
69
|
+
|
|
70
|
+
test("a red newest commit asks for the one just below it when four or fewer are unbuilt", () => {
|
|
71
|
+
const { commits, runs } = judged([red(), none(), none(), green()]);
|
|
72
|
+
const p = plan(commits, runs);
|
|
73
|
+
expect(p.requests).toEqual([expect.objectContaining({ commit: commits[1].sha, phases: ["suites"], reason: "bisect", tag: `ci/build/${commits[1].sha}` })]);
|
|
74
|
+
expect(suites(commits[1])).toMatchObject({ verdict: "pending", reason: "requested" });
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("halves the range above four, and asks for nothing while a request in it waits", () => {
|
|
78
|
+
const { commits, runs } = judged([red(), none(), none(), none(), none(), none(), none(), green()]);
|
|
79
|
+
const p = plan(commits, runs);
|
|
80
|
+
expect(p.requests.map((r) => r.commit)).toEqual([commits[4].sha]);
|
|
81
|
+
const waiting: BuildRequest = { ...p.requests[0], at: ago(60_000) };
|
|
82
|
+
const again = judged([red(), none(), none(), none(), none(), none(), none(), green()]);
|
|
83
|
+
expect(plan(again.commits, again.runs, { requests: new Map([[waiting.commit, waiting]]) }).requests).toEqual([]);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test("names the culprit on it and every commit after it once the red sits on a green", () => {
|
|
87
|
+
const { commits, runs } = judged([red(), none(), red(), green()]);
|
|
88
|
+
// The commit below the newest red is unbuilt between two reds: the culprit is at or below the older red.
|
|
89
|
+
plan(commits, runs);
|
|
90
|
+
expect(commits.map((c) => suites(c).culprit)).toEqual([commits[2].sha, commits[2].sha, commits[2].sha, undefined]);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test("names no culprit without a green below, and an every phase gets one too", () => {
|
|
94
|
+
const noGreen = judged([red(), red()]);
|
|
95
|
+
plan(noGreen.commits, noGreen.runs);
|
|
96
|
+
expect(noGreen.commits.map((c) => suites(c).culprit)).toEqual([undefined, undefined]);
|
|
97
|
+
const every = judged([[run("check", "failure")], [run("check", "failure")], [run("check", "success")]]);
|
|
98
|
+
plan(every.commits, every.runs);
|
|
99
|
+
expect(every.commits.map((c) => c.verdict!.phases[0].culprit)).toEqual([every.commits[1].sha, every.commits[1].sha, undefined]);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe("requests (#4169)", () => {
|
|
104
|
+
const req = (commit: string, at: string): BuildRequest => ({ schema: 1, tag: `ci/build/${commit}`, commit, branch: "main", phases: ["suites"], reason: "requested", at });
|
|
105
|
+
|
|
106
|
+
test("a request holds its phase pending; once decided, or too old, or out of the window, it is done", () => {
|
|
107
|
+
const { commits, runs } = judged([[run("check", "success"), run("suites", "success")], [run("check", "success")]]);
|
|
108
|
+
const waiting = req(commits[1].sha, ago(60_000));
|
|
109
|
+
const p = plan(commits, runs, { requests: new Map([[waiting.commit, waiting]]) });
|
|
110
|
+
expect(suites(commits[1])).toMatchObject({ verdict: "pending", reason: "requested" });
|
|
111
|
+
expect(p.resolved).toEqual([]);
|
|
112
|
+
|
|
113
|
+
const old = judged([[run("check", "success"), run("suites", "success")], [run("check", "success")]]);
|
|
114
|
+
const stale = req(old.commits[1].sha, ago(BUILD_REQUEST_TTL_MS + 1));
|
|
115
|
+
expect(plan(old.commits, old.runs, { requests: new Map([[stale.commit, stale]]) }).resolved).toEqual([stale.tag]);
|
|
116
|
+
expect(suites(old.commits[1])).toMatchObject({ verdict: "unbuilt", reason: "request-unserved" });
|
|
117
|
+
|
|
118
|
+
const done = judged([[run("check", "success"), run("suites", "success")]]);
|
|
119
|
+
const served = req(done.commits[0].sha, ago(60_000));
|
|
120
|
+
const gone = req(sha(99), ago(60_000));
|
|
121
|
+
expect(plan(done.commits, done.runs, { requests: new Map([[served.commit, served], [gone.commit, gone]]) }).resolved.sort()).toEqual([served.tag, gone.tag].sort());
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
describe("retry (#4169)", () => {
|
|
126
|
+
test("a failed run with one attempt is run again and holds the commit pending; a second attempt decides", () => {
|
|
127
|
+
const failed = run("check", "failure");
|
|
128
|
+
const { commits, runs } = judged([[failed, run("suites", "success")]]);
|
|
129
|
+
const p = plan(commits, runs, { retryVia: "forge" });
|
|
130
|
+
expect(p.retries).toEqual([{ sha: commits[0].sha, run: failed }]);
|
|
131
|
+
expect(commits[0].verdict!.verdict).toBe("pending");
|
|
132
|
+
expect(commits[0].verdict!.phases[0]).toMatchObject({ verdict: "pending", reason: "retrying" });
|
|
133
|
+
|
|
134
|
+
const twice = judged([[failed, run("check", "failure"), run("suites", "success")]]);
|
|
135
|
+
expect(plan(twice.commits, twice.runs, { retryVia: "forge" }).retries).toEqual([]);
|
|
136
|
+
expect(twice.commits[0].verdict!.verdict).toBe("fail");
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test("a retry asked for waits an hour for its attempt, then the failure counts; chant runs ask by request; a green commit is never retried", () => {
|
|
140
|
+
const failed = run("check", "failure");
|
|
141
|
+
const asked = (at: string): CiRecord => ({ schema: 1, commit: sha(1), branch: "main", state: "pending", at, phases: {}, retried: { check: { run: failed.id, at } } });
|
|
142
|
+
const waiting = judged([[failed, run("suites", "success")]]);
|
|
143
|
+
expect(plan(waiting.commits, waiting.runs, { retryVia: "forge", records: new Map([[sha(1), asked(ago(60_000))]]) }).retries).toEqual([]);
|
|
144
|
+
expect(waiting.commits[0].verdict!.verdict).toBe("pending");
|
|
145
|
+
const late = judged([[failed, run("suites", "success")]]);
|
|
146
|
+
plan(late.commits, late.runs, { retryVia: "forge", records: new Map([[sha(1), asked(ago(RETRY_TTL_MS + 1))]]) });
|
|
147
|
+
expect(late.commits[0].verdict!.verdict).toBe("fail");
|
|
148
|
+
|
|
149
|
+
const viaRequest = judged([[failed, run("suites", "success")]]);
|
|
150
|
+
expect(plan(viaRequest.commits, viaRequest.runs, { retryVia: "request" }).requests).toEqual([expect.objectContaining({ commit: sha(1), phases: ["check"], reason: "retry" })]);
|
|
151
|
+
|
|
152
|
+
const tagged = judged([[failed, run("suites", "success")]], ["green"]);
|
|
153
|
+
expect(plan(tagged.commits, tagged.runs, { retryVia: "forge" }).retries).toEqual([]);
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe("records (#4169)", () => {
|
|
158
|
+
test("say green, red, unbuilt or pending with each phase's verdict, reason and covering commit, and skip the time when compared", () => {
|
|
159
|
+
const { commits, runs } = judged([[run("check", "success"), run("suites", "success")], [run("check", "success")]]);
|
|
160
|
+
plan(commits, runs);
|
|
161
|
+
commits[0].made = { tag: `ci/green/${commits[0].sha}`, message: "" };
|
|
162
|
+
const top = recordOf({ green: GREEN, commit: commits[0], retries: [], requests: new Map(), now: NOW });
|
|
163
|
+
expect(top).toMatchObject({ state: "green", commit: commits[0].sha, phases: { check: { verdict: "pass", build: "every" }, suites: { verdict: "pass", build: "newest" } } });
|
|
164
|
+
const below = recordOf({ green: GREEN, commit: commits[1], retries: [], requests: new Map(), now: NOW });
|
|
165
|
+
expect(below).toMatchObject({ state: "unbuilt", phases: { suites: { verdict: "unbuilt", reason: "superseded", coveredBy: commits[0].sha } } });
|
|
166
|
+
expect(sameRecord({ ...below, at: "2020-01-01T00:00:00Z" }, below)).toBe(true);
|
|
167
|
+
expect(sameRecord({ ...below, state: "pending" }, below)).toBe(false);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
test("a pending record that left the window is rewritten unbuilt, aged out", () => {
|
|
171
|
+
const pending: CiRecord = { schema: 1, commit: sha(1), branch: "main", state: "pending", at: ago(1), phases: { suites: { verdict: "pending", build: "newest", runs: [] } } };
|
|
172
|
+
expect(agedOut(pending, NOW)).toMatchObject({ state: "unbuilt", phases: { suites: { verdict: "unbuilt", reason: "aged-out" } } });
|
|
173
|
+
});
|
|
174
|
+
});
|