git-release-manager 0.0.14 → 0.6.0

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.
Files changed (66) hide show
  1. package/README.md +0 -0
  2. package/dist/commands/branch/command.js +84 -14
  3. package/dist/commands/branch/command.js.map +1 -1
  4. package/dist/commands/branch/types/BranchFinishCliArgs.js +3 -0
  5. package/dist/commands/branch/types/BranchFinishCliArgs.js.map +1 -0
  6. package/dist/commands/branch/types/BranchSyncCliArgs.js +3 -0
  7. package/dist/commands/branch/types/BranchSyncCliArgs.js.map +1 -0
  8. package/dist/commands/changelog/command.js +28 -3
  9. package/dist/commands/changelog/command.js.map +1 -1
  10. package/dist/commands/commit/command.js +8 -3
  11. package/dist/commands/commit/command.js.map +1 -1
  12. package/dist/commands/flow/command.js +196 -6
  13. package/dist/commands/flow/command.js.map +1 -1
  14. package/dist/commands/track/command.js +136 -0
  15. package/dist/commands/track/command.js.map +1 -0
  16. package/dist/commands/version/command.js +115 -23
  17. package/dist/commands/version/command.js.map +1 -1
  18. package/dist/config/defaults/config.json +375 -250
  19. package/dist/config/types/Flow.js +34 -0
  20. package/dist/config/types/Flow.js.map +1 -0
  21. package/dist/config/types/Track.js +3 -0
  22. package/dist/config/types/Track.js.map +1 -0
  23. package/dist/config/types/Versioning.js +3 -0
  24. package/dist/config/types/Versioning.js.map +1 -0
  25. package/dist/index.js +25 -6
  26. package/dist/index.js.map +1 -1
  27. package/dist/modules/FlowManager.js +47 -4
  28. package/dist/modules/FlowManager.js.map +1 -1
  29. package/dist/modules/branch/BranchController.js +33 -2
  30. package/dist/modules/branch/BranchController.js.map +1 -1
  31. package/dist/modules/changelog/ChangelogController.js.map +1 -1
  32. package/dist/modules/changelog/templateOperations.js.map +1 -1
  33. package/dist/modules/flow/FlowController.js +764 -0
  34. package/dist/modules/flow/FlowController.js.map +1 -0
  35. package/dist/modules/git/commits/commitProcessor.js +21 -3
  36. package/dist/modules/git/commits/commitProcessor.js.map +1 -1
  37. package/dist/modules/git/commits/index.js +9 -1
  38. package/dist/modules/git/commits/index.js.map +1 -1
  39. package/dist/modules/git/context/remoteHandler.js +1 -1
  40. package/dist/modules/git/context/remoteHandler.js.map +1 -1
  41. package/dist/modules/git/gitOperations.js.map +1 -1
  42. package/dist/modules/git/lineTags.js +58 -0
  43. package/dist/modules/git/lineTags.js.map +1 -0
  44. package/dist/modules/track/TrackController.js +320 -0
  45. package/dist/modules/track/TrackController.js.map +1 -0
  46. package/dist/modules/version/BumpDeriver.js +119 -0
  47. package/dist/modules/version/BumpDeriver.js.map +1 -0
  48. package/dist/modules/version/GitVersionManager.js +42 -14
  49. package/dist/modules/version/GitVersionManager.js.map +1 -1
  50. package/dist/modules/version/ProjectVersion.js +84 -3
  51. package/dist/modules/version/ProjectVersion.js.map +1 -1
  52. package/dist/modules/version/VersionController.js +238 -3
  53. package/dist/modules/version/VersionController.js.map +1 -1
  54. package/dist/modules/version/VersionStamper.js +139 -0
  55. package/dist/modules/version/VersionStamper.js.map +1 -0
  56. package/dist/modules/version/branchChannel.js +94 -0
  57. package/dist/modules/version/branchChannel.js.map +1 -0
  58. package/dist/modules/version/resolveVersionRef.js +78 -0
  59. package/dist/modules/version/resolveVersionRef.js.map +1 -0
  60. package/dist/modules/version/versionFormatter.js +19 -1
  61. package/dist/modules/version/versionFormatter.js.map +1 -1
  62. package/dist/templates/defaults/changelog.detailed.ejs +0 -0
  63. package/dist/templates/defaults/changelog.ejs +0 -0
  64. package/dist/utils/cmd.js +15 -2
  65. package/dist/utils/cmd.js.map +1 -1
  66. package/package.json +5 -2
@@ -1,6 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VersionController = void 0;
4
+ const resolveVersionRef_1 = require("./resolveVersionRef");
5
+ const branchChannel_1 = require("./branchChannel");
6
+ const configManager_1 = require("../../config/configManager");
7
+ const VersionStamper_1 = require("./VersionStamper");
8
+ const commitProcessor_1 = require("../git/commits/commitProcessor");
9
+ const BumpDeriver_1 = require("./BumpDeriver");
4
10
  const GitVersionManager_1 = require("./GitVersionManager");
