fireflyy 4.0.0-dev.a10ed44 → 4.0.0-dev.a8aacbe
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/assets/firefly.schema.json +19 -17
- package/dist/{commit-analysis.service-Ba6hLgsr.js → commit-analysis.service-B2Z128t8.js} +3 -3
- package/dist/config.d.ts +10 -4
- package/dist/debug-flags-K3yK5B6O.js +74 -0
- package/dist/{dry-run-Cdg-c0EP.js → dry-run-C7RaPEq8.js} +2 -2
- package/dist/{filesystem.service-B8qg87n-.js → filesystem.service-DS2AQGNq.js} +4 -4
- package/dist/{git.service-BBqDH7qx.js → git.service-B6RdTilO.js} +5 -4
- package/dist/main.js +5 -5
- package/dist/{package-json.service-CHmtIoQQ.js → package-json.service-BlMNgPGQ.js} +3 -3
- package/dist/{program-Dqo9sQjU.js → program-BOk_0Q6Q.js} +527 -208
- package/dist/{result.constructors-BMtOWD2-.js → result.constructors-DoAoYdfF.js} +5 -1
- package/dist/{result.utilities-BTVU-GsT.js → result.utilities-DXSJU70_.js} +1 -1
- package/dist/{schema.utilities-BxiRR-GI.js → schema.utilities-C1yimTtB.js} +1 -1
- package/dist/version-DJuocyXy.js +164 -0
- package/dist/version-bumper.service-glxzf9Qm.js +171 -0
- package/dist/{version-strategy.service-CmfeZLYC.js → version-strategy.service-Dln42gxC.js} +41 -42
- package/package.json +8 -8
- package/dist/version-bumper.service-DMYR0npB.js +0 -318
- /package/dist/{logging-BuIkRrn1.js → logging-Bpk2RzGc.js} +0 -0
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { t as RuntimeEnv } from "./main.js";
|
|
2
|
-
import {
|
|
3
|
-
import { n as
|
|
4
|
-
import { t as
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
2
|
+
import { t as DebugFlags } from "./debug-flags-K3yK5B6O.js";
|
|
3
|
+
import { _ as notFoundError, a as conflictErrAsync, b as wrapErrorMessage, c as invalidErrAsync, d as validationErr, f as validationErrAsync, h as failedError, i as FireflyOkAsync, l as notFoundErrAsync, n as FireflyErrAsync, o as failedErrAsync, p as conflictError, r as FireflyOk, s as invalidErr, t as FireflyErr, u as timeoutErrAsync, y as validationError } from "./result.constructors-DoAoYdfF.js";
|
|
4
|
+
import { n as wrapPromise, t as ensureNotAsync } from "./result.utilities-DXSJU70_.js";
|
|
5
|
+
import { t as logger } from "./logging-Bpk2RzGc.js";
|
|
6
|
+
import { t as Version } from "./version-DJuocyXy.js";
|
|
7
|
+
import { t as formatZodErrors } from "./schema.utilities-C1yimTtB.js";
|
|
8
|
+
import { Command, InvalidArgumentError } from "commander";
|
|
7
9
|
import { LogLevels } from "consola";
|
|
8
10
|
import { colors } from "consola/utils";
|
|
9
11
|
import { loadConfig } from "c12";
|
|
@@ -12,70 +14,6 @@ import z$1 from "zod";
|
|
|
12
14
|
import { parse } from "semver";
|
|
13
15
|
import * as path from "path";
|
|
14
16
|
|
|
15
|
-
//#region src/core/environment/debug-flags.ts
|
|
16
|
-
/**
|
|
17
|
-
* Debug flags are environment variables prefixed with `FIREFLY_DEBUG_` that
|
|
18
|
-
* enable diagnostic features during development and troubleshooting.
|
|
19
|
-
*
|
|
20
|
-
* @example
|
|
21
|
-
* ```typescript
|
|
22
|
-
* if (DebugFlags.showRawError) {
|
|
23
|
-
* logger.error(parseResult.error);
|
|
24
|
-
* }
|
|
25
|
-
* ```
|
|
26
|
-
*/
|
|
27
|
-
var DebugFlags = class {
|
|
28
|
-
constructor() {}
|
|
29
|
-
/**
|
|
30
|
-
* When enabled, displays raw Zod validation errors for configuration parsing.
|
|
31
|
-
*
|
|
32
|
-
* Useful for debugging configuration schema issues and understanding
|
|
33
|
-
* why validation failed at a granular level.
|
|
34
|
-
*/
|
|
35
|
-
static get showRawError() {
|
|
36
|
-
return Boolean(process.env.FIREFLY_DEBUG_SHOW_RAW_ERROR);
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* When enabled, logs the loaded configuration file contents.
|
|
40
|
-
*
|
|
41
|
-
* Useful for debugging configuration loading and understanding
|
|
42
|
-
* what values are being read from config files.
|
|
43
|
-
*/
|
|
44
|
-
static get showFileConfig() {
|
|
45
|
-
return Boolean(process.env.FIREFLY_DEBUG_SHOW_FILE_CONFIG);
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* When enabled, displays task graph statistics during release execution.
|
|
49
|
-
*
|
|
50
|
-
* Shows information about task dependencies, execution order,
|
|
51
|
-
* and graph structure for debugging workflow issues.
|
|
52
|
-
*/
|
|
53
|
-
static get showTaskGraphStats() {
|
|
54
|
-
return Boolean(process.env.FIREFLY_DEBUG_SHOW_TASK_GRAPH_STATS);
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* When enabled, prevents truncation of release notes in GitHub CLI logs.
|
|
58
|
-
*
|
|
59
|
-
* By default, release notes are truncated in logs to avoid pollution.
|
|
60
|
-
* Enable this flag to see full release notes content during debugging.
|
|
61
|
-
*/
|
|
62
|
-
static get dontTruncateReleaseNotes() {
|
|
63
|
-
return Boolean(process.env.FIREFLY_DEBUG_DONT_TRUNCATE_RELEASE_NOTES?.trim());
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* When enabled, prevents redaction of sensitive GitHub CLI arguments in logs.
|
|
67
|
-
*
|
|
68
|
-
* By default, sensitive values (tokens, passwords, etc.) are redacted.
|
|
69
|
-
* Enable this flag to see full argument values during debugging.
|
|
70
|
-
*
|
|
71
|
-
* WARNING: Use with caution as this may expose sensitive information.
|
|
72
|
-
*/
|
|
73
|
-
static get dontRedactGithubCliArgs() {
|
|
74
|
-
return Boolean(process.env.FIREFLY_DEBUG_DONT_REDACT_GITHUB_CLI_ARGS?.trim());
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
//#endregion
|
|
79
17
|
//#region src/cli/config/config.loader.ts
|
|
80
18
|
/**
|
|
81
19
|
* Loads and resolves Firefly configuration from files.
|
|
@@ -185,6 +123,223 @@ function camelToKebab(str) {
|
|
|
185
123
|
return result.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase().replace(/_/g, "-");
|
|
186
124
|
}
|
|
187
125
|
|
|
126
|
+
//#endregion
|
|
127
|
+
//#region src/cli/options/options.validation.ts
|
|
128
|
+
/**
|
|
129
|
+
* Extracts enum values from a Zod schema (handles wrapped types like optional, default).
|
|
130
|
+
*
|
|
131
|
+
* @param schema - The Zod schema to extract enum values from
|
|
132
|
+
* @returns Array of string values if it's an enum, or null if not
|
|
133
|
+
*/
|
|
134
|
+
function extractEnumValues(schema) {
|
|
135
|
+
const unwrapped = unwrapZodSchema(schema);
|
|
136
|
+
if (unwrapped instanceof z$1.ZodEnum) return getEnumValuesFromZodEnum(unwrapped);
|
|
137
|
+
if (unwrapped instanceof z$1.ZodUnion) {
|
|
138
|
+
const unionOptions = getZodDef(unwrapped).options;
|
|
139
|
+
if (!unionOptions) return null;
|
|
140
|
+
const values = [];
|
|
141
|
+
for (const option of unionOptions) {
|
|
142
|
+
if (typeof option === "string") continue;
|
|
143
|
+
const innerUnwrapped = unwrapZodSchema(option);
|
|
144
|
+
if (innerUnwrapped instanceof z$1.ZodEnum) {
|
|
145
|
+
const enumValues = getEnumValuesFromZodEnum(innerUnwrapped);
|
|
146
|
+
if (enumValues) values.push(...enumValues);
|
|
147
|
+
} else if (innerUnwrapped instanceof z$1.ZodLiteral) {
|
|
148
|
+
const literalValue = getZodDef(innerUnwrapped).value;
|
|
149
|
+
if (typeof literalValue === "string" && literalValue !== "") values.push(literalValue);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return values.length > 0 ? values : null;
|
|
153
|
+
}
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Extracts enum values from a ZodEnum type.
|
|
158
|
+
* Handles both Zod v4 (options array or entries object) and legacy (values array) structures.
|
|
159
|
+
*
|
|
160
|
+
* @param enumSchema - The ZodEnum schema
|
|
161
|
+
* @returns Array of string values, or null if not found
|
|
162
|
+
*/
|
|
163
|
+
function getEnumValuesFromZodEnum(enumSchema) {
|
|
164
|
+
const schemaAsAny = enumSchema;
|
|
165
|
+
if (Array.isArray(schemaAsAny.options)) return schemaAsAny.options;
|
|
166
|
+
const def = getZodDef(enumSchema);
|
|
167
|
+
if (def.entries && typeof def.entries === "object") return Object.values(def.entries);
|
|
168
|
+
if (def.values && Array.isArray(def.values)) return def.values;
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Extracts literal values from a Zod union schema (e.g., z.union([z.literal("0"), z.literal("1")])).
|
|
173
|
+
*
|
|
174
|
+
* @param schema - The Zod schema to extract literal values from
|
|
175
|
+
* @returns Array of literal values if it's a union of literals, or null if not
|
|
176
|
+
*/
|
|
177
|
+
function extractLiteralValues(schema) {
|
|
178
|
+
const unwrapped = unwrapZodSchema(schema);
|
|
179
|
+
if (unwrapped instanceof z$1.ZodUnion) {
|
|
180
|
+
const options = getZodDef(unwrapped).options;
|
|
181
|
+
if (!options) return null;
|
|
182
|
+
const values = [];
|
|
183
|
+
for (const option of options) {
|
|
184
|
+
if (typeof option === "string" || typeof option === "number") continue;
|
|
185
|
+
const innerUnwrapped = unwrapZodSchema(option);
|
|
186
|
+
if (innerUnwrapped instanceof z$1.ZodLiteral) {
|
|
187
|
+
const value = getZodDef(innerUnwrapped).value;
|
|
188
|
+
if (typeof value === "string" || typeof value === "number") values.push(value);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return values.length > 0 ? values : null;
|
|
192
|
+
}
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Creates a CLI option validator for enum fields.
|
|
197
|
+
*
|
|
198
|
+
* Commander.js requires throwing InvalidArgumentError for validation errors.
|
|
199
|
+
* This is a boundary where exceptions are appropriate for the CLI framework.
|
|
200
|
+
*
|
|
201
|
+
* @param schema - The Zod schema for validation
|
|
202
|
+
* @param optionName - The CLI option name (for error messages)
|
|
203
|
+
* @param choices - The valid enum choices
|
|
204
|
+
* @returns A parser function that throws InvalidArgumentError on failure
|
|
205
|
+
*/
|
|
206
|
+
function createEnumValidator(schema, optionName, choices) {
|
|
207
|
+
return (input) => {
|
|
208
|
+
const result = schema.safeParse(input);
|
|
209
|
+
if (!result.success) throw new InvalidArgumentError(`Invalid value for --${optionName}: "${input}". Must be one of: ${choices.join(", ")}`);
|
|
210
|
+
return result.data;
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Creates a CLI option validator for number fields.
|
|
215
|
+
*
|
|
216
|
+
* Commander.js requires throwing InvalidArgumentError for validation errors.
|
|
217
|
+
* This is a boundary where exceptions are appropriate for the CLI framework.
|
|
218
|
+
*
|
|
219
|
+
* @param schema - The Zod schema for validation
|
|
220
|
+
* @param optionName - The CLI option name (for error messages)
|
|
221
|
+
* @returns A parser function that throws InvalidArgumentError on failure
|
|
222
|
+
*/
|
|
223
|
+
function createNumberValidator(schema, optionName) {
|
|
224
|
+
return (input) => {
|
|
225
|
+
const num = Number(input);
|
|
226
|
+
if (Number.isNaN(num)) throw new InvalidArgumentError(`Invalid number for --${optionName}: "${input}". Expected a valid number.`);
|
|
227
|
+
const result = schema.safeParse(num);
|
|
228
|
+
if (!result.success) throw new InvalidArgumentError(`Invalid value for --${optionName}: "${input}". ${formatZodErrorMessage(result.error)}`);
|
|
229
|
+
return result.data;
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Creates a CLI option validator for string fields.
|
|
234
|
+
*
|
|
235
|
+
* Commander.js requires throwing InvalidArgumentError for validation errors.
|
|
236
|
+
* This is a boundary where exceptions are appropriate for the CLI framework.
|
|
237
|
+
*
|
|
238
|
+
* @param schema - The Zod schema for validation
|
|
239
|
+
* @param optionName - The CLI option name (for error messages)
|
|
240
|
+
* @returns A parser function that throws InvalidArgumentError on failure
|
|
241
|
+
*/
|
|
242
|
+
function createStringValidator(schema, optionName) {
|
|
243
|
+
return (input) => {
|
|
244
|
+
const result = schema.safeParse(input);
|
|
245
|
+
if (!result.success) throw new InvalidArgumentError(`Invalid value for --${optionName}: "${input}". ${formatZodErrorMessage(result.error)}`);
|
|
246
|
+
return result.data;
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Creates a CLI option validator for union types with literal values.
|
|
251
|
+
*
|
|
252
|
+
* Commander.js requires throwing InvalidArgumentError for validation errors.
|
|
253
|
+
* This is a boundary where exceptions are appropriate for the CLI framework.
|
|
254
|
+
*
|
|
255
|
+
* @param schema - The Zod schema for validation
|
|
256
|
+
* @param optionName - The CLI option name (for error messages)
|
|
257
|
+
* @param values - The valid literal values
|
|
258
|
+
* @returns A parser function that throws InvalidArgumentError on failure
|
|
259
|
+
*/
|
|
260
|
+
function createLiteralUnionValidator(schema, optionName, values) {
|
|
261
|
+
return (input) => {
|
|
262
|
+
const numericValues = values.filter((v) => typeof v === "number");
|
|
263
|
+
let parsedInput = input;
|
|
264
|
+
if (numericValues.length > 0 && !Number.isNaN(Number(input))) parsedInput = Number(input);
|
|
265
|
+
const result = schema.safeParse(parsedInput);
|
|
266
|
+
if (!result.success) throw new InvalidArgumentError(`Invalid value for --${optionName}: "${input}". Must be one of: ${values.map((v) => typeof v === "string" ? `"${v}"` : String(v)).join(", ")}`);
|
|
267
|
+
return result.data;
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Creates a generic CLI option validator.
|
|
272
|
+
*
|
|
273
|
+
* Commander.js requires throwing InvalidArgumentError for validation errors.
|
|
274
|
+
* This is a boundary where exceptions are appropriate for the CLI framework.
|
|
275
|
+
*
|
|
276
|
+
* @param schema - The Zod schema for validation
|
|
277
|
+
* @param optionName - The CLI option name (for error messages)
|
|
278
|
+
* @returns A parser function that throws InvalidArgumentError on failure
|
|
279
|
+
*/
|
|
280
|
+
function createGenericValidator(schema, optionName) {
|
|
281
|
+
return (input) => {
|
|
282
|
+
const result = schema.safeParse(input);
|
|
283
|
+
if (!result.success) throw new InvalidArgumentError(`Invalid value for --${optionName}: "${input}". ${formatZodErrorMessage(result.error)}`);
|
|
284
|
+
return result.data;
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Formats a Zod error into a user-friendly message.
|
|
289
|
+
*
|
|
290
|
+
* @param error - The Zod error object
|
|
291
|
+
* @returns A formatted error message
|
|
292
|
+
*/
|
|
293
|
+
function formatZodErrorMessage(error) {
|
|
294
|
+
const firstIssue = error.issues[0];
|
|
295
|
+
if (!firstIssue) return "Validation failed.";
|
|
296
|
+
switch (firstIssue.code) {
|
|
297
|
+
case "invalid_value": {
|
|
298
|
+
const issue = firstIssue;
|
|
299
|
+
if (issue.values) return `Expected one of: ${issue.values.join(", ")}`;
|
|
300
|
+
return firstIssue.message;
|
|
301
|
+
}
|
|
302
|
+
case "invalid_type": return `Expected ${firstIssue.expected}`;
|
|
303
|
+
case "too_small":
|
|
304
|
+
case "too_big": return firstIssue.message;
|
|
305
|
+
default: return firstIssue.message;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Gets the internal definition object from a Zod type.
|
|
310
|
+
* Handles both modern Zod v4 (_zod.def) and legacy (_def) structures.
|
|
311
|
+
*
|
|
312
|
+
* @param field - The Zod type to get the definition from
|
|
313
|
+
* @returns The internal definition object
|
|
314
|
+
*/
|
|
315
|
+
function getZodDef(field) {
|
|
316
|
+
const zodContainer = field._zod;
|
|
317
|
+
if (zodContainer?.def) return zodContainer.def;
|
|
318
|
+
return field._def ?? {};
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Unwraps Zod wrapper types (optional, default, etc.) to get the inner type.
|
|
322
|
+
*
|
|
323
|
+
* @param field - The Zod type to unwrap
|
|
324
|
+
* @returns The unwrapped inner type
|
|
325
|
+
*/
|
|
326
|
+
function unwrapZodSchema(field) {
|
|
327
|
+
const def = getZodDef(field);
|
|
328
|
+
if (field instanceof z$1.ZodDefault) {
|
|
329
|
+
const inner = def.innerType;
|
|
330
|
+
return inner ? unwrapZodSchema(inner) : field;
|
|
331
|
+
}
|
|
332
|
+
if (field instanceof z$1.ZodOptional) {
|
|
333
|
+
const inner = def.innerType;
|
|
334
|
+
return inner ? unwrapZodSchema(inner) : field;
|
|
335
|
+
}
|
|
336
|
+
if (field instanceof z$1.ZodNullable) {
|
|
337
|
+
const inner = def.innerType;
|
|
338
|
+
return inner ? unwrapZodSchema(inner) : field;
|
|
339
|
+
}
|
|
340
|
+
return field;
|
|
341
|
+
}
|
|
342
|
+
|
|
188
343
|
//#endregion
|
|
189
344
|
//#region src/cli/options/options.builder.ts
|
|
190
345
|
/**
|
|
@@ -305,15 +460,14 @@ var OptionsBuilder = class {
|
|
|
305
460
|
this.registerGenericOption(ctx);
|
|
306
461
|
}
|
|
307
462
|
/**
|
|
308
|
-
* Registers a number option with numeric parsing.
|
|
463
|
+
* Registers a number option with numeric parsing and validation.
|
|
309
464
|
*
|
|
310
465
|
* @param ctx - The option context
|
|
311
466
|
*/
|
|
312
467
|
registerNumberOption(ctx) {
|
|
313
468
|
const { command, rawField, optionFlag, optionName, description, parsedDefault } = ctx;
|
|
314
|
-
const
|
|
315
|
-
|
|
316
|
-
command.option(`${optionFlag} <${optionName}>`, description, wrappedParser, parsedDefault);
|
|
469
|
+
const validator = createNumberValidator(rawField, optionName);
|
|
470
|
+
command.option(`${optionFlag} <${optionName}>`, description, validator, parsedDefault);
|
|
317
471
|
}
|
|
318
472
|
/**
|
|
319
473
|
* Registers an enum option with choice validation.
|
|
@@ -321,111 +475,46 @@ var OptionsBuilder = class {
|
|
|
321
475
|
* @param ctx - The option context
|
|
322
476
|
*/
|
|
323
477
|
registerEnumOption(ctx) {
|
|
324
|
-
const { command, rawField,
|
|
325
|
-
const choices =
|
|
326
|
-
const
|
|
327
|
-
const wrappedParser = this.wrapParser(parser);
|
|
478
|
+
const { command, rawField, optionFlag, optionName, description, parsedDefault } = ctx;
|
|
479
|
+
const choices = extractEnumValues(rawField) ?? [];
|
|
480
|
+
const validator = createEnumValidator(rawField, optionName, choices);
|
|
328
481
|
const fullDescription = `${description}${choices.length ? ` (choices: ${choices.join(", ")})` : ""}`;
|
|
329
|
-
command.option(`${optionFlag} <${optionName}>`, fullDescription,
|
|
482
|
+
command.option(`${optionFlag} <${optionName}>`, fullDescription, validator, parsedDefault);
|
|
330
483
|
}
|
|
331
484
|
/**
|
|
332
|
-
*
|
|
485
|
+
* Registers a string option with validation.
|
|
333
486
|
*
|
|
334
487
|
* @param ctx - The option context
|
|
335
488
|
*/
|
|
336
489
|
registerStringOption(ctx) {
|
|
337
490
|
const { command, rawField, optionFlag, optionName, description, parsedDefault } = ctx;
|
|
338
|
-
const
|
|
339
|
-
|
|
340
|
-
command.option(`${optionFlag} <${optionName}>`, description, wrappedParser, parsedDefault);
|
|
491
|
+
const validator = createStringValidator(rawField, optionName);
|
|
492
|
+
command.option(`${optionFlag} <${optionName}>`, description, validator, parsedDefault);
|
|
341
493
|
}
|
|
342
494
|
/**
|
|
343
495
|
* Registers a generic option for other Zod types.
|
|
496
|
+
* Handles union types with literal values specially for better error messages.
|
|
344
497
|
*
|
|
345
498
|
* @param ctx - The option context
|
|
346
499
|
*/
|
|
347
500
|
registerGenericOption(ctx) {
|
|
348
501
|
const { command, rawField, optionFlag, optionName, description, parsedDefault } = ctx;
|
|
349
|
-
const
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
if (result.isErr()) throw new Error(result.error);
|
|
366
|
-
return result.value;
|
|
367
|
-
};
|
|
368
|
-
}
|
|
369
|
-
/**
|
|
370
|
-
* Creates a parser for number options.
|
|
371
|
-
*
|
|
372
|
-
* @template T - The expected return type
|
|
373
|
-
* @param rawField - The raw Zod field
|
|
374
|
-
* @param optionName - The option name for error messages
|
|
375
|
-
* @returns A parser function that converts strings to numbers with validation
|
|
376
|
-
*/
|
|
377
|
-
createNumberParser(rawField, optionName) {
|
|
378
|
-
return (input) => {
|
|
379
|
-
const num = Number(input);
|
|
380
|
-
if (Number.isNaN(num)) return err(`Invalid number for --${optionName}: ${input}`);
|
|
381
|
-
const result = parseSchema(rawField, num);
|
|
382
|
-
if (result.isErr()) return err(result.error.message);
|
|
383
|
-
return ok(result.value);
|
|
384
|
-
};
|
|
385
|
-
}
|
|
386
|
-
/**
|
|
387
|
-
* Creates a parser for enum options.
|
|
388
|
-
*
|
|
389
|
-
* @template T - The expected return type
|
|
390
|
-
* @param rawField - The raw Zod field
|
|
391
|
-
* @param optionName - The option name for error messages
|
|
392
|
-
* @param choices - The valid enum choices
|
|
393
|
-
* @returns A parser function that validates input against the enum choices
|
|
394
|
-
*/
|
|
395
|
-
createEnumParser(rawField, optionName, choices) {
|
|
396
|
-
return (input) => {
|
|
397
|
-
const result = parseSchema(rawField, input);
|
|
398
|
-
if (result.isErr()) return err(`Invalid value for --${optionName}: ${input}. Allowed: ${choices.join(", ")}`);
|
|
399
|
-
return ok(result.value);
|
|
400
|
-
};
|
|
401
|
-
}
|
|
402
|
-
/**
|
|
403
|
-
* Creates a parser for string options.
|
|
404
|
-
*
|
|
405
|
-
* @template T - The expected return type
|
|
406
|
-
* @param rawField - The raw Zod field
|
|
407
|
-
* @returns A parser function that validates input against the schema
|
|
408
|
-
*/
|
|
409
|
-
createStringParser(rawField) {
|
|
410
|
-
return (input) => {
|
|
411
|
-
const result = parseSchema(rawField, input);
|
|
412
|
-
if (result.isErr()) return err(result.error.message);
|
|
413
|
-
return ok(result.value);
|
|
414
|
-
};
|
|
415
|
-
}
|
|
416
|
-
/**
|
|
417
|
-
* Creates a generic parser using Zod validation.
|
|
418
|
-
*
|
|
419
|
-
* @template T - The expected return type
|
|
420
|
-
* @param rawField - The raw Zod field
|
|
421
|
-
* @returns A parser function that validates input against the schema
|
|
422
|
-
*/
|
|
423
|
-
createGenericParser(rawField) {
|
|
424
|
-
return (input) => {
|
|
425
|
-
const result = parseSchema(rawField, input);
|
|
426
|
-
if (result.isErr()) return err(result.error.message);
|
|
427
|
-
return ok(result.value);
|
|
428
|
-
};
|
|
502
|
+
const literalValues = extractLiteralValues(rawField);
|
|
503
|
+
if (literalValues) {
|
|
504
|
+
const validator$1 = createLiteralUnionValidator(rawField, optionName, literalValues);
|
|
505
|
+
const fullDescription = `${description} (choices: ${literalValues.map((v) => typeof v === "string" ? v : String(v)).join(", ")})`;
|
|
506
|
+
command.option(`${optionFlag} <${optionName}>`, fullDescription, validator$1, parsedDefault);
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
const enumValues = extractEnumValues(rawField);
|
|
510
|
+
if (enumValues) {
|
|
511
|
+
const validator$1 = createEnumValidator(rawField, optionName, enumValues);
|
|
512
|
+
const fullDescription = `${description} (choices: ${enumValues.join(", ")})`;
|
|
513
|
+
command.option(`${optionFlag} <${optionName}>`, fullDescription, validator$1, parsedDefault);
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
const validator = createGenericValidator(rawField, optionName);
|
|
517
|
+
command.option(`${optionFlag} <${optionName}>`, description, validator, parsedDefault);
|
|
429
518
|
}
|
|
430
519
|
/**
|
|
431
520
|
* Gets the internal definition object from a Zod type.
|
|
@@ -470,15 +559,6 @@ var OptionsBuilder = class {
|
|
|
470
559
|
const def = this.getInternalDef(rawField);
|
|
471
560
|
return (def.innerType ?? def.schema) instanceof z$1.ZodBoolean;
|
|
472
561
|
}
|
|
473
|
-
/**
|
|
474
|
-
* Extracts enum choices from a ZodEnum field.
|
|
475
|
-
*
|
|
476
|
-
* @param field - The ZodEnum field
|
|
477
|
-
* @returns The array of valid enum choices
|
|
478
|
-
*/
|
|
479
|
-
getEnumChoices(field) {
|
|
480
|
-
return this.getInternalDef(field).values ?? [];
|
|
481
|
-
}
|
|
482
562
|
};
|
|
483
563
|
|
|
484
564
|
//#endregion
|
|
@@ -805,10 +885,63 @@ var TaskBuilder = class TaskBuilder {
|
|
|
805
885
|
|
|
806
886
|
//#endregion
|
|
807
887
|
//#region src/commands/release/tasks/bump-release-version.task.ts
|
|
888
|
+
const PACKAGE_JSON_FILE$1 = "package.json";
|
|
889
|
+
/**
|
|
890
|
+
* Updates the configured package.json with the next version.
|
|
891
|
+
*
|
|
892
|
+
* @param ctx - The current release context
|
|
893
|
+
* @returns A FireflyAsyncResult resolving to the release context after update
|
|
894
|
+
*/
|
|
895
|
+
function updatePackageJsonVersion(ctx) {
|
|
896
|
+
return ctx.services.packageJson.updateVersion(PACKAGE_JSON_FILE$1, ctx.data.nextVersion).map(() => ctx);
|
|
897
|
+
}
|
|
898
|
+
/**
|
|
899
|
+
* Restores a previous version value in the configured package.json.
|
|
900
|
+
*
|
|
901
|
+
* @param ctx - The current release context
|
|
902
|
+
* @param previousVersion - The previous version string to restore
|
|
903
|
+
* @returns A FireflyAsyncResult resolving to the release context after restore
|
|
904
|
+
*/
|
|
905
|
+
function restorePackageJsonVersion(ctx, previousVersion) {
|
|
906
|
+
return ctx.services.packageJson.updateVersion(PACKAGE_JSON_FILE$1, previousVersion).map(() => ctx);
|
|
907
|
+
}
|
|
908
|
+
/**
|
|
909
|
+
* Validates that the release context contains a next version value.
|
|
910
|
+
*
|
|
911
|
+
* @param ctx - The current release context
|
|
912
|
+
* @returns A FireflyResult with the next version or a validation error
|
|
913
|
+
*/
|
|
914
|
+
function parseNextVersion(ctx) {
|
|
915
|
+
const nextVersion = ctx.data.nextVersion;
|
|
916
|
+
if (!nextVersion) return validationErr({ message: "Next version is undefined" });
|
|
917
|
+
return FireflyOk(nextVersion);
|
|
918
|
+
}
|
|
919
|
+
/**
|
|
920
|
+
* Creates the Bump Release Version task.
|
|
921
|
+
*
|
|
922
|
+
* This task updates the version of the project to the next version determined
|
|
923
|
+
* by earlier steps. Specifically, it:
|
|
924
|
+
* 1. Validates that a `nextVersion` exists in the release context
|
|
925
|
+
* 2. Writes the `nextVersion` into the configured package.json file
|
|
926
|
+
* 3. Provides an undo operation that restores the original version
|
|
927
|
+
*/
|
|
808
928
|
function createBumpReleaseVersion() {
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
929
|
+
/**
|
|
930
|
+
* Holds the previous version before bumping, for undo purposes if needed.
|
|
931
|
+
*/
|
|
932
|
+
let previousVersion;
|
|
933
|
+
return TaskBuilder.create("bump-release-version").description("Applies the new version bump to relevant files").dependsOnAll("straight-version-bump", "determine-automatic-bump", "prompt-manual-version", "prompt-bump-strategy").skipWhenWithReason((ctx) => ctx.config.skipBump || !ctx.data.nextVersion, "Skipped: skipBump is enabled or next version is not set").execute((ctx) => {
|
|
934
|
+
previousVersion = ctx.data.currentVersion;
|
|
935
|
+
const nextVersionRes = parseNextVersion(ctx);
|
|
936
|
+
if (nextVersionRes.isErr()) return FireflyErrAsync(nextVersionRes.error);
|
|
937
|
+
logger.info(`Next version to be released: ${colors.green(nextVersionRes.value)}`);
|
|
938
|
+
return updatePackageJsonVersion(ctx).andTee(() => logger.success("package.json version updated successfully."));
|
|
939
|
+
}).withUndo((ctx) => {
|
|
940
|
+
if (!previousVersion) {
|
|
941
|
+
logger.verbose("BumpReleaseVersionTask: Previous version is undefined, skipping undo operation.");
|
|
942
|
+
return FireflyOkAsync(void 0);
|
|
943
|
+
}
|
|
944
|
+
return restorePackageJsonVersion(ctx, previousVersion).map(() => void 0);
|
|
812
945
|
}).build();
|
|
813
946
|
}
|
|
814
947
|
|
|
@@ -1029,22 +1162,60 @@ function createDelegateBumpStrategyTask() {
|
|
|
1029
1162
|
shouldSkip,
|
|
1030
1163
|
reason: shouldSkip ? getSkipReason(ctx) : void 0
|
|
1031
1164
|
});
|
|
1032
|
-
}).execute((ctx) =>
|
|
1033
|
-
logger.info("delegate-bump-strategy");
|
|
1034
|
-
return FireflyOkAsync(ctx);
|
|
1035
|
-
}).build();
|
|
1165
|
+
}).execute((ctx) => FireflyOkAsync(ctx)).build();
|
|
1036
1166
|
}
|
|
1037
1167
|
|
|
1038
1168
|
//#endregion
|
|
1039
1169
|
//#region src/commands/release/tasks/determine-automatic-bump.task.ts
|
|
1170
|
+
/**
|
|
1171
|
+
* Parses the current version from a raw string.
|
|
1172
|
+
*
|
|
1173
|
+
* @param currentVersionRaw - The raw string representing the current version
|
|
1174
|
+
* @returns A FireflyResult containing the parsed Version or a validation error
|
|
1175
|
+
*/
|
|
1176
|
+
function parseCurrentVersion$2(currentVersionRaw) {
|
|
1177
|
+
if (!currentVersionRaw) return validationErr({ message: "Current version is undefined" });
|
|
1178
|
+
return Version.from(currentVersionRaw);
|
|
1179
|
+
}
|
|
1180
|
+
/**
|
|
1181
|
+
* Logs the analysis recommendation with formatting.
|
|
1182
|
+
*
|
|
1183
|
+
* @param reason - The reason string from the recommendation
|
|
1184
|
+
*/
|
|
1185
|
+
function logRecommendation(reason) {
|
|
1186
|
+
if (!reason) return;
|
|
1187
|
+
if (reason.startsWith("Analysis found:")) {
|
|
1188
|
+
const prefix = "Analysis found:";
|
|
1189
|
+
const details = reason.slice(15).trim();
|
|
1190
|
+
logger.info(`${prefix} ${colors.green(details)}`);
|
|
1191
|
+
} else logger.info(reason);
|
|
1192
|
+
}
|
|
1193
|
+
/**
|
|
1194
|
+
* Performs the automatic bump by analyzing commits and resolving version strategy.
|
|
1195
|
+
*/
|
|
1196
|
+
function executeAutomaticBump(ctx) {
|
|
1197
|
+
const currentVersionResult = parseCurrentVersion$2(ctx.data.currentVersion);
|
|
1198
|
+
if (currentVersionResult.isErr()) return FireflyErrAsync(currentVersionResult.error);
|
|
1199
|
+
const currentVersion = currentVersionResult.value;
|
|
1200
|
+
return ctx.services.commitAnalysis.analyzeForVersion().andThen((recommendation) => {
|
|
1201
|
+
logRecommendation(recommendation.reason);
|
|
1202
|
+
const options = {
|
|
1203
|
+
currentVersion,
|
|
1204
|
+
preReleaseId: ctx.config.preReleaseId,
|
|
1205
|
+
preReleaseBase: ctx.config.preReleaseBase
|
|
1206
|
+
};
|
|
1207
|
+
return ctx.services.versionStrategy.resolveVersion(options, recommendation);
|
|
1208
|
+
}).andThen((newVersion) => {
|
|
1209
|
+
const from = ctx.data.currentVersion || "unknown";
|
|
1210
|
+
logger.info(`Determined version: ${colors.green(from)} -> ${colors.green(newVersion.raw)}`);
|
|
1211
|
+
return FireflyOkAsync(ctx.fork("nextVersion", newVersion.toString()));
|
|
1212
|
+
});
|
|
1213
|
+
}
|
|
1040
1214
|
function createDetermineAutomaticBump() {
|
|
1041
1215
|
return TaskBuilder.create("determine-automatic-bump").description("Automatically determines the version bump from commit messages").dependsOn("delegate-bump-strategy").skipWhenWithReason((ctx) => {
|
|
1042
1216
|
const bumpStrategy = ctx.data.selectedBumpStrategy ?? ctx.config.bumpStrategy;
|
|
1043
1217
|
return ctx.config.skipBump || bumpStrategy !== BUMP_STRATEGY_AUTO;
|
|
1044
|
-
}, "Skipped: skipBump enabled or bumpStrategy is not 'auto'").execute((ctx) =>
|
|
1045
|
-
logger.info("determine-automatic-bump");
|
|
1046
|
-
return FireflyOkAsync(ctx);
|
|
1047
|
-
}).build();
|
|
1218
|
+
}, "Skipped: skipBump enabled or bumpStrategy is not 'auto'").execute((ctx) => executeAutomaticBump(ctx)).build();
|
|
1048
1219
|
}
|
|
1049
1220
|
|
|
1050
1221
|
//#endregion
|
|
@@ -1091,29 +1262,108 @@ function promptBumpStrategy() {
|
|
|
1091
1262
|
return FireflyOkAsync(selected);
|
|
1092
1263
|
});
|
|
1093
1264
|
}
|
|
1265
|
+
/**
|
|
1266
|
+
* Creates the Prompt Bump Strategy Task.
|
|
1267
|
+
*
|
|
1268
|
+
* This task prompts the user to select a version bump strategy (automatic or manual) and
|
|
1269
|
+
* stores it in the release context. It depends on `initialize-release-version` and will be
|
|
1270
|
+
* skipped when `skipBump` is enabled or a `bumpStrategy`/`releaseType` is already provided.
|
|
1271
|
+
*
|
|
1272
|
+
* This task:
|
|
1273
|
+
* 1. Prompts the user to select a bump strategy
|
|
1274
|
+
*/
|
|
1094
1275
|
function createPromptBumpStrategyTask() {
|
|
1095
1276
|
return TaskBuilder.create("prompt-bump-strategy").description("Prompts the user for a version bump strategy").dependsOn("initialize-release-version").skipWhenWithReason((ctx) => ctx.config.skipBump || Boolean(ctx.config.bumpStrategy) || Boolean(ctx.config.releaseType), "Skipped: skipBump enabled, or bumpStrategy/releaseType already specified").execute((ctx) => promptBumpStrategy().andThen((strategy) => FireflyOkAsync(ctx.fork("selectedBumpStrategy", strategy)))).build();
|
|
1096
1277
|
}
|
|
1097
1278
|
|
|
1098
1279
|
//#endregion
|
|
1099
1280
|
//#region src/commands/release/tasks/prompt-manual-bump.task.ts
|
|
1281
|
+
/**
|
|
1282
|
+
* Parses the current version from a raw string.
|
|
1283
|
+
*
|
|
1284
|
+
* @param currentVersionRaw - The raw string representing the current version
|
|
1285
|
+
* @returns A FireflyResult containing the parsed Version or a validation error
|
|
1286
|
+
*/
|
|
1287
|
+
function parseCurrentVersion$1(currentVersionRaw) {
|
|
1288
|
+
if (!currentVersionRaw) return validationErr({ message: "Current version is undefined" });
|
|
1289
|
+
return Version.from(currentVersionRaw);
|
|
1290
|
+
}
|
|
1291
|
+
/**
|
|
1292
|
+
* Generates version choices and prompts the user to select one.
|
|
1293
|
+
*/
|
|
1294
|
+
function promptForManualVersion(ctx) {
|
|
1295
|
+
const currentVersionResult = parseCurrentVersion$1(ctx.data.currentVersion);
|
|
1296
|
+
if (currentVersionResult.isErr()) return FireflyErrAsync(currentVersionResult.error);
|
|
1297
|
+
const currentVersion = currentVersionResult.value;
|
|
1298
|
+
logger.verbose("PromptManualVersionTask: Generating version choices...");
|
|
1299
|
+
return ctx.services.versionStrategy.generateChoices({
|
|
1300
|
+
currentVersion,
|
|
1301
|
+
preReleaseId: ctx.config.preReleaseId,
|
|
1302
|
+
preReleaseBase: ctx.config.preReleaseBase
|
|
1303
|
+
}).andThen((choices) => {
|
|
1304
|
+
if (!choices || choices.length === 0) return validationErrAsync({ message: "No version choices available" });
|
|
1305
|
+
logger.verbose(`PromptManualVersionTask: Generated ${choices.length} version choices.`);
|
|
1306
|
+
const defaultChoice = choices[0];
|
|
1307
|
+
return wrapPromise(logger.prompt("Select version to release", {
|
|
1308
|
+
type: "select",
|
|
1309
|
+
options: choices,
|
|
1310
|
+
initial: defaultChoice?.value,
|
|
1311
|
+
cancel: "undefined"
|
|
1312
|
+
})).andThen((selected) => {
|
|
1313
|
+
if (!selected || selected === "") return failedErrAsync({ message: "Operation cancelled by user" });
|
|
1314
|
+
if (logger.level === LogLevels.verbose) logger.log("");
|
|
1315
|
+
if (logger.level !== LogLevels.verbose) logger.log("");
|
|
1316
|
+
logger.verbose(`PromptManualVersionTask: Selected version: '${selected}'`);
|
|
1317
|
+
return FireflyOkAsync(selected);
|
|
1318
|
+
});
|
|
1319
|
+
});
|
|
1320
|
+
}
|
|
1100
1321
|
function createPromptManualVersionTask() {
|
|
1101
|
-
return TaskBuilder.create("prompt-manual-version").description("Prompts the user
|
|
1322
|
+
return TaskBuilder.create("prompt-manual-version").description("Prompts the user to manually select the next version").dependsOn("delegate-bump-strategy").skipWhenWithReason((ctx) => {
|
|
1102
1323
|
const bumpStrategy = ctx.data.selectedBumpStrategy ?? ctx.config.bumpStrategy;
|
|
1103
1324
|
return ctx.config.skipBump || bumpStrategy !== BUMP_STRATEGY_MANUAL;
|
|
1104
|
-
}, "Skipped: skipBump enabled or bumpStrategy is not 'manual'").execute((ctx) =>
|
|
1105
|
-
logger.info("prompt-manual-version");
|
|
1106
|
-
return FireflyOkAsync(ctx);
|
|
1107
|
-
}).build();
|
|
1325
|
+
}, "Skipped: skipBump enabled or bumpStrategy is not 'manual'").execute((ctx) => promptForManualVersion(ctx).andThen((selectedVersion) => FireflyOkAsync(ctx.fork("nextVersion", selectedVersion)))).build();
|
|
1108
1326
|
}
|
|
1109
1327
|
|
|
1110
1328
|
//#endregion
|
|
1111
1329
|
//#region src/commands/release/tasks/straight-version-bump.task.ts
|
|
1330
|
+
/**
|
|
1331
|
+
* Parses the current version from a raw string.
|
|
1332
|
+
*
|
|
1333
|
+
* @param currentVersionRaw - The raw string representing the current version
|
|
1334
|
+
* @returns A FireflyResult containing the parsed Version or a validation error
|
|
1335
|
+
*/
|
|
1336
|
+
function parseCurrentVersion(currentVersionRaw) {
|
|
1337
|
+
if (!currentVersionRaw) return validationErr({ message: "Current version is undefined" });
|
|
1338
|
+
return Version.from(currentVersionRaw);
|
|
1339
|
+
}
|
|
1340
|
+
/**
|
|
1341
|
+
* Builds the bump options from the release context.
|
|
1342
|
+
*/
|
|
1343
|
+
function buildBumpOptionsFromContext(ctx) {
|
|
1344
|
+
const currentVersionResult = parseCurrentVersion(ctx.data.currentVersion);
|
|
1345
|
+
if (currentVersionResult.isErr()) return FireflyErrAsync(currentVersionResult.error);
|
|
1346
|
+
const releaseType = ctx.config.releaseType;
|
|
1347
|
+
if (releaseType === void 0) return invalidErrAsync({ message: "Release type is required for straight bump" });
|
|
1348
|
+
return FireflyOkAsync({
|
|
1349
|
+
currentVersion: currentVersionResult.value,
|
|
1350
|
+
releaseType,
|
|
1351
|
+
preReleaseId: ctx.config.preReleaseId,
|
|
1352
|
+
preReleaseBase: ctx.config.preReleaseBase
|
|
1353
|
+
});
|
|
1354
|
+
}
|
|
1355
|
+
/**
|
|
1356
|
+
* Performs the straight bump by delegating to the version bumper service.
|
|
1357
|
+
*/
|
|
1358
|
+
function executeStraightVersionBump(ctx) {
|
|
1359
|
+
return buildBumpOptionsFromContext(ctx).andThen((options) => ctx.services.versionBumper.bump(options)).andThen((newVersion) => {
|
|
1360
|
+
const from = ctx.data.currentVersion || "unknown";
|
|
1361
|
+
logger.info(`Bumped version: ${colors.green(from)} -> ${colors.green(newVersion.raw)}`);
|
|
1362
|
+
return FireflyOkAsync(ctx.fork("nextVersion", newVersion.toString()));
|
|
1363
|
+
});
|
|
1364
|
+
}
|
|
1112
1365
|
function createStraightVersionBump() {
|
|
1113
|
-
return TaskBuilder.create("straight-version-bump").description("Performs a direct version bump based on the configured release type").dependsOn("initialize-release-version").skipWhenWithReason((ctx) => ctx.config.skipBump || ctx.config.releaseType === void 0, "Skipped: skipBump is enabled or no release type specified").execute((ctx) =>
|
|
1114
|
-
logger.info("straight-version-bump");
|
|
1115
|
-
return FireflyOkAsync(ctx);
|
|
1116
|
-
}).build();
|
|
1366
|
+
return TaskBuilder.create("straight-version-bump").description("Performs a direct version bump based on the configured release type").dependsOn("initialize-release-version").skipWhenWithReason((ctx) => ctx.config.skipBump || ctx.config.releaseType === void 0, "Skipped: skipBump is enabled or no release type specified").execute((ctx) => executeStraightVersionBump(ctx)).build();
|
|
1117
1367
|
}
|
|
1118
1368
|
|
|
1119
1369
|
//#endregion
|
|
@@ -1167,7 +1417,7 @@ function getVersionFromPackageJson(ctx) {
|
|
|
1167
1417
|
*/
|
|
1168
1418
|
function createInitializeReleaseVersion() {
|
|
1169
1419
|
return TaskBuilder.create("initialize-release-version").description("Initialize current release version from package.json").dependsOn("prepare-release-config").execute((ctx) => getVersionFromPackageJson(ctx).andThen((currentVersion) => {
|
|
1170
|
-
logger.info(`Current version is ${currentVersion}`);
|
|
1420
|
+
logger.info(`Current version is ${colors.green(currentVersion)}`);
|
|
1171
1421
|
return FireflyOkAsync(ctx.fork("currentVersion", currentVersion));
|
|
1172
1422
|
})).build();
|
|
1173
1423
|
}
|
|
@@ -1280,7 +1530,7 @@ function hydrateScopeFromPackageJson(ctx, packageJson) {
|
|
|
1280
1530
|
* 3. Otherwise the function defaults to "alpha".
|
|
1281
1531
|
*/
|
|
1282
1532
|
function hydratePreReleaseIdFromPackageJson(ctx, packageJson) {
|
|
1283
|
-
if (ctx.config
|
|
1533
|
+
if (Object.hasOwn(ctx.config, "preReleaseId") && ctx.config.preReleaseId !== void 0) {
|
|
1284
1534
|
logger.verbose(`PrepareReleaseConfigTask: Using provided preReleaseId: "${ctx.config.preReleaseId}" as it is explicitly set`);
|
|
1285
1535
|
return FireflyOkAsync(ctx.config.preReleaseId);
|
|
1286
1536
|
}
|
|
@@ -1297,26 +1547,47 @@ function hydratePreReleaseIdFromPackageJson(ctx, packageJson) {
|
|
|
1297
1547
|
return FireflyOkAsync("alpha");
|
|
1298
1548
|
}
|
|
1299
1549
|
/**
|
|
1550
|
+
* Hydrates the `preReleaseBase` field.
|
|
1551
|
+
*
|
|
1552
|
+
* Behavior:
|
|
1553
|
+
* - If explicitly provided in config (key exists and value is not undefined) use as-is.
|
|
1554
|
+
* - Otherwise default to 0.
|
|
1555
|
+
*
|
|
1556
|
+
* Note: we do NOT infer `preReleaseBase` from package.json anymore.
|
|
1557
|
+
*/
|
|
1558
|
+
function hydratePreReleaseBase(ctx) {
|
|
1559
|
+
const baseMaybe = ctx.config.preReleaseBase;
|
|
1560
|
+
if (Object.hasOwn(ctx.config, "preReleaseBase") && baseMaybe !== void 0) {
|
|
1561
|
+
logger.verbose(`PrepareReleaseConfigTask: Using provided preReleaseBase: "${ctx.config.preReleaseBase}" as it is explicitly set`);
|
|
1562
|
+
return FireflyOkAsync(baseMaybe);
|
|
1563
|
+
}
|
|
1564
|
+
logger.verbose("PrepareReleaseConfigTask: No preReleaseBase explicitly provided, defaulting to 0");
|
|
1565
|
+
return FireflyOkAsync(0);
|
|
1566
|
+
}
|
|
1567
|
+
/**
|
|
1300
1568
|
* Hydrates name, scope, and preReleaseId from package.json.
|
|
1301
1569
|
*
|
|
1302
1570
|
* Behavior:
|
|
1303
1571
|
* - If package.json does not exist, returns all values as undefined.
|
|
1304
1572
|
* - If it exists, reads package.json and returns parsed results for name, scope and preReleaseId.
|
|
1573
|
+
* - If preReleaseBase is explicitly provided in config, it is used as-is, if not, it defaults to 0.
|
|
1305
1574
|
*/
|
|
1306
1575
|
function hydrateFromPackageJson(ctx) {
|
|
1307
1576
|
return ctx.services.fs.exists("package.json").andThen((exists) => {
|
|
1308
1577
|
if (!exists) return FireflyOkAsync({
|
|
1309
1578
|
name: void 0,
|
|
1310
1579
|
scope: void 0,
|
|
1311
|
-
preReleaseId: void 0
|
|
1580
|
+
preReleaseId: void 0,
|
|
1581
|
+
preReleaseBase: void 0
|
|
1312
1582
|
});
|
|
1313
|
-
return ctx.services.packageJson.read("package.json").andThen((pkg) => hydrateNameFromPackageJson(ctx, pkg).andThen((name) => hydrateScopeFromPackageJson(ctx, pkg).andThen((scope) => hydratePreReleaseIdFromPackageJson(ctx, pkg).
|
|
1583
|
+
return ctx.services.packageJson.read("package.json").andThen((pkg) => hydrateNameFromPackageJson(ctx, pkg).andThen((name) => hydrateScopeFromPackageJson(ctx, pkg).andThen((scope) => hydratePreReleaseIdFromPackageJson(ctx, pkg).andThen((preReleaseId) => hydratePreReleaseBase(ctx).map((preReleaseBase) => {
|
|
1314
1584
|
const result = {};
|
|
1315
1585
|
if (name) result.name = name;
|
|
1316
1586
|
if (scope) result.scope = scope;
|
|
1317
1587
|
if (preReleaseId) result.preReleaseId = preReleaseId;
|
|
1588
|
+
if (preReleaseBase !== void 0) result.preReleaseBase = preReleaseBase;
|
|
1318
1589
|
return result;
|
|
1319
|
-
}))));
|
|
1590
|
+
})))));
|
|
1320
1591
|
});
|
|
1321
1592
|
}
|
|
1322
1593
|
/**
|
|
@@ -1447,12 +1718,13 @@ function createPrepareReleaseConfigTask() {
|
|
|
1447
1718
|
if (pkgData.name) hydrated.name = pkgData.name;
|
|
1448
1719
|
if (pkgData.scope) hydrated.scope = pkgData.scope;
|
|
1449
1720
|
if (pkgData.preReleaseId) hydrated.preReleaseId = pkgData.preReleaseId;
|
|
1721
|
+
if (pkgData.preReleaseBase !== void 0) hydrated.preReleaseBase = pkgData.preReleaseBase;
|
|
1450
1722
|
return hydrateReleaseFlags(ctx);
|
|
1451
1723
|
}).map((releaseFlags) => {
|
|
1452
1724
|
hydrated.releaseLatest = releaseFlags.releaseLatest;
|
|
1453
1725
|
hydrated.releasePreRelease = releaseFlags.releasePreRelease;
|
|
1454
1726
|
hydrated.releaseDraft = releaseFlags.releaseDraft;
|
|
1455
|
-
return ctx.
|
|
1727
|
+
return ctx.forkConfig(hydrated);
|
|
1456
1728
|
});
|
|
1457
1729
|
}).build();
|
|
1458
1730
|
}
|
|
@@ -1662,17 +1934,23 @@ function validateSkipFlagCombinations(ctx) {
|
|
|
1662
1934
|
input: ctx.value
|
|
1663
1935
|
});
|
|
1664
1936
|
}
|
|
1665
|
-
|
|
1937
|
+
/**
|
|
1938
|
+
* Base release configuration schema without refinements.
|
|
1939
|
+
* Use this schema for JSON schema generation and `.partial()` operations.
|
|
1940
|
+
* Zod v4 does not allow `.partial()` on schemas with refinements.
|
|
1941
|
+
*/
|
|
1942
|
+
const ReleaseConfigBaseSchema = z$1.object({
|
|
1666
1943
|
name: z$1.string().optional().describe("Unscoped project name. Auto-detected from package.json."),
|
|
1667
1944
|
scope: z$1.string().optional().describe("Org/user scope without '@'. Auto-detected from package.json."),
|
|
1668
|
-
|
|
1945
|
+
repository: z$1.string().optional().describe("GitHub repository in 'owner/repo' format."),
|
|
1946
|
+
base: z$1.string().optional().describe("Relative path from repository root to project root."),
|
|
1669
1947
|
branch: z$1.string().optional().describe("Git branch to release from."),
|
|
1670
1948
|
changelogPath: z$1.string().default("CHANGELOG.md").describe("Changelog file path, relative to project root."),
|
|
1671
1949
|
bumpStrategy: BumpStrategySchema.describe("\"auto\" (from commits) or \"manual\" (user-specified)."),
|
|
1672
1950
|
releaseType: ReleaseTypeSchema.optional().describe("The release type to bump."),
|
|
1673
1951
|
preReleaseId: z$1.string().optional().describe("Pre-release ID (e.g., \"alpha\", \"beta\")."),
|
|
1674
1952
|
preReleaseBase: PreReleaseBaseSchema.describe("Starting version for pre-releases."),
|
|
1675
|
-
releaseNotes: z$1.string().
|
|
1953
|
+
releaseNotes: z$1.string().optional().describe("Custom release notes for changelog."),
|
|
1676
1954
|
commitMessage: z$1.string().default(COMMIT_MSG_TEMPLATE).describe("Commit message template with placeholders."),
|
|
1677
1955
|
tagName: z$1.string().default(TAG_NAME_TEMPLATE).describe("Tag name template with placeholders."),
|
|
1678
1956
|
skipBump: z$1.coerce.boolean().default(false).describe("Skip version bump step."),
|
|
@@ -1685,7 +1963,12 @@ const ReleaseConfigSchema = z$1.object({
|
|
|
1685
1963
|
releaseLatest: z$1.coerce.boolean().optional().describe("Mark as latest release."),
|
|
1686
1964
|
releasePreRelease: z$1.coerce.boolean().optional().describe("Mark as pre-release."),
|
|
1687
1965
|
releaseDraft: z$1.coerce.boolean().optional().describe("Release as draft version.")
|
|
1688
|
-
})
|
|
1966
|
+
});
|
|
1967
|
+
/**
|
|
1968
|
+
* Release configuration schema with runtime validation refinements.
|
|
1969
|
+
* Use this schema for parsing and validating user input.
|
|
1970
|
+
*/
|
|
1971
|
+
const ReleaseConfigSchema = ReleaseConfigBaseSchema.check((ctx) => {
|
|
1689
1972
|
validateReleaseFlagExclusivity(ctx);
|
|
1690
1973
|
validateSkipGitRedundancy(ctx);
|
|
1691
1974
|
validateBumpStrategyCompatibility(ctx);
|
|
@@ -1738,30 +2021,30 @@ function defineService(definition) {
|
|
|
1738
2021
|
*/
|
|
1739
2022
|
const SERVICE_DEFINITIONS = {
|
|
1740
2023
|
fs: defineService({ factory: async ({ basePath }) => {
|
|
1741
|
-
const { createFileSystemService } = await import("./filesystem.service-
|
|
2024
|
+
const { createFileSystemService } = await import("./filesystem.service-DS2AQGNq.js");
|
|
1742
2025
|
return createFileSystemService(basePath);
|
|
1743
2026
|
} }),
|
|
1744
2027
|
packageJson: defineService({
|
|
1745
2028
|
dependencies: ["fs"],
|
|
1746
2029
|
factory: async ({ getService }) => {
|
|
1747
2030
|
const fs = await getService("fs");
|
|
1748
|
-
const { createPackageJsonService } = await import("./package-json.service-
|
|
2031
|
+
const { createPackageJsonService } = await import("./package-json.service-BlMNgPGQ.js");
|
|
1749
2032
|
return createPackageJsonService(fs);
|
|
1750
2033
|
}
|
|
1751
2034
|
}),
|
|
1752
2035
|
git: defineService({ factory: async ({ basePath }) => {
|
|
1753
|
-
const { createGitService } = await import("./git.service-
|
|
2036
|
+
const { createGitService } = await import("./git.service-B6RdTilO.js");
|
|
1754
2037
|
return createGitService(basePath);
|
|
1755
2038
|
} }),
|
|
1756
2039
|
versionBumper: defineService({ factory: async () => {
|
|
1757
|
-
const { createVersionBumperService } = await import("./version-bumper.service-
|
|
2040
|
+
const { createVersionBumperService } = await import("./version-bumper.service-glxzf9Qm.js");
|
|
1758
2041
|
return createVersionBumperService();
|
|
1759
2042
|
} }),
|
|
1760
2043
|
versionStrategy: defineService({
|
|
1761
2044
|
dependencies: ["versionBumper"],
|
|
1762
2045
|
factory: async ({ getService }) => {
|
|
1763
2046
|
const versionBumper = await getService("versionBumper");
|
|
1764
|
-
const { createVersionStrategyService } = await import("./version-strategy.service-
|
|
2047
|
+
const { createVersionStrategyService } = await import("./version-strategy.service-Dln42gxC.js");
|
|
1765
2048
|
return createVersionStrategyService(versionBumper);
|
|
1766
2049
|
}
|
|
1767
2050
|
}),
|
|
@@ -1769,7 +2052,7 @@ const SERVICE_DEFINITIONS = {
|
|
|
1769
2052
|
dependencies: ["git"],
|
|
1770
2053
|
factory: async ({ getService }) => {
|
|
1771
2054
|
const git = await getService("git");
|
|
1772
|
-
const { createCommitAnalysisService } = await import("./commit-analysis.service-
|
|
2055
|
+
const { createCommitAnalysisService } = await import("./commit-analysis.service-B2Z128t8.js");
|
|
1773
2056
|
return createCommitAnalysisService(git);
|
|
1774
2057
|
}
|
|
1775
2058
|
})
|
|
@@ -2033,7 +2316,7 @@ function logGraphStatistics(stats) {
|
|
|
2033
2316
|
|
|
2034
2317
|
//#endregion
|
|
2035
2318
|
//#region src/commands/release/release.command.ts
|
|
2036
|
-
const RELEASE_SERVICES = defineServiceKeys("fs", "packageJson", "git");
|
|
2319
|
+
const RELEASE_SERVICES = defineServiceKeys("fs", "packageJson", "git", "commitAnalysis", "versionBumper", "versionStrategy");
|
|
2037
2320
|
const releaseCommand = createCommand({
|
|
2038
2321
|
meta: {
|
|
2039
2322
|
name: "release",
|
|
@@ -2353,6 +2636,30 @@ var ImmutableWorkflowContext = class ImmutableWorkflowContext {
|
|
|
2353
2636
|
services: this.services
|
|
2354
2637
|
});
|
|
2355
2638
|
}
|
|
2639
|
+
/**
|
|
2640
|
+
* @example Merging hydrated config values
|
|
2641
|
+
* ```typescript
|
|
2642
|
+
* const updatedCtx = ctx.forkConfig({
|
|
2643
|
+
* repository: "owner/repo",
|
|
2644
|
+
* branch: "main"
|
|
2645
|
+
* });
|
|
2646
|
+
* ```
|
|
2647
|
+
*/
|
|
2648
|
+
forkConfig(updates) {
|
|
2649
|
+
if (Object.keys(updates).length === 0) return this;
|
|
2650
|
+
const mergedConfig = {
|
|
2651
|
+
...this.config,
|
|
2652
|
+
...updates
|
|
2653
|
+
};
|
|
2654
|
+
const frozenConfig = Object.freeze(mergedConfig);
|
|
2655
|
+
return new ImmutableWorkflowContext({
|
|
2656
|
+
startTime: this.startTime,
|
|
2657
|
+
workspace: this.workspace,
|
|
2658
|
+
config: frozenConfig,
|
|
2659
|
+
data: this.#data,
|
|
2660
|
+
services: this.services
|
|
2661
|
+
});
|
|
2662
|
+
}
|
|
2356
2663
|
has(key) {
|
|
2357
2664
|
return key in this.#data;
|
|
2358
2665
|
}
|
|
@@ -3191,6 +3498,18 @@ async function resolveServiceWithContext(key, context) {
|
|
|
3191
3498
|
/**
|
|
3192
3499
|
* Creates a lazy proxy that defers async service instantiation until first access.
|
|
3193
3500
|
*
|
|
3501
|
+
* IMPORTANT:
|
|
3502
|
+
* This proxy always defers instantiation and wraps calls in a ResultAsync chain
|
|
3503
|
+
* in order to safely await the real service instance before invoking the method.
|
|
3504
|
+
*
|
|
3505
|
+
* At runtime the proxy therefore returns ResultAsync even if the concrete service
|
|
3506
|
+
* method returns a synchronous Result.
|
|
3507
|
+
*
|
|
3508
|
+
* Because of this behavior, service interfaces should return FireflyAsyncResult<T>
|
|
3509
|
+
* from their public methods to avoid type mismatches and confusion. Implementations
|
|
3510
|
+
* that have purely synchronous behavior should return FireflyOkAsync / FireflyErrAsync
|
|
3511
|
+
* so they still conform to the async contract expected by the proxy.
|
|
3512
|
+
*
|
|
3194
3513
|
* @template T - The service interface type
|
|
3195
3514
|
* @param factory - Async function that creates the actual service instance
|
|
3196
3515
|
* @returns A proxy that behaves like the service but instantiates lazily
|