yadflow 3.18.1 → 4.0.0-next.1
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/CHANGELOG.md +355 -0
- package/README.md +79 -26
- package/bin/commands.mjs +41 -0
- package/bin/yad.mjs +437 -124
- package/cli/artifact-status.mjs +34 -15
- package/cli/checkpoint.mjs +69 -49
- package/cli/codeowners-command.mjs +170 -0
- package/cli/codeowners.mjs +397 -0
- package/cli/commit.mjs +13 -9
- package/cli/companion.mjs +2 -2
- package/cli/dial.mjs +183 -0
- package/cli/docs.mjs +88 -32
- package/cli/doctor.mjs +1472 -97
- package/cli/epic-state.mjs +3478 -232
- package/cli/epic.mjs +506 -0
- package/cli/errors.mjs +4 -1
- package/cli/gate.mjs +1002 -209
- package/cli/history.mjs +556 -0
- package/cli/hook.mjs +266 -55
- package/cli/hubcommit.mjs +6 -17
- package/cli/index-command.mjs +87 -0
- package/cli/ledger.mjs +57 -7
- package/cli/lib.mjs +184 -18
- package/cli/manifest.mjs +367 -56
- package/cli/migrate.mjs +726 -53
- package/cli/mode.mjs +170 -0
- package/cli/next.mjs +349 -90
- package/cli/openpr.mjs +191 -39
- package/cli/people.mjs +654 -0
- package/cli/plan.mjs +417 -132
- package/cli/platform.mjs +110 -129
- package/cli/product-index.mjs +287 -0
- package/cli/protection.mjs +706 -0
- package/cli/reconcile.mjs +38 -12
- package/cli/repo-publish.mjs +24 -26
- package/cli/repo.mjs +23 -14
- package/cli/report.mjs +21 -15
- package/cli/review.mjs +24 -27
- package/cli/riskmap-command.mjs +289 -0
- package/cli/riskmap.mjs +373 -0
- package/cli/setup.mjs +139 -287
- package/cli/ship.mjs +7 -6
- package/cli/skill.mjs +180 -0
- package/cli/skip.mjs +211 -30
- package/cli/thread.mjs +42 -17
- package/cli/tidy.mjs +20 -20
- package/cli/update-commit.mjs +22 -22
- package/cli/usage.mjs +115 -109
- package/package.json +3 -3
- package/skills/sdlc/config.yaml +166 -87
- package/skills/sdlc/module-help.csv +35 -35
- package/skills/yad-analysis/SKILL.md +125 -65
- package/skills/yad-architecture/SKILL.md +34 -23
- package/skills/yad-architecture/references/contract-format.md +10 -8
- package/skills/yad-backfill/SKILL.md +14 -8
- package/skills/yad-backfill/references/backfill.md +1 -1
- package/skills/yad-change/SKILL.md +127 -52
- package/skills/yad-change/references/triage.md +42 -28
- package/skills/yad-checks/SKILL.md +89 -45
- package/skills/yad-checks/references/check-gates.md +315 -92
- package/skills/yad-checks/templates/checks/build-test-lint.sh +25 -7
- package/skills/yad-checks/templates/checks/commit-message.sh +17 -3
- package/skills/yad-checks/templates/checks/contract-check.sh +58 -2
- package/skills/yad-checks/templates/checks/epic-open.sh +3 -3
- package/skills/yad-checks/templates/checks/install-deps.sh +46 -0
- package/skills/yad-checks/templates/checks/ledger-guard.sh +94 -18
- package/skills/yad-checks/templates/checks/lineage-check.sh +23 -9
- package/skills/yad-checks/templates/checks/package-manager.sh +140 -0
- package/skills/yad-checks/templates/checks/reconcile-debt-check.sh +4 -4
- package/skills/yad-checks/templates/checks/risk-map-check.sh +438 -0
- package/skills/yad-checks/templates/checks/verified-commits.sh +20 -46
- package/skills/yad-checks/templates/github/yad-checks.yml +37 -5
- package/skills/yad-checks/templates/github/yad-hub-checks.yml +5 -5
- package/skills/yad-checks/templates/github/yad-update-guard.yml +3 -4
- package/skills/yad-checks/templates/github/yad-verified-commits.yml +4 -4
- package/skills/yad-checks/templates/gitlab/.gitlab-ci.yml +7 -1
- package/skills/yad-checks/templates/gitlab/yad-checks.gitlab-ci.yml +22 -4
- package/skills/yad-checks/templates/gitlab/yad-hub-checks.gitlab-ci.yml +5 -5
- package/skills/yad-checks/templates/gitlab/yad-verified-commits.gitlab-ci.yml +4 -4
- package/skills/yad-checks/templates/hooks/ledger-guard-cursor.sh +91 -0
- package/skills/yad-checks/templates/hooks/ledger-guard.sh +38 -7
- package/skills/yad-commit/SKILL.md +6 -6
- package/skills/yad-connect-design/SKILL.md +6 -6
- package/skills/yad-connect-design/references/design-context.md +1 -1
- package/skills/yad-connect-design/references/design-registry.md +2 -2
- package/skills/yad-connect-docs/SKILL.md +12 -12
- package/skills/yad-connect-docs/references/docs-registry.md +1 -1
- package/skills/yad-connect-learning/SKILL.md +5 -5
- package/skills/yad-connect-learning/references/learning-registry.md +2 -2
- package/skills/yad-connect-repos/SKILL.md +92 -54
- package/skills/yad-connect-repos/references/code-context.md +6 -6
- package/skills/yad-connect-repos/references/hub-config.md +68 -58
- package/skills/yad-connect-repos/references/repos-registry.md +10 -9
- package/skills/yad-connect-repos/references/risk-map.md +81 -0
- package/skills/yad-connect-testing/SKILL.md +6 -6
- package/skills/yad-connect-testing/references/testing-context.md +3 -4
- package/skills/yad-connect-testing/references/testing-registry.md +2 -2
- package/skills/yad-defects/SKILL.md +8 -8
- package/skills/yad-discovery/SKILL.md +130 -94
- package/skills/yad-discovery/references/discovery-schema.md +23 -7
- package/skills/yad-discovery/references/foundation-schema.md +374 -0
- package/skills/yad-docs/SKILL.md +16 -11
- package/skills/yad-docs/references/data-mapping.md +9 -7
- package/skills/yad-docs/templates/app/package-lock.json +3 -3
- package/skills/yad-docs-overview/SKILL.md +32 -17
- package/skills/yad-docs-overview/references/pipeline-model.md +47 -28
- package/skills/yad-docs-sync/SKILL.md +10 -5
- package/skills/yad-docs-sync/references/staleness.md +8 -7
- package/skills/yad-engineer-review/SKILL.md +88 -24
- package/skills/yad-engineer-review/references/ship-and-record.md +25 -16
- package/skills/yad-epic/SKILL.md +178 -100
- package/skills/yad-epic/references/state-schema.md +626 -117
- package/skills/yad-hub-bridge/SKILL.md +66 -48
- package/skills/yad-hub-bridge/references/bridge.md +110 -83
- package/skills/yad-hub-bridge/references/login-roster.md +163 -70
- package/skills/yad-hub-bridge/templates/checks/hub-route.sh +22 -19
- package/skills/yad-hub-bridge/templates/github/yad-gate-sync.yml +34 -14
- package/skills/yad-hub-bridge/templates/gitlab/gitlab-ci.include-root.yml +2 -2
- package/skills/yad-hub-bridge/templates/gitlab/yad-gate-sync.gitlab-ci.yml +22 -12
- package/skills/yad-implement/SKILL.md +29 -15
- package/skills/yad-implement/references/implement-conventions.md +2 -2
- package/skills/yad-learn/SKILL.md +9 -9
- package/skills/yad-learn/references/learning-state.md +2 -2
- package/skills/yad-open-pr/SKILL.md +64 -29
- package/skills/yad-pair-review/SKILL.md +18 -16
- package/skills/yad-pair-review/references/session-state.md +4 -4
- package/skills/yad-pr-template/SKILL.md +48 -27
- package/skills/yad-pr-template/references/risk-routing.md +97 -24
- package/skills/yad-pr-template/templates/checks/pr-template.sh +37 -15
- package/skills/yad-pr-template/templates/checks/pr-title.sh +27 -13
- package/skills/yad-pr-template/templates/checks/risk-route.sh +107 -14
- package/skills/yad-pr-template/templates/github/pull_request_template.md +7 -5
- package/skills/yad-pr-template/templates/gitlab/merge_request_templates/Default.md +7 -5
- package/skills/yad-pr-template/templates/hub/github/pull_request_template.md +15 -14
- package/skills/yad-pr-template/templates/hub/gitlab/merge_request_templates/Default.md +15 -13
- package/skills/yad-reconcile/SKILL.md +3 -3
- package/skills/yad-report/SKILL.md +5 -5
- package/skills/yad-review-companion/SKILL.md +12 -9
- package/skills/yad-review-gate/SKILL.md +198 -79
- package/skills/yad-review-gate/references/gating.md +230 -54
- package/skills/yad-run/SKILL.md +86 -56
- package/skills/yad-run/references/run-loop.md +67 -45
- package/skills/yad-ship/SKILL.md +18 -14
- package/skills/yad-spec/SKILL.md +31 -17
- package/skills/yad-spec/references/spec-handoff.md +17 -5
- package/skills/yad-status/SKILL.md +114 -56
- package/skills/yad-stories/SKILL.md +42 -27
- package/skills/yad-stories/references/story-schema.md +10 -9
- package/skills/yad-stub/SKILL.md +59 -48
- package/skills/yad-sync-repos/SKILL.md +3 -3
- package/skills/yad-test-cases/SKILL.md +37 -30
- package/skills/yad-test-cases/references/test-cases-schema.md +8 -5
- package/skills/yad-timeline/SKILL.md +8 -7
- package/skills/yad-ui/SKILL.md +46 -25
- package/cli/roster.mjs +0 -164
- package/skills/sdlc/install.sh +0 -68
package/cli/tidy.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// `yad tidy up` — fold FINISHED
|
|
1
|
+
// `yad tidy up` — fold FINISHED Build shards back into their single folded ledger, on demand.
|
|
2
2
|
//
|
|
3
3
|
// The two logs are shard-then-fold (cli/ledger.mjs): writers drop one loose file per entry so
|
|
4
4
|
// concurrent writers never conflict. Left alone they accumulate; `yad tidy up` is the "pack it up"
|
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
import fs from 'node:fs';
|
|
10
10
|
import path from 'node:path';
|
|
11
11
|
import { c, log, ok, info, fail, hand, exists, pushWithRebase } from './lib.mjs';
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
12
|
+
import { productConfigPath } from './manifest.mjs';
|
|
13
|
+
import { loadProduct } from './gate.mjs';
|
|
14
|
+
import { platformLogin } from './platform.mjs';
|
|
15
15
|
import { checkpointAuthor } from './checkpoint.mjs';
|
|
16
|
-
import {
|
|
16
|
+
import { productGit, resolveDefaultBranch, guardDefaultBranch } from './hubcommit.mjs';
|
|
17
17
|
import { foldTrust, foldBuild } from './ledger.mjs';
|
|
18
18
|
import { epicRoot, isValidEpicId, readFrontmatter } from './epic-state.mjs';
|
|
19
19
|
|
|
@@ -39,14 +39,14 @@ function epicsWithLedgers(root) {
|
|
|
39
39
|
export async function runTidy(root, opts = {}) {
|
|
40
40
|
log(c.bold('\nyad tidy up'));
|
|
41
41
|
if (!exists(path.join(root, '.git'))) { fail('not a git repo'); process.exitCode = 1; return; }
|
|
42
|
-
if (!exists(
|
|
43
|
-
fail('no .sdlc/hub.json — run `yad tidy up` from the
|
|
42
|
+
if (!exists(productConfigPath(root))) {
|
|
43
|
+
fail('no .sdlc/hub.json — run `yad tidy up` from the Product');
|
|
44
44
|
process.exitCode = 1;
|
|
45
45
|
return;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
const { hub } =
|
|
49
|
-
const git =
|
|
48
|
+
const { hub } = loadProduct(root);
|
|
49
|
+
const git = productGit(root);
|
|
50
50
|
const branch = git('rev-parse', '--abbrev-ref', 'HEAD').stdout;
|
|
51
51
|
const defaultBranch = resolveDefaultBranch(git, hub);
|
|
52
52
|
if (!guardDefaultBranch(branch, defaultBranch, { allowBranch: opts.allowBranch, cmd: 'yad tidy up' })) return;
|
|
@@ -68,16 +68,16 @@ export async function runTidy(root, opts = {}) {
|
|
|
68
68
|
info(`${epic}: ${opts.dryRun ? 'would fold' : 'folded'} ${t.folded} trust + ${b.folded} build shard(s)`);
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
|
-
if (!folded) { info('nothing to tidy — no finished shards to fold'); return { folded: 0 }; }
|
|
71
|
+
if (!folded) { info('nothing to tidy — no finished shards to fold'); return { folded: 0, epics: [], message: null, committed: false, pushed: false, dryRun: !!opts.dryRun }; }
|
|
72
72
|
|
|
73
|
-
const author = checkpointAuthor(
|
|
73
|
+
const author = checkpointAuthor(platformLogin(root, hub?.platform), git('config', 'user.name').stdout);
|
|
74
74
|
const label = touched.length === 1 ? touched[0] : `${touched.length} epics`;
|
|
75
|
-
const message = `chore(hub): tidy
|
|
75
|
+
const message = `chore(hub): tidy Build ledgers — ${label} by ${author} [skip ci]`;
|
|
76
76
|
|
|
77
77
|
if (opts.dryRun) {
|
|
78
78
|
log('\n' + c.dim(message) + '\n');
|
|
79
79
|
info('dry run — nothing folded or committed');
|
|
80
|
-
return { message, folded };
|
|
80
|
+
return { message, folded, epics: touched, committed: false, pushed: false, dryRun: true };
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
// Stage the fold (modified folded files + deleted shards) under each touched epic's ledger paths.
|
|
@@ -90,11 +90,11 @@ export async function runTidy(root, opts = {}) {
|
|
|
90
90
|
});
|
|
91
91
|
const pathspecs = candidates.filter((spec) =>
|
|
92
92
|
exists(path.join(root, spec)) || git('ls-files', '--error-unmatch', '--', spec).ok);
|
|
93
|
-
if (!pathspecs.length) { info('fold produced no stageable change'); return { folded }; }
|
|
93
|
+
if (!pathspecs.length) { info('fold produced no stageable change'); return { message: null, folded, epics: touched, committed: false, pushed: false, dryRun: false }; }
|
|
94
94
|
const add = git('add', '-A', '--', ...pathspecs);
|
|
95
|
-
if (!add.ok) { fail(`git add failed — ${add.stderr.split('\n')[0] || add.code}`); process.exitCode = 1; return { folded }; }
|
|
95
|
+
if (!add.ok) { fail(`git add failed — ${add.stderr.split('\n')[0] || add.code}`); process.exitCode = 1; return { message: null, folded, epics: touched, committed: false, pushed: false, dryRun: false }; }
|
|
96
96
|
const staged = git('diff', '--cached', '--name-only', '--', ...pathspecs).stdout.split('\n').filter(Boolean);
|
|
97
|
-
if (!staged.length) { info('fold produced no net change — nothing to commit'); return { folded }; }
|
|
97
|
+
if (!staged.length) { info('fold produced no net change — nothing to commit'); return { message: null, folded, epics: touched, committed: false, pushed: false, dryRun: false }; }
|
|
98
98
|
|
|
99
99
|
const cm = git('commit', '-m', message, '--', ...staged);
|
|
100
100
|
if (!cm.ok) {
|
|
@@ -103,14 +103,14 @@ export async function runTidy(root, opts = {}) {
|
|
|
103
103
|
fail(`git commit failed — ${cm.stderr.split('\n')[0] || cm.code}`);
|
|
104
104
|
hand('the fold is staged — re-run `yad tidy up`, or `yad checkpoint` to land it');
|
|
105
105
|
process.exitCode = 1;
|
|
106
|
-
return { message, folded };
|
|
106
|
+
return { message, folded, epics: touched, committed: false, pushed: false, dryRun: false };
|
|
107
107
|
}
|
|
108
108
|
ok(`tidied ${folded} shard(s) into ${touched.length} epic ledger(s): ${c.dim(label)}`);
|
|
109
109
|
|
|
110
|
-
if (!opts.push) return { message, folded };
|
|
111
|
-
if (pushWithRebase(root, branch).ok) { ok(`pushed to origin/${branch}`); return { message, folded }; }
|
|
110
|
+
if (!opts.push) return { message, folded, epics: touched, committed: true, pushed: false, dryRun: false };
|
|
111
|
+
if (pushWithRebase(root, branch).ok) { ok(`pushed to origin/${branch}`); return { message, folded, epics: touched, committed: true, pushed: true, dryRun: false }; }
|
|
112
112
|
fail(`could not push to origin/${branch} — a protected branch, or an unresolvable rebase conflict`);
|
|
113
113
|
hand(`run \`git pull --rebase\` and re-run \`yad tidy up --push\``);
|
|
114
114
|
process.exitCode = 1;
|
|
115
|
-
return { message, folded };
|
|
115
|
+
return { message, folded, epics: touched, committed: true, pushed: false, dryRun: false };
|
|
116
116
|
}
|
package/cli/update-commit.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// `yad update --push` / `yad check --fix --push` — after reconcile applies drift into the working
|
|
2
|
-
// trees, commit the applied changes PER REPO (the
|
|
2
|
+
// trees, commit the applied changes PER REPO (the Product and every connected repo) and push them
|
|
3
3
|
// straight to the default branch, so a package update "just lands" everywhere instead of leaving
|
|
4
4
|
// dirty trees for someone to hand-commit across N repos. This is the update-flow analogue of the
|
|
5
|
-
//
|
|
5
|
+
// Build `yad checkpoint` (cli/checkpoint.mjs) and reuses its machine-commit machinery.
|
|
6
6
|
//
|
|
7
7
|
// Invariants (shared with checkpoint):
|
|
8
8
|
// 1. Stage an EXPLICIT per-repo allowlist — exactly the paths the reconcile actions declared they
|
|
@@ -23,24 +23,24 @@ import fs from 'node:fs';
|
|
|
23
23
|
import path from 'node:path';
|
|
24
24
|
import { c, log, ok, info, warn, fail, hand, run, pushWithRebase } from './lib.mjs';
|
|
25
25
|
import { VERSION } from './manifest.mjs';
|
|
26
|
-
import {
|
|
26
|
+
import { productGit, resolveDefaultBranch } from './hubcommit.mjs';
|
|
27
27
|
|
|
28
28
|
// Collapse whitespace/newline runs to a single space — keeps a stray path or hostile value from
|
|
29
29
|
// breaking the one-line subject or injecting a fake trailer line.
|
|
30
30
|
const oneLine = (s = '') => String(s).replace(/\s+/g, ' ').trim();
|
|
31
31
|
|
|
32
|
-
// A short, human label for a repo root relative to the
|
|
32
|
+
// A short, human label for a repo root relative to the Product: 'hub' for the Product itself, else the
|
|
33
33
|
// registered path (e.g. demo-repos/backend), else the basename.
|
|
34
|
-
export function repoLabel(
|
|
35
|
-
if (root ===
|
|
36
|
-
const r = path.relative(
|
|
34
|
+
export function repoLabel(productRoot, root) {
|
|
35
|
+
if (root === productRoot) return 'hub';
|
|
36
|
+
const r = path.relative(productRoot, root);
|
|
37
37
|
return r && !r.startsWith('..') ? r.split(path.sep).join('/') : path.basename(root);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
// PURE — group applied reconcile actions by the repo root they wrote to. Each group carries the
|
|
41
41
|
// deduped pathspecs to stage plus the human-readable item labels for the commit body. Actions with
|
|
42
42
|
// no root/paths (e.g. gaps, or a status:'ok' that was force-reapplied without a root) are ignored.
|
|
43
|
-
// Order follows first-encounter, so the
|
|
43
|
+
// Order follows first-encounter, so the Product (its module and Product actions come first in reconcile)
|
|
44
44
|
// leads and connected repos follow in registry order.
|
|
45
45
|
export function groupByRoot(actions = []) {
|
|
46
46
|
const groups = new Map();
|
|
@@ -94,14 +94,14 @@ function stageAllowlist(git, root, paths) {
|
|
|
94
94
|
// Commit (and, with push, push) one repo group. `defaultBranch` is the repo's configured default
|
|
95
95
|
// (hub.default_branch / repo.default_branch); falls back to origin/HEAD then 'main'. Returns a small
|
|
96
96
|
// result object; never throws. On any hard error it sets process.exitCode so the CLI reports failure.
|
|
97
|
-
export function commitAndPush(group, { push = false, allowBranch = false,
|
|
97
|
+
export function commitAndPush(group, { push = false, allowBranch = false, productRoot, defaultBranch } = {}) {
|
|
98
98
|
const { root, paths, items } = group;
|
|
99
|
-
const label = repoLabel(
|
|
100
|
-
const git =
|
|
99
|
+
const label = repoLabel(productRoot ?? root, root);
|
|
100
|
+
const git = productGit(root);
|
|
101
101
|
|
|
102
102
|
// `root` must be the TOP of its OWN git repo — not merely "inside a work tree". A registered repo
|
|
103
103
|
// whose clone is missing (reconcile's apply() happily recreates the wiring files) but whose path
|
|
104
|
-
// sits under the
|
|
104
|
+
// sits under the Product would otherwise report inside-work-tree=true against the HUB: git resolves the
|
|
105
105
|
// pathspecs relative to cwd, so we would stage the connected repo's files into the HUB's index and
|
|
106
106
|
// push them to the HUB's remote, mislabeled. Require the worktree top to BE this root.
|
|
107
107
|
const top = git('rev-parse', '--show-toplevel');
|
|
@@ -110,7 +110,7 @@ export function commitAndPush(group, { push = false, allowBranch = false, hubRoo
|
|
|
110
110
|
})();
|
|
111
111
|
if (!sameRepo) {
|
|
112
112
|
warn(`${label}: not its own git repo (missing/renamed clone?) — skipped (changes left in the working tree)`);
|
|
113
|
-
return { label, committed: false, skipped: true };
|
|
113
|
+
return { label, committed: false, pushed: false, skipped: true, error: false };
|
|
114
114
|
}
|
|
115
115
|
const branch = git('rev-parse', '--abbrev-ref', 'HEAD').stdout;
|
|
116
116
|
const target = defaultBranch || resolveDefaultBranch(git);
|
|
@@ -120,13 +120,13 @@ export function commitAndPush(group, { push = false, allowBranch = false, hubRoo
|
|
|
120
120
|
warn(`${label}: on '${branch}', not default '${target}' — --allow-branch: commit/push go to origin/${branch}`);
|
|
121
121
|
} else {
|
|
122
122
|
warn(`${label}: on '${branch}', not the default branch '${target}' — skipped (switch to '${target}' or pass --allow-branch)`);
|
|
123
|
-
return { label, committed: false, skipped: true };
|
|
123
|
+
return { label, committed: false, pushed: false, skipped: true, error: false };
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
const { staged, addError } = stageAllowlist(git, root, paths);
|
|
128
128
|
if (addError) warn(`${label}: git add reported "${addError}" — staging may be incomplete`);
|
|
129
|
-
if (!staged.length) { info(`${label}: nothing to commit (unchanged or ignored)`); return { label, committed: false }; }
|
|
129
|
+
if (!staged.length) { info(`${label}: nothing to commit (unchanged or ignored)`); return { label, committed: false, pushed: false, skipped: false, error: false }; }
|
|
130
130
|
|
|
131
131
|
// Pushing HEAD lands any local commits ahead of the remote too. Warn before we add ours so the
|
|
132
132
|
// operator sees unpublished WIP about to ride the update push (never silently publish it).
|
|
@@ -142,27 +142,27 @@ export function commitAndPush(group, { push = false, allowBranch = false, hubRoo
|
|
|
142
142
|
git('reset', '-q', '--', ...staged); // don't leave our allowlist staged for an unrelated commit to sweep up
|
|
143
143
|
fail(`${label}: git commit failed — ${cm.stderr.split('\n')[0] || cm.code}`);
|
|
144
144
|
process.exitCode = 1;
|
|
145
|
-
return { label, committed: false, error: true };
|
|
145
|
+
return { label, committed: false, pushed: false, skipped: false, error: true };
|
|
146
146
|
}
|
|
147
147
|
ok(`${label}: committed ${staged.length} file(s)`);
|
|
148
148
|
|
|
149
|
-
if (!push) return { label, committed: true };
|
|
150
|
-
if (pushWithRebase(root, branch).ok) { ok(`${label}: pushed to origin/${branch}`); return { label, committed: true, pushed: true }; }
|
|
149
|
+
if (!push) return { label, committed: true, pushed: false, skipped: false, error: false };
|
|
150
|
+
if (pushWithRebase(root, branch).ok) { ok(`${label}: pushed to origin/${branch}`); return { label, committed: true, pushed: true, skipped: false, error: false }; }
|
|
151
151
|
// The commit already landed locally — a re-run of `yad update --push` would see no drift and skip
|
|
152
152
|
// this repo, so point the operator at the direct push of the commit that already exists.
|
|
153
153
|
fail(`${label}: could not push to origin/${branch} — a protected branch, or an unresolvable rebase conflict`);
|
|
154
154
|
hand(`resolve it in ${label === 'hub' ? '.' : label}, then push the existing commit with \`git push origin ${branch}\``);
|
|
155
155
|
process.exitCode = 1;
|
|
156
|
-
return { label, committed: true, pushed: false, error: true };
|
|
156
|
+
return { label, committed: true, pushed: false, skipped: false, error: true };
|
|
157
157
|
}
|
|
158
158
|
|
|
159
159
|
// Orchestrate the per-repo commit/push over the grouped applied actions, bookended by the announce
|
|
160
160
|
// banners. `defaultBranchFor(root)` yields each repo's configured default branch (undefined ->
|
|
161
161
|
// resolve from the remote). Prints, commits/pushes each group, then the done banner.
|
|
162
|
-
export function commitUpdates(
|
|
162
|
+
export function commitUpdates(productRoot, groups, { push = false, allowBranch = false, defaultBranchFor, guardInactiveGitlab } = {}) {
|
|
163
163
|
if (!groups.length) { info('no committable changes were applied'); return []; }
|
|
164
164
|
|
|
165
|
-
const labels = groups.map((g) => repoLabel(
|
|
165
|
+
const labels = groups.map((g) => repoLabel(productRoot, g.root));
|
|
166
166
|
log('');
|
|
167
167
|
log(c.bold(`yad update — ${push ? 'publishing to default branches' : 'committing locally (no --push)'}`));
|
|
168
168
|
warn(`about to ${push ? 'commit + push directly to the default branch' : 'commit'} on: ${labels.join(', ')}`);
|
|
@@ -170,7 +170,7 @@ export function commitUpdates(hubRoot, groups, { push = false, allowBranch = fal
|
|
|
170
170
|
|
|
171
171
|
const results = [];
|
|
172
172
|
for (const g of groups) {
|
|
173
|
-
const r = commitAndPush(g, { push, allowBranch,
|
|
173
|
+
const r = commitAndPush(g, { push, allowBranch, productRoot, defaultBranch: defaultBranchFor?.(g.root) });
|
|
174
174
|
if (push && r.pushed && guardInactiveGitlab?.(g.root)) {
|
|
175
175
|
hand(`${r.label}: GitLab yad-update-guard is not active — add \`- local: '.gitlab/ci/yad-update-guard.yml'\` to the root .gitlab-ci.yml include (re-run the yad-checks wire step) so this direct-to-default push is gated`);
|
|
176
176
|
}
|