5
11
  const ProjectVersion_1 = require("./ProjectVersion");
6
12
  const ReleaseManager_1 = require("./ReleaseManager");
@@ -12,8 +18,161 @@ class VersionController {
12
18
  this.validator = new VersionValidator_1.VersionValidator();
13
19
  this.projectVersionManager = new ProjectVersion_1.ProjectVersionManager();
14
20
  }
21
+ /**
22
+ * resolveBaselineRef — the shared resolver, kept as a method so the call
23
+ * sites below read unchanged.
24
+ *
25
+ * THE BODY MOVED to modules/version/resolveVersionRef (DECISIONS D4). It was
26
+ * private here while `--revert` and `--compare` each answered the same
27
+ * question their own way — three verbs, three behaviours. One place is the
28
+ * decision; this wrapper is what keeps it one.
29
+ */
30
+ async resolveBaselineRef(baseline, prefix) {
31
+ return (0, resolveVersionRef_1.resolveVersionRef)(baseline, prefix);
32
+ }
33
+ /**
34
+ * deriveBumpFromRange — read the commits this version would cover and grade
35
+ * them against the configured taxonomy.
36
+ *
37
+ * Returns null when the range cannot be established, and the caller then
38
+ * proceeds with its normal default rather than failing. That is deliberate:
39
+ * `--derive` asks the history for an OPINION, and a repository with no
40
+ * baseline (the first version ever) genuinely has none to give. Refusing
41
+ * there would make the first release the one command nobody can run.
42
+ */
43
+ async deriveBumpFromRange(options) {
44
+ var _a, _b, _c;
45
+ try {
46
+ const config = await (0, configManager_1.readConfig)(options.config, options.environment);
47
+ const baseline = (_a = options.from) !== null && _a !== void 0 ? _a : (await this.gitManager.getLatestTag(options.prefix, options.channel));
48
+ if (!baseline)
49
+ return null;
50
+ // THE BASELINE IS A VERSION; THE RANGE NEEDS A REF, and they are not
51
+ // the same string. `--from 1.0.0` is a perfectly good baseline for
52
+ // the arithmetic — semver does not care about a `v` — while the tag
53
+ // in the repository is `v1.0.0`, so handing it straight to `git log`
54
+ // produces "ambiguous argument '1.0.0..HEAD'". The arithmetic then
55
+ // still answers, from a range that was never read: a derivation that
56
+ // silently graded nothing.
57
+ //
58
+ // --since IS THE CALLER SAYING THE TWO CANNOT BE INFERRED FROM EACH
59
+ // OTHER. A project running several version LINES tags them
60
+ // `<line>-vX.Y.Z`, so the baseline it hands over is the bare semver
61
+ // core `1.0.0` while the ref that starts the range is
62
+ // `catalystctl-v1.0.0`. Guessing from the core alone finds the
63
+ // repository's OWN `v1.0.0` — a real tag, at the wrong point in
64
+ // history — and the derivation then grades a range belonging to a
65
+ // different line. Measured: a component whose tree had not been
66
+ // touched derived a patch bump from another line's commits.
67
+ const from = options.since
68
+ ? await this.resolveBaselineRef(options.since, options.prefix)
69
+ : await this.resolveBaselineRef(baseline, options.prefix);
70
+ if (!from) {
71
+ console.error(`bump: ${options.since ? `range start '${options.since}'` : `baseline '${baseline}'`} ` +
72
+ `does not resolve to a ref in this repository, ` +
73
+ `so there is no range to grade; falling back to the flags given`);
74
+ return null;
75
+ }
76
+ const to = (_b = options.to) !== null && _b !== void 0 ? _b : 'HEAD';
77
+ // --no-merges: a merge commit carries no type and never could. Its
78
+ // content is the commits it joins, and those are in this range too.
79
+ //
80
+ // --paths scopes the derivation to ONE component's tree. Without it
81
+ // a repository with several independently-versioned products grades
82
+ // every one of them against every commit, so a fix in product A
83
+ // bumps product B — and the two lines, whose whole purpose is to be
84
+ // independent, move in lockstep while each claims to be its own.
85
+ // `--` separates pathspecs from revisions; without it git resolves a
86
+ // path that happens to look like a ref and answers about the wrong
87
+ // thing.
88
+ const pathspecs = ((_c = options.paths) !== null && _c !== void 0 ? _c : '').split(/\s+/).filter(Boolean);
89
+ const logArgs = ['--no-merges', ...(pathspecs.length ? ['--', ...pathspecs] : [])];
90
+ const commits = await (0, commitProcessor_1.getGitLogAsJson)(`${from}..${to}`, logArgs);
91
+ if (!(commits === null || commits === void 0 ? void 0 : commits.length))
92
+ return null;
93
+ return (0, BumpDeriver_1.deriveBump)(commits, config);
94
+ }
95
+ catch (error) {
96
+ // A derivation that cannot run must not take the version path down
97
+ // with it — the caller still has an explicit default. It says so on
98
+ // stderr, because a SILENT fallback would look exactly like a range
99
+ // that legitimately voted patch.
100
+ console.error(`bump: could not derive from history (${error instanceof Error ? error.message : String(error)}); ` +
101
+ `falling back to the flags given`);
102
+ return null;
103
+ }
104
+ }
105
+ /**
106
+ * withConfiguredPrefix — let `tag.prefix` in the config be the default for
107
+ * `--prefix`.
108
+ *
109
+ * WHY THIS EXISTS. The prefix was DECLARED in three places and read in one.
110
+ * Measured 2026-08-06: `tag.prefix` (a project config), `tag.format` (the
111
+ * packaged default and the Config type) and `config.tagPrefix` (read by
112
+ * FlowManager, declared by no config, so it interpolated the string
113
+ * "undefined" into its patterns). The only live knob was the CLI flag. A
114
+ * setting a project writes and nothing reads is worse than no setting: the
115
+ * next reader assumes the prefix is configured and it is not.
116
+ *
117
+ * THE FLAG STILL WINS, always. A caller that passes --prefix has said
118
+ * something more specific than the file, and a caller that passes NOTHING
119
+ * on a project with no tag.prefix gets exactly today's behaviour — so this
120
+ * cannot change what any existing invocation does.
121
+ */
122
+ async withConfiguredPrefix(options) {
123
+ var _a;
124
+ if (options.prefix !== undefined)
125
+ return options;
126
+ try {
127
+ const config = await (0, configManager_1.readConfig)(options.config, options.environment);
128
+ const prefix = (_a = config === null || config === void 0 ? void 0 : config.tag) === null || _a === void 0 ? void 0 : _a.prefix;
129
+ if (typeof prefix === 'string' && prefix.length > 0)
130
+ return { ...options, prefix };
131
+ }
132
+ catch (_b) {
133
+ // A config that cannot be read is not a reason to fail a version
134
+ // command that never needed it.
135
+ }
136
+ return options;
137
+ }
138
+ /**
139
+ * maybeStamp — write the version into the files the project declared.
140
+ *
141
+ * Never fatal by default. Stamping is a CONVENIENCE over a version that has
142
+ * already been decided and, at this point, already recorded; failing the
143
+ * command here would leave the caller believing no version was cut when one
144
+ * was. A file the project marked `required` still throws — that is the
145
+ * project saying the stamp is not a convenience — and the throw reaches the
146
+ * outer catch, which is why this does not swallow those.
147
+ */
148
+ async maybeStamp(version, options) {
149
+ if (options.skipStamp)
150
+ return;
151
+ let config;
152
+ try {
153
+ config = await (0, configManager_1.readConfig)(options.config, options.environment);
154
+ }
155
+ catch (_a) {
156
+ return; // no config, nothing declared, nothing to stamp
157
+ }
158
+ if (!config)
159
+ return;
160
+ const stamper = new VersionStamper_1.VersionStamper(config, process.cwd());
161
+ if (!stamper.configured)
162
+ return;
163
+ if (!stamper.onBump && !options.stamp)
164
+ return;
165
+ const result = await stamper.stamp(version);
166
+ console.error(`stamp: ${VersionStamper_1.VersionStamper.describe(result)}`);
167
+ // An UNMATCHED file is the silent-failure case this feature exists to
168
+ // prevent, so it is named individually rather than left as a count.
169
+ for (const f of result.unmatched) {
170
+ console.error(`stamp: WARNING ${f} — the configured pattern matched nothing; not stamped`);
171
+ }
172
+ }
15
173
  async handleVersionCommand(options) {
16
174
  try {
175
+ options = await this.withConfiguredPrefix(options);
17
176
  // Validate version manipulation options
18
177
  this.validator.validateVersionOptions(options);
19
178
  if (options.reset) {
@@ -46,11 +205,11 @@ class VersionController {
46
205
  return;
47
206
  }
48
207
  if (options.compare) {
49
- await this.gitManager.compareVersions(options.compare);
208
+ await this.gitManager.compareVersions(options.compare, options.prefix);
50
209
  return;
51
210
  }
52
211
  if (options.revert) {
53
- await this.gitManager.revertToVersion(options.revert, options.push);
212
+ await this.gitManager.revertToVersion(options.revert, options.push, options.prefix);
54
213
  return;
55
214
  }
56
215
  if (options.validate) {
@@ -61,6 +220,46 @@ class VersionController {
61
220
  await this.gitManager.syncVersions(options.push);
62
221
  return;
63
222
  }
223
+ // --derive: let the COMMITS name the bump, through the taxonomy this
224
+ // project already configured for its changelog.
225
+ //
226
+ // AN EXPLICIT FLAG ALWAYS WINS, and quietly. `--derive --minor` is an
227
+ // operator saying something the history cannot know — a compatibility
228
+ // break nobody marked, a release deliberately held back — and a tool
229
+ // that argued there would be overruled by hand every time until
230
+ // somebody stopped passing --derive at all.
231
+ //
232
+ // THE RANGE IS THE BASELINE'S. Whatever version this run bumps FROM
233
+ // is the only defensible start: it names the commit the previous
234
+ // version pointed at, so the range is exactly the work that is new.
235
+ // A wider range re-grades released commits and would re-derive the
236
+ // same major forever once one lands.
237
+ if (options.derive && !options.major && !options.minor && !options.patch) {
238
+ const evidence = await this.deriveBumpFromRange(options);
239
+ if (evidence) {
240
+ if (options.explainBump)
241
+ console.error(`bump: ${(0, BumpDeriver_1.explainBump)(evidence)}`);
242
+ options = { ...options, [evidence.bump]: true };
243
+ }
244
+ }
245
+ // ── THE BRANCH MAY IMPLY A CHANNEL (DECISIONS D1) ───────────────
246
+ //
247
+ // A feature deploy cuts a real prerelease named after its branch:
248
+ // `feature/new-thing` → `v1.0.1-feature-new-thing.1`. Off unless the
249
+ // branch's strategy declares `channelFromBranch`, and never when the
250
+ // caller named a channel itself — an explicit `--channel` is the
251
+ // operator saying which line they mean, and deriving over it would
252
+ // put the build somewhere they did not ask for.
253
+ // The config is read HERE rather than threaded in: this path is
254
+ // reached from several verbs and only one of them already holds it.
255
+ // A config that cannot be read is not a reason to fail a version —
256
+ // impliedChannel simply finds no declaration and derives nothing.
257
+ const branchCfg = await (0, configManager_1.readConfig)(options.config, options.environment).catch(() => undefined);
258
+ const implied = await (0, branchChannel_1.impliedChannel)(branchCfg, options.channel);
259
+ if (implied) {
260
+ options = { ...options, channel: implied };
261
+ console.error(`channel: ${implied} (from the current branch — branchStrategies.channelFromBranch)`);
262
+ }
64
263
  // Handle version creation/update
65
264
  let newVersion = '';
66
265
  if (options.version) {
@@ -72,11 +271,47 @@ class VersionController {
72
271
  else {
73
272
  newVersion = await this.gitManager.generateNewVersion(options);
74
273
  }
274
+ // --dry-run: answer "what WOULD be cut" without cutting.
275
+ //
276
+ // Every other path here mutates — createVersion writes release
277
+ // notes, createGitTag moves refs, push touches the remote — so
278
+ // asking the question used to mean performing the answer. A
279
+ // release plane whose only way to report the next version is to
280
+ // MINT it cannot be consulted by anything upstream: a build that
281
+ // wants to stamp the version it is about to produce, a CI gate
282
+ // checking the bump is the intended one, or an operator simply
283
+ // looking. The version is printed on stdout ALONE so it can be
284
+ // captured with $(...); everything explanatory goes to stderr.
285
+ if (options.dryRun) {
286
+ console.error(`dry-run: would create ${newVersion} (nothing was written)`);
287
+ console.log(newVersion);
288
+ return;
289
+ }
75
290
  await this.releaseManager.createVersion(newVersion, options);
291
+ // ── STAMP THE WORKING TREE, BEFORE THE TAG ────────────────────
292
+ //
293
+ // The order is the whole point. A tag is a pointer to a COMMIT, so
294
+ // stamping after tagging produces a tag whose files still say the
295
+ // previous version — the artefact built from that tag then carries
296
+ // a number that contradicts the tag it was built from, and the
297
+ // contradiction is invisible until somebody installs it.
298
+ //
299
+ // Opt-in twice over: nothing happens unless `versioning.stamp.files`
300
+ // is configured, and even then only with `--stamp` or
301
+ // `versioning.stamp.onBump`. A project that has never heard of this
302
+ // feature must behave on upgrade exactly as it did before.
303
+ await this.maybeStamp(newVersion, options);
76
304
  // Create git tag
77
305
  if (options.tag !== false) {
78
306
  // Default to true if not explicitly set to false
79
- await this.gitManager.createGitTag(newVersion);
307
+ // The note becomes the ANNOTATED TAG'S BODY. It was being
308
+ // dropped: createGitTag was called without it, so the tag
309
+ // message defaulted to the version string and the release note
310
+ // lived only wherever createVersion put it. An annotated tag
311
+ // whose body merely repeats its own name records nothing —
312
+ // "who cut this, from what, and why" is the entire reason the
313
+ // tag is an object rather than a ref.
314
+ await this.gitManager.createGitTag(newVersion, options.note);
80
315
  console.log(`Created tag: ${newVersion}`);
81
316
  }
82
317
  // Push changes if requested
@@ -1 +1 @@
1
- {"version":3,"file":"VersionController.js","sourceRoot":"","sources":["../../../src/modules/version/VersionController.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"VersionController.js","sourceRoot":"","sources":["../../../src/modules/version/VersionController.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,139 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.VersionStamper = void 0;
7
+ const fs_1 = require("fs");
8
+ const path_1 = require("path");
9
+ const simple_git_1 = __importDefault(require("simple-git"));
10
+ const ProjectVersion_1 = require("./ProjectVersion");
11
+ class VersionStamper {
12
+ constructor(config, root = process.cwd()) {
13
+ this.config = config;
14
+ this.root = root;
15
+ }
16
+ /** Whether the project has asked for any stamping at all. */
17
+ get configured() {
18
+ var _a, _b, _c, _d, _e;
19
+ return ((_e = (_d = (_c = (_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.versioning) === null || _b === void 0 ? void 0 : _b.stamp) === null || _c === void 0 ? void 0 : _c.files) === null || _d === void 0 ? void 0 : _d.length) !== null && _e !== void 0 ? _e : 0) > 0;
20
+ }
21
+ /** Whether a bump should stamp without being asked. Opt-in, default off. */
22
+ get onBump() {
23
+ var _a, _b;
24
+ return this.configured && ((_b = (_a = this.config.versioning) === null || _a === void 0 ? void 0 : _a.stamp) === null || _b === void 0 ? void 0 : _b.onBump) === true;
25
+ }
26
+ /**
27
+ * Expand one configured entry to concrete files.
28
+ *
29
+ * The wildcard rules are ProjectVersion's, deliberately: one matcher in the
30
+ * codebase, one set of refusals, one place that has been told why `glob` is
31
+ * not used here. A pattern this matcher cannot serve throws by name rather
32
+ * than resolving to "no files", which would read as "nothing to stamp".
33
+ */
34
+ expand(entry) {
35
+ const rel = entry.path;
36
+ if (!rel.includes('*')) {
37
+ return [rel];
38
+ }
39
+ const idx = rel.lastIndexOf('/');
40
+ const dir = idx === -1 ? '' : rel.slice(0, idx);
41
+ const base = idx === -1 ? rel : rel.slice(idx + 1);
42
+ const abs = (0, path_1.isAbsolute)(dir) ? dir : (0, path_1.join)(this.root, dir);
43
+ if (!(0, fs_1.existsSync)(abs))
44
+ return [];
45
+ return (0, ProjectVersion_1.matchFilesInDirectory)(base, abs).map(f => (dir ? `${dir}/${f}` : f));
46
+ }
47
+ /**
48
+ * Substitute the placeholders a project may use in `replace` and in the
49
+ * commit message. `{versionCore}` exists because a tag prefix belongs to the
50
+ * LINE, not to the version: a manifest field that must parse as semver
51
+ * cannot hold `v1.2.3`, and a project should not have to strip it with a
52
+ * regex in the replacement string.
53
+ */
54
+ fill(template, version) {
55
+ const core = version.replace(/^[^0-9]*/, '');
56
+ return template
57
+ .replace(/\{version\}/g, version)
58
+ .replace(/\{versionCore\}/g, core);
59
+ }
60
+ async stamp(version, opts = {}) {
61
+ var _a, _b, _c, _d, _e, _f;
62
+ const out = { stamped: [], unmatched: [], missing: [], unchanged: [] };
63
+ const stampCfg = (_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.versioning) === null || _b === void 0 ? void 0 : _b.stamp;
64
+ if (!((_c = stampCfg === null || stampCfg === void 0 ? void 0 : stampCfg.files) === null || _c === void 0 ? void 0 : _c.length))
65
+ return out;
66
+ for (const entry of stampCfg.files) {
67
+ const files = this.expand(entry);
68
+ if (files.length === 0) {
69
+ if (entry.required) {
70
+ throw new Error(`Version stamp: required path '${entry.path}' matched no file under ${this.root}.`);
71
+ }
72
+ out.missing.push(entry.path);
73
+ continue;
74
+ }
75
+ for (const rel of files) {
76
+ const abs = (0, path_1.isAbsolute)(rel) ? rel : (0, path_1.resolve)(this.root, rel);
77
+ if (!(0, fs_1.existsSync)(abs)) {
78
+ if (entry.required) {
79
+ throw new Error(`Version stamp: required file '${rel}' does not exist.`);
80
+ }
81
+ out.missing.push(rel);
82
+ continue;
83
+ }
84
+ const before = (0, fs_1.readFileSync)(abs, 'utf8');
85
+ // `m` so `^`/`$` anchor per LINE: the overwhelmingly common
86
+ // shape is a single `version:` line, and without it a pattern
87
+ // anchored at `^` can only ever match the first line of a file.
88
+ const re = new RegExp(entry.pattern, (_d = entry.flags) !== null && _d !== void 0 ? _d : 'm');
89
+ // `test` on a /g regex ADVANCES lastIndex, and the same object
90
+ // is reused for the replace below. `String.replace` happens to
91
+ // reset it, so this is currently harmless — and it is reset
92
+ // explicitly anyway, because "harmless because of what the
93
+ // other method does" is exactly the kind of coupling that
94
+ // breaks when one of the two lines moves.
95
+ const matched = re.test(before);
96
+ re.lastIndex = 0;
97
+ if (!matched) {
98
+ if (entry.required) {
99
+ throw new Error(`Version stamp: pattern /${entry.pattern}/ found nothing in required file '${rel}'.`);
100
+ }
101
+ out.unmatched.push(rel);
102
+ continue;
103
+ }
104
+ const after = before.replace(re, this.fill(entry.replace, version));
105
+ if (after === before) {
106
+ out.unchanged.push(rel);
107
+ continue;
108
+ }
109
+ if (!opts.dryRun)
110
+ (0, fs_1.writeFileSync)(abs, after);
111
+ out.stamped.push(rel);
112
+ }
113
+ }
114
+ if (!opts.dryRun && out.stamped.length > 0 && ((_e = stampCfg.commit) === null || _e === void 0 ? void 0 : _e.enabled)) {
115
+ const git = (0, simple_git_1.default)(this.root);
116
+ // PATHSPEC, never `-a`. See refusal 2 in the header.
117
+ await git.add(['--', ...out.stamped]);
118
+ const msg = this.fill((_f = stampCfg.commit.message) !== null && _f !== void 0 ? _f : 'chore(version): stamp {version}', version);
119
+ const res = await git.commit(msg, out.stamped);
120
+ out.commit = res.commit || undefined;
121
+ }
122
+ return out;
123
+ }
124
+ /** A one-line human summary — the shape a CLI prints on STDERR. */
125
+ static describe(r) {
126
+ const bits = [`${r.stamped.length} stamped`];
127
+ if (r.unchanged.length)
128
+ bits.push(`${r.unchanged.length} already current`);
129
+ if (r.unmatched.length)
130
+ bits.push(`${r.unmatched.length} UNMATCHED`);
131
+ if (r.missing.length)
132
+ bits.push(`${r.missing.length} missing`);
133
+ if (r.commit)
134
+ bits.push(`committed ${r.commit.slice(0, 10)}`);
135
+ return bits.join(' · ');
136
+ }
137
+ }
138
+ exports.VersionStamper = VersionStamper;
139
+ //# sourceMappingURL=VersionStamper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VersionStamper.js","sourceRoot":"","sources":["../../../src/modules/version/VersionStamper.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.channelFromBranchName = channelFromBranchName;
7
+ exports.strategyForBranch = strategyForBranch;
8
+ exports.impliedChannel = impliedChannel;
9
+ const simple_git_1 = __importDefault(require("simple-git"));
10
+ /**
11
+ * The prerelease channel a BRANCH implies, when its strategy asks for one.
12
+ *
13
+ * ── WHY A FEATURE DEPLOY IS A VERSION HERE (DECISIONS D1) ───────────────────
14
+ *
15
+ * A developer wants a feature branch on a server to look at. Two shapes were on
16
+ * the table: an identity (`feature-new-thing-<sha>`, nothing spent, nothing left
17
+ * behind) and a VERSION (`v1.0.1-feature-new-thing.1`). The operator chose the
18
+ * version, and the cost is understood rather than hidden: every look-at-it
19
+ * deploy spends an immutable number, and the tag outlives the branch it names.
20
+ *
21
+ * ── IT IS OFF UNTIL A STRATEGY ASKS FOR IT ──────────────────────────────────
22
+ *
23
+ * `branchStrategies.<type>.channelFromBranch: true` is the switch, and there is
24
+ * no global one. A project that has not asked cuts exactly what it cut before —
25
+ * this engine ships to other repositories, and a version scheme that turns
26
+ * itself on when someone happens to be on a branch would be a surprise arriving
27
+ * through an upgrade.
28
+ *
29
+ * ── THE CHANNEL IS THE BRANCH NAME, SANITISED, AND KEEPS ITS PREFIX ─────────
30
+ *
31
+ * `feature/new-thing` → `feature-new-thing`, not `new-thing`. Dropping the type
32
+ * would make `feature/login` and `bugfix/login` the same channel, so two
33
+ * branches would share a counter and each would renumber the other's builds.
34
+ * Semver's prerelease alphabet is [0-9A-Za-z-], so everything outside it
35
+ * becomes `-`.
36
+ */
37
+ function channelFromBranchName(branch) {
38
+ return branch
39
+ .replace(/[^0-9A-Za-z-]+/g, '-') // `/`, `_`, `.`, spaces → `-`
40
+ .replace(/-+/g, '-')
41
+ .replace(/^-|-$/g, '')
42
+ .toLowerCase();
43
+ }
44
+ /**
45
+ * The declared strategy whose prefix this branch carries, or undefined.
46
+ *
47
+ * Longest prefix wins, so a project declaring both `feature/` and
48
+ * `feature/exp/` gets the more specific one rather than whichever the object
49
+ * happened to enumerate first.
50
+ */
51
+ function strategyForBranch(config, branch) {
52
+ var _a, _b, _c;
53
+ const strategies = ((_a = config === null || config === void 0 ? void 0 : config.branchStrategies) !== null && _a !== void 0 ? _a : {});
54
+ let best;
55
+ for (const name of Object.keys(strategies)) {
56
+ const prefix = (_c = (_b = strategies[name]) === null || _b === void 0 ? void 0 : _b.branchPrefix) !== null && _c !== void 0 ? _c : `${name}/`;
57
+ if (!branch.startsWith(prefix))
58
+ continue;
59
+ if (!best || prefix.length > best.prefix.length)
60
+ best = { name, prefix };
61
+ }
62
+ return best;
63
+ }
64
+ /**
65
+ * The channel the CURRENT branch implies, or undefined when nothing asks.
66
+ *
67
+ * Returns undefined — never a channel — when: the caller already named one, the
68
+ * branch matches no declared strategy, that strategy has not set
69
+ * `channelFromBranch`, or git cannot say which branch this is (a detached HEAD
70
+ * has no name to derive from, and inventing one would put a build on a channel
71
+ * nobody can find again).
72
+ */
73
+ async function impliedChannel(config, explicit) {
74
+ var _a, _b;
75
+ if (explicit)
76
+ return undefined;
77
+ let branch = '';
78
+ try {
79
+ branch = (await (0, simple_git_1.default)().raw(['rev-parse', '--abbrev-ref', 'HEAD'])).trim();
80
+ }
81
+ catch (_c) {
82
+ return undefined;
83
+ }
84
+ if (!branch || branch === 'HEAD')
85
+ return undefined;
86
+ const strategy = strategyForBranch(config, branch);
87
+ if (!strategy)
88
+ return undefined;
89
+ const declared = ((_a = config === null || config === void 0 ? void 0 : config.branchStrategies) !== null && _a !== void 0 ? _a : {});
90
+ if (((_b = declared[strategy.name]) === null || _b === void 0 ? void 0 : _b.channelFromBranch) !== true)
91
+ return undefined;
92
+ return channelFromBranchName(branch);
93
+ }
94
+ //# sourceMappingURL=branchChannel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"branchChannel.js","sourceRoot":"","sources":["../../../src/modules/version/branchChannel.ts"],"names":[],"mappings":";;;;;AA8BA,sDAMC;AASD,8CAUC;AAWD,wCAgBC;AAlFD,4DAAkC;AAGlC;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,SAAgB,qBAAqB,CAAC,MAAc;IAChD,OAAO,MAAM;SACR,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAG,8BAA8B;SAChE,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;SACrB,WAAW,EAAE,CAAA;AACtB,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,iBAAiB,CAAC,MAA0B,EAAE,MAAc;;IAExE,MAAM,UAAU,GAAG,CAAC,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,gBAAgB,mCAAI,EAAE,CAA8C,CAAA;IAChG,IAAI,IAAkD,CAAA;IACtD,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QACzC,MAAM,MAAM,GAAG,MAAA,MAAA,UAAU,CAAC,IAAI,CAAC,0CAAE,YAAY,mCAAI,GAAG,IAAI,GAAG,CAAA;QAC3D,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC;YAAE,SAAQ;QACxC,IAAI,CAAC,IAAI,IAAI,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM;YAAE,IAAI,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;IAC5E,CAAC;IACD,OAAO,IAAI,CAAA;AACf,CAAC;AAED;;;;;;;;GAQG;AACI,KAAK,UAAU,cAAc,CAAC,MAA0B,EAAE,QAAiB;;IAC9E,IAAI,QAAQ;QAAE,OAAO,SAAS,CAAA;IAC9B,IAAI,MAAM,GAAG,EAAE,CAAA;IACf,IAAI,CAAC;QACD,MAAM,GAAG,CAAC,MAAM,IAAA,oBAAS,GAAE,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IAClF,CAAC;IAAC,WAAM,CAAC;QACL,OAAO,SAAS,CAAA;IACpB,CAAC;IACD,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,MAAM;QAAE,OAAO,SAAS,CAAA;IAElD,MAAM,QAAQ,GAAG,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAClD,IAAI,CAAC,QAAQ;QAAE,OAAO,SAAS,CAAA;IAC/B,MAAM,QAAQ,GAAG,CAAC,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,gBAAgB,mCAAI,EAAE,CAAoD,CAAA;IACpG,IAAI,CAAA,MAAA,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,0CAAE,iBAAiB,MAAK,IAAI;QAAE,OAAO,SAAS,CAAA;IAEzE,OAAO,qBAAqB,CAAC,MAAM,CAAC,CAAA;AACxC,CAAC"}
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.resolveVersionRef = resolveVersionRef;
7
+ exports.requireVersionRef = requireVersionRef;
8
+ const simple_git_1 = __importDefault(require("simple-git"));
9
+ /**
10
+ * Turn a version STRING into a ref this repository actually has.
11
+ *
12
+ * ── ONE NORMALISATION POINT, AND THAT IS THE WHOLE POINT (DECISIONS D4) ──────
13
+ *
14
+ * Every verb that takes a version by name has to answer the same question, and
15
+ * before this lived in one place they answered it differently — measured
16
+ * 2026-08-24 on a repo tagged `v1.0.0`:
17
+ *
18
+ * grm version --validate 1.0.0 accepted (it only checks the string's shape)
19
+ * grm version --compare 1.0.0 answered (…then built the range `1.0.0...v1.1.0`)
20
+ * grm version --revert 1.0.0 FATAL (straight into `git reset --hard`)
21
+ *
22
+ * Three verbs, three behaviours, one question. Per-verb handling is how that
23
+ * happens; a shared resolver is how it stops.
24
+ *
25
+ * Candidates in order: the string itself, then the configured prefix, then a
26
+ * bare `v`. Most-explicit-first, so a caller that already passed a real ref is
27
+ * never second-guessed, and `v` last because it is a convention rather than
28
+ * this repository's declaration.
29
+ *
30
+ * ── 🔴 THE ANSWER IS THE SHA, NOT THE ABSENCE OF A THROW ─────────────────────
31
+ *
32
+ * `rev-parse --verify --quiet` exits non-zero with EMPTY output when a ref does
33
+ * not resolve, and that shape does not reliably surface as a rejected promise.
34
+ * Measured: the first candidate was accepted for a tag that does not exist, the
35
+ * range stayed `1.0.0..HEAD`, and `git log` failed one call later in a place
36
+ * that could no longer say which spelling was wrong. So the sha is matched,
37
+ * not the control flow.
38
+ */
39
+ async function resolveVersionRef(input, prefix) {
40
+ const git = (0, simple_git_1.default)();
41
+ const candidates = [input];
42
+ if (prefix && !input.startsWith(prefix))
43
+ candidates.push(`${prefix}${input}`);
44
+ if (!input.startsWith('v'))
45
+ candidates.push(`v${input}`);
46
+ for (const candidate of candidates) {
47
+ try {
48
+ const out = await git.raw(['rev-parse', '--verify', '--quiet', `${candidate}^{commit}`]);
49
+ if (/^[0-9a-f]{40}/.test((out !== null && out !== void 0 ? out : '').trim()))
50
+ return candidate;
51
+ }
52
+ catch (_a) {
53
+ // Not a ref here. Try the next spelling — this is a lookup, and a
54
+ // miss is data, not a failure.
55
+ }
56
+ }
57
+ return null;
58
+ }
59
+ /**
60
+ * The same lookup, with a refusal that names every spelling it tried.
61
+ *
62
+ * A verb that is about to hand the answer to git wants this one: "1.0.0 is not
63
+ * a version in this repository (tried 1.0.0, v1.0.0)" is a sentence an operator
64
+ * can act on, where `fatal: ambiguous argument` is one they have to decode.
65
+ */
66
+ async function requireVersionRef(input, prefix) {
67
+ const ref = await resolveVersionRef(input, prefix);
68
+ if (ref)
69
+ return ref;
70
+ const tried = [input];
71
+ if (prefix && !input.startsWith(prefix))
72
+ tried.push(`${prefix}${input}`);
73
+ if (!input.startsWith('v'))
74
+ tried.push(`v${input}`);
75
+ throw new Error(`'${input}' is not a version in this repository (tried ${tried.join(', ')}). ` +
76
+ `Both the bare number and the tag spelling are accepted; neither resolves here.`);
77
+ }
78
+ //# sourceMappingURL=resolveVersionRef.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveVersionRef.js","sourceRoot":"","sources":["../../../src/modules/version/resolveVersionRef.ts"],"names":[],"mappings":";;;;;AAgCA,8CAgBC;AASD,8CAUC;AAnED,4DAAkC;AAElC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACI,KAAK,UAAU,iBAAiB,CAAC,KAAa,EAAE,MAAe;IAClE,MAAM,GAAG,GAAG,IAAA,oBAAS,GAAE,CAAA;IACvB,MAAM,UAAU,GAAG,CAAC,KAAK,CAAC,CAAA;IAC1B,IAAI,MAAM,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,UAAU,CAAC,IAAI,CAAC,GAAG,MAAM,GAAG,KAAK,EAAE,CAAC,CAAA;IAC7E,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,UAAU,CAAC,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC,CAAA;IAExD,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACjC,IAAI,CAAC;YACD,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,SAAS,WAAW,CAAC,CAAC,CAAA;YACxF,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC,GAAG,aAAH,GAAG,cAAH,GAAG,GAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;gBAAE,OAAO,SAAS,CAAA;QAClE,CAAC;QAAC,WAAM,CAAC;YACL,kEAAkE;YAClE,+BAA+B;QACnC,CAAC;IACL,CAAC;IACD,OAAO,IAAI,CAAA;AACf,CAAC;AAED;;;;;;GAMG;AACI,KAAK,UAAU,iBAAiB,CAAC,KAAa,EAAE,MAAe;IAClE,MAAM,GAAG,GAAG,MAAM,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;IAClD,IAAI,GAAG;QAAE,OAAO,GAAG,CAAA;IACnB,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,CAAA;IACrB,IAAI,MAAM,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,GAAG,KAAK,EAAE,CAAC,CAAA;IACxE,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC,CAAA;IACnD,MAAM,IAAI,KAAK,CACX,IAAI,KAAK,gDAAgD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK;QAC9E,gFAAgF,CACnF,CAAA;AACL,CAAC"}