fireflyy 4.0.0-alpha.8 → 4.0.0-dev.25c80f6
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 +4 -0
- package/dist/{filesystem.service-B_dgIoTJ.js → filesystem.service-9VHML130.js} +6 -8
- package/dist/{git.service-C5zcZ5BB.js → git.service-CACrfCW8.js} +92 -20
- package/dist/index.d.ts +1 -0
- package/dist/main.js +2 -2
- package/dist/{package-json.service-QN7SzRTt.js → package-json.service-DACeZzRg.js} +2 -1
- package/dist/{program-CASpr1JR.js → program-DcCz3-Sc.js} +108 -18
- package/dist/{result.utilities-oXWCXEvw.js → result.utilities-DC5shlhT.js} +2 -8
- package/package.json +6 -6
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { t as logger } from "./main.js";
|
|
1
2
|
import { c as notFoundErrAsync } from "./result.constructors-C9M1MP3_.js";
|
|
2
|
-
import { n as wrapPromise } from "./result.utilities-
|
|
3
|
+
import { n as wrapPromise } from "./result.utilities-DC5shlhT.js";
|
|
3
4
|
import { t as withDryRun } from "./dry-run-BfYCtldz.js";
|
|
4
5
|
|
|
5
6
|
//#region src/services/implementations/filesystem.service.ts
|
|
@@ -29,21 +30,18 @@ var DefaultFileSystemService = class {
|
|
|
29
30
|
}
|
|
30
31
|
exists(path) {
|
|
31
32
|
const resolved = this.resolvePath(path);
|
|
32
|
-
return wrapPromise(Bun.file(resolved).exists());
|
|
33
|
+
return wrapPromise(Bun.file(resolved).exists()).andTee(() => logger.verbose(`DefaultFileSystemService: Checked existence of file: ${resolved}`));
|
|
33
34
|
}
|
|
34
35
|
read(path) {
|
|
35
36
|
const resolved = this.resolvePath(path);
|
|
36
37
|
const file = Bun.file(resolved);
|
|
37
38
|
return wrapPromise(file.exists()).andThen((fileExists) => {
|
|
38
|
-
if (!fileExists) return notFoundErrAsync({
|
|
39
|
-
|
|
40
|
-
source: "FileSystemService.read"
|
|
41
|
-
});
|
|
42
|
-
return wrapPromise(file.text());
|
|
39
|
+
if (!fileExists) return notFoundErrAsync({ message: `File not found: ${resolved}` });
|
|
40
|
+
return wrapPromise(file.text()).andTee(() => logger.verbose(`DefaultFileSystemService: Read file: ${resolved}`));
|
|
43
41
|
});
|
|
44
42
|
}
|
|
45
43
|
write(path, content, options) {
|
|
46
|
-
return withDryRun(options, `Writing to ${this.resolvePath(path)}`, () => wrapPromise(Bun.write(this.resolvePath(path), content).then(() => {})));
|
|
44
|
+
return withDryRun(options, `Writing to ${this.resolvePath(path)}`, () => wrapPromise(Bun.write(this.resolvePath(path), content).then(() => {})).andTee(() => logger.verbose(`DefaultFileSystemService: Wrote file: ${this.resolvePath(path)}`)));
|
|
47
45
|
}
|
|
48
46
|
};
|
|
49
47
|
/**
|
|
@@ -250,14 +250,14 @@ var DefaultGitService = class {
|
|
|
250
250
|
return executeGitCommand(args, {
|
|
251
251
|
cwd: this.cwd,
|
|
252
252
|
dryRun: options?.dryRun,
|
|
253
|
-
verbose: options?.verbose ??
|
|
253
|
+
verbose: options?.verbose ?? true
|
|
254
254
|
});
|
|
255
255
|
}
|
|
256
256
|
isInsideRepository() {
|
|
257
257
|
return this.git(["rev-parse", "--is-inside-work-tree"]).map(() => true).orElse(() => FireflyOkAsync(false));
|
|
258
258
|
}
|
|
259
259
|
getRepositoryRoot() {
|
|
260
|
-
return this.git(["rev-parse", "--show-toplevel"]).map((output) => output.trim());
|
|
260
|
+
return this.git(["rev-parse", "--show-toplevel"]).andTee(() => logger.verbose("DefaultGitService: Resolving repository root")).map((output) => output.trim()).andTee(() => logger.verbose("DefaultGitService: Repository root resolved"));
|
|
261
261
|
}
|
|
262
262
|
getRemoteUrl(remote) {
|
|
263
263
|
const remoteName = remote ?? "origin";
|
|
@@ -280,12 +280,14 @@ var DefaultGitService = class {
|
|
|
280
280
|
else if (index !== " " && index !== "?") hasStaged = true;
|
|
281
281
|
if (workTree !== " " && workTree !== "?") hasUnstaged = true;
|
|
282
282
|
}
|
|
283
|
-
|
|
283
|
+
const status = {
|
|
284
284
|
hasStaged,
|
|
285
285
|
hasUnstaged,
|
|
286
286
|
hasUntracked,
|
|
287
287
|
isClean: lines.length === 0
|
|
288
288
|
};
|
|
289
|
+
logger.verbose(`DefaultGitService: Git status: staged=${status.hasStaged},unstaged=${status.hasUnstaged},untracked=${status.hasUntracked},clean=${status.isClean}`);
|
|
290
|
+
return status;
|
|
289
291
|
});
|
|
290
292
|
}
|
|
291
293
|
isWorkingTreeClean() {
|
|
@@ -312,7 +314,7 @@ var DefaultGitService = class {
|
|
|
312
314
|
const includeStaged = filter?.staged ?? true;
|
|
313
315
|
const includeUnstaged = filter?.unstaged ?? true;
|
|
314
316
|
return this.git(["status", "--porcelain"]).map((output) => {
|
|
315
|
-
|
|
317
|
+
const filtered = this.parseStatusOutput(output).filter((file) => {
|
|
316
318
|
const isStaged = file.indexStatus !== " " && file.indexStatus !== "?";
|
|
317
319
|
const isUnstaged = file.workTreeStatus !== " " && file.workTreeStatus !== "?";
|
|
318
320
|
if (includeStaged && includeUnstaged) return isStaged || isUnstaged;
|
|
@@ -320,6 +322,8 @@ var DefaultGitService = class {
|
|
|
320
322
|
if (includeUnstaged) return isUnstaged;
|
|
321
323
|
return false;
|
|
322
324
|
});
|
|
325
|
+
logger.verbose(`DefaultGitService: Found ${filtered.length} file(s) for filter staged=${includeStaged} unstaged=${includeUnstaged}`);
|
|
326
|
+
return filtered;
|
|
323
327
|
});
|
|
324
328
|
}
|
|
325
329
|
getFileNames(filter) {
|
|
@@ -344,11 +348,13 @@ var DefaultGitService = class {
|
|
|
344
348
|
const isRemote = line.includes("remotes/");
|
|
345
349
|
let branchName = line.replace(CURRENT_BRANCH_MARKER_REGEX, "").trim();
|
|
346
350
|
if (isRemote) branchName = branchName.replace(REMOTES_PREFIX_REGEX, "");
|
|
347
|
-
|
|
351
|
+
const branch = {
|
|
348
352
|
name: branchName,
|
|
349
353
|
isCurrent,
|
|
350
354
|
isRemote
|
|
351
355
|
};
|
|
356
|
+
logger.verbose(`DefaultGitService: Parsed branch: ${branch.name} current=${branch.isCurrent} remote=${branch.isRemote}`);
|
|
357
|
+
return branch;
|
|
352
358
|
}
|
|
353
359
|
listBranches(includeRemote) {
|
|
354
360
|
const args = ["branch"];
|
|
@@ -359,7 +365,7 @@ var DefaultGitService = class {
|
|
|
359
365
|
}
|
|
360
366
|
createCommit(message, options) {
|
|
361
367
|
if (options?.dryRun) {
|
|
362
|
-
logger.verbose("
|
|
368
|
+
logger.verbose("DefaultGitService: Dry run, skipping commit");
|
|
363
369
|
return FireflyOkAsync({ sha: "dry-run-sha" });
|
|
364
370
|
}
|
|
365
371
|
const args = [
|
|
@@ -402,6 +408,7 @@ var DefaultGitService = class {
|
|
|
402
408
|
`${upstream}..HEAD`
|
|
403
409
|
]).map((output) => {
|
|
404
410
|
const count = Number.parseInt(output.trim(), 10) || 0;
|
|
411
|
+
logger.verbose(`DefaultGitService: Unpushed commits count for ${upstream}: ${count}`);
|
|
405
412
|
return {
|
|
406
413
|
hasUnpushed: count > 0,
|
|
407
414
|
count
|
|
@@ -413,6 +420,7 @@ var DefaultGitService = class {
|
|
|
413
420
|
"HEAD"
|
|
414
421
|
]).map((output) => {
|
|
415
422
|
const count = Number.parseInt(output.trim(), 10) || 0;
|
|
423
|
+
logger.verbose(`DefaultGitService: Total commit count: ${count}`);
|
|
416
424
|
return {
|
|
417
425
|
hasUnpushed: count > 0,
|
|
418
426
|
count
|
|
@@ -426,7 +434,7 @@ var DefaultGitService = class {
|
|
|
426
434
|
}
|
|
427
435
|
createTag(name, options) {
|
|
428
436
|
if (options?.dryRun) {
|
|
429
|
-
logger.verbose(`
|
|
437
|
+
logger.verbose(`DefaultGitService: Dry run, skipping tag creation: ${name}`);
|
|
430
438
|
return FireflyOkAsync(void 0);
|
|
431
439
|
}
|
|
432
440
|
const args = ["tag"];
|
|
@@ -439,7 +447,7 @@ var DefaultGitService = class {
|
|
|
439
447
|
const scope = options?.scope ?? "local";
|
|
440
448
|
const remote = options?.remote ?? "origin";
|
|
441
449
|
if (options?.dryRun) {
|
|
442
|
-
logger.verbose(`
|
|
450
|
+
logger.verbose(`DefaultGitService: Dry run, skipping tag deletion (${scope}): ${name}`);
|
|
443
451
|
return FireflyOkAsync(void 0);
|
|
444
452
|
}
|
|
445
453
|
if (scope === "local") return this.git([
|
|
@@ -447,11 +455,15 @@ var DefaultGitService = class {
|
|
|
447
455
|
"-d",
|
|
448
456
|
name
|
|
449
457
|
]).map(() => void 0);
|
|
450
|
-
if (scope === "remote")
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
458
|
+
if (scope === "remote") {
|
|
459
|
+
logger.verbose(`DefaultGitService: Deleting remote tag: ${name} on ${remote}`);
|
|
460
|
+
return this.git([
|
|
461
|
+
"push",
|
|
462
|
+
remote,
|
|
463
|
+
`:refs/tags/${name}`
|
|
464
|
+
]).andTee(() => logger.verbose(`DefaultGitService: Remote tag deleted: ${name} on ${remote}`)).map(() => void 0);
|
|
465
|
+
}
|
|
466
|
+
logger.verbose(`DefaultGitService: Deleting tag locally and remotely: ${name} on ${remote}`);
|
|
455
467
|
return this.git([
|
|
456
468
|
"tag",
|
|
457
469
|
"-d",
|
|
@@ -460,17 +472,21 @@ var DefaultGitService = class {
|
|
|
460
472
|
"push",
|
|
461
473
|
remote,
|
|
462
474
|
`:refs/tags/${name}`
|
|
463
|
-
])).map(() => void 0);
|
|
475
|
+
])).andTee(() => logger.verbose(`DefaultGitService: Local and remote tag deleted: ${name} on ${remote}`)).map(() => void 0);
|
|
464
476
|
}
|
|
465
477
|
hasTag(name) {
|
|
466
478
|
return this.git([
|
|
467
479
|
"tag",
|
|
468
480
|
"--list",
|
|
469
481
|
name
|
|
470
|
-
]).map((output) =>
|
|
482
|
+
]).map((output) => {
|
|
483
|
+
const exists = output.trim() === name;
|
|
484
|
+
logger.verbose(`DefaultGitService: Tag ${name} exists=${exists}`);
|
|
485
|
+
return exists;
|
|
486
|
+
});
|
|
471
487
|
}
|
|
472
488
|
hasAnyTags() {
|
|
473
|
-
return this.getLatestTag().map((tag) => tag !== null);
|
|
489
|
+
return this.getLatestTag().andTee(() => logger.verbose("DefaultGitService: Checking if any tags exist")).map((tag) => tag !== null);
|
|
474
490
|
}
|
|
475
491
|
listTags() {
|
|
476
492
|
return this.git(["tag", "--list"]).map((output) => output.split("\n").map((tag) => tag.trim()).filter((tag) => tag.length > 0));
|
|
@@ -494,25 +510,28 @@ var DefaultGitService = class {
|
|
|
494
510
|
"--format=%(contents)",
|
|
495
511
|
name
|
|
496
512
|
]).map((output) => {
|
|
497
|
-
|
|
513
|
+
const message = output.trim();
|
|
514
|
+
logger.verbose(`DefaultGitService: Tag message for ${name}: ${message?.substring(0, 60) ?? "(none)"}`);
|
|
515
|
+
return message || null;
|
|
498
516
|
}).orElse(() => FireflyOkAsync(null));
|
|
499
517
|
}
|
|
500
518
|
stage(paths) {
|
|
501
519
|
const pathArray = Array.isArray(paths) ? paths : [paths];
|
|
502
|
-
return this.git(["add", ...pathArray]).map(() => void 0);
|
|
520
|
+
return this.git(["add", ...pathArray]).andTee(() => logger.verbose(`DefaultGitService: Staged paths: ${pathArray.join(", ")}`)).map(() => void 0);
|
|
503
521
|
}
|
|
504
522
|
unstage(paths) {
|
|
505
523
|
const pathArray = Array.isArray(paths) ? paths : [paths];
|
|
524
|
+
logger.verbose(`DefaultGitService: Unstaging paths: ${pathArray.join(", ")}`);
|
|
506
525
|
return this.git([
|
|
507
526
|
"reset",
|
|
508
527
|
"HEAD",
|
|
509
528
|
"--",
|
|
510
529
|
...pathArray
|
|
511
|
-
]).map(() => void 0);
|
|
530
|
+
]).andTee(() => logger.verbose(`DefaultGitService: Unstaged paths: ${pathArray.join(", ")}`)).map(() => void 0);
|
|
512
531
|
}
|
|
513
532
|
push(options) {
|
|
514
533
|
if (options?.dryRun) {
|
|
515
|
-
logger.verbose("
|
|
534
|
+
logger.verbose("DefaultGitService: Dry run, skipping push");
|
|
516
535
|
return FireflyOkAsync(void 0);
|
|
517
536
|
}
|
|
518
537
|
const args = ["push"];
|
|
@@ -523,6 +542,59 @@ var DefaultGitService = class {
|
|
|
523
542
|
if (options?.followTags) args.push("--follow-tags");
|
|
524
543
|
return this.git(args).map(() => void 0);
|
|
525
544
|
}
|
|
545
|
+
/**
|
|
546
|
+
* Gets the upstream remote name for the current branch.
|
|
547
|
+
* @returns The remote name or null if no upstream is configured.
|
|
548
|
+
*/
|
|
549
|
+
getUpstreamRemote() {
|
|
550
|
+
return this.git([
|
|
551
|
+
"rev-parse",
|
|
552
|
+
"--abbrev-ref",
|
|
553
|
+
"--symbolic-full-name",
|
|
554
|
+
"@{upstream}"
|
|
555
|
+
]).map((output) => {
|
|
556
|
+
const upstream = output.trim();
|
|
557
|
+
const slashIndex = upstream.indexOf("/");
|
|
558
|
+
if (slashIndex > 0) return upstream.substring(0, slashIndex);
|
|
559
|
+
return null;
|
|
560
|
+
}).orElse(() => FireflyOkAsync(null));
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* Lists all configured remotes.
|
|
564
|
+
* @returns Array of remote names.
|
|
565
|
+
*/
|
|
566
|
+
listRemotes() {
|
|
567
|
+
return this.git(["remote"]).map((output) => output.split("\n").map((remote) => remote.trim()).filter((remote) => remote.length > 0));
|
|
568
|
+
}
|
|
569
|
+
inferRepositoryUrl() {
|
|
570
|
+
return this.getUpstreamRemote().andThen((upstreamRemote) => {
|
|
571
|
+
if (upstreamRemote) {
|
|
572
|
+
logger.verbose(`DefaultGitService: Inferring repository URL from upstream remote: ${upstreamRemote}`);
|
|
573
|
+
return this.getRemoteUrl(upstreamRemote).map((url) => url).orElse(() => this.tryOriginOrFirstRemote());
|
|
574
|
+
}
|
|
575
|
+
logger.verbose("DefaultGitService: No upstream remote; falling back to origin or first remote");
|
|
576
|
+
return this.tryOriginOrFirstRemote();
|
|
577
|
+
});
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* Tries to get the repository URL from 'origin' or the first available remote.
|
|
581
|
+
*/
|
|
582
|
+
tryOriginOrFirstRemote() {
|
|
583
|
+
return this.getRemoteUrl("origin").map((url) => {
|
|
584
|
+
logger.verbose("DefaultGitService: Inferring repository URL from origin remote");
|
|
585
|
+
return url;
|
|
586
|
+
}).orElse(() => {
|
|
587
|
+
return this.listRemotes().andThen((remotes) => {
|
|
588
|
+
if (remotes.length === 0) {
|
|
589
|
+
logger.verbose("DefaultGitService: No remotes configured, cannot infer repository URL");
|
|
590
|
+
return FireflyOkAsync(null);
|
|
591
|
+
}
|
|
592
|
+
const firstRemote = remotes[0];
|
|
593
|
+
logger.verbose(`DefaultGitService: Inferring repository URL from first remote: ${firstRemote}`);
|
|
594
|
+
return this.getRemoteUrl(firstRemote).map((url) => url).orElse(() => FireflyOkAsync(null));
|
|
595
|
+
});
|
|
596
|
+
});
|
|
597
|
+
}
|
|
526
598
|
};
|
|
527
599
|
/**
|
|
528
600
|
* Creates a git service instance.
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ declare const FireflyConfigSchema: z.ZodObject<{
|
|
|
11
11
|
name: z.ZodOptional<z.ZodString>;
|
|
12
12
|
scope: z.ZodOptional<z.ZodString>;
|
|
13
13
|
base: z.ZodDefault<z.ZodString>;
|
|
14
|
+
branch: z.ZodOptional<z.ZodString>;
|
|
14
15
|
changelogPath: z.ZodDefault<z.ZodString>;
|
|
15
16
|
bumpStrategy: z.ZodDefault<z.ZodUnion<[z.ZodEnum<{
|
|
16
17
|
auto: "auto";
|
package/dist/main.js
CHANGED
|
@@ -71,7 +71,7 @@ const logger = createConsola({
|
|
|
71
71
|
|
|
72
72
|
//#endregion
|
|
73
73
|
//#region package.json
|
|
74
|
-
var version = "4.0.0-
|
|
74
|
+
var version = "4.0.0-dev.25c80f6";
|
|
75
75
|
var description = " CLI orchestrator for automatic semantic versioning, changelog generation, and creating releases. Built for my own use cases.";
|
|
76
76
|
var dependencies = {
|
|
77
77
|
"c12": "^3.3.2",
|
|
@@ -99,7 +99,7 @@ async function main() {
|
|
|
99
99
|
description,
|
|
100
100
|
gitCliffVersion: dependencies["git-cliff"]?.replace("^", "") || "unknown"
|
|
101
101
|
});
|
|
102
|
-
const { createFireflyCLI } = await import("./program-
|
|
102
|
+
const { createFireflyCLI } = await import("./program-DcCz3-Sc.js");
|
|
103
103
|
createFireflyCLI().parseAsync(process.argv).catch((error) => {
|
|
104
104
|
logger.error("Fatal error:", error);
|
|
105
105
|
process.exit(1);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { t as logger } from "./main.js";
|
|
1
2
|
import { d as validationErrAsync, g as toFireflyError, i as FireflyOkAsync, u as validationErr } from "./result.constructors-C9M1MP3_.js";
|
|
2
3
|
import { n as parseSchema } from "./schema.utilities-BGd9t1wm.js";
|
|
3
4
|
import { Result } from "neverthrow";
|
|
@@ -28,7 +29,7 @@ var DefaultPackageJsonService = class DefaultPackageJsonService {
|
|
|
28
29
|
return this.fs.read(path).map((content) => this.replaceVersionInContent(content, newVersion)).andThen((updatedContent) => this.fs.write(path, updatedContent)).andThen(() => this.read(path).andThen((pkg) => {
|
|
29
30
|
if (pkg.version !== newVersion) return validationErrAsync({ message: `Failed to verify updated version in package.json at path: ${path}` });
|
|
30
31
|
return FireflyOkAsync(void 0);
|
|
31
|
-
}));
|
|
32
|
+
})).andTee(() => logger.verbose(`DefaultPackageJsonService: Updated version in package.json at path: ${path} to ${newVersion}`));
|
|
32
33
|
}
|
|
33
34
|
/**
|
|
34
35
|
* Replaces the version string in the package.json content.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as RuntimeEnv, t as logger } from "./main.js";
|
|
2
2
|
import { _ as validationError, a as conflictErrAsync, c as notFoundErrAsync, d as validationErrAsync, f as conflictError, h as notFoundError, i as FireflyOkAsync, l as timeoutErrAsync, m as failedError, n as FireflyErrAsync, r as FireflyOk, s as invalidErr, t as FireflyErr, u as validationErr, v as wrapErrorMessage } from "./result.constructors-C9M1MP3_.js";
|
|
3
|
-
import {
|
|
3
|
+
import { n as wrapPromise, r as zip3Async, t as ensureNotAsync } from "./result.utilities-DC5shlhT.js";
|
|
4
4
|
import { n as parseSchema, t as formatZodErrors } from "./schema.utilities-BGd9t1wm.js";
|
|
5
5
|
import { LogLevels } from "consola";
|
|
6
6
|
import { colors } from "consola/utils";
|
|
@@ -1091,11 +1091,36 @@ function createBumpStrategyGroup() {
|
|
|
1091
1091
|
|
|
1092
1092
|
//#endregion
|
|
1093
1093
|
//#region src/commands/release/tasks/initialize-release-version.task.ts
|
|
1094
|
+
const PACKAGE_JSON_FILE = "package.json";
|
|
1095
|
+
/**
|
|
1096
|
+
* Reads package.json and extracts the version field.
|
|
1097
|
+
*
|
|
1098
|
+
* Behavior:
|
|
1099
|
+
* - Reads the configured package.json file.
|
|
1100
|
+
* - If the version property is missing, returns a validation error.
|
|
1101
|
+
* - Otherwise resolves with the version string.
|
|
1102
|
+
*/
|
|
1103
|
+
function getVersionFromPackageJson(ctx) {
|
|
1104
|
+
return ctx.services.packageJson.read(PACKAGE_JSON_FILE).andThen((pkg) => {
|
|
1105
|
+
const version = pkg.version;
|
|
1106
|
+
if (!version) return validationErrAsync({ message: "The 'version' field is missing in package.json." });
|
|
1107
|
+
logger.verbose(`InitializeReleaseVersionTask: Prepared current version: ${version}`);
|
|
1108
|
+
return FireflyOkAsync(version);
|
|
1109
|
+
});
|
|
1110
|
+
}
|
|
1111
|
+
/**
|
|
1112
|
+
* Creates the Initialize Release Version task.
|
|
1113
|
+
*
|
|
1114
|
+
* This task initializes the current release version by reading it from package.json.
|
|
1115
|
+
*
|
|
1116
|
+
* This task:
|
|
1117
|
+
* 1. Reads the version from package.json
|
|
1118
|
+
*/
|
|
1094
1119
|
function createInitializeReleaseVersion() {
|
|
1095
|
-
return TaskBuilder.create("initialize-release-version").description("
|
|
1096
|
-
logger.info(
|
|
1097
|
-
return FireflyOkAsync(ctx);
|
|
1098
|
-
}).build();
|
|
1120
|
+
return TaskBuilder.create("initialize-release-version").description("Initialize current release version from package.json").dependsOn("prepare-release-config").execute((ctx) => getVersionFromPackageJson(ctx).andThen((currentVersion) => {
|
|
1121
|
+
logger.info(`Current version is ${currentVersion}`);
|
|
1122
|
+
return FireflyOkAsync(ctx.fork("currentVersion", currentVersion));
|
|
1123
|
+
})).build();
|
|
1099
1124
|
}
|
|
1100
1125
|
|
|
1101
1126
|
//#endregion
|
|
@@ -1152,17 +1177,28 @@ function extractPreReleaseId(version) {
|
|
|
1152
1177
|
}
|
|
1153
1178
|
/**
|
|
1154
1179
|
* Hydrates the repository field from git remote URL.
|
|
1180
|
+
*
|
|
1181
|
+
* Behavior:
|
|
1182
|
+
* - If not inside a git repository, resolves to undefined.
|
|
1183
|
+
* - If inside a repository, detect the repository URL
|
|
1184
|
+
* using a fall-through strategy (upstream remote → origin → first remote).
|
|
1185
|
+
* - Parses the URL and returns "owner/repo" when possible.
|
|
1155
1186
|
*/
|
|
1156
1187
|
function hydrateRepository(ctx) {
|
|
1157
|
-
return ctx.services.git.
|
|
1158
|
-
if (!
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
}).orElse(() => FireflyOkAsync(null)).map((val) => val ?? void 0).andTee((repository) => logger.verbose(`PrepareReleaseConfigTask: Prepared repository: ${repository}`));
|
|
1164
|
-
});
|
|
1188
|
+
return ctx.services.git.inferRepositoryUrl().map((url) => {
|
|
1189
|
+
if (!url) return null;
|
|
1190
|
+
const parsed = parseGitRemoteUrl(url);
|
|
1191
|
+
if (parsed) return `${parsed.owner}/${parsed.repo}`;
|
|
1192
|
+
return null;
|
|
1193
|
+
}).map((val) => val ?? void 0).andTee((repository) => logger.verbose(`PrepareReleaseConfigTask: Prepared repository: ${repository}`));
|
|
1165
1194
|
}
|
|
1195
|
+
/**
|
|
1196
|
+
* Hydrates name, scope, and preReleaseId from package.json.
|
|
1197
|
+
*
|
|
1198
|
+
* Behavior:
|
|
1199
|
+
* - If package.json does not exist, returns all values as undefined.
|
|
1200
|
+
* - If it exists, reads package.json and returns parsed results for name, scope and preReleaseId.
|
|
1201
|
+
*/
|
|
1166
1202
|
function hydrateFromPackageJson(ctx) {
|
|
1167
1203
|
return ctx.services.fs.exists("package.json").andThen((exists) => {
|
|
1168
1204
|
if (!exists) return FireflyOkAsync({
|
|
@@ -1179,6 +1215,14 @@ function hydrateFromPackageJson(ctx) {
|
|
|
1179
1215
|
}));
|
|
1180
1216
|
});
|
|
1181
1217
|
}
|
|
1218
|
+
/**
|
|
1219
|
+
* Hydrates the `name` field from package.json when not provided in config.
|
|
1220
|
+
*
|
|
1221
|
+
* Cases:
|
|
1222
|
+
* 1. If name is undefined and package.json has no name, returns a validation error.
|
|
1223
|
+
* 2. If name is undefined and package.json has a name, extracts the name (stripping scope) and returns it.
|
|
1224
|
+
* 3. Otherwise uses provided name.
|
|
1225
|
+
*/
|
|
1182
1226
|
function hydrateNameFromPackageJson(ctx, packageJson) {
|
|
1183
1227
|
if (ctx.config.name === void 0 && !packageJson.name) return validationErrAsync({ message: "Could not find a valid name in package.json" });
|
|
1184
1228
|
if (ctx.config.name === void 0 && packageJson.name) {
|
|
@@ -1189,6 +1233,14 @@ function hydrateNameFromPackageJson(ctx, packageJson) {
|
|
|
1189
1233
|
logger.verbose(`PrepareReleaseConfigTask: Using provided name: "${ctx.config.name}" as it is explicitly set`);
|
|
1190
1234
|
return FireflyOkAsync(ctx.config.name);
|
|
1191
1235
|
}
|
|
1236
|
+
/**
|
|
1237
|
+
* Hydrates the `scope` field from package.json when not provided in config.
|
|
1238
|
+
*
|
|
1239
|
+
* Cases:
|
|
1240
|
+
* 1. If scope is explicitly provided (key exists and value is not undefined), it is used.
|
|
1241
|
+
* 2. If not provided, but package.json has a scoped `name` (e.g., "@scope/name"), the scope will be extracted and returned.
|
|
1242
|
+
* 3. Otherwise returns undefined.
|
|
1243
|
+
*/
|
|
1192
1244
|
function hydrateScopeFromPackageJson(ctx, packageJson) {
|
|
1193
1245
|
if (Object.hasOwn(ctx.config, "scope") && ctx.config.scope !== void 0) {
|
|
1194
1246
|
logger.verbose(`PrepareReleaseConfigTask: Using provided scope: "${ctx.config.scope}" as it is explicitly set`);
|
|
@@ -1204,6 +1256,14 @@ function hydrateScopeFromPackageJson(ctx, packageJson) {
|
|
|
1204
1256
|
logger.verbose("PrepareReleaseConfigTask: No scope to prepare from package.json");
|
|
1205
1257
|
return FireflyOkAsync(void 0);
|
|
1206
1258
|
}
|
|
1259
|
+
/**
|
|
1260
|
+
* Hydrates the `preReleaseId` field from `package.json.version` when not provided.
|
|
1261
|
+
*
|
|
1262
|
+
* Cases:
|
|
1263
|
+
* 1. If preReleaseId is explicitly provided and not an empty string, it is used.
|
|
1264
|
+
* 2. If not provided, and `package.json.version` contains a prerelease segment, the prerelease identifier will be extracted and returned.
|
|
1265
|
+
* 3. Otherwise the function defaults to "alpha".
|
|
1266
|
+
*/
|
|
1207
1267
|
function hydratePreReleaseIdFromPackageJson(ctx, packageJson) {
|
|
1208
1268
|
if (ctx.config.preReleaseId !== void 0 && ctx.config.preReleaseId.trim() !== "") {
|
|
1209
1269
|
logger.verbose(`PrepareReleaseConfigTask: Using provided preReleaseId: "${ctx.config.preReleaseId}" as it is explicitly set`);
|
|
@@ -1222,6 +1282,29 @@ function hydratePreReleaseIdFromPackageJson(ctx, packageJson) {
|
|
|
1222
1282
|
return FireflyOkAsync("alpha");
|
|
1223
1283
|
}
|
|
1224
1284
|
/**
|
|
1285
|
+
* Hydrates branch setting from git.
|
|
1286
|
+
*
|
|
1287
|
+
* Behavior:
|
|
1288
|
+
* - If not inside a git repository, resolves to undefined.
|
|
1289
|
+
* - If a branch is explicitly provided in the config, validates it against the
|
|
1290
|
+
* current git branch and returns it (otherwise returns a validation error).
|
|
1291
|
+
* - If no branch is provided in the config, uses current git branch.
|
|
1292
|
+
*/
|
|
1293
|
+
function hydrateBranch(ctx) {
|
|
1294
|
+
return ctx.services.git.isInsideRepository().andThen((isRepo) => {
|
|
1295
|
+
if (!isRepo) return FireflyOkAsync(void 0);
|
|
1296
|
+
return ctx.services.git.getCurrentBranch().andThen((currentBranch) => {
|
|
1297
|
+
if (Object.hasOwn(ctx.config, "branch") && ctx.config.branch !== void 0 && ctx.config.branch.trim() !== "") {
|
|
1298
|
+
if (ctx.config.branch !== currentBranch) return validationErrAsync({ message: `Configured branch "${ctx.config.branch}" does not match current git branch "${currentBranch}"` });
|
|
1299
|
+
logger.verbose(`PrepareReleaseConfigTask: Using provided branch: "${ctx.config.branch}" as it is explicitly set`);
|
|
1300
|
+
return FireflyOkAsync(ctx.config.branch);
|
|
1301
|
+
}
|
|
1302
|
+
logger.verbose(`PrepareReleaseConfigTask: Prepared branch from git: ${currentBranch}`);
|
|
1303
|
+
return FireflyOkAsync(currentBranch);
|
|
1304
|
+
});
|
|
1305
|
+
});
|
|
1306
|
+
}
|
|
1307
|
+
/**
|
|
1225
1308
|
* Creates the Prepare Release Config Task.
|
|
1226
1309
|
*
|
|
1227
1310
|
* This task determines and hydrates configuration settings, by inferring values from the environment.
|
|
@@ -1230,15 +1313,17 @@ function hydratePreReleaseIdFromPackageJson(ctx, packageJson) {
|
|
|
1230
1313
|
* 1. Detects repository owner/repo from git remote URL
|
|
1231
1314
|
* 2. Extracts name and scope from package.json
|
|
1232
1315
|
* 3. Extracts preReleaseId from package.json version
|
|
1316
|
+
* 4. Detects current git branch if not provided
|
|
1233
1317
|
*/
|
|
1234
1318
|
function createPrepareReleaseConfigTask() {
|
|
1235
1319
|
return TaskBuilder.create("prepare-release-config").description("Hydrate and prepare the release configuration").execute((ctx) => {
|
|
1236
1320
|
const hydrated = {};
|
|
1237
|
-
return
|
|
1321
|
+
return zip3Async(hydrateRepository(ctx), hydrateFromPackageJson(ctx), hydrateBranch(ctx)).map(([repository, pkgData, branch]) => {
|
|
1238
1322
|
if (repository) hydrated.repository = repository;
|
|
1239
1323
|
if (pkgData.name) hydrated.name = pkgData.name;
|
|
1240
1324
|
if (pkgData.scope) hydrated.scope = pkgData.scope;
|
|
1241
1325
|
if (pkgData.preReleaseId) hydrated.preReleaseId = pkgData.preReleaseId;
|
|
1326
|
+
if (branch) hydrated.branch = branch;
|
|
1242
1327
|
logger.verbose(`PrepareReleaseConfigTask: Hydrated config: ${JSON.stringify(hydrated)}`);
|
|
1243
1328
|
return ctx.fork("hydratedConfig", hydrated);
|
|
1244
1329
|
});
|
|
@@ -1454,6 +1539,7 @@ const ReleaseConfigSchema = z$1.object({
|
|
|
1454
1539
|
name: z$1.string().optional().describe("Unscoped project name. Auto-detected from package.json."),
|
|
1455
1540
|
scope: z$1.string().optional().describe("Org/user scope without '@'. Auto-detected from package.json."),
|
|
1456
1541
|
base: z$1.string().default("").describe("Relative path from repository root to project root."),
|
|
1542
|
+
branch: z$1.string().optional().describe("Git branch to release from."),
|
|
1457
1543
|
changelogPath: z$1.string().default("CHANGELOG.md").describe("Changelog file path, relative to project root."),
|
|
1458
1544
|
bumpStrategy: BumpStrategySchema.describe("\"auto\" (from commits) or \"manual\" (user-specified)."),
|
|
1459
1545
|
releaseType: ReleaseTypeSchema.optional().describe("The release type to bump."),
|
|
@@ -1525,19 +1611,19 @@ function defineService(definition) {
|
|
|
1525
1611
|
*/
|
|
1526
1612
|
const SERVICE_DEFINITIONS = {
|
|
1527
1613
|
fs: defineService({ factory: async ({ basePath }) => {
|
|
1528
|
-
const { createFileSystemService } = await import("./filesystem.service-
|
|
1614
|
+
const { createFileSystemService } = await import("./filesystem.service-9VHML130.js");
|
|
1529
1615
|
return createFileSystemService(basePath);
|
|
1530
1616
|
} }),
|
|
1531
1617
|
packageJson: defineService({
|
|
1532
1618
|
dependencies: ["fs"],
|
|
1533
1619
|
factory: async ({ getService }) => {
|
|
1534
1620
|
const fs = await getService("fs");
|
|
1535
|
-
const { createPackageJsonService } = await import("./package-json.service-
|
|
1621
|
+
const { createPackageJsonService } = await import("./package-json.service-DACeZzRg.js");
|
|
1536
1622
|
return createPackageJsonService(fs);
|
|
1537
1623
|
}
|
|
1538
1624
|
}),
|
|
1539
1625
|
git: defineService({ factory: async ({ basePath }) => {
|
|
1540
|
-
const { createGitService } = await import("./git.service-
|
|
1626
|
+
const { createGitService } = await import("./git.service-CACrfCW8.js");
|
|
1541
1627
|
return createGitService(basePath);
|
|
1542
1628
|
} })
|
|
1543
1629
|
};
|
|
@@ -2178,7 +2264,11 @@ var WorkflowExecutor = class {
|
|
|
2178
2264
|
const startTime = /* @__PURE__ */ new Date();
|
|
2179
2265
|
const executedTaskIds = [];
|
|
2180
2266
|
const skippedTaskIds = [];
|
|
2181
|
-
if (this.options.dryRun) logger.warn("
|
|
2267
|
+
if (this.options.dryRun) logger.warn("Running in DRY-RUN mode: No changes will be made.");
|
|
2268
|
+
const version = RuntimeEnv.version;
|
|
2269
|
+
const dashIndex = version.indexOf("-");
|
|
2270
|
+
if (dashIndex !== -1) if (dashIndex === version.length - 1 || version[dashIndex + 1] === "n") logger.warn(`You are running a DEVELOPMENT build of Firefly (${colors.dim(version)}). This is a 'next' build and may be unstable.`);
|
|
2271
|
+
else logger.warn(`You are running a PRE-RELEASE version of Firefly (${colors.dim(version)}). Unexpected behavior or bugs may occur.`);
|
|
2182
2272
|
logger.verbose(`WorkflowExecutor: Starting execution of ${tasks.length} tasks`);
|
|
2183
2273
|
return this.executeTasksSequentially(tasks, initialContext, executedTaskIds, skippedTaskIds).andThen(() => this.buildExecutionSuccessResult(startTime, executedTaskIds, skippedTaskIds)).orElse((error) => this.handleExecutionFailure({
|
|
2184
2274
|
error,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { d as validationErrAsync, g as toFireflyError, i as FireflyOkAsync, p as createFireflyError } from "./result.constructors-C9M1MP3_.js";
|
|
2
|
-
import { ResultAsync
|
|
2
|
+
import { ResultAsync } from "neverthrow";
|
|
3
3
|
|
|
4
4
|
//#region src/core/result/result.utilities.ts
|
|
5
5
|
/**
|
|
@@ -18,12 +18,6 @@ function ensureNotAsync(condition, errorOpts) {
|
|
|
18
18
|
return condition ? validationErrAsync(errorOpts) : FireflyOkAsync(void 0);
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
|
-
* Async version of zip.
|
|
22
|
-
*/
|
|
23
|
-
function zipAsync(resultA, resultB) {
|
|
24
|
-
return ResultAsync.combine([resultA, resultB]);
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
21
|
* Async version of zip3.
|
|
28
22
|
*/
|
|
29
23
|
function zip3Async(resultA, resultB, resultC) {
|
|
@@ -35,4 +29,4 @@ function zip3Async(resultA, resultB, resultC) {
|
|
|
35
29
|
}
|
|
36
30
|
|
|
37
31
|
//#endregion
|
|
38
|
-
export {
|
|
32
|
+
export { wrapPromise as n, zip3Async as r, ensureNotAsync as t };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fireflyy",
|
|
3
|
-
"version": "4.0.0-
|
|
3
|
+
"version": "4.0.0-dev.25c80f6",
|
|
4
4
|
"description": " CLI orchestrator for automatic semantic versioning, changelog generation, and creating releases. Built for my own use cases.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
}
|
|
32
32
|
},
|
|
33
33
|
"bin": {
|
|
34
|
-
"firefly": "
|
|
35
|
-
"ff": "
|
|
34
|
+
"firefly": "dist/main.js",
|
|
35
|
+
"ff": "dist/main.js"
|
|
36
36
|
},
|
|
37
37
|
"publishConfig": {
|
|
38
38
|
"access": "public",
|
|
@@ -62,12 +62,12 @@
|
|
|
62
62
|
"zod": "^4.1.13"
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
65
|
-
"@biomejs/biome": "2.3.
|
|
65
|
+
"@biomejs/biome": "2.3.8",
|
|
66
66
|
"@types/bun": "^1.3.3",
|
|
67
67
|
"@types/semver": "^7.7.1",
|
|
68
|
-
"tsdown": "^0.17.0-beta.
|
|
68
|
+
"tsdown": "^0.17.0-beta.5",
|
|
69
69
|
"typescript": "^5.9.3",
|
|
70
|
-
"ultracite": "6.3.
|
|
70
|
+
"ultracite": "6.3.8"
|
|
71
71
|
},
|
|
72
72
|
"keywords": [
|
|
73
73
|
"cli",
|