@intentius/chant 0.124.45 → 0.124.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__golden__/wave-loop/op-by-apply-after-fails.json +10 -0
- package/dist/__golden__/wave-loop/op-by-apply-hold.json +10 -0
- package/dist/__golden__/wave-loop/op-by-apply-ignored.json +10 -0
- package/dist/__golden__/wave-loop/op-by-apply-pass.json +10 -0
- package/dist/__golden__/wave-loop/op-by-apply-skip.json +10 -0
- package/dist/__golden__/wave-loop/op-cost-member-clash.json +6 -0
- package/dist/__golden__/wave-loop/op-cost-member.json +13 -0
- package/dist/__golden__/wave-loop/op-denied-source.json +16 -0
- package/dist/__golden__/wave-loop/op-denied.json +16 -0
- package/dist/__golden__/wave-loop/op-discover-rest-short.json +6 -0
- package/dist/__golden__/wave-loop/op-discover-rest-stops.json +13 -0
- package/dist/__golden__/wave-loop/op-discover-rest.json +26 -0
- package/dist/__golden__/wave-loop/op-discover-wide.json +26 -0
- package/dist/__golden__/wave-loop/op-held-on-again.json +16 -0
- package/dist/__golden__/wave-loop/op-held-on-before-apply.json +16 -0
- package/dist/__golden__/wave-loop/op-held-on.json +16 -0
- package/dist/__golden__/wave-loop/op-hooks-apply-fails.json +13 -0
- package/dist/__golden__/wave-loop/op-hooks-fail-after-apply.json +13 -0
- package/dist/__golden__/wave-loop/op-hooks-fail-before-apply.json +13 -0
- package/dist/__golden__/wave-loop/op-hooks-fail-before-plan.json +13 -0
- package/dist/__golden__/wave-loop/op-hooks-held.json +13 -0
- package/dist/__golden__/wave-loop/op-hooks-hold-before-apply.json +13 -0
- package/dist/__golden__/wave-loop/op-hooks-pass.json +13 -0
- package/dist/__golden__/wave-loop/op-hooks-refused-at-base.json +13 -0
- package/dist/__golden__/wave-loop/op-hooks-share.json +33 -0
- package/dist/__golden__/wave-loop/op-outcome-held.json +10 -0
- package/dist/__golden__/wave-loop/op-outcome-replan-approved.json +10 -0
- package/dist/__golden__/wave-loop/op-outcome-replan-forever.json +10 -0
- package/dist/__golden__/wave-loop/op-outcome-replan.json +10 -0
- package/dist/__golden__/wave-loop/op-outcome-stood-down.json +10 -0
- package/dist/__golden__/wave-loop/op-outcome-unreadable.json +10 -0
- package/dist/__golden__/wave-loop/op-overridden.json +16 -0
- package/dist/__golden__/wave-loop/op-per-run.json +20 -0
- package/dist/__golden__/wave-loop/op-point.json +13 -0
- package/dist/__golden__/wave-loop/op-pr-review.json +10 -0
- package/dist/__golden__/wave-loop/op-sealed.json +10 -0
- package/dist/__golden__/wave-loop/op-spend-change-only.json +10 -0
- package/dist/__golden__/wave-loop/op-spend.json +10 -0
- package/dist/__golden__/wave-loop/op-wave-commands.json +55 -0
- package/dist/__golden__/wave-loop/op-wide-refused.json +26 -0
- package/dist/__golden__/wave-loop/op-wide-waiting.json +29 -0
- package/dist/__golden__/wave-loop/op-wide.json +39 -0
- package/dist/action-pins.d.ts +61 -0
- package/dist/action-pins.d.ts.map +1 -0
- package/dist/action-pins.js +77 -0
- package/dist/capabilities/aws.paths +148 -0
- package/dist/capabilities/base-mappings.json +122 -0
- package/dist/capabilities/catalog.d.ts +89 -0
- package/dist/capabilities/catalog.d.ts.map +1 -0
- package/dist/capabilities/catalog.js +204 -0
- package/dist/capabilities/language.d.ts +103 -0
- package/dist/capabilities/language.d.ts.map +1 -0
- package/dist/capabilities/language.js +335 -0
- package/dist/capabilities/matcher.d.ts +65 -0
- package/dist/capabilities/matcher.d.ts.map +1 -0
- package/dist/capabilities/matcher.js +299 -0
- package/dist/capabilities/view.d.ts +207 -0
- package/dist/capabilities/view.d.ts.map +1 -0
- package/dist/capabilities/view.js +484 -0
- package/dist/cli/commands/carve.d.ts +3 -0
- package/dist/cli/commands/carve.d.ts.map +1 -1
- package/dist/cli/commands/carve.js +36 -7
- package/dist/cli/commands/import-report.d.ts +26 -0
- package/dist/cli/commands/import-report.d.ts.map +1 -0
- package/dist/cli/commands/import-report.js +65 -0
- package/dist/cli/commands/import.d.ts +11 -1
- package/dist/cli/commands/import.d.ts.map +1 -1
- package/dist/cli/commands/import.js +22 -3
- package/dist/cli/commands/lint.d.ts.map +1 -1
- package/dist/cli/commands/lint.js +1 -0
- package/dist/cli/commands/migrate.d.ts +13 -1
- package/dist/cli/commands/migrate.d.ts.map +1 -1
- package/dist/cli/commands/migrate.js +134 -10
- package/dist/cli/handlers/approve.d.ts.map +1 -1
- package/dist/cli/handlers/approve.js +21 -2
- package/dist/cli/handlers/build.d.ts.map +1 -1
- package/dist/cli/handlers/build.js +6 -1
- package/dist/cli/handlers/declared-graph.d.ts +44 -0
- package/dist/cli/handlers/declared-graph.d.ts.map +1 -0
- package/dist/cli/handlers/declared-graph.js +87 -0
- package/dist/cli/handlers/graph.d.ts +25 -0
- package/dist/cli/handlers/graph.d.ts.map +1 -1
- package/dist/cli/handlers/graph.js +93 -87
- package/dist/cli/handlers/ledger.d.ts +3 -0
- package/dist/cli/handlers/ledger.d.ts.map +1 -0
- package/dist/cli/handlers/ledger.js +55 -0
- package/dist/cli/handlers/migrate.d.ts.map +1 -1
- package/dist/cli/handlers/migrate.js +18 -11
- package/dist/cli/handlers/misc.d.ts.map +1 -1
- package/dist/cli/handlers/misc.js +12 -1
- package/dist/cli/handlers/pr-env.d.ts.map +1 -1
- package/dist/cli/handlers/pr-env.js +4 -3
- package/dist/cli/handlers/pr.d.ts +15 -1
- package/dist/cli/handlers/pr.d.ts.map +1 -1
- package/dist/cli/handlers/pr.js +143 -39
- package/dist/cli/handlers/query.d.ts +7 -2
- package/dist/cli/handlers/query.d.ts.map +1 -1
- package/dist/cli/handlers/query.js +16 -4
- package/dist/cli/handlers/release.d.ts.map +1 -1
- package/dist/cli/handlers/release.js +6 -3
- package/dist/cli/handlers/search-count.d.ts +89 -0
- package/dist/cli/handlers/search-count.d.ts.map +1 -0
- package/dist/cli/handlers/search-count.js +132 -0
- package/dist/cli/handlers/search.d.ts +356 -6
- package/dist/cli/handlers/search.d.ts.map +1 -1
- package/dist/cli/handlers/search.js +1039 -155
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +88 -17
- package/dist/cli/mcp/server.d.ts.map +1 -1
- package/dist/cli/mcp/server.js +3 -0
- package/dist/cli/mcp/tools/capabilities.d.ts +7 -0
- package/dist/cli/mcp/tools/capabilities.d.ts.map +1 -0
- package/dist/cli/mcp/tools/capabilities.js +27 -0
- package/dist/cli/mcp/workspace-tools.d.ts +3 -1
- package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
- package/dist/cli/mcp/workspace-tools.js +47 -2
- package/dist/cli/parse-args.d.ts.map +1 -1
- package/dist/cli/parse-args.js +100 -19
- package/dist/cli/registry.d.ts +36 -4
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/components/builders.d.ts +5 -1
- package/dist/components/builders.d.ts.map +1 -1
- package/dist/components/builders.js +5 -0
- package/dist/components/capability-plugin-loader.d.ts.map +1 -1
- package/dist/components/capability-plugin-loader.js +16 -1
- package/dist/components/capability-plugin.d.ts +14 -0
- package/dist/components/capability-plugin.d.ts.map +1 -1
- package/dist/components/pr-env-ports.d.ts +29 -0
- package/dist/components/pr-env-ports.d.ts.map +1 -0
- package/dist/components/pr-env-ports.js +77 -0
- package/dist/components/pr-env-run.d.ts +5 -21
- package/dist/components/pr-env-run.d.ts.map +1 -1
- package/dist/components/pr-env-run.js +6 -70
- package/dist/components/pr-environment.d.ts +2 -1
- package/dist/components/pr-environment.d.ts.map +1 -1
- package/dist/components/pr-environment.js +1 -1
- package/dist/components/pr-hooks.d.ts +21 -1
- package/dist/components/pr-hooks.d.ts.map +1 -1
- package/dist/components/pr-hooks.js +72 -4
- package/dist/components/pr-pipeline.d.ts +45 -10
- package/dist/components/pr-pipeline.d.ts.map +1 -1
- package/dist/components/pr-pipeline.js +47 -14
- package/dist/components/pr-policy.d.ts +36 -0
- package/dist/components/pr-policy.d.ts.map +1 -1
- package/dist/components/pr-policy.js +36 -0
- package/dist/components/starter-plugin.d.ts +1 -0
- package/dist/components/starter-plugin.d.ts.map +1 -1
- package/dist/components/starter-plugin.js +5 -1
- package/dist/components/verbs/index.d.ts +2 -0
- package/dist/components/verbs/index.d.ts.map +1 -1
- package/dist/components/verbs/index.js +2 -0
- package/dist/components/verbs/publish-artifact.d.ts +65 -0
- package/dist/components/verbs/publish-artifact.d.ts.map +1 -0
- package/dist/components/verbs/publish-artifact.js +74 -0
- package/dist/components/verbs/publish-image.d.ts +129 -0
- package/dist/components/verbs/publish-image.d.ts.map +1 -0
- package/dist/components/verbs/publish-image.js +145 -0
- package/dist/config-environments.d.ts +112 -0
- package/dist/config-environments.d.ts.map +1 -0
- package/dist/config-environments.js +114 -0
- package/dist/config.d.ts +32 -84
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +13 -96
- package/dist/gate-decision.d.ts +11 -2
- package/dist/gate-decision.d.ts.map +1 -1
- package/dist/gate-decision.js +15 -3
- package/dist/graph-detail.d.ts.map +1 -1
- package/dist/graph-detail.js +15 -3
- package/dist/graph-effective.d.ts +33 -2
- package/dist/graph-effective.d.ts.map +1 -1
- package/dist/graph-effective.js +215 -68
- package/dist/graph-ir.d.ts +48 -0
- package/dist/graph-ir.d.ts.map +1 -1
- package/dist/graph-ir.js +130 -0
- package/dist/graph-sub-template.d.ts +11 -0
- package/dist/graph-sub-template.d.ts.map +1 -0
- package/dist/graph-sub-template.js +19 -0
- package/dist/graph-walk.d.ts +66 -0
- package/dist/graph-walk.d.ts.map +1 -0
- package/dist/graph-walk.js +70 -0
- package/dist/import/parser.d.ts +19 -0
- package/dist/import/parser.d.ts.map +1 -1
- package/dist/lexicon.d.ts +80 -6
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.d.ts +11 -0
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/git.d.ts +2 -5
- package/dist/lifecycle/git.d.ts.map +1 -1
- package/dist/lifecycle/ledger-read.d.ts +65 -0
- package/dist/lifecycle/ledger-read.d.ts.map +1 -0
- package/dist/lifecycle/ledger-read.js +160 -0
- package/dist/lifecycle/observe.d.ts +28 -0
- package/dist/lifecycle/observe.d.ts.map +1 -1
- package/dist/lifecycle/observe.js +23 -1
- package/dist/lifecycle/release-workstation.d.ts +7 -0
- package/dist/lifecycle/release-workstation.d.ts.map +1 -1
- package/dist/lifecycle/release-workstation.js +25 -0
- package/dist/lifecycle/run-ledger.d.ts +4 -3
- package/dist/lifecycle/run-ledger.d.ts.map +1 -1
- package/dist/lifecycle/run-ledger.js +1 -0
- package/dist/lint/discover.js +3 -1
- package/dist/lint/post-synth.d.ts +127 -1
- package/dist/lint/post-synth.d.ts.map +1 -1
- package/dist/lint/post-synth.js +84 -2
- package/dist/lint/rule.d.ts +6 -0
- package/dist/lint/rule.d.ts.map +1 -1
- package/dist/lint/rules/op/index.d.ts +1 -0
- package/dist/lint/rules/op/index.d.ts.map +1 -1
- package/dist/lint/rules/op/index.js +2 -0
- package/dist/lint/rules/op/ops019-workspace-op-target.d.ts +32 -0
- package/dist/lint/rules/op/ops019-workspace-op-target.d.ts.map +1 -0
- package/dist/lint/rules/op/ops019-workspace-op-target.js +63 -0
- package/dist/live-endpoint.d.ts +1 -1
- package/dist/live-endpoint.d.ts.map +1 -1
- package/dist/live-endpoint.js +1 -1
- package/dist/observation.d.ts +48 -1
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +21 -5
- package/dist/op/activities/activity-contracts.d.ts +9 -6
- package/dist/op/activities/activity-contracts.d.ts.map +1 -1
- package/dist/op/activities/activity-contracts.js +5 -2
- package/dist/op/activities/index.d.ts +2 -2
- package/dist/op/activities/index.d.ts.map +1 -1
- package/dist/op/activities/index.js +1 -1
- package/dist/op/activities/review-agent.d.ts +90 -4
- package/dist/op/activities/review-agent.d.ts.map +1 -1
- package/dist/op/activities/review-agent.js +217 -19
- package/dist/op/activities/work-evidence.d.ts +8 -1
- package/dist/op/activities/work-evidence.d.ts.map +1 -1
- package/dist/op/activities/work-evidence.js +1 -0
- package/dist/op/builders.d.ts +9 -5
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/builders.js +9 -5
- package/dist/op/composites/apply-op.d.ts +29 -2
- package/dist/op/composites/apply-op.d.ts.map +1 -1
- package/dist/op/composites/apply-op.js +20 -1
- package/dist/op/gate-approval.d.ts +11 -5
- package/dist/op/gate-approval.d.ts.map +1 -1
- package/dist/op/gate-approval.js +11 -6
- package/dist/op/gate-quorum.d.ts +100 -3
- package/dist/op/gate-quorum.d.ts.map +1 -1
- package/dist/op/gate-quorum.js +108 -6
- package/dist/op/gate-review.d.ts +9 -0
- package/dist/op/gate-review.d.ts.map +1 -1
- package/dist/op/gate-review.js +13 -0
- package/dist/op/gate.d.ts +44 -3
- package/dist/op/gate.d.ts.map +1 -1
- package/dist/op/gate.js +25 -4
- package/dist/op/index.d.ts +3 -3
- package/dist/op/index.d.ts.map +1 -1
- package/dist/op/index.js +1 -1
- package/dist/op/local-executor.d.ts +38 -3
- package/dist/op/local-executor.d.ts.map +1 -1
- package/dist/op/local-executor.js +48 -6
- package/dist/op/op-waves-run.d.ts +26 -1
- package/dist/op/op-waves-run.d.ts.map +1 -1
- package/dist/op/op-waves-run.js +259 -13
- package/dist/op/op-waves.d.ts +72 -5
- package/dist/op/op-waves.d.ts.map +1 -1
- package/dist/op/op-waves.js +110 -15
- package/dist/op/runtime.d.ts +11 -0
- package/dist/op/runtime.d.ts.map +1 -1
- package/dist/op/schedule-overdue.d.ts +16 -0
- package/dist/op/schedule-overdue.d.ts.map +1 -1
- package/dist/op/schedule-overdue.js +36 -0
- package/dist/op/stage-hooks.d.ts +9 -2
- package/dist/op/stage-hooks.d.ts.map +1 -1
- package/dist/op/stage-hooks.js +7 -5
- package/dist/op/workspace-run-env.d.ts +22 -0
- package/dist/op/workspace-run-env.d.ts.map +1 -0
- package/dist/op/workspace-run-env.js +21 -0
- package/dist/pr-forge.d.ts +24 -0
- package/dist/pr-forge.d.ts.map +1 -1
- package/dist/pr-forge.js +47 -0
- package/dist/pr-post.d.ts +42 -0
- package/dist/pr-post.d.ts.map +1 -1
- package/dist/pr-post.js +67 -1
- package/dist/read-filter.d.ts +65 -0
- package/dist/read-filter.d.ts.map +1 -0
- package/dist/read-filter.js +179 -0
- package/dist/run-event.d.ts +1 -1
- package/dist/run-event.d.ts.map +1 -1
- package/dist/terraform/carve.d.ts +24 -3
- package/dist/terraform/carve.d.ts.map +1 -1
- package/dist/terraform/carve.js +32 -14
- package/dist/terraform/cuts.d.ts +97 -0
- package/dist/terraform/cuts.d.ts.map +1 -0
- package/dist/terraform/cuts.js +138 -0
- package/dist/terraform/folds.d.ts +26 -0
- package/dist/terraform/folds.d.ts.map +1 -0
- package/dist/terraform/folds.js +38 -0
- package/dist/terraform/graph.d.ts.map +1 -1
- package/dist/terraform/graph.js +10 -0
- package/dist/terraform/reach.d.ts +140 -0
- package/dist/terraform/reach.d.ts.map +1 -0
- package/dist/terraform/reach.js +170 -0
- package/dist/terraform/score.d.ts +14 -0
- package/dist/terraform/score.d.ts.map +1 -1
- package/dist/terraform/score.js +14 -31
- package/dist/terraform/state.d.ts.map +1 -1
- package/dist/terraform/state.js +4 -2
- package/dist/terraform/types.d.ts +8 -0
- package/dist/terraform/types.d.ts.map +1 -1
- package/dist/wave-blocked.d.ts +10 -1
- package/dist/wave-blocked.d.ts.map +1 -1
- package/dist/wave-blocked.js +31 -3
- package/dist/wave-runtime.mjs +266 -256
- package/dist/workspace/capabilities-contract.d.ts +66 -0
- package/dist/workspace/capabilities-contract.d.ts.map +1 -0
- package/dist/workspace/capabilities-contract.js +107 -0
- package/dist/workspace/capabilities.schema.json +229 -0
- package/dist/workspace/check.schema.json +11 -2
- package/dist/workspace/checks/ci-branch.d.ts +44 -0
- package/dist/workspace/checks/ci-branch.d.ts.map +1 -0
- package/dist/workspace/checks/ci-branch.js +133 -0
- package/dist/workspace/checks/links.d.ts +3 -0
- package/dist/workspace/checks/links.d.ts.map +1 -1
- package/dist/workspace/checks/links.js +12 -1
- package/dist/workspace/checks/org.d.ts +48 -0
- package/dist/workspace/checks/org.d.ts.map +1 -0
- package/dist/workspace/checks/org.js +156 -0
- package/dist/workspace/checks.d.ts +11 -1
- package/dist/workspace/checks.d.ts.map +1 -1
- package/dist/workspace/checks.js +59 -7
- package/dist/workspace/ci-branches.d.ts +16 -0
- package/dist/workspace/ci-branches.d.ts.map +1 -1
- package/dist/workspace/ci-branches.js +27 -0
- package/dist/workspace/ci-green-cli.js +7 -7
- package/dist/workspace/ci-green-workflow.d.ts +1 -1
- package/dist/workspace/ci-green-workflow.d.ts.map +1 -1
- package/dist/workspace/ci-green-workflow.js +13 -8
- package/dist/workspace/ci-green.d.ts +14 -0
- package/dist/workspace/ci-green.d.ts.map +1 -1
- package/dist/workspace/ci-green.js +44 -11
- package/dist/workspace/ci-run.d.ts +9 -1
- package/dist/workspace/ci-run.d.ts.map +1 -1
- package/dist/workspace/ci-run.js +67 -6
- package/dist/workspace/ci-serve.d.ts +9 -0
- package/dist/workspace/ci-serve.d.ts.map +1 -1
- package/dist/workspace/ci-serve.js +114 -76
- package/dist/workspace/compose-graph.d.ts +23 -0
- package/dist/workspace/compose-graph.d.ts.map +1 -1
- package/dist/workspace/compose-graph.js +3 -1
- package/dist/workspace/composites.d.ts +4 -1
- package/dist/workspace/composites.d.ts.map +1 -1
- package/dist/workspace/composites.js +5 -2
- package/dist/workspace/composites.schema.json +22 -0
- package/dist/workspace/conformance/__writer_fixture__/work/work.schema.json +105 -1
- package/dist/workspace/conformance/index.d.ts +1 -1
- package/dist/workspace/conformance/index.d.ts.map +1 -1
- package/dist/workspace/conformance/index.js +39 -2
- package/dist/workspace/cross-root-lint.d.ts +56 -0
- package/dist/workspace/cross-root-lint.d.ts.map +1 -0
- package/dist/workspace/cross-root-lint.js +111 -0
- package/dist/workspace/dbt-models-reader.d.ts +44 -0
- package/dist/workspace/dbt-models-reader.d.ts.map +1 -0
- package/dist/workspace/dbt-models-reader.js +356 -0
- package/dist/workspace/dbt-project-common.d.ts +40 -0
- package/dist/workspace/dbt-project-common.d.ts.map +1 -0
- package/dist/workspace/dbt-project-common.js +106 -0
- package/dist/workspace/dbt-project-reader.d.ts +4 -3
- package/dist/workspace/dbt-project-reader.d.ts.map +1 -1
- package/dist/workspace/dbt-project-reader.js +14 -108
- package/dist/workspace/decision-rank.d.ts +26 -0
- package/dist/workspace/decision-rank.d.ts.map +1 -0
- package/dist/workspace/decision-rank.js +16 -0
- package/dist/workspace/declaration.d.ts +43 -2
- package/dist/workspace/declaration.d.ts.map +1 -1
- package/dist/workspace/declaration.js +45 -11
- package/dist/workspace/declaration.schema.json +133 -24
- package/dist/workspace/environments.d.ts +26 -2
- package/dist/workspace/environments.d.ts.map +1 -1
- package/dist/workspace/environments.js +26 -2
- package/dist/workspace/flyway-dir.d.ts +39 -0
- package/dist/workspace/flyway-dir.d.ts.map +1 -0
- package/dist/workspace/flyway-dir.js +104 -0
- package/dist/workspace/flyway-layout.d.ts +96 -0
- package/dist/workspace/flyway-layout.d.ts.map +1 -0
- package/dist/workspace/flyway-layout.js +308 -0
- package/dist/workspace/graph-cache.d.ts +8 -0
- package/dist/workspace/graph-cache.d.ts.map +1 -1
- package/dist/workspace/graph-cache.js +27 -3
- package/dist/workspace/graph-cli.d.ts +39 -2
- package/dist/workspace/graph-cli.d.ts.map +1 -1
- package/dist/workspace/graph-cli.js +92 -32
- package/dist/workspace/graph.schema.json +182 -0
- package/dist/workspace/intent.d.ts +2 -3
- package/dist/workspace/intent.d.ts.map +1 -1
- package/dist/workspace/intent.js +5 -9
- package/dist/workspace/kind-link-readers.d.ts +59 -2
- package/dist/workspace/kind-link-readers.d.ts.map +1 -1
- package/dist/workspace/kind-link-readers.js +17 -1
- package/dist/workspace/kind-readers.d.ts +3 -0
- package/dist/workspace/kind-readers.d.ts.map +1 -1
- package/dist/workspace/kind-readers.js +7 -1
- package/dist/workspace/kinds.d.ts +66 -2
- package/dist/workspace/kinds.d.ts.map +1 -1
- package/dist/workspace/kinds.js +98 -4
- package/dist/workspace/ledger.schema.json +158 -0
- package/dist/workspace/lexicon-outputs.d.ts +20 -1
- package/dist/workspace/lexicon-outputs.d.ts.map +1 -1
- package/dist/workspace/lexicon-outputs.js +102 -10
- package/dist/workspace/lineage-check.d.ts +3 -0
- package/dist/workspace/lineage-check.d.ts.map +1 -1
- package/dist/workspace/lineage-check.js +23 -4
- package/dist/workspace/links.d.ts +8 -1
- package/dist/workspace/links.d.ts.map +1 -1
- package/dist/workspace/links.js +25 -1
- package/dist/workspace/ls.d.ts +8 -0
- package/dist/workspace/ls.d.ts.map +1 -1
- package/dist/workspace/ls.js +7 -1
- package/dist/workspace/ls.schema.json +7 -0
- package/dist/workspace/member-commands.d.ts +10 -1
- package/dist/workspace/member-commands.d.ts.map +1 -1
- package/dist/workspace/member-commands.js +71 -6
- package/dist/workspace/migrate-links.d.ts +45 -0
- package/dist/workspace/migrate-links.d.ts.map +1 -0
- package/dist/workspace/migrate-links.js +100 -0
- package/dist/workspace/migration-dirs.d.ts +74 -0
- package/dist/workspace/migration-dirs.d.ts.map +1 -0
- package/dist/workspace/migration-dirs.js +254 -0
- package/dist/workspace/nested-graph.d.ts +2 -0
- package/dist/workspace/nested-graph.d.ts.map +1 -1
- package/dist/workspace/nested-graph.js +32 -1
- package/dist/workspace/reason-codes.d.ts +18 -0
- package/dist/workspace/reason-codes.d.ts.map +1 -1
- package/dist/workspace/reason-codes.js +23 -0
- package/dist/workspace/records-cli.d.ts +11 -0
- package/dist/workspace/records-cli.d.ts.map +1 -1
- package/dist/workspace/records-cli.js +57 -5
- package/dist/workspace/records.schema.json +5 -0
- package/dist/workspace/release-candidates.d.ts +2 -0
- package/dist/workspace/release-candidates.d.ts.map +1 -1
- package/dist/workspace/release-candidates.js +5 -2
- package/dist/workspace/release-train.d.ts +53 -0
- package/dist/workspace/release-train.d.ts.map +1 -0
- package/dist/workspace/release-train.js +134 -0
- package/dist/workspace/release-workflow.d.ts.map +1 -1
- package/dist/workspace/release-workflow.js +4 -3
- package/dist/workspace/repo-ref.d.ts +45 -0
- package/dist/workspace/repo-ref.d.ts.map +1 -0
- package/dist/workspace/repo-ref.js +114 -0
- package/dist/workspace/run-event.schema.json +2 -2
- package/dist/workspace/runs-cli.d.ts +9 -0
- package/dist/workspace/runs-cli.d.ts.map +1 -1
- package/dist/workspace/runs-cli.js +48 -3
- package/dist/workspace/runs.schema.json +7 -0
- package/dist/workspace/search-cli.d.ts +204 -0
- package/dist/workspace/search-cli.d.ts.map +1 -0
- package/dist/workspace/search-cli.js +466 -0
- package/dist/workspace/search-contract.d.ts +56 -0
- package/dist/workspace/search-contract.d.ts.map +1 -0
- package/dist/workspace/search-contract.js +70 -0
- package/dist/workspace/search.schema.json +822 -0
- package/dist/workspace/status-decisions.d.ts +37 -0
- package/dist/workspace/status-decisions.d.ts.map +1 -0
- package/dist/workspace/status-decisions.js +147 -0
- package/dist/workspace/status-gates.d.ts +9 -0
- package/dist/workspace/status-gates.d.ts.map +1 -1
- package/dist/workspace/status.d.ts +4 -0
- package/dist/workspace/status.d.ts.map +1 -1
- package/dist/workspace/status.js +14 -2
- package/dist/workspace/status.schema.json +6 -0
- package/dist/workspace/work-cli.d.ts.map +1 -1
- package/dist/workspace/work-cli.js +5 -3
- package/dist/workspace/work-evidence-ops.d.ts +83 -0
- package/dist/workspace/work-evidence-ops.d.ts.map +1 -0
- package/dist/workspace/work-evidence-ops.js +169 -0
- package/dist/workspace/work-evidence.d.ts +12 -2
- package/dist/workspace/work-evidence.d.ts.map +1 -1
- package/dist/workspace/work-evidence.js +21 -3
- package/dist/workspace/work-evidence.schema.json +49 -2
- package/dist/workspace/workspace-gates.d.ts +110 -0
- package/dist/workspace/workspace-gates.d.ts.map +1 -0
- package/dist/workspace/workspace-gates.js +140 -0
- package/dist/workspace/workspace-kinds.schema.json +58 -3
- package/dist/workspace/workspace-ledger.d.ts +76 -0
- package/dist/workspace/workspace-ledger.d.ts.map +1 -0
- package/dist/workspace/workspace-ledger.js +91 -0
- package/dist/workspace/workspace-run.d.ts +112 -0
- package/dist/workspace/workspace-run.d.ts.map +1 -0
- package/dist/workspace/workspace-run.js +432 -0
- package/package.json +1 -1
- package/src/__golden__/wave-loop/op-by-apply-after-fails.json +10 -0
- package/src/__golden__/wave-loop/op-by-apply-hold.json +10 -0
- package/src/__golden__/wave-loop/op-by-apply-ignored.json +10 -0
- package/src/__golden__/wave-loop/op-by-apply-pass.json +10 -0
- package/src/__golden__/wave-loop/op-by-apply-skip.json +10 -0
- package/src/__golden__/wave-loop/op-cost-member-clash.json +6 -0
- package/src/__golden__/wave-loop/op-cost-member.json +13 -0
- package/src/__golden__/wave-loop/op-denied-source.json +16 -0
- package/src/__golden__/wave-loop/op-denied.json +16 -0
- package/src/__golden__/wave-loop/op-discover-rest-short.json +6 -0
- package/src/__golden__/wave-loop/op-discover-rest-stops.json +13 -0
- package/src/__golden__/wave-loop/op-discover-rest.json +26 -0
- package/src/__golden__/wave-loop/op-discover-wide.json +26 -0
- package/src/__golden__/wave-loop/op-held-on-again.json +16 -0
- package/src/__golden__/wave-loop/op-held-on-before-apply.json +16 -0
- package/src/__golden__/wave-loop/op-held-on.json +16 -0
- package/src/__golden__/wave-loop/op-hooks-apply-fails.json +13 -0
- package/src/__golden__/wave-loop/op-hooks-fail-after-apply.json +13 -0
- package/src/__golden__/wave-loop/op-hooks-fail-before-apply.json +13 -0
- package/src/__golden__/wave-loop/op-hooks-fail-before-plan.json +13 -0
- package/src/__golden__/wave-loop/op-hooks-held.json +13 -0
- package/src/__golden__/wave-loop/op-hooks-hold-before-apply.json +13 -0
- package/src/__golden__/wave-loop/op-hooks-pass.json +13 -0
- package/src/__golden__/wave-loop/op-hooks-refused-at-base.json +13 -0
- package/src/__golden__/wave-loop/op-hooks-share.json +33 -0
- package/src/__golden__/wave-loop/op-outcome-held.json +10 -0
- package/src/__golden__/wave-loop/op-outcome-replan-approved.json +10 -0
- package/src/__golden__/wave-loop/op-outcome-replan-forever.json +10 -0
- package/src/__golden__/wave-loop/op-outcome-replan.json +10 -0
- package/src/__golden__/wave-loop/op-outcome-stood-down.json +10 -0
- package/src/__golden__/wave-loop/op-outcome-unreadable.json +10 -0
- package/src/__golden__/wave-loop/op-overridden.json +16 -0
- package/src/__golden__/wave-loop/op-per-run.json +20 -0
- package/src/__golden__/wave-loop/op-point.json +13 -0
- package/src/__golden__/wave-loop/op-pr-review.json +10 -0
- package/src/__golden__/wave-loop/op-sealed.json +10 -0
- package/src/__golden__/wave-loop/op-spend-change-only.json +10 -0
- package/src/__golden__/wave-loop/op-spend.json +10 -0
- package/src/__golden__/wave-loop/op-wave-commands.json +55 -0
- package/src/__golden__/wave-loop/op-wide-refused.json +26 -0
- package/src/__golden__/wave-loop/op-wide-waiting.json +29 -0
- package/src/__golden__/wave-loop/op-wide.json +39 -0
- package/src/__snapshots__/okf.test.ts.snap +10 -0
- package/src/action-pins.test.ts +78 -0
- package/src/action-pins.ts +92 -0
- package/src/capabilities/aws.paths +148 -0
- package/src/capabilities/base-mappings.json +122 -0
- package/src/capabilities/catalog.ts +230 -0
- package/src/capabilities/language.test.ts +191 -0
- package/src/capabilities/language.ts +373 -0
- package/src/capabilities/matcher.ts +315 -0
- package/src/capabilities/view-compose.test.ts +76 -0
- package/src/capabilities/view.ts +631 -0
- package/src/cli/commands/carve-score-once.test.ts +99 -0
- package/src/cli/commands/carve.ts +37 -6
- package/src/cli/commands/check-lexicon.test.ts +2 -2
- package/src/cli/commands/import-report.ts +71 -0
- package/src/cli/commands/import.ts +33 -3
- package/src/cli/commands/lint.ts +1 -0
- package/src/cli/commands/migrate-dialect.test.ts +145 -0
- package/src/cli/commands/migrate.ts +132 -11
- package/src/cli/handlers/__snapshots__/build-member.test.ts.snap +4 -4
- package/src/cli/handlers/approve.ts +23 -2
- package/src/cli/handlers/build.ts +7 -1
- package/src/cli/handlers/declared-graph.ts +99 -0
- package/src/cli/handlers/graph.test.ts +94 -3
- package/src/cli/handlers/graph.ts +123 -96
- package/src/cli/handlers/ledger.ts +54 -0
- package/src/cli/handlers/migrate.ts +21 -12
- package/src/cli/handlers/misc.ts +10 -1
- package/src/cli/handlers/pr-env.ts +3 -4
- package/src/cli/handlers/pr.ts +138 -36
- package/src/cli/handlers/query.ts +16 -4
- package/src/cli/handlers/release.ts +6 -3
- package/src/cli/handlers/search-build-roots.test.ts +144 -0
- package/src/cli/handlers/search-count.test.ts +191 -0
- package/src/cli/handlers/search-count.ts +165 -0
- package/src/cli/handlers/search-json.test.ts +333 -0
- package/src/cli/handlers/search-live.test.ts +387 -0
- package/src/cli/handlers/search-paths.test.ts +235 -0
- package/src/cli/handlers/search.ts +1291 -166
- package/src/cli/main.test.ts +43 -3
- package/src/cli/main.ts +88 -17
- package/src/cli/mcp/server.test.ts +3 -3
- package/src/cli/mcp/server.ts +3 -0
- package/src/cli/mcp/tools/capabilities.ts +32 -0
- package/src/cli/mcp/workspace-tools.e2e.test.ts +21 -1
- package/src/cli/mcp/workspace-tools.ts +47 -2
- package/src/cli/parse-args.ts +79 -15
- package/src/cli/registry.ts +36 -4
- package/src/components/builders.ts +8 -0
- package/src/components/capability-plugin-loader.ts +13 -1
- package/src/components/capability-plugin.ts +16 -0
- package/src/components/pr-env-ports.ts +89 -0
- package/src/components/pr-env-run-bundle.test.ts +54 -0
- package/src/components/pr-env-run.ts +5 -76
- package/src/components/pr-environment.ts +2 -1
- package/src/components/pr-hooks.test.ts +73 -5
- package/src/components/pr-hooks.ts +95 -5
- package/src/components/pr-pipeline.ts +64 -16
- package/src/components/pr-policy.test.ts +64 -1
- package/src/components/pr-policy.ts +53 -0
- package/src/components/registry.test.ts +1 -1
- package/src/components/starter-plugin.ts +6 -0
- package/src/components/verbs/index.ts +2 -0
- package/src/components/verbs/publish-artifact.test.ts +60 -0
- package/src/components/verbs/publish-artifact.ts +122 -0
- package/src/components/verbs/publish-image.test.ts +101 -0
- package/src/components/verbs/publish-image.ts +265 -0
- package/src/config-environments.ts +160 -0
- package/src/config.ts +44 -124
- package/src/gate-decision-bundle.test.ts +1 -0
- package/src/gate-decision-identity.test.ts +9 -0
- package/src/gate-decision.ts +26 -3
- package/src/graph-detail.ts +15 -3
- package/src/graph-effective.ts +226 -75
- package/src/graph-ir.test.ts +163 -0
- package/src/graph-ir.ts +174 -0
- package/src/graph-sub-template.ts +22 -0
- package/src/graph-walk.test.ts +44 -0
- package/src/graph-walk.ts +102 -0
- package/src/import/parser.ts +20 -0
- package/src/lexicon.ts +84 -6
- package/src/lifecycle/gate-ledger.ts +8 -0
- package/src/lifecycle/git.ts +2 -2
- package/src/lifecycle/ledger-read.test.ts +107 -0
- package/src/lifecycle/ledger-read.ts +195 -0
- package/src/lifecycle/observe.test.ts +27 -1
- package/src/lifecycle/observe.ts +43 -1
- package/src/lifecycle/release-workstation.ts +24 -0
- package/src/lifecycle/run-ledger.ts +5 -2
- package/src/lint/cross-root.test.ts +122 -0
- package/src/lint/discover.ts +3 -1
- package/src/lint/post-synth.ts +212 -2
- package/src/lint/rule.ts +6 -0
- package/src/lint/rules/op/index.ts +2 -0
- package/src/lint/rules/op/ops019-workspace-op-target.ts +89 -0
- package/src/live-endpoint.ts +1 -1
- package/src/observation.test.ts +25 -0
- package/src/observation.ts +69 -5
- package/src/op/activities/activity-contracts.ts +5 -2
- package/src/op/activities/index.ts +2 -2
- package/src/op/activities/review-agent.test.ts +221 -4
- package/src/op/activities/review-agent.ts +265 -22
- package/src/op/activities/work-evidence.ts +9 -1
- package/src/op/builders.ts +9 -5
- package/src/op/composites/apply-op.test.ts +108 -0
- package/src/op/composites/apply-op.ts +37 -2
- package/src/op/gate-approval.test.ts +6 -1
- package/src/op/gate-approval.ts +12 -6
- package/src/op/gate-quorum-at-base.test.ts +211 -0
- package/src/op/gate-quorum.ts +156 -8
- package/src/op/gate-review.ts +14 -0
- package/src/op/gate.ts +67 -8
- package/src/op/index.ts +3 -2
- package/src/op/local-executor.ts +69 -9
- package/src/op/op-waves-depends-on.test.ts +81 -0
- package/src/op/op-waves-hook-targets.test.ts +4 -2
- package/src/op/op-waves-quorum-product.test.ts +158 -0
- package/src/op/op-waves-run.ts +288 -14
- package/src/op/op-waves.ts +143 -14
- package/src/op/runtime.ts +8 -0
- package/src/op/schedule-overdue.ts +33 -0
- package/src/op/stage-hooks.ts +13 -5
- package/src/op/workspace-run-env.ts +29 -0
- package/src/pr-forge-bundle.test.ts +2 -2
- package/src/pr-forge.test.ts +47 -0
- package/src/pr-forge.ts +68 -0
- package/src/pr-post-open.e2e.test.ts +36 -0
- package/src/pr-post.test.ts +102 -3
- package/src/pr-post.ts +89 -1
- package/src/read-filter.test.ts +54 -0
- package/src/read-filter.ts +193 -0
- package/src/run-event.ts +1 -1
- package/src/stage-hooks-bundle.test.ts +1 -0
- package/src/terraform/carve.ts +52 -15
- package/src/terraform/cuts.test.ts +173 -0
- package/src/terraform/cuts.ts +188 -0
- package/src/terraform/folds.ts +44 -0
- package/src/terraform/graph.ts +9 -0
- package/src/terraform/radius.test.ts +90 -0
- package/src/terraform/reach.test.ts +146 -0
- package/src/terraform/reach.ts +247 -0
- package/src/terraform/score.ts +27 -29
- package/src/terraform/state.ts +3 -1
- package/src/terraform/types.ts +8 -0
- package/src/wave-blocked.ts +28 -3
- package/src/wave-loop-golden.test.ts +4 -3
- package/src/workspace/behold-kinds.test.ts +1 -1
- package/src/workspace/capabilities-contract.test.ts +88 -0
- package/src/workspace/capabilities-contract.ts +132 -0
- package/src/workspace/capabilities.schema.json +229 -0
- package/src/workspace/check-contract.test.ts +7 -6
- package/src/workspace/check.schema.json +11 -2
- package/src/workspace/checks/ci-branch.test.ts +128 -0
- package/src/workspace/checks/ci-branch.ts +141 -0
- package/src/workspace/checks/links.ts +12 -1
- package/src/workspace/checks/org.ts +169 -0
- package/src/workspace/checks.ts +64 -7
- package/src/workspace/ci-branches.ts +31 -0
- package/src/workspace/ci-green-branches.test.ts +153 -0
- package/src/workspace/ci-green-cli.ts +7 -7
- package/src/workspace/ci-green-workflow.test.ts +4 -3
- package/src/workspace/ci-green-workflow.ts +13 -9
- package/src/workspace/ci-green.ts +49 -12
- package/src/workspace/ci-run.test.ts +72 -1
- package/src/workspace/ci-run.ts +68 -8
- package/src/workspace/ci-serve.test.ts +95 -0
- package/src/workspace/ci-serve.ts +106 -65
- package/src/workspace/component-environments.test.ts +25 -2
- package/src/workspace/compose-graph.ts +19 -3
- package/src/workspace/composites.schema.json +22 -0
- package/src/workspace/composites.test.ts +39 -8
- package/src/workspace/composites.ts +6 -2
- package/src/workspace/conformance/__writer_fixture__/work/work.schema.json +105 -1
- package/src/workspace/conformance/conformance.e2e.test.ts +14 -1
- package/src/workspace/conformance/index.ts +31 -2
- package/src/workspace/cross-root-lint.test.ts +90 -0
- package/src/workspace/cross-root-lint.ts +126 -0
- package/src/workspace/dbt-kind.test.ts +3 -2
- package/src/workspace/dbt-models-reader.ts +362 -0
- package/src/workspace/dbt-models.test.ts +248 -0
- package/src/workspace/dbt-project-common.ts +113 -0
- package/src/workspace/dbt-project-reader.ts +29 -112
- package/src/workspace/decision-rank.ts +40 -0
- package/src/workspace/declaration.schema.json +133 -24
- package/src/workspace/declaration.ts +84 -15
- package/src/workspace/environments.ts +40 -4
- package/src/workspace/flyway-dir.ts +113 -0
- package/src/workspace/flyway-layout.ts +337 -0
- package/src/workspace/graph-cache.ts +27 -3
- package/src/workspace/graph-cli.ts +119 -32
- package/src/workspace/graph-contract.test.ts +4 -2
- package/src/workspace/graph.schema.json +182 -0
- package/src/workspace/identity.test.ts +14 -2
- package/src/workspace/intent.ts +6 -14
- package/src/workspace/kind-link-readers.ts +68 -3
- package/src/workspace/kind-readers.e2e.test.ts +28 -0
- package/src/workspace/kind-readers.test.ts +1 -1
- package/src/workspace/kind-readers.ts +7 -1
- package/src/workspace/kinds.test.ts +12 -7
- package/src/workspace/kinds.ts +132 -7
- package/src/workspace/ledger.schema.json +158 -0
- package/src/workspace/lexicon-outputs.ts +132 -13
- package/src/workspace/lineage-check.ts +30 -7
- package/src/workspace/links.ts +24 -1
- package/src/workspace/ls-contract.test.ts +1 -1
- package/src/workspace/ls.schema.json +7 -0
- package/src/workspace/ls.ts +10 -1
- package/src/workspace/member-commands.ts +82 -3
- package/src/workspace/member-file-schema.test.ts +124 -0
- package/src/workspace/migrate-links.test.ts +99 -0
- package/src/workspace/migrate-links.ts +108 -0
- package/src/workspace/migration-dirs.test.ts +272 -0
- package/src/workspace/migration-dirs.ts +267 -0
- package/src/workspace/nested-graph.ts +32 -1
- package/src/workspace/org-scope.test.ts +238 -0
- package/src/workspace/reason-codes.test.ts +13 -1
- package/src/workspace/reason-codes.ts +23 -0
- package/src/workspace/records-cli.ts +58 -5
- package/src/workspace/records.schema.json +5 -0
- package/src/workspace/release-candidates.ts +7 -2
- package/src/workspace/release-train.ts +157 -0
- package/src/workspace/release-workflow.ts +4 -3
- package/src/workspace/repo-ref.ts +113 -0
- package/src/workspace/run-event.schema.json +2 -2
- package/src/workspace/runs-cli.ts +48 -4
- package/src/workspace/runs.schema.json +7 -0
- package/src/workspace/search-cli.e2e.test.ts +305 -0
- package/src/workspace/search-cli.ts +591 -0
- package/src/workspace/search-contract.ts +95 -0
- package/src/workspace/search.schema.json +822 -0
- package/src/workspace/status-contract.test.ts +46 -1
- package/src/workspace/status-decisions.test.ts +100 -0
- package/src/workspace/status-decisions.ts +151 -0
- package/src/workspace/status-gates.ts +9 -0
- package/src/workspace/status.schema.json +6 -0
- package/src/workspace/status.ts +17 -3
- package/src/workspace/where-filters.test.ts +39 -0
- package/src/workspace/work-cli.ts +5 -3
- package/src/workspace/work-evidence-ops.test.ts +176 -0
- package/src/workspace/work-evidence-ops.ts +189 -0
- package/src/workspace/work-evidence.schema.json +49 -2
- package/src/workspace/work-evidence.ts +22 -3
- package/src/workspace/workspace-gates.ts +200 -0
- package/src/workspace/workspace-kinds.schema.json +58 -3
- package/src/workspace/workspace-ledger.ts +130 -0
- package/src/workspace/workspace-run.test.ts +322 -0
- package/src/workspace/workspace-run.ts +461 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #4325: `ci.green` names several branches when `ci.branches` routes members
|
|
3
|
+
* to branches of their own. Each is judged as the single branch always was, a
|
|
4
|
+
* one-branch declaration reads as before, and `release cut` takes a commit of
|
|
5
|
+
* any of them.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { afterAll, describe, expect, test } from "vitest";
|
|
9
|
+
import { greenBranches, parseDeclaration } from "./declaration";
|
|
10
|
+
import { cleanScratch, declaration, git, scratchDir, writeFiles } from "./__fixtures__/contract-repo";
|
|
11
|
+
import { ciList, ciTick, formatTick, greenOn, lastGreen } from "./ci-green";
|
|
12
|
+
import type { CheckRun, CiForge } from "./ci-green-forge";
|
|
13
|
+
import { buildTriggerEdits, renderCiGreenWorkflow } from "./ci-green-workflow";
|
|
14
|
+
import { checkOnGreenBranches, checkOnTrunk, resolveTrunk, WorkstationCheckError } from "../lifecycle/release-workstation";
|
|
15
|
+
|
|
16
|
+
afterAll(cleanScratch);
|
|
17
|
+
|
|
18
|
+
const PHASES = { test: ["test"] };
|
|
19
|
+
const decl = (green: unknown) => JSON.stringify({ name: "w", schema: 1, members: [{ name: "app", dir: "app", kind: "other", because: "x" }], ci: { green } });
|
|
20
|
+
const parse = (branch: unknown) => parseDeclaration(decl({ branch, phases: PHASES, require: ["test"] }), "chant.workspace.json").ci!.green!;
|
|
21
|
+
|
|
22
|
+
describe("ci.green.branch as one branch or several (#4325)", () => {
|
|
23
|
+
test("a string reads exactly as it did: no branches field", () => {
|
|
24
|
+
const g = parse("main");
|
|
25
|
+
expect(g.branch).toBe("main");
|
|
26
|
+
expect("branches" in g).toBe(false);
|
|
27
|
+
expect(greenBranches(g)).toEqual(["main"]);
|
|
28
|
+
// A list of one is the same declaration.
|
|
29
|
+
expect(parse(["main"])).toEqual(g);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test("a list judges each branch, and the first is the trunk readers use", () => {
|
|
33
|
+
const g = parse(["main", "release"]);
|
|
34
|
+
expect(g.branch).toBe("main");
|
|
35
|
+
expect(g.branches).toEqual(["main", "release"]);
|
|
36
|
+
expect(greenBranches(g)).toEqual(["main", "release"]);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test("an empty list, a repeated branch and a malformed name are refused", () => {
|
|
40
|
+
for (const bad of [[], ["main", "main"], ["main", "has space"], [3]]) {
|
|
41
|
+
expect(() => parse(bad), JSON.stringify(bad)).toThrow();
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("greenOn picks a branch ci.green names and refuses one it doesn't", () => {
|
|
46
|
+
const g = parse(["main", "release"]);
|
|
47
|
+
expect(greenOn(g, undefined).branch).toBe("main");
|
|
48
|
+
expect(greenOn(g, "release").branch).toBe("release");
|
|
49
|
+
expect("branches" in greenOn(g, "release")).toBe(false);
|
|
50
|
+
expect(() => greenOn(g, "staging")).toThrow(/judges main, release, not staging/);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// ── The tick, against a real remote ──────────────────────────────────────────
|
|
55
|
+
|
|
56
|
+
const NOW = new Date();
|
|
57
|
+
const run = (id: number, name: string, conclusion: string): CheckRun => ({ id, name, status: "completed", conclusion, completedAt: null, url: `https://example.com/runs/${id}` });
|
|
58
|
+
|
|
59
|
+
function commit(root: string, file: string): string {
|
|
60
|
+
writeFiles(root, { [file]: `${file}\n` });
|
|
61
|
+
git(root, "add", "-A");
|
|
62
|
+
git(root, "commit", "-q", "-m", file);
|
|
63
|
+
return git(root, "rev-parse", "HEAD");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** A checkout with `main` and `release` pushed to a bare origin, one commit each past a shared base. */
|
|
67
|
+
function twoBranches(green: unknown): { root: string; origin: string; main: string; release: string } {
|
|
68
|
+
const origin = scratchDir("chant-ci-branches-origin-");
|
|
69
|
+
git(origin, "init", "-q", "--bare");
|
|
70
|
+
const root = scratchDir("chant-ci-branches-work-");
|
|
71
|
+
git(root, "init", "-q");
|
|
72
|
+
git(root, "symbolic-ref", "HEAD", "refs/heads/main");
|
|
73
|
+
writeFiles(root, { "chant.workspace.json": declaration([{ name: "app", dir: "app", kind: "other", because: "the app" }], { ci: { green } }) });
|
|
74
|
+
git(root, "remote", "add", "origin", origin);
|
|
75
|
+
commit(root, "app/base.txt");
|
|
76
|
+
git(root, "checkout", "-q", "-b", "release");
|
|
77
|
+
const release = commit(root, "app/release.txt");
|
|
78
|
+
git(root, "checkout", "-q", "main");
|
|
79
|
+
const main = commit(root, "app/main.txt");
|
|
80
|
+
git(root, "push", "-q", "origin", "main", "release");
|
|
81
|
+
return { root, origin, main, release };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const remoteTags = (origin: string) => git(origin, "for-each-ref", "--format=%(refname:lstrip=2)", "refs/tags/").split("\n").filter(Boolean).sort();
|
|
85
|
+
const forge = (shas: string[]): CiForge => ({ kind: "github", checkRuns: async (sha) => (shas.includes(sha) ? [run(1, "test", "success")] : []) });
|
|
86
|
+
|
|
87
|
+
describe("the tick judges each branch ci.green names (#4325)", () => {
|
|
88
|
+
test("a commit of a routed branch gets a green tag, and last-green reads each branch", async () => {
|
|
89
|
+
const { root, origin, main, release } = twoBranches({ branch: ["main", "release"], phases: PHASES, require: ["test"] });
|
|
90
|
+
const result = await ciTick({ cwd: root, forge: forge([main, release]), now: NOW });
|
|
91
|
+
expect(result.branch).toBe("main");
|
|
92
|
+
expect(result.routed?.map((r) => r.branch)).toEqual(["release"]);
|
|
93
|
+
expect(result.made.sort()).toEqual([`ci/green/${main}`, `ci/green/${release}`].sort());
|
|
94
|
+
expect(remoteTags(origin)).toEqual([`ci/green/${main}`, `ci/green/${release}`].sort());
|
|
95
|
+
// The tag says which branch it judged.
|
|
96
|
+
const note = git(origin, "tag", "-l", "--format=%(contents)", `ci/green/${release}`);
|
|
97
|
+
expect(JSON.parse(note.slice(note.indexOf("{")))).toMatchObject({ tag: "green", commit: release, branch: "release" });
|
|
98
|
+
|
|
99
|
+
expect((lastGreen({ cwd: root }) as { commit: { sha: string } }).commit.sha).toBe(main);
|
|
100
|
+
const onRelease = lastGreen({ cwd: root, branch: "release" }) as { branch: string; commit: { sha: string } };
|
|
101
|
+
expect([onRelease.branch, onRelease.commit.sha]).toEqual(["release", release]);
|
|
102
|
+
expect(lastGreen({ cwd: root, branch: "staging" })).toMatchObject({ error: { code: "ci-branch-unknown" } });
|
|
103
|
+
|
|
104
|
+
const listed = await ciList({ cwd: root, branch: "release", now: NOW });
|
|
105
|
+
expect("commits" in listed && listed.commits.filter((c) => c.state === "green").map((c) => c.sha)).toEqual([release]);
|
|
106
|
+
|
|
107
|
+
const text = formatTick(result);
|
|
108
|
+
expect(text).toContain("main, commits within 24h");
|
|
109
|
+
expect(text).toContain("release, commits within 24h");
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test("a one-branch declaration ticks one branch, with no routed results", async () => {
|
|
113
|
+
const { root, main, release } = twoBranches({ branch: "main", phases: PHASES, require: ["test"] });
|
|
114
|
+
const result = await ciTick({ cwd: root, forge: forge([main, release]), now: NOW });
|
|
115
|
+
expect(result.routed).toBeUndefined();
|
|
116
|
+
expect(result.made).toEqual([`ci/green/${main}`]);
|
|
117
|
+
expect(lastGreen({ cwd: root, branch: "release" })).toMatchObject({ error: { code: "ci-branch-unknown" } });
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
describe("the generated tick workflow follows the branches (#4325)", () => {
|
|
122
|
+
const green = (branch: string | string[]) => parse(branch);
|
|
123
|
+
|
|
124
|
+
test("workflow_run lists every branch, and one branch renders as before", () => {
|
|
125
|
+
const render = (g: ReturnType<typeof green>) => renderCiGreenWorkflow({ green: g, workflows: ["ci"], chantVersion: "0.0.0", workspaceRoot: ".", install: undefined, chant: undefined, npmLock: undefined, push: undefined });
|
|
126
|
+
const many = render(green(["main", "release"]));
|
|
127
|
+
expect(many).toMatch(/branches:\n\s+- "?main"?\n\s+- "?release"?\n/);
|
|
128
|
+
// The checkout stays on the first branch, which holds the declaration the tick reads.
|
|
129
|
+
expect(many).toMatch(/ref: "?main"?/);
|
|
130
|
+
expect(render(green("main"))).not.toContain("release");
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test("a push-triggered build lists every branch", () => {
|
|
134
|
+
const sources = [{ path: ".github/workflows/ci.yml", text: "name: ci\non:\n push:\n branches: [main]\njobs:\n test:\n runs-on: ubuntu-latest\n steps: []\n" }];
|
|
135
|
+
const g = parseDeclaration(decl({ branch: ["main", "release"], phases: { test: { runs: ["test"], build: "newest" } }, require: ["test"] }), "chant.workspace.json").ci!.green!;
|
|
136
|
+
const [edit] = buildTriggerEdits(g, sources as never, { compose: false });
|
|
137
|
+
expect(edit!.text).toMatch(/branches:\n\s+- main\n\s+- release/);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
describe("release cut takes a commit of any branch ci.green names (#4325)", () => {
|
|
142
|
+
test("a routed branch's commit is on trunk for the cut, and an unrelated one is not", () => {
|
|
143
|
+
const { root, main, release } = twoBranches({ branch: ["main", "release"], phases: PHASES, require: ["test"] });
|
|
144
|
+
git(root, "fetch", "-q", "origin");
|
|
145
|
+
const trunk = resolveTrunk(root, "main");
|
|
146
|
+
expect(() => checkOnTrunk(root, main, trunk)).not.toThrow();
|
|
147
|
+
expect(() => checkOnTrunk(root, release, trunk)).toThrow(WorkstationCheckError);
|
|
148
|
+
expect(checkOnGreenBranches(root, main, trunk, ["release"]).branch).toBe("main");
|
|
149
|
+
expect(checkOnGreenBranches(root, release, trunk, ["release"]).branch).toBe("release");
|
|
150
|
+
// Without the routed branch listed, the first branch's refusal stands.
|
|
151
|
+
expect(() => checkOnGreenBranches(root, release, trunk, [])).toThrow(WorkstationCheckError);
|
|
152
|
+
});
|
|
153
|
+
});
|
|
@@ -32,12 +32,12 @@ import { findWorkspaceRoot } from "../project-root";
|
|
|
32
32
|
import { ciList, ciTick, CiGreenError, formatList, formatTick, lastGreen, RUNNER_KEY_ENV } from "./ci-green";
|
|
33
33
|
import { ciForgeFromEnv } from "./ci-green-forge";
|
|
34
34
|
import { ACTIONS_NAME, buildTriggerEdits, CI_GREEN_WORKFLOW_FILE, ciGreenHeader, type PushToken, readWorkflowSources, renderCiGreenWorkflow, workflowsHolding, writeWorkflowFile } from "./ci-green-workflow";
|
|
35
|
-
import { readDeclaration, readerVersion, WorkspaceReadError, type CiSource } from "./declaration";
|
|
35
|
+
import { greenBranches, readDeclaration, readerVersion, WorkspaceReadError, type CiSource } from "./declaration";
|
|
36
36
|
import { recordGeneratedFiles, resolveMemberContext, shellArg } from "./member-pipeline";
|
|
37
37
|
import { gitTop, workingTree } from "./tree";
|
|
38
38
|
|
|
39
39
|
const USAGE =
|
|
40
|
-
"chant ci last-green [--json] [--from <rev>] | ci list [--json] [--limit <n>] [--since <rev>] [--forge github] [--source checks|runs] | ci tick [--dry-run] [--forge github] [--source checks|runs] [--key <runner key.pem>] | " +
|
|
40
|
+
"chant ci last-green [--json] [--from <rev>] [--branch <branch>] | ci list [--json] [--branch <branch>] [--limit <n>] [--since <rev>] [--forge github] [--source checks|runs] | ci tick [--dry-run] [--forge github] [--source checks|runs] [--key <runner key.pem>] | " +
|
|
41
41
|
"ci workflow [--workflow <name>]... [--output <file>] [--chant <command>] [--install <command>] [--token-secret <NAME> | --app-id-var <VAR> --app-key-secret <NAME>] [--runner-key-secret <NAME>]";
|
|
42
42
|
|
|
43
43
|
export { RUNNER_KEY_ENV };
|
|
@@ -56,7 +56,7 @@ function warnIgnored(ignored: readonly { tag: string; status: string; reason: st
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
export async function runCiLastGreen(ctx: CommandContext): Promise<number> {
|
|
59
|
-
const doc = lastGreen({ cwd: process.cwd(), ...(ctx.args.migrateFrom !== undefined ? { from: ctx.args.migrateFrom } : {}) });
|
|
59
|
+
const doc = lastGreen({ cwd: process.cwd(), ...(ctx.args.branch !== undefined ? { branch: ctx.args.branch } : {}), ...(ctx.args.migrateFrom !== undefined ? { from: ctx.args.migrateFrom } : {}) });
|
|
60
60
|
if (ctx.args.json) {
|
|
61
61
|
console.log(JSON.stringify(doc, null, 2));
|
|
62
62
|
return "error" in doc ? 1 : 0;
|
|
@@ -81,7 +81,7 @@ export async function runCiList(ctx: CommandContext): Promise<number> {
|
|
|
81
81
|
// Only an explicit --forge reaches the network; without it the list reads local refs and tags.
|
|
82
82
|
const forge = ctx.args.forge !== undefined ? ciForgeFromEnv(ctx.args.forge) : undefined;
|
|
83
83
|
const source = sourceOf(ctx.args);
|
|
84
|
-
const doc = await ciList({ cwd: process.cwd(), limit, since: ctx.args.since, forge, ...(source ? { source } : {}) });
|
|
84
|
+
const doc = await ciList({ cwd: process.cwd(), ...(ctx.args.branch !== undefined ? { branch: ctx.args.branch } : {}), limit, since: ctx.args.since, forge, ...(source ? { source } : {}) });
|
|
85
85
|
if (ctx.args.json) {
|
|
86
86
|
console.log(JSON.stringify(doc, null, 2));
|
|
87
87
|
return "error" in doc ? 1 : 0;
|
|
@@ -185,14 +185,14 @@ export async function runCiWorkflow(ctx: CommandContext): Promise<number> {
|
|
|
185
185
|
const yaml = renderCiGreenWorkflow({ green, workflows, chantVersion: readerVersion(), workspaceRoot, chant: ctx.args.ciChant, install: ctx.args.ciInstall, npmLock, push, ...(runnerKeySecret ? { runnerKeySecret } : {}), ...(compose ? { compose } : {}) });
|
|
186
186
|
const written = writeWorkflowFile(target, ciGreenHeader(command, member ? "member" : "root") + yaml);
|
|
187
187
|
if (member) recordGeneratedFiles(member.memberRoot, [{ path: fromRepo, command }]);
|
|
188
|
-
console.log(`Wrote ${written}: ticks when ${workflows.join(", ")} complete${workflows.length === 1 ? "s" : ""} on ${green.
|
|
188
|
+
console.log(`Wrote ${written}: ticks when ${workflows.join(", ")} complete${workflows.length === 1 ? "s" : ""} on ${greenBranches(green).join(", ")}${compose ? " or a chant/compose/ branch" : ""}, and every 15 minutes.`);
|
|
189
189
|
for (const e of edits) {
|
|
190
190
|
if (!e.changed) continue;
|
|
191
191
|
const path = writeWorkflowFile(join(repoRoot, e.path), e.text);
|
|
192
192
|
console.log(
|
|
193
193
|
e.build === "newest"
|
|
194
|
-
? `Wrote ${path}'s triggers and concurrency: ${e.phases.join(", ")} build${e.phases.length === 1 ? "s" : ""} the newest commit on ${green.
|
|
195
|
-
: `Wrote ${path}'s triggers and concurrency: ${e.phases.join(", ")} build${e.phases.length === 1 ? "s" : ""} every commit on ${green.
|
|
194
|
+
? `Wrote ${path}'s triggers and concurrency: ${e.phases.join(", ")} build${e.phases.length === 1 ? "s" : ""} the newest commit on ${greenBranches(green).join(", ")} when a run ends, and a ci/build/<sha> tag by hand.`
|
|
195
|
+
: `Wrote ${path}'s triggers and concurrency: ${e.phases.join(", ")} build${e.phases.length === 1 ? "s" : ""} every commit on ${greenBranches(green).join(", ")}, none cancelled, and a ci/build/<sha> tag by hand when the forge ran nothing.`,
|
|
196
196
|
);
|
|
197
197
|
}
|
|
198
198
|
return 0;
|
|
@@ -14,6 +14,7 @@ import { runCiWorkflow } from "./ci-green-cli";
|
|
|
14
14
|
import { BUILD_BLOCK_MARKER, buildTriggerEdits, CI_GREEN_WORKFLOW_FILE, dispatchableWorkflows, jobCheckRuns, renderCiGreenWorkflow, workflowsHolding, writeTopLevel } from "./ci-green-workflow";
|
|
15
15
|
import { parseDeclaration } from "./declaration";
|
|
16
16
|
import { cleanScratch, declaration, git, scratchDir, writeFiles } from "./__fixtures__/contract-repo";
|
|
17
|
+
import { ACTION_PINS, usesRef } from "../action-pins";
|
|
17
18
|
|
|
18
19
|
afterAll(cleanScratch);
|
|
19
20
|
|
|
@@ -82,7 +83,7 @@ describe("the workflows that hold required check runs (#3573)", () => {
|
|
|
82
83
|
expect(doc.concurrency).toEqual({ group: "chant-ci-green", "cancel-in-progress": false });
|
|
83
84
|
expect(doc.permissions).toEqual({ contents: "write", checks: "read" });
|
|
84
85
|
const steps = doc.jobs.tick.steps;
|
|
85
|
-
expect(steps[0]).toEqual({ uses:
|
|
86
|
+
expect(steps[0]).toEqual({ uses: usesRef(ACTION_PINS.checkout6), with: { ref: "main", "fetch-depth": 0 } });
|
|
86
87
|
expect(steps[2].run).toBe("npx --yes @intentius/chant@0.108.0 ci tick");
|
|
87
88
|
expect(steps[2]["working-directory"]).toBeUndefined();
|
|
88
89
|
expect(steps[2].env.GITHUB_TOKEN).toBe("${{ github.token }}");
|
|
@@ -128,7 +129,7 @@ describe("the token the tick pushes its tags with (#3573)", () => {
|
|
|
128
129
|
const plain = renderCiGreenWorkflow(base);
|
|
129
130
|
const text = renderCiGreenWorkflow({ ...base, push: { secret: "CI_GREEN_TOKEN" } });
|
|
130
131
|
const steps = (parseYAMLDocument(text) as Yaml).jobs.tick.steps;
|
|
131
|
-
expect(steps[0]).toEqual({ uses:
|
|
132
|
+
expect(steps[0]).toEqual({ uses: usesRef(ACTION_PINS.checkout6), with: { ref: "main", "fetch-depth": 0, token: "${{ secrets.CI_GREEN_TOKEN || github.token }}" } });
|
|
132
133
|
// Check runs are still read with the Actions token: a fine-grained token can't call the Checks API.
|
|
133
134
|
expect(steps[2].env.GITHUB_TOKEN).toBe("${{ github.token }}");
|
|
134
135
|
expect((parseYAMLDocument(text) as Yaml).permissions).toEqual({ contents: "write", checks: "read" });
|
|
@@ -147,7 +148,7 @@ describe("the token the tick pushes its tags with (#3573)", () => {
|
|
|
147
148
|
const steps = (parseYAMLDocument(renderCiGreenWorkflow({ ...base, push: { appIdVar: "CI_GREEN_APP_ID", appKeySecret: "CI_GREEN_APP_KEY" } })) as Yaml).jobs.tick.steps;
|
|
148
149
|
expect(steps[0]).toMatchObject({
|
|
149
150
|
id: "app-token",
|
|
150
|
-
uses:
|
|
151
|
+
uses: usesRef(ACTION_PINS.createGithubAppToken2),
|
|
151
152
|
with: { "app-id": "${{ vars.CI_GREEN_APP_ID }}", "private-key": "${{ secrets.CI_GREEN_APP_KEY }}" },
|
|
152
153
|
});
|
|
153
154
|
expect(steps[1].with.token).toBe("${{ steps.app-token.outputs.token }}");
|
|
@@ -48,8 +48,9 @@
|
|
|
48
48
|
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
49
49
|
import { dirname, join, relative, resolve, sep } from "node:path";
|
|
50
50
|
import { GENERATED_MARKER } from "../discovery/files";
|
|
51
|
+
import { ACTION_PINS, tagComments, usesRef } from "../action-pins";
|
|
51
52
|
import { emitYAMLEntry, parseYAMLDocument } from "../yaml";
|
|
52
|
-
import type
|
|
53
|
+
import { greenBranches, type CiBuild, type CiGreen } from "./declaration";
|
|
53
54
|
import { matchesCheckRun } from "./ci-green";
|
|
54
55
|
import { githubSecretOrJobToken } from "../ci-jobs";
|
|
55
56
|
import { COMPOSE_BRANCH_PREFIX } from "../lifecycle/compose-refs";
|
|
@@ -228,7 +229,7 @@ export function renderCiGreenWorkflow(input: WorkflowInput): string {
|
|
|
228
229
|
? [
|
|
229
230
|
" - name: Mint a GitHub App token that may push tags to commits that change workflows",
|
|
230
231
|
" id: app-token",
|
|
231
|
-
|
|
232
|
+
` uses: ${usesRef(ACTION_PINS.createGithubAppToken2)}`,
|
|
232
233
|
" with:",
|
|
233
234
|
` app-id: \${{ vars.${push.appIdVar} }}`,
|
|
234
235
|
` private-key: \${{ secrets.${push.appKeySecret} }}`,
|
|
@@ -247,7 +248,7 @@ export function renderCiGreenWorkflow(input: WorkflowInput): string {
|
|
|
247
248
|
" types:",
|
|
248
249
|
" - completed",
|
|
249
250
|
" branches:",
|
|
250
|
-
` - ${q(
|
|
251
|
+
...greenBranches(green).map((b) => ` - ${q(b)}`),
|
|
251
252
|
// #4169: a build the tick asked for runs at a ci/build/<sha> tag, and its completion ticks too.
|
|
252
253
|
...(newestPhases(green) ? [` - ${q("ci/build/**")}`] : []),
|
|
253
254
|
// #4220: a composed commit's phases run on its chant/compose/<name> branch, and their completion ticks too.
|
|
@@ -273,12 +274,12 @@ export function renderCiGreenWorkflow(input: WorkflowInput): string {
|
|
|
273
274
|
" timeout-minutes: 15",
|
|
274
275
|
" steps:",
|
|
275
276
|
...mint,
|
|
276
|
-
|
|
277
|
+
` - uses: ${usesRef(ACTION_PINS.checkout6)}`,
|
|
277
278
|
" with:",
|
|
278
279
|
` ref: ${q(green.branch)}`,
|
|
279
280
|
" fetch-depth: 0",
|
|
280
281
|
...token,
|
|
281
|
-
|
|
282
|
+
` - uses: ${usesRef(ACTION_PINS.setupNode6)}`,
|
|
282
283
|
" with:",
|
|
283
284
|
" node-version: \"24\"",
|
|
284
285
|
...cache,
|
|
@@ -292,7 +293,7 @@ export function renderCiGreenWorkflow(input: WorkflowInput): string {
|
|
|
292
293
|
...(input.runnerKeySecret ? [` CHANT_RUNNER_KEY: \${{ secrets.${input.runnerKeySecret} }}`] : []),
|
|
293
294
|
` run: ${tick}`,
|
|
294
295
|
];
|
|
295
|
-
return lines.join("\n") + "\n";
|
|
296
|
+
return tagComments(lines.join("\n") + "\n");
|
|
296
297
|
}
|
|
297
298
|
|
|
298
299
|
/** Whether any phase sets `build` (#4169): then the tick may re-run jobs and start workflows. */
|
|
@@ -370,7 +371,7 @@ export function buildTriggerEdits(green: CiGreen, sources: readonly WorkflowSour
|
|
|
370
371
|
delete on.schedule;
|
|
371
372
|
const push = isObject(on.push) ? { ...on.push } : {};
|
|
372
373
|
const branches = Array.isArray(push.branches) ? push.branches.filter((b): b is string => typeof b === "string") : [];
|
|
373
|
-
const withBranch = branches
|
|
374
|
+
const withBranch = [...branches, ...greenBranches(green).filter((b) => !branches.includes(b))];
|
|
374
375
|
push.branches = compose && !withBranch.includes(COMPOSE_BRANCHES) ? [...withBranch, COMPOSE_BRANCHES] : withBranch;
|
|
375
376
|
const { push: _push, workflow_dispatch: dispatch, ...rest } = on;
|
|
376
377
|
text = writeTopLevel(text, "on", { push, workflow_dispatch: dispatch ?? {}, ...rest });
|
|
@@ -388,8 +389,11 @@ export function buildTriggerEdits(green: CiGreen, sources: readonly WorkflowSour
|
|
|
388
389
|
if (!("workflow_dispatch" in next)) next = { ...next, workflow_dispatch: {} };
|
|
389
390
|
if (next !== on) text = writeTopLevel(text, "on", next);
|
|
390
391
|
// #4220: a compose branch's commits each get a verdict, so its runs are keyed by commit, as the trunk branch's are.
|
|
391
|
-
|
|
392
|
-
const
|
|
392
|
+
// #4325: each branch ci.green judges is keyed by commit.
|
|
393
|
+
const heads = greenBranches(green).map((b) => `github.ref == 'refs/heads/${b}'`);
|
|
394
|
+
const several = heads.length > 1;
|
|
395
|
+
const keyed = compose ? `(${[...heads, `startsWith(github.ref, 'refs/heads/${COMPOSE_BRANCH_PREFIX}')`].join(" || ")})` : several ? `(${heads.join(" || ")})` : `github.ref == '${main}'`;
|
|
396
|
+
const unkeyed = compose || several ? `!${keyed}` : `github.ref != '${main}'`;
|
|
393
397
|
// Written as lines: the emitter would quote the expression, and GitHub reads it the same either way.
|
|
394
398
|
text = writeTopLevel(text, "concurrency", [
|
|
395
399
|
"concurrency:",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
|
|
56
56
|
import { judgeCommits, mergeCommits, readWorkIndex, type CommitLink } from "./commit-links";
|
|
57
57
|
import { execFileSync } from "node:child_process";
|
|
58
|
-
import { readDeclaration, readerVersion, WORKSPACE_ERROR_CODES, WorkspaceReadError, type CiGreen, type CiPhase, type CiSource } from "./declaration";
|
|
58
|
+
import { greenBranches, readDeclaration, readerVersion, WORKSPACE_ERROR_CODES, WorkspaceReadError, type CiGreen, type CiPhase, type CiSource } from "./declaration";
|
|
59
59
|
import type { CheckRun, CiForge, OpRunRef } from "./ci-green-forge";
|
|
60
60
|
import type { OpRunRecord } from "../op/runtime";
|
|
61
61
|
import { readRunLedger } from "../lifecycle/run-ledger";
|
|
@@ -514,8 +514,25 @@ export function readGreen(cwd: string): { green: CiGreen; top: string; workspace
|
|
|
514
514
|
return { green, top, workspace: { name: declaration.name, root: located.root, file: declaration.file } };
|
|
515
515
|
}
|
|
516
516
|
|
|
517
|
+
/**
|
|
518
|
+
* `green` judging `branch` (#4325): `ci.green` names several branches when
|
|
519
|
+
* `ci.branches` routes members to branches of their own, and each is judged
|
|
520
|
+
* as the single branch always was. Without `branch` the first is judged.
|
|
521
|
+
* Refuses a branch `ci.green` does not name.
|
|
522
|
+
*/
|
|
523
|
+
export function greenOn(green: CiGreen, branch: string | undefined): CiGreen {
|
|
524
|
+
const { branches: _all, ...rest } = green;
|
|
525
|
+
if (branch === undefined || branch === green.branch) return rest;
|
|
526
|
+
if (!greenBranches(green).includes(branch)) {
|
|
527
|
+
throw new CiGreenError("ci-branch-unknown", `ci.green judges ${greenBranches(green).join(", ")}, not ${branch}; add it to ci.green.branch to give it a green verdict`);
|
|
528
|
+
}
|
|
529
|
+
return { ...rest, branch };
|
|
530
|
+
}
|
|
531
|
+
|
|
517
532
|
export interface TickRequest {
|
|
518
533
|
cwd: string;
|
|
534
|
+
/** Judge this one branch of `ci.green.branch` (#4325). Without it a tick judges every branch the declaration names. */
|
|
535
|
+
branch?: string;
|
|
519
536
|
/**
|
|
520
537
|
* Where check runs come from. A function is called only when the source
|
|
521
538
|
* is `checks`, so a tick from runs needs no forge token. Required for
|
|
@@ -547,6 +564,8 @@ export interface ComposedBranchTick {
|
|
|
547
564
|
|
|
548
565
|
export interface TickResult {
|
|
549
566
|
branch: string;
|
|
567
|
+
/** The other branches `ci.green` names (#4325), each judged as this one is. Their tags are in `made`. Absent for a one-branch declaration. */
|
|
568
|
+
routed?: TickResult[];
|
|
550
569
|
window: string;
|
|
551
570
|
/** The ref the commits were read from. */
|
|
552
571
|
ref: string;
|
|
@@ -601,7 +620,16 @@ export function ciTagSigner(top: string, base: string, pem: string, what = "the
|
|
|
601
620
|
export async function ciTick(req: TickRequest): Promise<TickResult> {
|
|
602
621
|
const read = readGreen(req.cwd);
|
|
603
622
|
const top = read.top;
|
|
604
|
-
const
|
|
623
|
+
const names = greenBranches(read.green);
|
|
624
|
+
if (req.branch === undefined && names.length > 1) {
|
|
625
|
+
const first = await ciTick({ ...req, branch: names[0]! });
|
|
626
|
+
const routed: TickResult[] = [];
|
|
627
|
+
for (const b of names.slice(1)) routed.push(await ciTick({ ...req, branch: b }));
|
|
628
|
+
return { ...first, routed, made: [...first.made, ...routed.flatMap((r) => r.made)] };
|
|
629
|
+
}
|
|
630
|
+
const green: CiGreen = { ...greenOn(read.green, req.branch), source: req.source ?? read.green.source };
|
|
631
|
+
// Compose branches are walked from trunk, so only the first branch's tick walks them.
|
|
632
|
+
const walksCompose = green.branch === read.green.branch;
|
|
605
633
|
const forge = green.source === "checks" ? (typeof req.forge === "function" ? req.forge() : req.forge) : undefined;
|
|
606
634
|
if (green.source === "checks" && !forge) throw new Error("ci.green.source is checks, so the tick reads check runs and needs a forge");
|
|
607
635
|
const remote = req.remote ?? "origin";
|
|
@@ -671,7 +699,7 @@ export async function ciTick(req: TickRequest): Promise<TickResult> {
|
|
|
671
699
|
if (links) for (const c of planned) c.work = links.get(c.sha);
|
|
672
700
|
// Compose branches (#4168 4.3): each composed commit within the window is judged as trunk's are, and its tags name its branch.
|
|
673
701
|
const composed: ComposedBranchTick[] = [];
|
|
674
|
-
for (const b of remoteComposeBranches(top, remote)) {
|
|
702
|
+
for (const b of walksCompose ? remoteComposeBranches(top, remote) : []) {
|
|
675
703
|
const own = git(top, ["log", "--first-parent", `--max-age=${cutoff}`, "--format=%H %ct", b.ref, `^${tracking}`])
|
|
676
704
|
.split("\n")
|
|
677
705
|
.filter(Boolean)
|
|
@@ -904,18 +932,20 @@ export interface RequestBuildResult {
|
|
|
904
932
|
*/
|
|
905
933
|
export async function requestBuild(req: { cwd: string; at: string; remote?: string; forge?: CiForge; now?: Date }): Promise<RequestBuildResult> {
|
|
906
934
|
const read = readGreen(req.cwd);
|
|
907
|
-
const {
|
|
935
|
+
const { top } = read;
|
|
936
|
+
const green = greenOn(read.green, undefined);
|
|
937
|
+
const names = greenBranches(read.green);
|
|
908
938
|
const remote = req.remote ?? "origin";
|
|
909
|
-
const
|
|
939
|
+
const trackingOf = (b: string): string => `refs/remotes/${remote}/${b}`;
|
|
910
940
|
try {
|
|
911
|
-
git(top, ["fetch", "--quiet", "--no-tags", remote, `+refs/heads/${
|
|
941
|
+
git(top, ["fetch", "--quiet", "--no-tags", remote, ...names.map((b) => `+refs/heads/${b}:${trackingOf(b)}`), `+refs/tags/${CI_BUILD_TAG_PREFIX}*:refs/tags/${CI_BUILD_TAG_PREFIX}*`]);
|
|
912
942
|
} catch (err) {
|
|
913
|
-
throw new Error(`could not fetch ${
|
|
943
|
+
throw new Error(`could not fetch ${names.join(", ")} and the build requests from ${remote}: ${stderrOf(err)}`);
|
|
914
944
|
}
|
|
915
945
|
if (req.at.startsWith("-") || tryGit(top, ["rev-parse", "--verify", "--quiet", `${req.at}^{commit}`]) === null) throw new WorkspaceReadError("revision-unknown", `--at ${req.at} names no commit in this repository`);
|
|
916
946
|
const sha = git(top, ["rev-parse", `${req.at}^{commit}`]);
|
|
917
|
-
const onBranch =
|
|
918
|
-
if (!onBranch) throw new Error(`${sha.slice(0, 12)} is not a first-parent commit of ${remote}/${
|
|
947
|
+
const onBranch = names.some((b) => tryGit(top, ["rev-list", "--first-parent", trackingOf(b)])?.split("\n").includes(sha));
|
|
948
|
+
if (!onBranch) throw new Error(`${sha.slice(0, 12)} is not a first-parent commit of ${names.map((b) => `${remote}/${b}`).join(" or ")}, and only those are judged green`);
|
|
919
949
|
const existing = readBuildRequests(top).get(sha);
|
|
920
950
|
const request = existing ?? requestedBuild(green, sha, green.require, req.now ?? new Date());
|
|
921
951
|
const warnings: string[] = [];
|
|
@@ -1101,6 +1131,7 @@ export function whyWorkUnknown(work: CommitLink | null | undefined): string | un
|
|
|
1101
1131
|
|
|
1102
1132
|
/** The text `chant ci tick` prints. */
|
|
1103
1133
|
export function formatTick(r: TickResult, dryRun = false): string {
|
|
1134
|
+
if (r.routed) return [formatTick({ ...r, routed: undefined }, dryRun), ...r.routed.map((b) => formatTick(b, dryRun))].join("\n");
|
|
1104
1135
|
const lines = [`${r.branch}, commits within ${r.window}${r.source === "runs" ? ", judged from chant runs" : ""}: ${r.commits.length}`];
|
|
1105
1136
|
for (const c of r.commits) {
|
|
1106
1137
|
const short = c.sha.slice(0, 12);
|
|
@@ -1187,10 +1218,12 @@ export const LAST_GREEN_NEWER = 50;
|
|
|
1187
1218
|
* green tag and no revoked tag. It reads local refs and tags and never
|
|
1188
1219
|
* fetches, so a reader fetches first (`git fetch origin --tags`).
|
|
1189
1220
|
*/
|
|
1190
|
-
export function lastGreen(req: { cwd: string; remote?: string; from?: string }): LastGreenDocument {
|
|
1221
|
+
export function lastGreen(req: { cwd: string; remote?: string; from?: string; branch?: string }): LastGreenDocument {
|
|
1191
1222
|
const head = { $schema: CI_LAST_GREEN_SCHEMA_ID, contract: CI_LAST_GREEN_CONTRACT_VERSION, chant: readerVersion() };
|
|
1192
1223
|
try {
|
|
1193
|
-
const
|
|
1224
|
+
const read = readGreen(req.cwd);
|
|
1225
|
+
const { top, workspace } = read;
|
|
1226
|
+
const green = greenOn(read.green, req.branch);
|
|
1194
1227
|
const branchRef = branchRefOf(top, green, req.remote);
|
|
1195
1228
|
let ref = branchRef;
|
|
1196
1229
|
if (req.from !== undefined) {
|
|
@@ -1355,6 +1388,8 @@ function recordedPhase(green: CountedCiTag | undefined, phase: string): CiListPh
|
|
|
1355
1388
|
|
|
1356
1389
|
export interface ListRequest {
|
|
1357
1390
|
cwd: string;
|
|
1391
|
+
/** List this branch of `ci.green.branch` (#4325). The first when absent. */
|
|
1392
|
+
branch?: string;
|
|
1358
1393
|
remote?: string;
|
|
1359
1394
|
/** Keep only the newest n commits. */
|
|
1360
1395
|
limit?: number;
|
|
@@ -1380,7 +1415,9 @@ export interface ListRequest {
|
|
|
1380
1415
|
export async function ciList(req: ListRequest): Promise<CiListDocument> {
|
|
1381
1416
|
const head = { $schema: CI_LIST_SCHEMA_ID, contract: CI_LIST_CONTRACT_VERSION, chant: readerVersion() };
|
|
1382
1417
|
try {
|
|
1383
|
-
const
|
|
1418
|
+
const read = readGreen(req.cwd);
|
|
1419
|
+
const { top, workspace } = read;
|
|
1420
|
+
const green = greenOn(read.green, req.branch);
|
|
1384
1421
|
const ref = branchRefOf(top, green, req.remote);
|
|
1385
1422
|
|
|
1386
1423
|
const logArgs = ["log", "--first-parent", "--format=%H %ct"];
|
|
@@ -17,7 +17,7 @@ import { join } from "node:path";
|
|
|
17
17
|
import { afterAll, beforeAll, describe, expect, test } from "vitest";
|
|
18
18
|
import { cleanScratch, declaration, git, repoFixture, scratchDir, writeFiles } from "./__fixtures__/contract-repo";
|
|
19
19
|
import { checkRunEventLines } from "./__fixtures__/run-event-check";
|
|
20
|
-
import { ciJobCommand, ciJobEnv, ciJobFailure, ciJobOp, ciLoopOptions, ciRun, CiRunError, ciStatusContext, ciStatusFromEnv, ciStatusUrl, formatCiRun } from "./ci-run";
|
|
20
|
+
import { chantNodeModules, ciJobCommand, ciJobEnv, ciJobFailure, ciJobOp, ciLoopOptions, ciRun, CiRunError, ciStatusContext, ciStatusFromEnv, ciStatusUrl, formatCiRun } from "./ci-run";
|
|
21
21
|
import type { CommitStatus, ForgeStatus, PrForge } from "../pr-forge";
|
|
22
22
|
import { FORGE_TOKEN_VARS } from "../ci-handover";
|
|
23
23
|
import { ciList, ciTick, evaluateCommit, readOpRunSource, revokedAnnotation } from "./ci-green";
|
|
@@ -1040,6 +1040,77 @@ describe("the plan's steps hold no forge token (#4295)", () => {
|
|
|
1040
1040
|
});
|
|
1041
1041
|
});
|
|
1042
1042
|
|
|
1043
|
+
/** A scheduled watch Op's file, shaped as discovery reads one (entity.props = OpConfig), importing nothing. */
|
|
1044
|
+
const WATCH_OP = (name: string): string =>
|
|
1045
|
+
`export default { props: { name: ${JSON.stringify(name)}, overview: "t", schedule: { cron: "0 * * * *" }, labels: { Watch: "true" }, phases: [{ name: "Run", steps: [] }] } };\n`;
|
|
1046
|
+
|
|
1047
|
+
describe("chant ci run plan checks the scheduled Ops at --base for the note (#4328)", () => {
|
|
1048
|
+
/**
|
|
1049
|
+
* The base declares watch Op `drift`, with its generated workflow. The
|
|
1050
|
+
* change deletes it and adds `sneaky`. The note names the Op the base has,
|
|
1051
|
+
* since the check reads the Ops at --base, and never the change's own.
|
|
1052
|
+
*/
|
|
1053
|
+
function stale(): { app: string; base: string; sha: string } {
|
|
1054
|
+
const { root, app } = workspace();
|
|
1055
|
+
writeFiles(root, {
|
|
1056
|
+
"app/chant.config.json": "{}",
|
|
1057
|
+
"app/ops/drift.op.ts": WATCH_OP("drift"),
|
|
1058
|
+
".forgejo/workflows/app-drift.yml": "on: schedule\n",
|
|
1059
|
+
});
|
|
1060
|
+
const base = commitAt(root, 1, "app/b.txt");
|
|
1061
|
+
execFileSync("git", ["rm", "-q", "app/ops/drift.op.ts"], { cwd: root });
|
|
1062
|
+
writeFiles(root, { "app/ops/sneaky.op.ts": WATCH_OP("sneaky"), ".forgejo/workflows/app-sneaky.yml": "on: schedule\n" });
|
|
1063
|
+
const sha = commitAt(root, 0.5, "app/c.txt");
|
|
1064
|
+
return { app, base, sha };
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
function overdueForge(): { forge: PrForge; notes: string[]; asked: string[] } {
|
|
1068
|
+
const notes: string[] = [];
|
|
1069
|
+
const asked: string[] = [];
|
|
1070
|
+
const forge = {
|
|
1071
|
+
kind: "forgejo",
|
|
1072
|
+
host: "forgejo.localhost",
|
|
1073
|
+
async setStatus() {},
|
|
1074
|
+
async upsertNote(_pr: number, _marker: string, body: string) {
|
|
1075
|
+
notes.push(body);
|
|
1076
|
+
return "1";
|
|
1077
|
+
},
|
|
1078
|
+
// Every Op last ran a year ago: overdue whichever is asked about.
|
|
1079
|
+
async scheduledRuns(q: { op: string }) {
|
|
1080
|
+
asked.push(q.op);
|
|
1081
|
+
return { last: "2025-10-01T00:00:00Z" };
|
|
1082
|
+
},
|
|
1083
|
+
} as unknown as PrForge;
|
|
1084
|
+
return { forge, notes, asked };
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
test("on the runner, the note warns of the base's overdue Op and not of one the change added", async () => {
|
|
1088
|
+
const { app, base, sha } = stale();
|
|
1089
|
+
const forge = overdueForge();
|
|
1090
|
+
const r = await ciRun({ image: JOB_IMAGE, cwd: app, job: "plan", env: "prod", forge: "forgejo", base, pr: 7, chant: fakeChant(), hostEnv: { ...HOST, FAKE_REPORT: planReport(sha) }, passEnv: ["FAKE_REPORT"], planForge: forge.forge, push: false, output: join(scratchDir("chant-ci-overdue-"), "pr") });
|
|
1091
|
+
expect(r.status).toBe("ok");
|
|
1092
|
+
expect(forge.asked).toEqual(["drift"]);
|
|
1093
|
+
expect(forge.notes).toHaveLength(1);
|
|
1094
|
+
expect(forge.notes[0]).toContain("Op `drift` is overdue");
|
|
1095
|
+
expect(forge.notes[0]).not.toContain("sneaky");
|
|
1096
|
+
expect(r.warnings).toEqual([expect.stringMatching(/Op `drift` is overdue/)]);
|
|
1097
|
+
});
|
|
1098
|
+
|
|
1099
|
+
test("in place, the check still reads the base, not the checkout the change runs in", async () => {
|
|
1100
|
+
const { app, base, sha } = stale();
|
|
1101
|
+
const forge = overdueForge();
|
|
1102
|
+
const r = await ciRun({ cwd: app, job: "plan", env: "prod", forge: "forgejo", base, pr: 7, chant: fakeChant(), hostEnv: { ...HOST, GITHUB_JOB: "plan", FAKE_REPORT: planReport(sha) }, inPlace: true, push: false, planForge: forge.forge });
|
|
1103
|
+
expect(r.status).toBe("ok");
|
|
1104
|
+
expect(forge.asked).toEqual(["drift"]);
|
|
1105
|
+
expect(forge.notes[0]).toContain("Op `drift` is overdue");
|
|
1106
|
+
});
|
|
1107
|
+
|
|
1108
|
+
test("the base checkout resolves packages from the node_modules the running chant is installed in", () => {
|
|
1109
|
+
expect(chantNodeModules("/opt/ci/node_modules/@intentius/chant/dist/workspace/ci-run.js")).toBe("/opt/ci/node_modules");
|
|
1110
|
+
expect(chantNodeModules("/src/chant/packages/core/src/workspace/ci-run.ts")).toBeUndefined();
|
|
1111
|
+
});
|
|
1112
|
+
});
|
|
1113
|
+
|
|
1043
1114
|
/**
|
|
1044
1115
|
* #4330: a pull request environment's jobs run through `ci run` too. The
|
|
1045
1116
|
* stand-in chant keeps each action's arguments, environment, directory and
|