@intentius/chant 0.124.46 → 0.124.49
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/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/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 +41 -14
- package/dist/cli/handlers/build.d.ts.map +1 -1
- package/dist/cli/handlers/build.js +6 -1
- package/dist/cli/handlers/graph-reader.d.ts +26 -0
- package/dist/cli/handlers/graph-reader.d.ts.map +1 -0
- package/dist/cli/handlers/graph-reader.js +41 -0
- package/dist/cli/handlers/graph.d.ts.map +1 -1
- package/dist/cli/handlers/graph.js +14 -0
- 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.js +2 -2
- 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 +183 -40
- 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.d.ts +2 -4
- package/dist/cli/handlers/search.d.ts.map +1 -1
- package/dist/cli/handlers/search.js +13 -39
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +87 -14
- package/dist/cli/parse-args.d.ts.map +1 -1
- package/dist/cli/parse-args.js +47 -2
- package/dist/cli/registry.d.ts +22 -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-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/pr-run.d.ts +3 -0
- package/dist/components/pr-run.d.ts.map +1 -1
- package/dist/components/pr-run.js +1 -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 +20 -0
- package/dist/config-environments.d.ts.map +1 -1
- package/dist/config-environments.js +12 -0
- package/dist/config.d.ts +25 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +10 -2
- package/dist/gate-decision.d.ts +20 -2
- package/dist/gate-decision.d.ts.map +1 -1
- package/dist/gate-decision.js +30 -3
- package/dist/graph-ir.d.ts +25 -0
- package/dist/graph-ir.d.ts.map +1 -1
- 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 +94 -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/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/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/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-base.d.ts +25 -0
- package/dist/op/gate-approval-base.d.ts.map +1 -0
- package/dist/op/gate-approval-base.js +71 -0
- package/dist/op/gate-approval.d.ts +18 -9
- package/dist/op/gate-approval.d.ts.map +1 -1
- package/dist/op/gate-approval.js +13 -31
- package/dist/op/gate-name.d.ts +13 -0
- package/dist/op/gate-name.d.ts.map +1 -1
- package/dist/op/gate-name.js +14 -1
- 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 +47 -5
- 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 +45 -3
- package/dist/op/local-executor.d.ts.map +1 -1
- package/dist/op/local-executor.js +68 -7
- 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-loop.d.ts +10 -0
- package/dist/pr-loop.d.ts.map +1 -1
- package/dist/pr-loop.js +4 -0
- package/dist/pr-migrations.d.ts +62 -0
- package/dist/pr-migrations.d.ts.map +1 -0
- package/dist/pr-migrations.js +50 -0
- package/dist/pr-post.d.ts +42 -0
- package/dist/pr-post.d.ts.map +1 -1
- package/dist/pr-post.js +68 -2
- 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 +264 -254
- package/dist/workspace/check.schema.json +13 -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/gate-approval.d.ts +58 -0
- package/dist/workspace/checks/gate-approval.d.ts.map +1 -0
- package/dist/workspace/checks/gate-approval.js +103 -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 +12 -1
- package/dist/workspace/checks.d.ts.map +1 -1
- package/dist/workspace/checks.js +63 -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 +14 -0
- package/dist/workspace/compose-graph.d.ts.map +1 -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/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 +50 -2
- package/dist/workspace/declaration.d.ts.map +1 -1
- package/dist/workspace/declaration.js +57 -11
- package/dist/workspace/declaration.schema.json +166 -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/exit-cli.d.ts +44 -0
- package/dist/workspace/exit-cli.d.ts.map +1 -0
- package/dist/workspace/exit-cli.js +198 -0
- package/dist/workspace/exit.d.ts +159 -0
- package/dist/workspace/exit.d.ts.map +1 -0
- package/dist/workspace/exit.js +480 -0
- package/dist/workspace/exit.schema.json +257 -0
- 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 +3 -1
- package/dist/workspace/graph-cache.d.ts.map +1 -1
- package/dist/workspace/graph-cache.js +12 -1
- package/dist/workspace/graph-cli.d.ts.map +1 -1
- package/dist/workspace/graph-cli.js +26 -8
- package/dist/workspace/graph.schema.json +34 -0
- package/dist/workspace/import-fetch.d.ts +38 -0
- package/dist/workspace/import-fetch.d.ts.map +1 -0
- package/dist/workspace/import-fetch.js +99 -0
- package/dist/workspace/import-init.d.ts +26 -0
- package/dist/workspace/import-init.d.ts.map +1 -0
- package/dist/workspace/import-init.js +130 -0
- package/dist/workspace/import-source.d.ts +147 -0
- package/dist/workspace/import-source.d.ts.map +1 -0
- package/dist/workspace/import-source.js +370 -0
- package/dist/workspace/init.d.ts +4 -0
- package/dist/workspace/init.d.ts.map +1 -1
- package/dist/workspace/init.js +70 -3
- 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 +6 -0
- package/dist/workspace/kind-readers.d.ts.map +1 -1
- package/dist/workspace/kind-readers.js +18 -0
- package/dist/workspace/kinds.d.ts +90 -3
- package/dist/workspace/kinds.d.ts.map +1 -1
- package/dist/workspace/kinds.js +161 -7
- 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/lineage-upgrade.d.ts.map +1 -1
- package/dist/workspace/lineage-upgrade.js +13 -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.map +1 -1
- package/dist/workspace/member-commands.js +54 -5
- 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/new-migrations.d.ts +47 -0
- package/dist/workspace/new-migrations.d.ts.map +1 -0
- package/dist/workspace/new-migrations.js +91 -0
- package/dist/workspace/pr-report.schema.json +46 -0
- package/dist/workspace/promote.d.ts +96 -0
- package/dist/workspace/promote.d.ts.map +1 -0
- package/dist/workspace/promote.js +263 -0
- package/dist/workspace/reason-codes.d.ts +21 -0
- package/dist/workspace/reason-codes.d.ts.map +1 -1
- package/dist/workspace/reason-codes.js +25 -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-contract.d.ts +1 -1
- package/dist/workspace/search-contract.d.ts.map +1 -1
- 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 +108 -10
- 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/action-pins.test.ts +78 -0
- package/src/action-pins.ts +92 -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/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 +33 -4
- package/src/cli/handlers/build.ts +7 -1
- package/src/cli/handlers/graph-reader.test.ts +31 -0
- package/src/cli/handlers/graph-reader.ts +51 -0
- package/src/cli/handlers/graph.ts +14 -0
- 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 +2 -2
- package/src/cli/handlers/pr.ts +176 -37
- package/src/cli/handlers/query.ts +16 -4
- package/src/cli/handlers/release.ts +6 -3
- package/src/cli/handlers/search.ts +13 -34
- package/src/cli/main.test.ts +17 -0
- package/src/cli/main.ts +87 -14
- package/src/cli/parse-args.ts +35 -2
- package/src/cli/registry.ts +22 -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-run-bundle.test.ts +1 -0
- 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/pr-run.ts +4 -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 +28 -1
- package/src/config.ts +24 -1
- package/src/gate-decision-bundle.test.ts +5 -2
- package/src/gate-decision-identity.test.ts +20 -0
- package/src/gate-decision.ts +46 -3
- package/src/graph-ir.ts +27 -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 +98 -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/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/rules/op/index.ts +2 -0
- package/src/lint/rules/op/ops019-workspace-op-target.ts +89 -0
- 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-at-base.test.ts +97 -0
- package/src/op/gate-approval-base.ts +72 -0
- package/src/op/gate-approval.test.ts +6 -1
- package/src/op/gate-approval.ts +22 -27
- package/src/op/gate-name.ts +16 -1
- 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 +69 -9
- package/src/op/index.ts +3 -2
- package/src/op/local-executor.ts +91 -11
- 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-loop-bundle.test.ts +3 -2
- package/src/pr-loop.test.ts +52 -0
- package/src/pr-loop.ts +12 -0
- package/src/pr-migrations.ts +97 -0
- package/src/pr-post-open.e2e.test.ts +36 -0
- package/src/pr-post.test.ts +102 -3
- package/src/pr-post.ts +90 -2
- 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/__fixtures__/import/spacelift.json +9 -0
- package/src/workspace/__fixtures__/import/tfc.json +13 -0
- package/src/workspace/behold-kinds.test.ts +2 -1
- package/src/workspace/check-contract.test.ts +8 -6
- package/src/workspace/check.schema.json +13 -2
- package/src/workspace/checks/ci-branch.test.ts +128 -0
- package/src/workspace/checks/ci-branch.ts +141 -0
- package/src/workspace/checks/gate-approval.test.ts +77 -0
- package/src/workspace/checks/gate-approval.ts +121 -0
- package/src/workspace/checks/links.ts +12 -1
- package/src/workspace/checks/org.ts +169 -0
- package/src/workspace/checks.ts +68 -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 +9 -2
- 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/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 +166 -24
- package/src/workspace/declaration.ts +101 -15
- package/src/workspace/environments.ts +40 -4
- package/src/workspace/exit-cli.ts +219 -0
- package/src/workspace/exit.schema.json +257 -0
- package/src/workspace/exit.test.ts +185 -0
- package/src/workspace/exit.ts +560 -0
- package/src/workspace/flyway-dir.ts +113 -0
- package/src/workspace/flyway-layout.ts +337 -0
- package/src/workspace/graph-cache.ts +12 -2
- package/src/workspace/graph-cli.ts +25 -10
- package/src/workspace/graph-contract.test.ts +4 -2
- package/src/workspace/graph.schema.json +34 -0
- package/src/workspace/identity.test.ts +29 -2
- package/src/workspace/import-fetch.ts +151 -0
- package/src/workspace/import-init.ts +147 -0
- package/src/workspace/import-source.test.ts +183 -0
- package/src/workspace/import-source.ts +462 -0
- package/src/workspace/init.test.ts +55 -1
- package/src/workspace/init.ts +66 -4
- package/src/workspace/intent.ts +6 -14
- package/src/workspace/kind-link-readers.ts +68 -3
- package/src/workspace/kind-readers.test.ts +36 -0
- package/src/workspace/kind-readers.ts +18 -1
- package/src/workspace/kinds.test.ts +35 -7
- package/src/workspace/kinds.ts +212 -11
- 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/lineage-upgrade.test.ts +20 -0
- package/src/workspace/lineage-upgrade.ts +16 -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 +60 -2
- 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/new-migrations.test.ts +98 -0
- package/src/workspace/new-migrations.ts +109 -0
- package/src/workspace/org-scope.test.ts +238 -0
- package/src/workspace/pr-report.schema.json +46 -0
- package/src/workspace/promote.test.ts +114 -0
- package/src/workspace/promote.ts +302 -0
- package/src/workspace/reason-codes.test.ts +10 -1
- package/src/workspace/reason-codes.ts +25 -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/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 +108 -10
- 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
package/src/op/op-waves.ts
CHANGED
|
@@ -17,8 +17,16 @@
|
|
|
17
17
|
* (`shares` > 1) is a deciding job that plans every run and decides the gate,
|
|
18
18
|
* plus `shares` jobs that each apply a slice of the runs and refuse a run
|
|
19
19
|
* whose plan moved since the decision. Each wave's jobs need the previous
|
|
20
|
-
* wave's last jobs, so a wave that waits (exit 3)
|
|
21
|
-
*
|
|
20
|
+
* wave's last jobs, so a wave that waits (exit 3) stops every later wave.
|
|
21
|
+
*
|
|
22
|
+
* ## A failed run blocks its dependents (#4322)
|
|
23
|
+
*
|
|
24
|
+
* A run's `dependsOn` names the runs it needs applied first. Each job writes
|
|
25
|
+
* an outcome file ({@link OpWaveJob.outcome}, `../wave-blocked.ts`) and the
|
|
26
|
+
* next wave's jobs read every earlier one, so a run that failed blocks only
|
|
27
|
+
* the runs that depend on it, in its own wave and later ones, and the rest
|
|
28
|
+
* apply. The generated pipelines run a wave's jobs after a failure in the
|
|
29
|
+
* wave before; a job exits 1 only for its own failed or blocked runs.
|
|
22
30
|
*
|
|
23
31
|
* ## The gate
|
|
24
32
|
*
|
|
@@ -51,6 +59,13 @@
|
|
|
51
59
|
* in `.chant/trust.json` at base), one of them not the author with
|
|
52
60
|
* `notAuthor`. See `./gate-quorum.ts`.
|
|
53
61
|
*
|
|
62
|
+
* Two more settings feed those rules, read at base with them (#4333):
|
|
63
|
+
* `approvals.reviewLedger` names the op whose ledger holds the reviews a
|
|
64
|
+
* product records itself under `pr-review` (terragucci's `tf-apply`), and
|
|
65
|
+
* `approvals.involved` names the accounts an agent acts as and, with
|
|
66
|
+
* `exclude`, leaves an approval by anyone involved in the change out of
|
|
67
|
+
* every rule.
|
|
68
|
+
*
|
|
54
69
|
* ## Wave-level commands and hooks (#3762)
|
|
55
70
|
*
|
|
56
71
|
* A product whose tool plans a whole wave in one call (Terragrunt's `run
|
|
@@ -81,6 +96,7 @@ import { gatePointProblems, type GatePoint } from "./gate-point";
|
|
|
81
96
|
import { quorumProblems, type GateQuorumRule } from "./gate-quorum";
|
|
82
97
|
import { notifyConfigProblem, type NotifyConfig } from "../notify";
|
|
83
98
|
import { WAVE_GATE_NAME_PATTERN, waveGateNameFrom, waveShare } from "../wave-layout";
|
|
99
|
+
import { waveOutcomeFileName } from "../wave-blocked";
|
|
84
100
|
|
|
85
101
|
/**
|
|
86
102
|
* The variables a wave job reads its notify secrets from, for the lexicons
|
|
@@ -217,6 +233,15 @@ export interface OpWaveRun {
|
|
|
217
233
|
target: string;
|
|
218
234
|
/** The Op to run. Default: the spec's `op`. */
|
|
219
235
|
op?: string;
|
|
236
|
+
/**
|
|
237
|
+
* The runs this one needs applied first (#4322), by target: a run of an
|
|
238
|
+
* earlier wave (the latest earlier wave that has the target), or one listed
|
|
239
|
+
* before it in its own wave. A run that failed, or was blocked, blocks this
|
|
240
|
+
* one, which then is neither planned nor applied; a run with no failed
|
|
241
|
+
* dependency applies whatever else failed. Within its own wave only when
|
|
242
|
+
* one job applies the wave (no `shares`, no `jobs`).
|
|
243
|
+
*/
|
|
244
|
+
dependsOn?: string[];
|
|
220
245
|
}
|
|
221
246
|
|
|
222
247
|
/**
|
|
@@ -505,6 +530,48 @@ export interface OpWavesApprovals {
|
|
|
505
530
|
* author from that pull request. See `./gate-quorum.ts`.
|
|
506
531
|
*/
|
|
507
532
|
quorum?: GateQuorumRule[];
|
|
533
|
+
/**
|
|
534
|
+
* The op whose ledger (`_gates/<op>.jsonl` on `chant/lifecycle`) holds the
|
|
535
|
+
* reviews a product records itself (#4333): lines with `via: "pr-review"`,
|
|
536
|
+
* the reviewed `head` and the approving `reviewers` by forge login, as
|
|
537
|
+
* terragucci writes them under `tf-apply`. Each reviewer counts toward
|
|
538
|
+
* `quorum` as one approver of the line's digest, and under `pr-review` is
|
|
539
|
+
* proven, as a review chant reads from the forge is. Read at the base
|
|
540
|
+
* commit, so a change cannot name a ledger its own wave is judged by.
|
|
541
|
+
*/
|
|
542
|
+
reviewLedger?: string;
|
|
543
|
+
/** Who else was involved in a change, for `quorum` (#4333). Read at the base commit. */
|
|
544
|
+
involved?: OpWavesInvolved;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* Who was involved in a change besides its pull request's author (#4333):
|
|
549
|
+
* each login a `Requested-by:` trailer names on the commits after base, and
|
|
550
|
+
* the accounts listed here. `notAuthor` is met only by a proven approver
|
|
551
|
+
* none of them is.
|
|
552
|
+
*/
|
|
553
|
+
export interface OpWavesInvolved {
|
|
554
|
+
/** The accounts an agent acts as, as principals (`github:tg-bot`) or logins: a change's author can post a review as the agent with its token. */
|
|
555
|
+
agents?: string[];
|
|
556
|
+
/** An approval by anyone involved counts toward no rule, not only toward `notAuthor`. Default false. */
|
|
557
|
+
exclude?: boolean;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
/** An op name a ledger file is named by (`_gates/<op>.jsonl`). */
|
|
561
|
+
export const OP_LEDGER_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
562
|
+
|
|
563
|
+
/** Everything wrong with `approvals.involved` (#4333), one line each. */
|
|
564
|
+
export function opWavesInvolvedProblems(value: unknown): string[] {
|
|
565
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return ["`approvals.involved` must be { \"agents\"?: [...], \"exclude\"?: true | false }"];
|
|
566
|
+
const problems: string[] = [];
|
|
567
|
+
for (const [key, v] of Object.entries(value as Record<string, unknown>)) {
|
|
568
|
+
if (key === "agents") {
|
|
569
|
+
if (!Array.isArray(v) || v.length === 0 || v.some((a) => typeof a !== "string" || a.trim() === "")) problems.push("`approvals.involved.agents` must be a non-empty list of principals or logins");
|
|
570
|
+
} else if (key === "exclude") {
|
|
571
|
+
if (typeof v !== "boolean") problems.push("`approvals.involved.exclude` must be true or false");
|
|
572
|
+
} else problems.push(`\`approvals.involved.${key}\` is not a setting; use agents or exclude`);
|
|
573
|
+
}
|
|
574
|
+
return problems;
|
|
508
575
|
}
|
|
509
576
|
|
|
510
577
|
/** The scheduled resume job of an Op waves pipeline (#3683). */
|
|
@@ -549,6 +616,23 @@ export interface OpWaveJob {
|
|
|
549
616
|
command: string[];
|
|
550
617
|
/** On a share job: the decision record to download. On a deciding job: the one to upload. */
|
|
551
618
|
record?: string;
|
|
619
|
+
/**
|
|
620
|
+
* The outcome file the job writes (#4322), which the forge keeps whatever
|
|
621
|
+
* the job's exit code: each of its runs' outcome, as `../wave-blocked.ts`
|
|
622
|
+
* writes them. A job with `needs` reads the earlier ones from
|
|
623
|
+
* {@link opWaveOutcomeDir} first.
|
|
624
|
+
*/
|
|
625
|
+
outcome: string;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
/** Where a wave job writes its outcome file and finds the earlier ones (#4322), at any depth. */
|
|
629
|
+
export function opWaveOutcomeDir(spec: Pick<OpWavesSpec, "name">): string {
|
|
630
|
+
return `.chant/op-waves/${spec.name}/outcomes`;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/** The outcome file of wave `wave`'s job, or of one group or share of it (#4322). */
|
|
634
|
+
export function opWaveOutcomePath(spec: Pick<OpWavesSpec, "name">, wave: number, part: { group?: string; share?: number } = {}): string {
|
|
635
|
+
return `${opWaveOutcomeDir(spec)}/${waveOutcomeFileName(wave, part)}`;
|
|
552
636
|
}
|
|
553
637
|
|
|
554
638
|
const NAME = /^[a-z0-9][a-z0-9_-]*$/;
|
|
@@ -592,7 +676,7 @@ export function assertOpWavesSpec(spec: OpWavesSpec): void {
|
|
|
592
676
|
}
|
|
593
677
|
if (spec.approvals !== undefined) {
|
|
594
678
|
const a = spec.approvals as unknown;
|
|
595
|
-
if (a === null || typeof a !== "object" || Array.isArray(a)) throw new Error(`${where}: \`approvals\` must be { "spend"?: true | false, "quorum"?: [...] }.`);
|
|
679
|
+
if (a === null || typeof a !== "object" || Array.isArray(a)) throw new Error(`${where}: \`approvals\` must be { "spend"?: true | false, "quorum"?: [...], "reviewLedger"?: "<op>", "involved"?: {...} }.`);
|
|
596
680
|
for (const [key, value] of Object.entries(a as Record<string, unknown>)) {
|
|
597
681
|
if (key === "quorum") {
|
|
598
682
|
// #4290: approval rules, read at base like the policy.
|
|
@@ -601,7 +685,17 @@ export function assertOpWavesSpec(spec: OpWavesSpec): void {
|
|
|
601
685
|
if (problems.length > 0) throw new Error(`${where}: ${problems.join("; ")}.`);
|
|
602
686
|
continue;
|
|
603
687
|
}
|
|
604
|
-
if (key
|
|
688
|
+
if (key === "reviewLedger") {
|
|
689
|
+
// #4333: the op a product records its reviews under, read at base.
|
|
690
|
+
if (typeof value !== "string" || !OP_LEDGER_NAME.test(value)) throw new Error(`${where}: approvals.reviewLedger must name an op, such as "tf-apply": letters, digits, dot, dash and underscore.`);
|
|
691
|
+
continue;
|
|
692
|
+
}
|
|
693
|
+
if (key === "involved") {
|
|
694
|
+
const problems = opWavesInvolvedProblems(value);
|
|
695
|
+
if (problems.length > 0) throw new Error(`${where}: ${problems.join("; ")}.`);
|
|
696
|
+
continue;
|
|
697
|
+
}
|
|
698
|
+
if (key !== "spend") throw new Error(`${where}: approvals.${key} is not a setting; the ones there are approvals.spend, approvals.quorum, approvals.reviewLedger and approvals.involved.`);
|
|
605
699
|
if (typeof value !== "boolean") throw new Error(`${where}: approvals.spend must be true or false.`);
|
|
606
700
|
}
|
|
607
701
|
if ((a as OpWavesApprovals).quorum?.length && (spec.point !== undefined || spec.waves.some((w) => w.point !== undefined))) {
|
|
@@ -698,6 +792,41 @@ export function assertOpWavesSpec(spec: OpWavesSpec): void {
|
|
|
698
792
|
if (problem) throw new Error(`${where}: ${problem}.`);
|
|
699
793
|
}
|
|
700
794
|
}
|
|
795
|
+
assertOpWaveDependsOn(where, spec);
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
/**
|
|
799
|
+
* Refuse a `dependsOn` (#4322) that names no run this one could follow: each
|
|
800
|
+
* entry is a target of an earlier wave, or of a run listed before it in its
|
|
801
|
+
* own wave when one job applies that wave. A discovering wave's runs are not
|
|
802
|
+
* in the spec, so after one any target is taken.
|
|
803
|
+
*/
|
|
804
|
+
function assertOpWaveDependsOn(where: string, spec: OpWavesSpec): void {
|
|
805
|
+
const earlier = new Set<string>();
|
|
806
|
+
let discovered = false;
|
|
807
|
+
for (const wave of spec.waves) {
|
|
808
|
+
const own = new Set<string>();
|
|
809
|
+
for (const run of wave.runs ?? []) {
|
|
810
|
+
const deps = run.dependsOn as unknown;
|
|
811
|
+
if (deps !== undefined) {
|
|
812
|
+
const at = `wave "${wave.name}" run "${run.target}"`;
|
|
813
|
+
if (!Array.isArray(deps) || !deps.every((d) => typeof d === "string" && d !== "")) throw new Error(`${where}: ${at} dependsOn must be a list of targets.`);
|
|
814
|
+
for (const dep of deps as string[]) {
|
|
815
|
+
if (dep === run.target && !earlier.has(dep)) throw new Error(`${where}: ${at} depends on itself.`);
|
|
816
|
+
if (own.has(dep)) {
|
|
817
|
+
if ((wave.shares ?? 1) > 1 || wave.jobs !== undefined) {
|
|
818
|
+
throw new Error(`${where}: ${at} depends on "${dep}" in its own wave, which ${wave.jobs ? "job groups" : "shares"} apply in separate jobs; move one of them to another wave.`);
|
|
819
|
+
}
|
|
820
|
+
continue;
|
|
821
|
+
}
|
|
822
|
+
if (!earlier.has(dep) && !discovered) throw new Error(`${where}: ${at} depends on "${dep}", which is no run of an earlier wave or listed before it in its own.`);
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
own.add(run.target);
|
|
826
|
+
}
|
|
827
|
+
for (const t of own) earlier.add(t);
|
|
828
|
+
if (wave.discover) discovered = true;
|
|
829
|
+
}
|
|
701
830
|
}
|
|
702
831
|
|
|
703
832
|
const ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
@@ -888,18 +1017,18 @@ export function assertOpWaveHooks(where: string, hooks: OpWaveHooks | undefined)
|
|
|
888
1017
|
/**
|
|
889
1018
|
* The moments a pull-request job runs hooks at (#4288): `pr-plan` and
|
|
890
1019
|
* `pr-record` run the observe and plan moments, and `pr-apply` the apply
|
|
891
|
-
* moments too.
|
|
1020
|
+
* moments too. `after-gate` (#4323) runs in `pr-apply` once the pull
|
|
1021
|
+
* request's gate has decided.
|
|
892
1022
|
*/
|
|
893
|
-
export const PR_LOOP_HOOK_MOMENTS: readonly OpWaveHookMoment[] = ["before-observe", "before-plan", "after-plan", "before-apply", "after-apply"];
|
|
1023
|
+
export const PR_LOOP_HOOK_MOMENTS: readonly OpWaveHookMoment[] = ["before-observe", "before-plan", "after-plan", "after-gate", "before-apply", "after-apply"];
|
|
894
1024
|
|
|
895
1025
|
/**
|
|
896
1026
|
* Refuse `ci.hooks` a pull-request job could not run (#4288): what
|
|
897
|
-
* {@link assertOpWaveHooks} refuses, plus `
|
|
898
|
-
*
|
|
1027
|
+
* {@link assertOpWaveHooks} refuses, plus `apply.runBy`, since chant itself
|
|
1028
|
+
* runs a pull request's apply.
|
|
899
1029
|
*/
|
|
900
1030
|
export function assertPrLoopHooks(where: string, hooks: OpWaveHooks | undefined): void {
|
|
901
1031
|
assertOpWaveHooks(where, hooks);
|
|
902
|
-
if (hooks?.after?.gate !== undefined) throw new Error(`${where}: hooks.after.gate runs in an Op waves job only; a pull-request job runs hooks before the observe, before and after the plan, and before and after the apply.`);
|
|
903
1032
|
if (hooks?.apply !== undefined) throw new Error(`${where}: hooks.apply.runBy is for an Op waves spec; chant runs a pull request's apply, so it runs the apply-stage hooks itself.`);
|
|
904
1033
|
}
|
|
905
1034
|
|
|
@@ -941,13 +1070,13 @@ export function opWaveJobs(spec: OpWavesSpec, specFile: string): OpWaveJob[] {
|
|
|
941
1070
|
const prefix = `wave-${k}-${wave.name}`;
|
|
942
1071
|
const shares = wave.shares ?? 1;
|
|
943
1072
|
if (shares === 1 && wave.jobs === undefined) {
|
|
944
|
-
jobs.push({ jobName: prefix, wave: k, waveName: wave.name, kind: "wave", needs: previous, command });
|
|
1073
|
+
jobs.push({ jobName: prefix, wave: k, waveName: wave.name, kind: "wave", needs: previous, command, outcome: opWaveOutcomePath(spec, k) });
|
|
945
1074
|
previous = [prefix];
|
|
946
1075
|
return;
|
|
947
1076
|
}
|
|
948
1077
|
const record = opWaveRecordPath(spec, k);
|
|
949
1078
|
const decide = `${prefix}-decide`;
|
|
950
|
-
jobs.push({ jobName: decide, wave: k, waveName: wave.name, kind: "decide", needs: previous, command: [...command, "--decide"], record });
|
|
1079
|
+
jobs.push({ jobName: decide, wave: k, waveName: wave.name, kind: "decide", needs: previous, command: [...command, "--decide"], record, outcome: opWaveOutcomePath(spec, k) });
|
|
951
1080
|
const shareJobs: string[] = [];
|
|
952
1081
|
if (wave.jobs !== undefined) {
|
|
953
1082
|
// #3914: a job per group, or per share of a group, each applying its runs under the deciding job's decision.
|
|
@@ -957,13 +1086,13 @@ export function opWaveJobs(spec: OpWavesSpec, specFile: string): OpWaveJob[] {
|
|
|
957
1086
|
if (groupShares === 1) {
|
|
958
1087
|
const jobName = `${prefix}-${group.name}`;
|
|
959
1088
|
shareJobs.push(jobName);
|
|
960
|
-
jobs.push({ jobName, wave: k, waveName: wave.name, kind: "share", group: group.name, needs: [decide], command: groupCommand, record });
|
|
1089
|
+
jobs.push({ jobName, wave: k, waveName: wave.name, kind: "share", group: group.name, needs: [decide], command: groupCommand, record, outcome: opWaveOutcomePath(spec, k, { group: group.name }) });
|
|
961
1090
|
continue;
|
|
962
1091
|
}
|
|
963
1092
|
for (let share = 1; share <= groupShares; share++) {
|
|
964
1093
|
const jobName = `${prefix}-${group.name}-share-${share}`;
|
|
965
1094
|
shareJobs.push(jobName);
|
|
966
|
-
jobs.push({ jobName, wave: k, waveName: wave.name, kind: "share", group: group.name, share, needs: [decide], command: [...groupCommand, "--share", String(share)], record });
|
|
1095
|
+
jobs.push({ jobName, wave: k, waveName: wave.name, kind: "share", group: group.name, share, needs: [decide], command: [...groupCommand, "--share", String(share)], record, outcome: opWaveOutcomePath(spec, k, { group: group.name, share }) });
|
|
967
1096
|
}
|
|
968
1097
|
}
|
|
969
1098
|
previous = shareJobs;
|
|
@@ -972,7 +1101,7 @@ export function opWaveJobs(spec: OpWavesSpec, specFile: string): OpWaveJob[] {
|
|
|
972
1101
|
for (let share = 1; share <= shares; share++) {
|
|
973
1102
|
const jobName = `${prefix}-share-${share}`;
|
|
974
1103
|
shareJobs.push(jobName);
|
|
975
|
-
jobs.push({ jobName, wave: k, waveName: wave.name, kind: "share", share, needs: [decide], command: [...command, "--share", String(share)], record });
|
|
1104
|
+
jobs.push({ jobName, wave: k, waveName: wave.name, kind: "share", share, needs: [decide], command: [...command, "--share", String(share)], record, outcome: opWaveOutcomePath(spec, k, { share }) });
|
|
976
1105
|
}
|
|
977
1106
|
previous = shareJobs;
|
|
978
1107
|
});
|
package/src/op/runtime.ts
CHANGED
|
@@ -175,6 +175,14 @@ export interface OpRunRecord {
|
|
|
175
175
|
* run id. Absent outside CI and on a record written before 0.124.28.
|
|
176
176
|
*/
|
|
177
177
|
runOrigin?: RunOrigin;
|
|
178
|
+
/**
|
|
179
|
+
* The workspace run that started this one (#2554, #2524 D17): `chant
|
|
180
|
+
* workspace run`'s id, and the workspace gate it ran under when it named
|
|
181
|
+
* one. The workspace run's own record, under `_members/_workspace/` on
|
|
182
|
+
* `chant/lifecycle`, names this run in turn. Absent on a run nothing in a
|
|
183
|
+
* workspace started, and on a record written before 0.124.47.
|
|
184
|
+
*/
|
|
185
|
+
workspaceRun?: { id: string; gate?: string };
|
|
178
186
|
/**
|
|
179
187
|
* The run's statement (#4044): a DSSE envelope over an in-toto statement
|
|
180
188
|
* (`https://intentius.io/chant/op-run/v1`) a runner key signed at the end
|
|
@@ -159,3 +159,36 @@ export async function checkOverdueOps(input: {
|
|
|
159
159
|
}
|
|
160
160
|
return out;
|
|
161
161
|
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* The overdue check over the Ops declared at `cwd` (#4289), as the plan note
|
|
165
|
+
* reports it: the Ops `discoverOps` finds there, and the repository root
|
|
166
|
+
* `cwd` is in. `pr-post` runs it in its own checkout, the target branch's
|
|
167
|
+
* commit, and `chant ci run plan` in a checkout of `--base` (#4328), so the
|
|
168
|
+
* Ops are never read from the change's code. Without a forge that can say
|
|
169
|
+
* when a job ran, nothing is checked. A failure is a line in `log` and no
|
|
170
|
+
* verdict, and the plan goes on.
|
|
171
|
+
*/
|
|
172
|
+
export async function overdueOpsAt(input: { forge: PrForge | undefined; cwd: string; member?: string; now?: Date; log: (line: string) => void }): Promise<OverdueOp[]> {
|
|
173
|
+
const { forge } = input;
|
|
174
|
+
if (!forge?.scheduledRuns) return [];
|
|
175
|
+
try {
|
|
176
|
+
const { discoverOps } = await import("./discover");
|
|
177
|
+
const discovered = await discoverOps({ cwd: input.cwd });
|
|
178
|
+
const watches = scheduledWatches([...discovered.ops.values()].map((d) => d.config));
|
|
179
|
+
if (watches.length === 0) return [];
|
|
180
|
+
const top = spawnSync("git", ["rev-parse", "--show-toplevel"], { cwd: input.cwd, encoding: "utf-8" });
|
|
181
|
+
if (top.status !== 0) return [];
|
|
182
|
+
return await checkOverdueOps({
|
|
183
|
+
watches,
|
|
184
|
+
forge,
|
|
185
|
+
repoRoot: top.stdout.trim(),
|
|
186
|
+
...(input.member ? { member: input.member } : {}),
|
|
187
|
+
now: input.now ?? new Date(),
|
|
188
|
+
log: input.log,
|
|
189
|
+
});
|
|
190
|
+
} catch (err) {
|
|
191
|
+
input.log(`could not check the scheduled Ops, so none is reported overdue: ${err instanceof Error ? err.message : String(err)}`);
|
|
192
|
+
return [];
|
|
193
|
+
}
|
|
194
|
+
}
|
package/src/op/stage-hooks.ts
CHANGED
|
@@ -290,6 +290,11 @@ export interface RunStageHooksOptions {
|
|
|
290
290
|
runsFile: string;
|
|
291
291
|
/** `CHANT_HOLD`, relative to `cwd`. */
|
|
292
292
|
holdFile: string;
|
|
293
|
+
/**
|
|
294
|
+
* Give the hooks that held on another gate in {@link StageHooksRun.otherGates}
|
|
295
|
+
* and leave them out of `holds` (#4323), for a caller that settles them.
|
|
296
|
+
*/
|
|
297
|
+
keepOtherGates?: boolean;
|
|
293
298
|
/** Added to every hook's environment. */
|
|
294
299
|
env?: Record<string, string>;
|
|
295
300
|
cwd?: string;
|
|
@@ -304,6 +309,8 @@ export interface StageHooksRun {
|
|
|
304
309
|
failed?: string;
|
|
305
310
|
/** The `onFailure: approve` hooks that failed. A hold on another gate counts as one here. */
|
|
306
311
|
holds: string[];
|
|
312
|
+
/** The hook calls that held on another gate, with `keepOtherGates` (#4323); absent otherwise. */
|
|
313
|
+
otherGates?: OtherGateHold[];
|
|
307
314
|
}
|
|
308
315
|
|
|
309
316
|
/** {@link RunStageHooksOptions} for {@link runStageHooksAsync} (#4334). */
|
|
@@ -318,7 +325,8 @@ function stagePlace(options: Omit<RunStageHooksOptions, "exec">): Omit<HookPlace
|
|
|
318
325
|
}
|
|
319
326
|
|
|
320
327
|
/** A stage run's result: a hold on another gate counts as a plain hold. */
|
|
321
|
-
function stageRun(out: HookListOutcome, name: string): StageHooksRun {
|
|
328
|
+
function stageRun(out: HookListOutcome, name: string, keep = false): StageHooksRun {
|
|
329
|
+
if (keep) return { outcomes: out.outcomes, ...(out.failed ? { failed: out.failed } : {}), holds: out.holds, otherGates: out.otherGates };
|
|
322
330
|
return { outcomes: out.outcomes, ...(out.failed ? { failed: out.failed } : {}), holds: [...out.holds, ...out.otherGates.map((g) => `${g.label} (on ${g.request.op ?? name} / ${g.request.gate})`)] };
|
|
323
331
|
}
|
|
324
332
|
|
|
@@ -326,12 +334,12 @@ function stageRun(out: HookListOutcome, name: string): StageHooksRun {
|
|
|
326
334
|
* Run one moment's hooks outside an Op waves job (#4288): the pull-request
|
|
327
335
|
* jobs, or a product's own stage, with the same `targets`, `perRun`,
|
|
328
336
|
* `onFailure` and argv filling a wave job uses. A hook that holds on another
|
|
329
|
-
* gate (`CHANT_HOLD`) is counted as a plain hold
|
|
330
|
-
* caller
|
|
337
|
+
* gate (`CHANT_HOLD`) is counted as a plain hold, unless `keepOtherGates` is
|
|
338
|
+
* set (#4323): then it comes back in `otherGates` for the caller to settle.
|
|
331
339
|
*/
|
|
332
340
|
export function runStageHooks(moment: OpWaveHookMoment, hooks: readonly OpWaveHook[] | undefined, options: RunStageHooksOptions): StageHooksRun {
|
|
333
341
|
const place = { ...stagePlace(options), exec: options.exec ?? spawnExec };
|
|
334
|
-
return stageRun(runHookList(place, moment, hooks, options.runs, options.runsFile, options.env), options.name);
|
|
342
|
+
return stageRun(runHookList(place, moment, hooks, options.runs, options.runsFile, options.env), options.name, options.keepOtherGates);
|
|
335
343
|
}
|
|
336
344
|
|
|
337
345
|
/**
|
|
@@ -342,5 +350,5 @@ export function runStageHooks(moment: OpWaveHookMoment, hooks: readonly OpWaveHo
|
|
|
342
350
|
*/
|
|
343
351
|
export async function runStageHooksAsync(moment: OpWaveHookMoment, hooks: readonly OpWaveHook[] | undefined, options: RunStageHooksAsyncOptions): Promise<StageHooksRun> {
|
|
344
352
|
const place = { ...stagePlace(options), exec: options.exec ?? spawnExecAsync };
|
|
345
|
-
return stageRun(await runHookListAsync(place, moment, hooks, options.runs, options.runsFile, options.env), options.name);
|
|
353
|
+
return stageRun(await runHookListAsync(place, moment, hooks, options.runs, options.runsFile, options.env), options.name, options.keepOtherGates);
|
|
346
354
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How a member's `chant run` learns that `chant workspace run` started it
|
|
3
|
+
* (#2554, #2524 D17). The workspace run sets these in the environment of the
|
|
4
|
+
* member's chant; the member's run record cites the workspace run, and a
|
|
5
|
+
* member gate may then ask the named workspace gate to stand in for it.
|
|
6
|
+
*
|
|
7
|
+
* Kept apart from the workspace code so the executor reads two environment
|
|
8
|
+
* variables and nothing more when no workspace run started it.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/** The workspace run's id. */
|
|
12
|
+
export const WORKSPACE_RUN_ENV = "CHANT_WORKSPACE_RUN";
|
|
13
|
+
/** The workspace gate the run was started under, when one was named. */
|
|
14
|
+
export const WORKSPACE_GATE_ENV = "CHANT_WORKSPACE_GATE";
|
|
15
|
+
|
|
16
|
+
/** What a run started by a workspace run knows about it. */
|
|
17
|
+
export interface WorkspaceRunCitation {
|
|
18
|
+
id: string;
|
|
19
|
+
/** The workspace gate the run was started under (`chant workspace run --gate`), when one was named. */
|
|
20
|
+
gate?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** The workspace run this process runs under, or undefined. */
|
|
24
|
+
export function resolveWorkspaceRun(env: NodeJS.ProcessEnv = process.env): WorkspaceRunCitation | undefined {
|
|
25
|
+
const id = env[WORKSPACE_RUN_ENV]?.trim();
|
|
26
|
+
if (!id) return undefined;
|
|
27
|
+
const gate = env[WORKSPACE_GATE_ENV]?.trim();
|
|
28
|
+
return { id, ...(gate ? { gate } : {}) };
|
|
29
|
+
}
|
|
@@ -34,7 +34,7 @@ describe("the pr-forge bundle", () => {
|
|
|
34
34
|
expect(inputs.filter((i) => pattern.test(i)), String(pattern)).toEqual([]);
|
|
35
35
|
}
|
|
36
36
|
expect(inputs.map((i) => i.replace(/^.*?packages\//, "packages/")).sort()).toEqual(["packages/core/src/pr-forge.ts"]);
|
|
37
|
-
// About
|
|
38
|
-
expect(result.outputFiles.reduce((n, f) => n + f.contents.byteLength, 0)).toBeLessThan(
|
|
37
|
+
// About 52 KB today, after the pull request authors (#4000), pullRequestOpen for target locks (#4293), the four requires checks of an apply before merge (#4301) the approver filter (#4337) the approved fields (#4287) and the plan job's GitLab note (#4328).
|
|
38
|
+
expect(result.outputFiles.reduce((n, f) => n + f.contents.byteLength, 0)).toBeLessThan(56 * 1024);
|
|
39
39
|
});
|
|
40
40
|
});
|
package/src/pr-forge.test.ts
CHANGED
|
@@ -321,6 +321,53 @@ describe("gitlab", () => {
|
|
|
321
321
|
expect(await forge.pullRequestOpen!(5)).toBe(true);
|
|
322
322
|
expect(await forge.pullRequestOpen!(6)).toBe(false);
|
|
323
323
|
});
|
|
324
|
+
|
|
325
|
+
test("the plan job of each open merge request's newest pipeline at its head, in this project (#4328)", async () => {
|
|
326
|
+
const OLD = "b".repeat(40);
|
|
327
|
+
const { fetch, calls } = fakeFetch({
|
|
328
|
+
"GET /api/v4/projects/42/merge_requests": [
|
|
329
|
+
{ iid: 9, sha: SHA, project_id: 42 },
|
|
330
|
+
{ iid: 5, sha: SHA, project_id: 42 },
|
|
331
|
+
{ iid: 6, sha: OLD, project_id: 42 },
|
|
332
|
+
],
|
|
333
|
+
// Newest at the head first is 301; 300 is an older pipeline of the same head; 299 is of an older head.
|
|
334
|
+
"GET /api/v4/projects/42/merge_requests/5/pipelines": [
|
|
335
|
+
{ id: 299, sha: OLD, project_id: 42 },
|
|
336
|
+
{ id: 301, sha: SHA, project_id: 42 },
|
|
337
|
+
{ id: 300, sha: SHA, project_id: 42 },
|
|
338
|
+
],
|
|
339
|
+
"GET /api/v4/projects/42/pipelines/301/jobs": [
|
|
340
|
+
{ id: 11, name: "plan", status: "success", web_url: "https://gitlab.example.com/acme/estate/-/jobs/11" },
|
|
341
|
+
{ id: 12, name: "network-plan", status: "running" },
|
|
342
|
+
],
|
|
343
|
+
// A fork's merge request whose pipeline ran in the fork: its jobs are not this project's.
|
|
344
|
+
"GET /api/v4/projects/42/merge_requests/6/pipelines": [{ id: 400, sha: OLD, project_id: 77 }],
|
|
345
|
+
// A merge request with no pipeline yet.
|
|
346
|
+
"GET /api/v4/projects/42/merge_requests/9/pipelines": [],
|
|
347
|
+
});
|
|
348
|
+
const forge = gitlabForge({ ...opts, fetch });
|
|
349
|
+
expect(await forge.mergeRequestJobs!("main", "plan")).toEqual([{ pr: 5, head: SHA, id: 11, status: "success", url: "https://gitlab.example.com/acme/estate/-/jobs/11" }]);
|
|
350
|
+
expect(new URL(calls[0]!.url).searchParams.get("target_branch")).toBe("main");
|
|
351
|
+
expect(new URL(calls[0]!.url).searchParams.get("state")).toBe("opened");
|
|
352
|
+
expect(calls.some((c) => c.url.includes("/pipelines/400/"))).toBe(false);
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
test("one file of a job's artifacts, undefined when the job kept none there, and the newest status's link (#4328)", async () => {
|
|
356
|
+
const { fetch, calls } = fakeFetch({
|
|
357
|
+
"GET /api/v4/projects/42/jobs/11/artifacts/infra/network/.chant/pr/pr-plan.json": { stage: "plan" },
|
|
358
|
+
[`GET /api/v4/projects/42/repository/commits/${SHA}/statuses`]: [
|
|
359
|
+
{ id: 1, name: "chant/plan", target_url: "https://gitlab.example.com/-/jobs/10" },
|
|
360
|
+
{ id: 3, name: "chant/plan", target_url: "https://gitlab.example.com/-/jobs/11" },
|
|
361
|
+
{ id: 4, name: "chant/plan/network", target_url: "https://gitlab.example.com/-/jobs/12" },
|
|
362
|
+
],
|
|
363
|
+
});
|
|
364
|
+
const forge = gitlabForge({ ...opts, fetch });
|
|
365
|
+
expect(JSON.parse((await forge.jobArtifact!(11, "infra/network/.chant/pr/pr-plan.json"))!)).toEqual({ stage: "plan" });
|
|
366
|
+
expect(await forge.jobArtifact!(12, ".chant/pr/pr-plan.json")).toBeUndefined();
|
|
367
|
+
expect(calls[0]!.headers["PRIVATE-TOKEN"]).toBe("glpat");
|
|
368
|
+
expect(await forge.statusUrl!(SHA, "chant/plan")).toBe("https://gitlab.example.com/-/jobs/11");
|
|
369
|
+
expect(await forge.statusUrl!(SHA, "chant/plan/other")).toBeUndefined();
|
|
370
|
+
});
|
|
324
371
|
});
|
|
325
372
|
|
|
326
373
|
describe("naming reviewers", () => {
|
package/src/pr-forge.ts
CHANGED
|
@@ -223,6 +223,20 @@ export interface PullRequest {
|
|
|
223
223
|
}
|
|
224
224
|
|
|
225
225
|
/** An open pull request as `chant ci serve` polls it (#4095). */
|
|
226
|
+
/** A merge request's job in its newest pipeline at its head (#4328), as {@link PrForge.mergeRequestJobs} finds it. */
|
|
227
|
+
export interface MergeRequestJob {
|
|
228
|
+
/** The merge request's iid. */
|
|
229
|
+
pr: number;
|
|
230
|
+
/** The merge request's head commit, as GitLab says it. */
|
|
231
|
+
head: string;
|
|
232
|
+
/** The job's id, which {@link PrForge.jobArtifact} reads its artifacts by. */
|
|
233
|
+
id: number;
|
|
234
|
+
/** GitLab's word for the job: `success`, `failed` and `canceled` are settled, any other is not. */
|
|
235
|
+
status: string;
|
|
236
|
+
/** The job's page. */
|
|
237
|
+
url?: string;
|
|
238
|
+
}
|
|
239
|
+
|
|
226
240
|
export interface OpenPullRequest {
|
|
227
241
|
number: number;
|
|
228
242
|
/** Its head branch. */
|
|
@@ -440,6 +454,17 @@ export interface PrForge {
|
|
|
440
454
|
* Pending while one still runs or none has reported.
|
|
441
455
|
*/
|
|
442
456
|
prChecksPassed?(pr: number, head: string, ignore?: readonly string[]): Promise<PrRequireResult>;
|
|
457
|
+
/**
|
|
458
|
+
* GitLab (#4328): each open merge request into `branch` whose newest
|
|
459
|
+
* pipeline at its head commit, in this project, ran a job named `job`,
|
|
460
|
+
* with that job. A merge request whose pipeline runs in a fork's project
|
|
461
|
+
* is left out, since its jobs and artifacts are the fork's. Oldest first.
|
|
462
|
+
*/
|
|
463
|
+
mergeRequestJobs?(branch: string, job: string): Promise<MergeRequestJob[]>;
|
|
464
|
+
/** GitLab (#4328): the text of the file at `path` in job `id`'s artifacts, or undefined when it has none there. */
|
|
465
|
+
jobArtifact?(id: number, path: string): Promise<string | undefined>;
|
|
466
|
+
/** GitLab (#4328): the target URL of the newest commit status named `context` on `sha`, or undefined when there is none or it has no URL. */
|
|
467
|
+
statusUrl?(sha: string, context: string): Promise<string | undefined>;
|
|
443
468
|
}
|
|
444
469
|
|
|
445
470
|
/**
|
|
@@ -596,6 +621,8 @@ export function forgePrincipalOf(kind: ForgeKind, host: string, login: string):
|
|
|
596
621
|
|
|
597
622
|
interface Transport {
|
|
598
623
|
call(method: string, path: string, body?: unknown): Promise<unknown>;
|
|
624
|
+
/** A GET whose body is returned as text, not parsed; undefined on a 404. */
|
|
625
|
+
text(path: string): Promise<string | undefined>;
|
|
599
626
|
/** Every page of a list, `pageParams(page)` appended to `path`. */
|
|
600
627
|
list(path: string, pageParams: (page: number) => string, pageSize: number): Promise<unknown[]>;
|
|
601
628
|
}
|
|
@@ -615,6 +642,14 @@ function transport(base: string, headers: Record<string, string>, fetchImpl: For
|
|
|
615
642
|
};
|
|
616
643
|
return {
|
|
617
644
|
call,
|
|
645
|
+
async text(path) {
|
|
646
|
+
const url = `${root}${path}`;
|
|
647
|
+
const res = await fetchImpl(url, { method: "GET", headers });
|
|
648
|
+
const body = await res.text();
|
|
649
|
+
if (res.status === 404) return undefined;
|
|
650
|
+
if (!res.ok) throw new ForgeApiError("GET", url, res.status, body);
|
|
651
|
+
return body;
|
|
652
|
+
},
|
|
618
653
|
async list(path, pageParams, pageSize) {
|
|
619
654
|
const out: unknown[] = [];
|
|
620
655
|
for (let page = 1; page <= 50; page++) {
|
|
@@ -1414,6 +1449,39 @@ export function gitlabForge(opts: GitlabForgeOptions): PrForge {
|
|
|
1414
1449
|
const last = newestTime(pipelines.map((p) => (isObject(p) ? str(p.created_at) : undefined)));
|
|
1415
1450
|
return { ...(last ? { last } : {}), ...(ours.length === 0 ? { noSchedule: true } : {}) };
|
|
1416
1451
|
},
|
|
1452
|
+
async mergeRequestJobs(branch, job) {
|
|
1453
|
+
const out: MergeRequestJob[] = [];
|
|
1454
|
+
const open = await api.list(`${notes}?state=opened&target_branch=${encodeURIComponent(branch)}`, pageParams, 100);
|
|
1455
|
+
for (const m of open) {
|
|
1456
|
+
if (!isObject(m)) continue;
|
|
1457
|
+
const iid = num(m.iid);
|
|
1458
|
+
const head = str(m.sha);
|
|
1459
|
+
const own = num(m.project_id);
|
|
1460
|
+
if (iid === undefined || !head) continue;
|
|
1461
|
+
// Newest first; only this project's pipelines at the head count.
|
|
1462
|
+
const pipelines = (await api.list(`${notes}/${iid}/pipelines`, pageParams, 100))
|
|
1463
|
+
.filter((p): p is Record<string, unknown> => isObject(p) && p.sha === head && (own === undefined || num(p.project_id) === undefined || num(p.project_id) === own))
|
|
1464
|
+
.sort((a, b) => (num(b.id) ?? 0) - (num(a.id) ?? 0));
|
|
1465
|
+
const newest = pipelines[0];
|
|
1466
|
+
const pid = newest ? num(newest.id) : undefined;
|
|
1467
|
+
if (pid === undefined) continue;
|
|
1468
|
+
const jobs = await api.list(`${project}/pipelines/${pid}/jobs`, pageParams, 100);
|
|
1469
|
+
const found = jobs.filter((j): j is Record<string, unknown> => isObject(j) && j.name === job).sort((a, b) => (num(b.id) ?? 0) - (num(a.id) ?? 0))[0];
|
|
1470
|
+
const id = found ? num(found.id) : undefined;
|
|
1471
|
+
if (!found || id === undefined) continue;
|
|
1472
|
+
const url = str(found.web_url);
|
|
1473
|
+
out.push({ pr: iid, head, id, status: str(found.status) ?? "unknown", ...(url ? { url } : {}) });
|
|
1474
|
+
}
|
|
1475
|
+
return out.sort((a, b) => a.pr - b.pr);
|
|
1476
|
+
},
|
|
1477
|
+
async jobArtifact(id, path) {
|
|
1478
|
+
return api.text(`${project}/jobs/${id}/artifacts/${path.split("/").map(encodeURIComponent).join("/")}`);
|
|
1479
|
+
},
|
|
1480
|
+
async statusUrl(sha, context) {
|
|
1481
|
+
const statuses = await api.list(`${project}/repository/commits/${sha}/statuses?all=true&name=${encodeURIComponent(context)}`, pageParams, 100);
|
|
1482
|
+
const newest = statuses.filter((st): st is Record<string, unknown> => isObject(st) && st.name === context).sort((a, b) => (num(b.id) ?? 0) - (num(a.id) ?? 0))[0];
|
|
1483
|
+
return newest ? (str(newest.target_url) ?? undefined) : undefined;
|
|
1484
|
+
},
|
|
1417
1485
|
async editPullRequest(mr, change) {
|
|
1418
1486
|
return mergeRequest(await api.call("PUT", `${notes}/${mr}`, { ...(change.title !== undefined ? { title: change.title } : {}), ...(change.body !== undefined ? { description: change.body } : {}) }));
|
|
1419
1487
|
},
|
|
@@ -40,8 +40,9 @@ describe("the pull-request loop bundle", () => {
|
|
|
40
40
|
"packages/core/src/plan-summary.ts",
|
|
41
41
|
"packages/core/src/pr-forge.ts",
|
|
42
42
|
"packages/core/src/pr-loop.ts",
|
|
43
|
+
"packages/core/src/pr-migrations.ts",
|
|
43
44
|
]);
|
|
44
|
-
// About 89 KB today, after the hooks line (#4288), the blocked set (#4291), the scheduled-run reads (#4289)
|
|
45
|
-
expect(result.outputFiles.reduce((n, f) => n + f.contents.byteLength, 0)).toBeLessThan(
|
|
45
|
+
// About 89 KB today, after the hooks line (#4288), the blocked set (#4291), the scheduled-run reads (#4289) the requires checks (#4301) and the migration notes (#4407), about 97 KB.
|
|
46
|
+
expect(result.outputFiles.reduce((n, f) => n + f.contents.byteLength, 0)).toBeLessThan(100 * 1024);
|
|
46
47
|
});
|
|
47
48
|
});
|
package/src/pr-loop.test.ts
CHANGED
|
@@ -424,3 +424,55 @@ describe("the policy in the report and the note (#4294)", () => {
|
|
|
424
424
|
expect(prStatusDescription({ ...denied, stage: "apply", status: "refused", refusal: "policy-denied" })).toBe("refused: the policy denied the plan (main.deny_public)");
|
|
425
425
|
});
|
|
426
426
|
});
|
|
427
|
+
|
|
428
|
+
describe("new migration files in the plan note (#4407)", () => {
|
|
429
|
+
const migrations: NonNullable<PrReport["migrations"]> = [
|
|
430
|
+
{
|
|
431
|
+
member: "ledger",
|
|
432
|
+
reader: "goose-dir",
|
|
433
|
+
file: "db/00002_index.sql",
|
|
434
|
+
version: "00002",
|
|
435
|
+
name: "index",
|
|
436
|
+
type: "versioned",
|
|
437
|
+
dialect: "postgres",
|
|
438
|
+
statements: [
|
|
439
|
+
{
|
|
440
|
+
index: 1,
|
|
441
|
+
sql: "CREATE INDEX orders_status_idx ON orders (status)",
|
|
442
|
+
outcome: "classified",
|
|
443
|
+
changes: [{ rule: "SQLPG241", class: "concurrently", label: "needs CONCURRENTLY", title: "Create an index without CONCURRENTLY", lock: "SHARE" }],
|
|
444
|
+
},
|
|
445
|
+
{
|
|
446
|
+
index: 2,
|
|
447
|
+
sql: "ALTER TABLE orders ALTER COLUMN a TYPE bigint",
|
|
448
|
+
outcome: "undecided",
|
|
449
|
+
changes: [],
|
|
450
|
+
candidates: [
|
|
451
|
+
{ rule: "SQLPG206", class: "metadata", label: "metadata only", title: "t" },
|
|
452
|
+
{ rule: "SQLPG207", class: "rewrite", label: "ACCESS EXCLUSIVE rewrite or scan", title: "t" },
|
|
453
|
+
],
|
|
454
|
+
note: "x",
|
|
455
|
+
},
|
|
456
|
+
],
|
|
457
|
+
},
|
|
458
|
+
];
|
|
459
|
+
const withMigrations: PrReport = { ...planReport, migrations };
|
|
460
|
+
|
|
461
|
+
test("the report validates and the note lists each statement with its class, rule and lock", () => {
|
|
462
|
+
expectValid(withMigrations);
|
|
463
|
+
const note = renderPrNote(withMigrations);
|
|
464
|
+
expect(note).toContain("New migration files (1), classified offline. Nothing is applied and no server is contacted.");
|
|
465
|
+
expect(note).toContain("`db/00002_index.sql` (member `ledger`, postgres)");
|
|
466
|
+
expect(note).toContain("- 1. `CREATE INDEX orders_status_idx ON orders (status)`: needs CONCURRENTLY (SQLPG241, SHARE)");
|
|
467
|
+
expect(note).toContain("undecided between SQLPG206 metadata only and SQLPG207 ACCESS EXCLUSIVE rewrite or scan");
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
test("a report with none renders as before", () => {
|
|
471
|
+
expect(renderPrNote(planReport)).not.toContain("migration");
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
test("a note line cannot be broken out of by a file's text", () => {
|
|
475
|
+
const note = renderPrNote({ ...withMigrations, migrations: [{ ...migrations[0]!, statements: [], error: "bad\n\n# heading `x`" }] });
|
|
476
|
+
expect(note).toContain("- not read: bad # heading `x`");
|
|
477
|
+
});
|
|
478
|
+
});
|