@intentius/chant 0.124.46 → 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/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 +21 -2
- package/dist/cli/handlers/build.d.ts.map +1 -1
- package/dist/cli/handlers/build.js +6 -1
- 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 +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.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 +65 -14
- package/dist/cli/parse-args.d.ts.map +1 -1
- package/dist/cli/parse-args.js +36 -2
- package/dist/cli/registry.d.ts +14 -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/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 +9 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +6 -2
- 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-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 +71 -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 +5 -2
- 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 +263 -254
- 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 +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 +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-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/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/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.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/reason-codes.d.ts +8 -0
- package/dist/workspace/reason-codes.d.ts.map +1 -1
- package/dist/workspace/reason-codes.js +11 -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 +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/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 +23 -2
- package/src/cli/handlers/build.ts +7 -1
- 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 +138 -36
- 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 +15 -0
- package/src/cli/main.ts +65 -14
- package/src/cli/parse-args.ts +27 -2
- package/src/cli/registry.ts +14 -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-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 +28 -1
- package/src/config.ts +8 -1
- 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-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 +74 -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.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/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 +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 +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-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 +14 -2
- package/src/workspace/intent.ts +6 -14
- package/src/workspace/kind-link-readers.ts +68 -3
- 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 +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/org-scope.test.ts +238 -0
- package/src/workspace/reason-codes.test.ts +6 -1
- package/src/workspace/reason-codes.ts +11 -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 +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
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, writeFileSync, readFileSync, readdirSync } from "fs";
|
|
2
2
|
import { join, resolve, basename, dirname } from "path";
|
|
3
3
|
import { formatSuccess, formatWarning, formatError } from "../format";
|
|
4
|
-
import type { TemplateIR, ResourceIR, ParameterIR, ParseContext } from "../../import/parser";
|
|
4
|
+
import type { TemplateIR, ResourceIR, ParameterIR, ParseContext, ImportDiagnostic } from "../../import/parser";
|
|
5
5
|
import type { GeneratedFile, TypeScriptGenerator } from "../../import/generator";
|
|
6
6
|
import { listInstalledLexicons, loadPlugin, loadPlugins, resolveProjectLexicons } from "../plugins";
|
|
7
7
|
import type { ExportedTemplate, LexiconPlugin, ResourceSelector } from "../../lexicon";
|
|
8
8
|
import { parseYAMLDocument, splitYAMLDocuments } from "../../yaml";
|
|
9
9
|
import { importLexiconPackage } from "../../lexicon-module";
|
|
10
10
|
import { resolveParserOptions } from "../../import/parser-options";
|
|
11
|
+
import { summarizeImportDiagnostics } from "./import-report";
|
|
11
12
|
import { EmbeddedImports, type EmbeddedContent, type RegisteredEmbeddedImporter } from "../../import/embedded";
|
|
12
13
|
|
|
13
14
|
/**
|
|
@@ -31,6 +32,8 @@ export interface ImportOptions {
|
|
|
31
32
|
* fails the import before anything is parsed.
|
|
32
33
|
*/
|
|
33
34
|
parserOptions?: string[];
|
|
35
|
+
/** `--validate` (#4398): check the parsed template on the lexicon's emulator before writing. */
|
|
36
|
+
validate?: boolean;
|
|
34
37
|
}
|
|
35
38
|
|
|
36
39
|
/**
|
|
@@ -52,6 +55,12 @@ export interface ImportResult {
|
|
|
52
55
|
* it was named (`--lexicon`, `--kustomize`) (#2965).
|
|
53
56
|
*/
|
|
54
57
|
detected?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* What the parser flagged for review (#4398), then what `--validate`
|
|
60
|
+
* rejected. `--report` writes them as SARIF and `--strict` fails while a
|
|
61
|
+
* `warning` or `error` is open; see `./import-report.ts`.
|
|
62
|
+
*/
|
|
63
|
+
diagnostics?: ImportDiagnostic[];
|
|
55
64
|
}
|
|
56
65
|
|
|
57
66
|
/**
|
|
@@ -353,6 +362,7 @@ export async function importCommand(options: ImportOptions): Promise<ImportResul
|
|
|
353
362
|
output: options.output,
|
|
354
363
|
force: options.force,
|
|
355
364
|
parserOptions: options.parserOptions,
|
|
365
|
+
validate: options.validate,
|
|
356
366
|
});
|
|
357
367
|
}
|
|
358
368
|
|
|
@@ -391,7 +401,7 @@ export async function importCommand(options: ImportOptions): Promise<ImportResul
|
|
|
391
401
|
);
|
|
392
402
|
}
|
|
393
403
|
|
|
394
|
-
const result = await parseAndWrite(plugin, content, outputDir, options.force, warnings, generatedFiles, plugin.name, projectDir, options.parserOptions);
|
|
404
|
+
const result = await parseAndWrite(plugin, content, outputDir, options.force, warnings, generatedFiles, plugin.name, projectDir, options.parserOptions, options.validate);
|
|
395
405
|
return { ...result, detected: true };
|
|
396
406
|
}
|
|
397
407
|
|
|
@@ -412,6 +422,8 @@ export interface ContentImportOptions {
|
|
|
412
422
|
force?: boolean;
|
|
413
423
|
/** `--parser-option` entries for the lexicon's parser (#2994); see {@link ImportOptions.parserOptions}. */
|
|
414
424
|
parserOptions?: string[];
|
|
425
|
+
/** `--validate`; see {@link ImportOptions.validate}. */
|
|
426
|
+
validate?: boolean;
|
|
415
427
|
}
|
|
416
428
|
|
|
417
429
|
export async function importFromContent(options: ContentImportOptions): Promise<ImportResult> {
|
|
@@ -432,7 +444,7 @@ export async function importFromContent(options: ContentImportOptions): Promise<
|
|
|
432
444
|
return { success: false, generatedFiles: [], warnings: [], error: `Lexicon "${options.lexicon}" not available.` };
|
|
433
445
|
}
|
|
434
446
|
const projectDir = resolve(options.output ? dirname(options.output) : ".");
|
|
435
|
-
return parseAndWrite(plugin, options.content, outputDir, options.force, [], [], plugin.name, projectDir, options.parserOptions);
|
|
447
|
+
return parseAndWrite(plugin, options.content, outputDir, options.force, [], [], plugin.name, projectDir, options.parserOptions, options.validate);
|
|
436
448
|
}
|
|
437
449
|
|
|
438
450
|
/**
|
|
@@ -568,6 +580,7 @@ async function parseAndWrite(
|
|
|
568
580
|
lexicon: string,
|
|
569
581
|
projectDir: string,
|
|
570
582
|
parserOptionEntries?: readonly string[],
|
|
583
|
+
validate?: boolean,
|
|
571
584
|
): Promise<ImportResult> {
|
|
572
585
|
// A lexicon can recognize a template (detectTemplate) without being able to
|
|
573
586
|
// import it (grafana had no parser until #2945). Every path funnels through here, so
|
|
@@ -609,6 +622,18 @@ async function parseAndWrite(
|
|
|
609
622
|
if (ir.warnings) {
|
|
610
623
|
warnings.push(...ir.warnings);
|
|
611
624
|
}
|
|
625
|
+
// Findings for review (#4398), and what the lexicon's emulator rejects.
|
|
626
|
+
const diagnostics: ImportDiagnostic[] = [...(ir.diagnostics ?? [])];
|
|
627
|
+
if (validate) {
|
|
628
|
+
if (!plugin.validateImport) {
|
|
629
|
+
return { success: false, generatedFiles: [], warnings: [], error: `lexicon "${plugin.name}" has no emulator to validate an import against`, lexicon: plugin.name };
|
|
630
|
+
}
|
|
631
|
+
try {
|
|
632
|
+
diagnostics.push(...(await plugin.validateImport(ir, resolved.options)));
|
|
633
|
+
} catch (err) {
|
|
634
|
+
return { success: false, generatedFiles: [], warnings: [], error: `--validate failed to run: ${err instanceof Error ? err.message : String(err)}`, lexicon: plugin.name };
|
|
635
|
+
}
|
|
636
|
+
}
|
|
612
637
|
// Embedded content the owner could not carry, or that no installed lexicon imports.
|
|
613
638
|
if (embedded) warnings.push(...embedded.warnings);
|
|
614
639
|
|
|
@@ -660,6 +685,7 @@ async function parseAndWrite(
|
|
|
660
685
|
generatedFiles,
|
|
661
686
|
warnings,
|
|
662
687
|
lexicon,
|
|
688
|
+
...(diagnostics.length > 0 ? { diagnostics } : {}),
|
|
663
689
|
};
|
|
664
690
|
}
|
|
665
691
|
|
|
@@ -894,6 +920,10 @@ export function printImportResult(result: ImportResult): void {
|
|
|
894
920
|
console.log(`${result.detected ? "Detected lexicon" : "Lexicon"}: ${result.lexicon}`);
|
|
895
921
|
}
|
|
896
922
|
|
|
923
|
+
if (result.diagnostics && result.diagnostics.length > 0) {
|
|
924
|
+
console.error(summarizeImportDiagnostics(result.diagnostics));
|
|
925
|
+
}
|
|
926
|
+
|
|
897
927
|
if (result.generatedFiles.length > 0) {
|
|
898
928
|
console.log(formatSuccess("Generated files:"));
|
|
899
929
|
for (const file of result.generatedFiles) {
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `chant migrate` naming and the target-server `--validate` (#4399): a side is
|
|
3
|
+
* `lexicon` or `lexicon/dialect`, a directory is a source only when the
|
|
4
|
+
* lexicon says so, and a result's own `validate` replaces the external linter.
|
|
5
|
+
*/
|
|
6
|
+
import { afterEach, beforeEach, describe, expect, test } from "vitest";
|
|
7
|
+
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
8
|
+
import { tmpdir } from "node:os";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
import { lexiconOfSide, migrateCommand } from "./migrate";
|
|
11
|
+
import type { LexiconPlugin, MigrationResult, MigrationSource } from "../../lexicon";
|
|
12
|
+
|
|
13
|
+
const seen: Array<{ from: string; to: string | undefined }> = [];
|
|
14
|
+
|
|
15
|
+
function sqlPlugin(over: { directory?: boolean; result?: Partial<MigrationResult>; transform?: MigrationSource["transform"] } = {}): LexiconPlugin {
|
|
16
|
+
return {
|
|
17
|
+
name: "sql",
|
|
18
|
+
serializer: { name: "sql", rulePrefix: "SQL", serialize: () => "" },
|
|
19
|
+
async generate() {},
|
|
20
|
+
async validate() {},
|
|
21
|
+
async coverage() {},
|
|
22
|
+
async package() {},
|
|
23
|
+
migrationSource(from: string, to?: string) {
|
|
24
|
+
seen.push({ from, to });
|
|
25
|
+
if (from !== "sql/postgres" || (to !== undefined && to !== "sql/clickhouse")) return undefined;
|
|
26
|
+
return {
|
|
27
|
+
detect: (content: string) => content.includes("CREATE TABLE"),
|
|
28
|
+
...(over.directory ? { directory: true } : {}),
|
|
29
|
+
transform: over.transform ?? (async () => ({ output: "-- ddl\n", provenance: [], diagnostics: [], ...over.result })),
|
|
30
|
+
};
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const base = { emit: "sql" as const, strict: false, validate: false, useComposites: false };
|
|
36
|
+
|
|
37
|
+
describe("lexiconOfSide", () => {
|
|
38
|
+
test("is the part before the slash", () => {
|
|
39
|
+
expect(lexiconOfSide("sql/clickhouse")).toBe("sql");
|
|
40
|
+
expect(lexiconOfSide("gitlab")).toBe("gitlab");
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe("migrateCommand with lexicon/dialect sides", () => {
|
|
45
|
+
let dir: string;
|
|
46
|
+
beforeEach(() => {
|
|
47
|
+
dir = mkdtempSync(join(tmpdir(), "chant-migrate-dialect-"));
|
|
48
|
+
seen.length = 0;
|
|
49
|
+
});
|
|
50
|
+
afterEach(() => rmSync(dir, { recursive: true, force: true }));
|
|
51
|
+
const file = () => {
|
|
52
|
+
const f = join(dir, "schema.sql");
|
|
53
|
+
writeFileSync(f, "CREATE TABLE t (id int);");
|
|
54
|
+
return f;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
test("finds the plugin by the lexicon part, and hands the source both sides as written", async () => {
|
|
58
|
+
const r = await migrateCommand({ ...base, sourceFile: file(), from: "sql/postgres", to: "sql/clickhouse", output: join(dir, "out.sql"), plugins: [sqlPlugin()] });
|
|
59
|
+
expect(r.exitCode).toBe(0);
|
|
60
|
+
expect(seen).toEqual([{ from: "sql/postgres", to: "sql/clickhouse" }]);
|
|
61
|
+
expect(readFileSync(join(dir, "out.sql"), "utf8")).toBe("-- ddl\n");
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("a dialect the lexicon does not know is refused by name", async () => {
|
|
65
|
+
const r = await migrateCommand({ ...base, sourceFile: file(), from: "sql/postgres", to: "sql/mysql", plugins: [sqlPlugin()] });
|
|
66
|
+
expect(r.exitCode).toBe(1);
|
|
67
|
+
expect(r.error).toContain('Lexicon "sql/mysql" does not support migration from "sql/postgres"');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test("creates the output's directory", async () => {
|
|
71
|
+
const out = join(dir, "a/b/out.sql");
|
|
72
|
+
const r = await migrateCommand({ ...base, sourceFile: file(), from: "sql/postgres", to: "sql/clickhouse", output: out, plugins: [sqlPlugin()] });
|
|
73
|
+
expect(r.exitCode).toBe(0);
|
|
74
|
+
expect(readFileSync(out, "utf8")).toBe("-- ddl\n");
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("a directory is refused unless the source reads directories; then detect is skipped and content is empty", async () => {
|
|
78
|
+
const member = join(dir, "db");
|
|
79
|
+
mkdirSync(member);
|
|
80
|
+
const refused = await migrateCommand({ ...base, sourceFile: member, from: "sql/postgres", to: "sql/clickhouse", plugins: [sqlPlugin()] });
|
|
81
|
+
expect(refused.exitCode).toBe(1);
|
|
82
|
+
expect(refused.error).toContain("is a directory");
|
|
83
|
+
let got: { content: string; sourceFile?: string } | undefined;
|
|
84
|
+
const ok = await migrateCommand({
|
|
85
|
+
...base,
|
|
86
|
+
sourceFile: member,
|
|
87
|
+
from: "sql/postgres",
|
|
88
|
+
to: "sql/clickhouse",
|
|
89
|
+
output: join(dir, "o.sql"),
|
|
90
|
+
plugins: [sqlPlugin({ directory: true, transform: async (content, opts) => ((got = { content, sourceFile: opts.sourceFile }), { output: "x", provenance: [], diagnostics: [] }) })],
|
|
91
|
+
});
|
|
92
|
+
expect(ok.exitCode).toBe(0);
|
|
93
|
+
expect(got).toEqual({ content: "", sourceFile: member });
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
describe("--validate with a result that checks itself", () => {
|
|
98
|
+
let dir: string;
|
|
99
|
+
beforeEach(() => {
|
|
100
|
+
dir = mkdtempSync(join(tmpdir(), "chant-migrate-validate-"));
|
|
101
|
+
});
|
|
102
|
+
afterEach(() => rmSync(dir, { recursive: true, force: true }));
|
|
103
|
+
const run = (result: Partial<MigrationResult>, extra: { strict?: boolean } = {}) => {
|
|
104
|
+
const f = join(dir, "schema.sql");
|
|
105
|
+
writeFileSync(f, "CREATE TABLE t (id int);");
|
|
106
|
+
return migrateCommand({ ...base, ...extra, validate: true, sourceFile: f, from: "sql/postgres", to: "sql/clickhouse", output: join(dir, "o.sql"), plugins: [sqlPlugin({ result })] });
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
test("a clean check passes and its diagnostics join the result", async () => {
|
|
110
|
+
const r = await run({ validate: async () => [] });
|
|
111
|
+
expect(r.exitCode).toBe(0);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test("a refused statement fails the run without --strict, and is in the diagnostics", async () => {
|
|
115
|
+
const r = await run({ validate: async () => [{ ruleId: "SQLRV012", severity: "error", message: "t: the emulator rejected the statement." }] });
|
|
116
|
+
expect(r.exitCode).toBe(1);
|
|
117
|
+
expect(r.diagnostics.map((d) => d.ruleId)).toEqual(["SQLRV012"]);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test("a server that cannot start is a validation that did not run, which fails", async () => {
|
|
121
|
+
const r = await run({
|
|
122
|
+
validate: async () => {
|
|
123
|
+
throw new Error("Docker is not available, so the ClickHouse emulator cannot start");
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
expect(r.exitCode).toBe(1);
|
|
127
|
+
expect(r.error).toContain("--validate did not run: Docker is not available");
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test("without --validate the check is not run", async () => {
|
|
131
|
+
let ran = false;
|
|
132
|
+
const f = join(dir, "schema.sql");
|
|
133
|
+
writeFileSync(f, "CREATE TABLE t (id int);");
|
|
134
|
+
const r = await migrateCommand({
|
|
135
|
+
...base,
|
|
136
|
+
sourceFile: f,
|
|
137
|
+
from: "sql/postgres",
|
|
138
|
+
to: "sql/clickhouse",
|
|
139
|
+
output: join(dir, "o.sql"),
|
|
140
|
+
plugins: [sqlPlugin({ result: { validate: async () => ((ran = true), []) } })],
|
|
141
|
+
});
|
|
142
|
+
expect(r.exitCode).toBe(0);
|
|
143
|
+
expect(ran).toBe(false);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
@@ -6,19 +6,30 @@
|
|
|
6
6
|
* stdout/stderr surfaces, and exit codes.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { readFileSync, writeFileSync } from "node:fs";
|
|
9
|
+
import { mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
10
|
+
import { dirname } from "node:path";
|
|
10
11
|
import { spawnSync } from "node:child_process";
|
|
11
12
|
import { formatError, formatInfo } from "../format";
|
|
12
13
|
import { formatSarif } from "../reporters/stylish";
|
|
13
14
|
import type { LexiconPlugin } from "../../lexicon";
|
|
14
15
|
import type { LintRule, LintDiagnostic } from "../../lint/rule";
|
|
15
16
|
import { ensureTypeScriptLoader } from "../../ts-loader";
|
|
17
|
+
import { planMigrateLinks } from "../../workspace/migrate-links";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* A side of `--from` or `--to`: a lexicon, or a lexicon and one of its
|
|
21
|
+
* dialects, `sql/clickhouse` (#4399). The plugin is the part before the slash.
|
|
22
|
+
*/
|
|
23
|
+
export function lexiconOfSide(side: string): string {
|
|
24
|
+
const slash = side.indexOf("/");
|
|
25
|
+
return slash === -1 ? side : side.slice(0, slash);
|
|
26
|
+
}
|
|
16
27
|
|
|
17
28
|
export interface MigrateCliOpts {
|
|
18
29
|
sourceFile: string;
|
|
19
30
|
from: string;
|
|
20
31
|
to: string;
|
|
21
|
-
emit: "yaml" | "ts";
|
|
32
|
+
emit: "yaml" | "ts" | "sql";
|
|
22
33
|
strict: boolean;
|
|
23
34
|
validate: boolean;
|
|
24
35
|
useComposites: boolean;
|
|
@@ -39,10 +50,13 @@ export interface MigrateCliResult {
|
|
|
39
50
|
error?: string;
|
|
40
51
|
/** Markdown summary lines printed to stderr */
|
|
41
52
|
markdownSummary?: string;
|
|
53
|
+
/** What was done about workspace links, or why nothing was (#4399) */
|
|
54
|
+
linkNote?: string;
|
|
42
55
|
}
|
|
43
56
|
|
|
44
57
|
export async function migrateCommand(opts: MigrateCliOpts): Promise<MigrateCliResult> {
|
|
45
|
-
const
|
|
58
|
+
const targetLexicon = lexiconOfSide(opts.to);
|
|
59
|
+
const targetPlugin = opts.plugins.find((p) => p.name === targetLexicon);
|
|
46
60
|
if (!targetPlugin) {
|
|
47
61
|
return {
|
|
48
62
|
exitCode: 1,
|
|
@@ -59,7 +73,7 @@ export async function migrateCommand(opts: MigrateCliOpts): Promise<MigrateCliRe
|
|
|
59
73
|
error: `Lexicon "${opts.to}" does not support migration`,
|
|
60
74
|
};
|
|
61
75
|
}
|
|
62
|
-
const source = targetPlugin.migrationSource(opts.from);
|
|
76
|
+
const source = targetPlugin.migrationSource(opts.from, opts.to);
|
|
63
77
|
if (!source) {
|
|
64
78
|
return {
|
|
65
79
|
exitCode: 1,
|
|
@@ -70,8 +84,23 @@ export async function migrateCommand(opts: MigrateCliOpts): Promise<MigrateCliRe
|
|
|
70
84
|
}
|
|
71
85
|
|
|
72
86
|
let content: string;
|
|
87
|
+
// A directory is a workspace member: the source reads it itself (#4399).
|
|
88
|
+
let isDirectory = false;
|
|
89
|
+
try {
|
|
90
|
+
isDirectory = statSync(opts.sourceFile).isDirectory();
|
|
91
|
+
} catch {
|
|
92
|
+
// The read below names the problem.
|
|
93
|
+
}
|
|
94
|
+
if (isDirectory && !source.directory) {
|
|
95
|
+
return {
|
|
96
|
+
exitCode: 1,
|
|
97
|
+
diagnostics: [],
|
|
98
|
+
provenance: [],
|
|
99
|
+
error: `${opts.sourceFile} is a directory, and migrating from "${opts.from}" reads a file`,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
73
102
|
try {
|
|
74
|
-
content = readFileSync(opts.sourceFile, "utf-8");
|
|
103
|
+
content = isDirectory ? "" : readFileSync(opts.sourceFile, "utf-8");
|
|
75
104
|
} catch (err) {
|
|
76
105
|
return {
|
|
77
106
|
exitCode: 1,
|
|
@@ -81,7 +110,7 @@ export async function migrateCommand(opts: MigrateCliOpts): Promise<MigrateCliRe
|
|
|
81
110
|
};
|
|
82
111
|
}
|
|
83
112
|
|
|
84
|
-
if (!source.detect(content)) {
|
|
113
|
+
if (!isDirectory && !source.detect(content)) {
|
|
85
114
|
return {
|
|
86
115
|
exitCode: 1,
|
|
87
116
|
diagnostics: [],
|
|
@@ -113,6 +142,7 @@ export async function migrateCommand(opts: MigrateCliOpts): Promise<MigrateCliRe
|
|
|
113
142
|
// Write output (--output file or stdout)
|
|
114
143
|
if (opts.output && opts.output !== "-") {
|
|
115
144
|
try {
|
|
145
|
+
mkdirSync(dirname(opts.output), { recursive: true });
|
|
116
146
|
writeFileSync(opts.output, result.output);
|
|
117
147
|
} catch (err) {
|
|
118
148
|
return {
|
|
@@ -126,9 +156,34 @@ export async function migrateCommand(opts: MigrateCliOpts): Promise<MigrateCliRe
|
|
|
126
156
|
process.stdout.write(result.output);
|
|
127
157
|
}
|
|
128
158
|
|
|
159
|
+
// The target's own server (--validate), when the source has one (#4399).
|
|
160
|
+
// A refusal always fails the run; so does a server that could not start,
|
|
161
|
+
// since a validation that did not run is not a pass.
|
|
162
|
+
let validationFailed = false;
|
|
163
|
+
if (opts.validate && result.validate) {
|
|
164
|
+
try {
|
|
165
|
+
const found = await result.validate();
|
|
166
|
+
result.diagnostics.push(...found);
|
|
167
|
+
if (found.some((d) => d.severity === "error")) {
|
|
168
|
+
validationFailed = true;
|
|
169
|
+
console.error(`Validator found ${found.filter((d) => d.severity === "error").length} refused statement(s):\n${found.map((d) => ` ${String(d.message)}`).join("\n")}`);
|
|
170
|
+
} else {
|
|
171
|
+
console.error("Validator (target server) OK");
|
|
172
|
+
}
|
|
173
|
+
} catch (err) {
|
|
174
|
+
return {
|
|
175
|
+
exitCode: 1,
|
|
176
|
+
output: result.output,
|
|
177
|
+
diagnostics: result.diagnostics,
|
|
178
|
+
provenance: result.provenance,
|
|
179
|
+
error: `--validate did not run: ${err instanceof Error ? err.message : String(err)}`,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
129
184
|
// External validator (--validate) — glci preferred, glab fallback.
|
|
130
185
|
let validatorWarning: string | undefined;
|
|
131
|
-
if (opts.validate && opts.emit === "yaml") {
|
|
186
|
+
if (opts.validate && !result.validate && opts.emit === "yaml") {
|
|
132
187
|
const v = tryValidateExternal(result.output);
|
|
133
188
|
if (!v.ran) {
|
|
134
189
|
validatorWarning = "neither glci nor glab is on PATH; skipping --validate";
|
|
@@ -157,11 +212,35 @@ export async function migrateCommand(opts: MigrateCliOpts): Promise<MigrateCliRe
|
|
|
157
212
|
}
|
|
158
213
|
}
|
|
159
214
|
|
|
215
|
+
// Links from the output's workspace member to the outputs it reads (#4399).
|
|
216
|
+
let linkNote: string | undefined;
|
|
217
|
+
if (result.links && result.links.length > 0) {
|
|
218
|
+
const outcome = planMigrateLinks({
|
|
219
|
+
sourcePath: opts.sourceFile,
|
|
220
|
+
outputPath: opts.output && opts.output !== "-" ? opts.output : undefined,
|
|
221
|
+
outputs: result.links,
|
|
222
|
+
});
|
|
223
|
+
if (outcome && "skipped" in outcome) linkNote = outcome.skipped;
|
|
224
|
+
else if (outcome) {
|
|
225
|
+
const { plan } = outcome;
|
|
226
|
+
if (plan.added.length === 0) {
|
|
227
|
+
linkNote = `member ${plan.consumer} already links every output it reads from ${plan.producer}`;
|
|
228
|
+
} else {
|
|
229
|
+
try {
|
|
230
|
+
writeFileSync(plan.file, plan.text);
|
|
231
|
+
linkNote = `added ${plan.added.length} link${plan.added.length === 1 ? "" : "s"} from member ${plan.consumer} to ${plan.producer} in ${plan.file}`;
|
|
232
|
+
} catch (err) {
|
|
233
|
+
linkNote = `could not write the links to ${plan.file}: ${err instanceof Error ? err.message : String(err)}`;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
160
239
|
// SARIF report (--report <path>) — reuse the lint-side formatSarif so any
|
|
161
240
|
// CI SARIF ingest path treats migration findings uniformly.
|
|
162
241
|
if (opts.reportFile) {
|
|
163
242
|
try {
|
|
164
|
-
const rules = await loadMigrationRules(
|
|
243
|
+
const rules = await loadMigrationRules(targetLexicon);
|
|
165
244
|
const lintShape = result.diagnostics as unknown as LintDiagnostic[];
|
|
166
245
|
const sarif = formatSarif(lintShape, rules);
|
|
167
246
|
writeFileSync(opts.reportFile, sarif);
|
|
@@ -172,7 +251,8 @@ export async function migrateCommand(opts: MigrateCliOpts): Promise<MigrateCliRe
|
|
|
172
251
|
}
|
|
173
252
|
|
|
174
253
|
// Markdown summary (always to stderr — leaves stdout clean for piping)
|
|
175
|
-
let markdownSummary =
|
|
254
|
+
let markdownSummary =
|
|
255
|
+
targetLexicon === "gitlab" ? formatMarkdownSummary(result.provenance, result.diagnostics, content) : formatDiagnosticSummary(result.provenance, result.diagnostics);
|
|
176
256
|
// Append the security posture section when security analysis ran (#306).
|
|
177
257
|
if (result.securityPosture) {
|
|
178
258
|
markdownSummary += `\n\n${result.securityPosture}`;
|
|
@@ -182,7 +262,7 @@ export async function migrateCommand(opts: MigrateCliOpts): Promise<MigrateCliRe
|
|
|
182
262
|
// The transformer already escalates needs-review → error when opts.strict
|
|
183
263
|
// is passed via MigrationSource.transform(); we double-check here.
|
|
184
264
|
const errorDiagnostics = result.diagnostics.filter((d) => d.severity === "error");
|
|
185
|
-
const exitCode = opts.strict && errorDiagnostics.length > 0 ? 1 : 0;
|
|
265
|
+
const exitCode = validationFailed || (opts.strict && errorDiagnostics.length > 0) ? 1 : 0;
|
|
186
266
|
|
|
187
267
|
return {
|
|
188
268
|
exitCode,
|
|
@@ -190,6 +270,7 @@ export async function migrateCommand(opts: MigrateCliOpts): Promise<MigrateCliRe
|
|
|
190
270
|
diagnostics: result.diagnostics,
|
|
191
271
|
provenance: result.provenance,
|
|
192
272
|
markdownSummary,
|
|
273
|
+
...(linkNote ? { linkNote } : {}),
|
|
193
274
|
};
|
|
194
275
|
}
|
|
195
276
|
|
|
@@ -231,7 +312,7 @@ export function tryValidateExternal(yamlText: string): ValidatorResult {
|
|
|
231
312
|
* Returns an empty array if the lexicon doesn't expose them.
|
|
232
313
|
*/
|
|
233
314
|
async function loadMigrationRules(targetLexicon: string): Promise<LintRule[]> {
|
|
234
|
-
//
|
|
315
|
+
// gitlab and sql expose migration rules. Hard-coded imports keep
|
|
235
316
|
// the dependency direction explicit; widen the switch when more
|
|
236
317
|
// lexicons ship their own migrate paths.
|
|
237
318
|
if (targetLexicon === "gitlab") {
|
|
@@ -243,9 +324,46 @@ async function loadMigrationRules(targetLexicon: string): Promise<LintRule[]> {
|
|
|
243
324
|
return [];
|
|
244
325
|
}
|
|
245
326
|
}
|
|
327
|
+
// The sql lexicon's needs-review catalog (#4399), one rule per finding id.
|
|
328
|
+
if (targetLexicon === "sql") {
|
|
329
|
+
try {
|
|
330
|
+
ensureTypeScriptLoader();
|
|
331
|
+
const mod = await import("@intentius/chant-lexicon-sql/clickhouse/review-catalog");
|
|
332
|
+
const rules = (mod as { REVIEW_RULES: Record<string, { id: string; name: string; summary: string; docs: readonly string[] }> }).REVIEW_RULES;
|
|
333
|
+
return Object.values(rules).map((r): LintRule => ({
|
|
334
|
+
id: r.id,
|
|
335
|
+
severity: "warning",
|
|
336
|
+
category: "correctness",
|
|
337
|
+
description: `${r.name}: ${r.summary}`,
|
|
338
|
+
helpUri: r.docs[0] ?? "https://intentius.io/chant/lexicons/sql/migrate-postgres-to-clickhouse/",
|
|
339
|
+
check: () => [],
|
|
340
|
+
}));
|
|
341
|
+
} catch {
|
|
342
|
+
return [];
|
|
343
|
+
}
|
|
344
|
+
}
|
|
246
345
|
return [];
|
|
247
346
|
}
|
|
248
347
|
|
|
348
|
+
/**
|
|
349
|
+
* The report for a pair that is not GitHub to GitLab: the counts and the
|
|
350
|
+
* diagnostics, with none of that pair's workflow advice (#4399).
|
|
351
|
+
*/
|
|
352
|
+
export function formatDiagnosticSummary(provenance: Array<Record<string, unknown>>, diagnostics: Array<Record<string, unknown>>): string {
|
|
353
|
+
const totals = { error: 0, warning: 0, info: 0 };
|
|
354
|
+
for (const d of diagnostics) {
|
|
355
|
+
const sev = d.severity as string;
|
|
356
|
+
if (sev === "error" || sev === "warning" || sev === "info") totals[sev]++;
|
|
357
|
+
}
|
|
358
|
+
const lines = ["", "## Migration report", "", `- Translated: ${provenance.length}`, `- Diagnostics: ${totals.error} error, ${totals.warning} warning, ${totals.info} info`];
|
|
359
|
+
if (diagnostics.length > 0) {
|
|
360
|
+
lines.push("", "### Diagnostics", "", "| Severity | Rule | Message |", "|---|---|---|");
|
|
361
|
+
for (const d of diagnostics.slice(0, 50)) lines.push(`| ${String(d.severity)} | ${String(d.ruleId)} | ${String(d.message).replace(/\|/g, "\\|").slice(0, 160)} |`);
|
|
362
|
+
if (diagnostics.length > 50) lines.push(`| ... | ... | ${diagnostics.length - 50} more diagnostics omitted |`);
|
|
363
|
+
}
|
|
364
|
+
return lines.join("\n");
|
|
365
|
+
}
|
|
366
|
+
|
|
249
367
|
/**
|
|
250
368
|
* Format the migration report as Markdown, mirroring the output format
|
|
251
369
|
* prescribed by the upstream gitlab-org/ci-cd/github-actions-to-gitlab-ci
|
|
@@ -471,6 +589,9 @@ export function printMigrateResult(result: MigrateCliResult): void {
|
|
|
471
589
|
if (result.markdownSummary) {
|
|
472
590
|
console.error(result.markdownSummary);
|
|
473
591
|
}
|
|
592
|
+
if (result.linkNote) {
|
|
593
|
+
console.error(`\nWorkspace links: ${result.linkNote}`);
|
|
594
|
+
}
|
|
474
595
|
if (result.exitCode === 0) {
|
|
475
596
|
console.error(formatInfo("\nMigration complete."));
|
|
476
597
|
} else {
|
|
@@ -14,10 +14,10 @@ jobs:
|
|
|
14
14
|
runs-on: ubuntu-latest
|
|
15
15
|
container: node:22
|
|
16
16
|
steps:
|
|
17
|
-
- uses: actions/checkout@v7
|
|
17
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
18
18
|
- run: chant run --components shared-alb --env staging --dump-outputs shared-alb.outputs.json
|
|
19
19
|
- name: Upload shared-alb outputs
|
|
20
|
-
uses: actions/upload-artifact@v4
|
|
20
|
+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
|
21
21
|
with:
|
|
22
22
|
name: shared-alb-outputs
|
|
23
23
|
path: shared-alb.outputs.json
|
|
@@ -27,9 +27,9 @@ jobs:
|
|
|
27
27
|
- shared-alb
|
|
28
28
|
container: node:22
|
|
29
29
|
steps:
|
|
30
|
-
- uses: actions/checkout@v7
|
|
30
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
31
31
|
- name: Download shared-alb outputs
|
|
32
|
-
uses: actions/download-artifact@v4
|
|
32
|
+
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
|
33
33
|
with:
|
|
34
34
|
name: shared-alb-outputs
|
|
35
35
|
path: .
|
|
@@ -599,6 +599,21 @@ export async function recordGateApproval(
|
|
|
599
599
|
// decision is written next to the approval, so a pass can be traced to the
|
|
600
600
|
// rule that allowed it.
|
|
601
601
|
const approval = standingForOrigin?.approval;
|
|
602
|
+
// #4290, #4324: roles come from .chant/trust.json at base, for an approver
|
|
603
|
+
// a seal proves. The quorum and the policy both read these, never --role.
|
|
604
|
+
const judge = trustQuorumJudge({ signers: scope.policy, roles: scope.policy.roles });
|
|
605
|
+
const trusted = judge({
|
|
606
|
+
version: 1,
|
|
607
|
+
op: opName,
|
|
608
|
+
gate,
|
|
609
|
+
...(environment !== undefined ? { environment } : {}),
|
|
610
|
+
...(planDigest !== undefined ? { planDigest } : {}),
|
|
611
|
+
resolvedBy,
|
|
612
|
+
...(relayedBy ? { relayedBy } : {}),
|
|
613
|
+
timestamp,
|
|
614
|
+
...(checkpointDigest !== undefined ? { checkpointDigest } : {}),
|
|
615
|
+
...(seal ? { seal } : {}),
|
|
616
|
+
}).roles;
|
|
602
617
|
let policyDecision: GatePolicyDecision | undefined;
|
|
603
618
|
if (approval?.policy) {
|
|
604
619
|
try {
|
|
@@ -610,6 +625,7 @@ export async function recordGateApproval(
|
|
|
610
625
|
gate,
|
|
611
626
|
resolvedBy,
|
|
612
627
|
approver,
|
|
628
|
+
roles: trusted,
|
|
613
629
|
...(planDigest !== undefined ? { planDigest } : {}),
|
|
614
630
|
...(approval.context ? { context: approval.context } : {}),
|
|
615
631
|
}),
|
|
@@ -680,9 +696,14 @@ export async function recordGateApproval(
|
|
|
680
696
|
"after it plans again. A moved plan or another commit starts it at the first phase.",
|
|
681
697
|
));
|
|
682
698
|
}
|
|
699
|
+
const untrusted = (approver.roles ?? []).filter((r) => !trusted.includes(r));
|
|
700
|
+
if (untrusted.length > 0) {
|
|
701
|
+
console.error(formatInfo(
|
|
702
|
+
`--role ${untrusted.join(", ")} is recorded on the approval and trusted by nothing: a gate's quorum and policy read ` +
|
|
703
|
+
`${record.resolvedBy}'s roles from .chant/trust.json at base, and only for an approval sealed by a signer listed at base (chant approve --sign).`,
|
|
704
|
+
));
|
|
705
|
+
}
|
|
683
706
|
if (approval) {
|
|
684
|
-
// #4290: the rules count roles from .chant/trust.json at base, for a proven approver.
|
|
685
|
-
const judge = trustQuorumJudge({ signers: scope.policy, roles: scope.policy.roles });
|
|
686
707
|
for (const line of describeApprovalProgress(approval, record, ledger.resolutions, standingForOrigin, ledger.pending, judge)) {
|
|
687
708
|
console.error(formatInfo(line));
|
|
688
709
|
}
|
|
@@ -171,6 +171,12 @@ async function runGenerateComponents(ctx: CommandContext): Promise<number> {
|
|
|
171
171
|
}
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
+
// #4327: ci.locks: plan adds the lock and unlock jobs. Read from the declaration, as the security groups are; GitLab keeps its own jobs.
|
|
175
|
+
let locks: "plan" | undefined;
|
|
176
|
+
if (found && args.prLoop && lexicon !== "gitlab") {
|
|
177
|
+
locks = (await import("../../workspace/ci-locks")).ciLocksAt(resolve(args.path)) === "plan" ? "plan" : undefined;
|
|
178
|
+
}
|
|
179
|
+
|
|
174
180
|
// Which lexicons support generate mode is a property of the loaded lexicon
|
|
175
181
|
// plugins (those implementing `generateComponentPipeline`, #688), not a
|
|
176
182
|
// hard-coded core list — `generateComponentsPipeline` returns a descriptive
|
|
@@ -192,7 +198,7 @@ async function runGenerateComponents(ctx: CommandContext): Promise<number> {
|
|
|
192
198
|
: {}),
|
|
193
199
|
// #3183: a plan job per pull request and an apply job per merge.
|
|
194
200
|
// #4292: on the branch ci.branches routes the member to, when it routes it.
|
|
195
|
-
...(args.prLoop ? { prLoop: { ...prLoopOption(args, reportUrl, reviewRules, isolatedRunners), ...(plan?.branch ? { branch: plan.branch } : {}), ...(identity ? { identity } : {}), ...(prEnvIdentity ? { prEnvIdentity } : {}) } } : {}),
|
|
201
|
+
...(args.prLoop ? { prLoop: { ...prLoopOption(args, reportUrl, reviewRules, isolatedRunners), ...(plan?.branch ? { branch: plan.branch } : {}), ...(identity ? { identity } : {}), ...(prEnvIdentity ? { prEnvIdentity } : {}), ...(locks ? { locks } : {}) } } : {}),
|
|
196
202
|
// #4002: the job image and the lines that install what it lacks, chant itself included.
|
|
197
203
|
...(args.image ? { image: args.image } : {}),
|
|
198
204
|
...(args.beforeScript?.length ? { beforeScript: args.beforeScript } : {}),
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `chant ledger <table> [dir] [--member <name>] [--where <field><op><value>]...
|
|
3
|
+
* [--since <time>] [--at <rev>] [--json]` (#4363): one ledger's rows from the
|
|
4
|
+
* local `chant/lifecycle` branch, filtered with typed filters. The read and
|
|
5
|
+
* its contract live in `../../lifecycle/ledger-read.ts`; the ledgers are read
|
|
6
|
+
* as `chant query` reads them (`./query.ts` {@link queryLedgers}).
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync } from "node:fs";
|
|
9
|
+
import { resolve } from "node:path";
|
|
10
|
+
import { formatError, formatWarning } from "../format";
|
|
11
|
+
import type { CommandContext } from "../registry";
|
|
12
|
+
import { queryLedgers } from "./query";
|
|
13
|
+
|
|
14
|
+
const USAGE = "chant ledger <resources|snapshots|runs|gates|deploys|releases|cuts> [dir] [--member <name>] [--where <field><op><value>]... [--since <time>] [--at <rev>] [--json]";
|
|
15
|
+
|
|
16
|
+
const cell = (v: unknown): string => (v === null || v === undefined ? "" : typeof v === "object" ? JSON.stringify(v) : String(v));
|
|
17
|
+
|
|
18
|
+
export async function runLedgerCommand(ctx: CommandContext): Promise<number> {
|
|
19
|
+
const { args } = ctx;
|
|
20
|
+
const table = args.positionals?.[0];
|
|
21
|
+
if (table === undefined || table.trim() === "") {
|
|
22
|
+
console.error(formatError({ message: "chant ledger needs a table", hint: USAGE }));
|
|
23
|
+
return 1;
|
|
24
|
+
}
|
|
25
|
+
const cwd = resolve(args.positionals?.[1] ?? ".");
|
|
26
|
+
if (!existsSync(cwd)) {
|
|
27
|
+
console.error(formatError({ message: `${cwd} does not exist`, hint: USAGE }));
|
|
28
|
+
return 1;
|
|
29
|
+
}
|
|
30
|
+
const { readLedgerTable, ledgerReadFailure, LedgerRevisionError } = await import("../../lifecycle/ledger-read");
|
|
31
|
+
const { QueryError } = await import("../../lifecycle/query");
|
|
32
|
+
let doc;
|
|
33
|
+
try {
|
|
34
|
+
doc = await readLedgerTable(table, () => queryLedgers(cwd, args.members, args.at), { where: args.where, since: args.since, at: args.at ?? null });
|
|
35
|
+
} catch (err) {
|
|
36
|
+
if (err instanceof LedgerRevisionError) doc = ledgerReadFailure("revision-unknown", err.message);
|
|
37
|
+
else if (err instanceof QueryError) doc = ledgerReadFailure("ledger-unreadable", err.message);
|
|
38
|
+
else throw err;
|
|
39
|
+
}
|
|
40
|
+
if (args.json) {
|
|
41
|
+
console.log(JSON.stringify(doc, null, 2));
|
|
42
|
+
return "error" in doc ? 1 : 0;
|
|
43
|
+
}
|
|
44
|
+
if ("error" in doc) {
|
|
45
|
+
console.error(formatError({ message: `${doc.error.code}: ${doc.error.message}`, hint: USAGE }));
|
|
46
|
+
return 1;
|
|
47
|
+
}
|
|
48
|
+
const widths = doc.columns.map((c) => Math.max(c.length, ...doc.rows.map((r) => cell(r[c]).length)));
|
|
49
|
+
const line = (vals: string[]): string => vals.map((v, i) => v.padEnd(widths[i])).join(" ").trimEnd();
|
|
50
|
+
console.log([line(doc.columns), line(widths.map((w) => "-".repeat(w))), ...doc.rows.map((r) => line(doc.columns.map((c) => cell(r[c]))))].join("\n"));
|
|
51
|
+
console.log(`(${doc.rows.length} of ${doc.total} ${doc.total === 1 ? "row" : "rows"})`);
|
|
52
|
+
if (doc.malformed > 0) console.error(formatWarning({ message: `left out ${doc.malformed} in ${doc.table} that could not be read` }));
|
|
53
|
+
return 0;
|
|
54
|
+
}
|