fireflyy 4.0.0-alpha.8 → 4.0.0-dev.fd79cb3

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.
@@ -35,6 +35,10 @@
35
35
  "default": "",
36
36
  "type": "string"
37
37
  },
38
+ "branch": {
39
+ "description": "Git branch to release from.",
40
+ "type": "string"
41
+ },
38
42
  "changelogPath": {
39
43
  "description": "Changelog file path, relative to project root.",
40
44
  "default": "CHANGELOG.md",
@@ -1,5 +1,5 @@
1
1
  import { c as notFoundErrAsync } from "./result.constructors-C9M1MP3_.js";
2
- import { n as wrapPromise } from "./result.utilities-oXWCXEvw.js";
2
+ import { n as wrapPromise } from "./result.utilities-B03Jkhlx.js";
3
3
  import { t as withDryRun } from "./dry-run-BfYCtldz.js";
4
4
 
5
5
  //#region src/services/implementations/filesystem.service.ts
@@ -250,7 +250,7 @@ var DefaultGitService = class {
250
250
  return executeGitCommand(args, {
251
251
  cwd: this.cwd,
252
252
  dryRun: options?.dryRun,
253
- verbose: options?.verbose ?? false
253
+ verbose: options?.verbose ?? true
254
254
  });
255
255
  }
256
256
  isInsideRepository() {
@@ -523,6 +523,58 @@ var DefaultGitService = class {
523
523
  if (options?.followTags) args.push("--follow-tags");
524
524
  return this.git(args).map(() => void 0);
525
525
  }
526
+ /**
527
+ * Gets the upstream remote name for the current branch.
528
+ * @returns The remote name or null if no upstream is configured.
529
+ */
530
+ getUpstreamRemote() {
531
+ return this.git([
532
+ "rev-parse",
533
+ "--abbrev-ref",
534
+ "--symbolic-full-name",
535
+ "@{upstream}"
536
+ ]).map((output) => {
537
+ const upstream = output.trim();
538
+ const slashIndex = upstream.indexOf("/");
539
+ if (slashIndex > 0) return upstream.substring(0, slashIndex);
540
+ return null;
541
+ }).orElse(() => FireflyOkAsync(null));
542
+ }
543
+ /**
544
+ * Lists all configured remotes.
545
+ * @returns Array of remote names.
546
+ */
547
+ listRemotes() {
548
+ return this.git(["remote"]).map((output) => output.split("\n").map((remote) => remote.trim()).filter((remote) => remote.length > 0));
549
+ }
550
+ inferRepositoryUrl() {
551
+ return this.getUpstreamRemote().andThen((upstreamRemote) => {
552
+ if (upstreamRemote) {
553
+ logger.verbose(`GitService: Inferring repository URL from upstream remote: ${upstreamRemote}`);
554
+ return this.getRemoteUrl(upstreamRemote).map((url) => url).orElse(() => this.tryOriginOrFirstRemote());
555
+ }
556
+ return this.tryOriginOrFirstRemote();
557
+ });
558
+ }
559
+ /**
560
+ * Tries to get the repository URL from 'origin' or the first available remote.
561
+ */
562
+ tryOriginOrFirstRemote() {
563
+ return this.getRemoteUrl("origin").map((url) => {
564
+ logger.verbose("GitService: Inferring repository URL from origin remote");
565
+ return url;
566
+ }).orElse(() => {
567
+ return this.listRemotes().andThen((remotes) => {
568
+ if (remotes.length === 0) {
569
+ logger.verbose("GitService: No remotes configured, cannot infer repository URL");
570
+ return FireflyOkAsync(null);
571
+ }
572
+ const firstRemote = remotes[0];
573
+ logger.verbose(`GitService: Inferring repository URL from first remote: ${firstRemote}`);
574
+ return this.getRemoteUrl(firstRemote).map((url) => url).orElse(() => FireflyOkAsync(null));
575
+ });
576
+ });
577
+ }
526
578
  };
527
579
  /**
528
580
  * 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-alpha.8";
74
+ var version = "4.0.0-dev.fd79cb3";
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-CASpr1JR.js");
102
+ const { createFireflyCLI } = await import("./program-DSPj4l5A.js");
103
103
  createFireflyCLI().parseAsync(process.argv).catch((error) => {
104
104
  logger.error("Fatal error:", error);
105
105
  process.exit(1);
@@ -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 { i as zipAsync, n as wrapPromise, r as zip3Async, t as ensureNotAsync } from "./result.utilities-oXWCXEvw.js";
3
+ import { n as wrapPromise, r as zip3Async, t as ensureNotAsync } from "./result.utilities-B03Jkhlx.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";
@@ -1152,17 +1152,28 @@ function extractPreReleaseId(version) {
1152
1152
  }
1153
1153
  /**
1154
1154
  * Hydrates the repository field from git remote URL.
1155
+ *
1156
+ * Behavior:
1157
+ * - If not inside a git repository, resolves to undefined.
1158
+ * - If inside a repository, detect the repository URL
1159
+ * using a fall-through strategy (upstream remote → origin → first remote).
1160
+ * - Parses the URL and returns "owner/repo" when possible.
1155
1161
  */
1156
1162
  function hydrateRepository(ctx) {
1157
- return ctx.services.git.isInsideRepository().andThen((isRepo) => {
1158
- if (!isRepo) return FireflyOkAsync(void 0);
1159
- return ctx.services.git.getRemoteUrl().map((url) => {
1160
- const parsed = parseGitRemoteUrl(url);
1161
- if (parsed) return `${parsed.owner}/${parsed.repo}`;
1162
- return null;
1163
- }).orElse(() => FireflyOkAsync(null)).map((val) => val ?? void 0).andTee((repository) => logger.verbose(`PrepareReleaseConfigTask: Prepared repository: ${repository}`));
1164
- });
1163
+ return ctx.services.git.inferRepositoryUrl().map((url) => {
1164
+ if (!url) return null;
1165
+ const parsed = parseGitRemoteUrl(url);
1166
+ if (parsed) return `${parsed.owner}/${parsed.repo}`;
1167
+ return null;
1168
+ }).map((val) => val ?? void 0).andTee((repository) => logger.verbose(`PrepareReleaseConfigTask: Prepared repository: ${repository}`));
1165
1169
  }
1170
+ /**
1171
+ * Hydrates name, scope, and preReleaseId from package.json.
1172
+ *
1173
+ * Behavior:
1174
+ * - If package.json does not exist, returns all values as undefined.
1175
+ * - If it exists, reads package.json and returns parsed results for name, scope and preReleaseId.
1176
+ */
1166
1177
  function hydrateFromPackageJson(ctx) {
1167
1178
  return ctx.services.fs.exists("package.json").andThen((exists) => {
1168
1179
  if (!exists) return FireflyOkAsync({
@@ -1179,6 +1190,14 @@ function hydrateFromPackageJson(ctx) {
1179
1190
  }));
1180
1191
  });
1181
1192
  }
1193
+ /**
1194
+ * Hydrates the `name` field from package.json when not provided in config.
1195
+ *
1196
+ * Cases:
1197
+ * 1. If name is undefined and package.json has no name, returns a validation error.
1198
+ * 2. If name is undefined and package.json has a name, extracts the name (stripping scope) and returns it.
1199
+ * 3. Otherwise uses provided name.
1200
+ */
1182
1201
  function hydrateNameFromPackageJson(ctx, packageJson) {
1183
1202
  if (ctx.config.name === void 0 && !packageJson.name) return validationErrAsync({ message: "Could not find a valid name in package.json" });
1184
1203
  if (ctx.config.name === void 0 && packageJson.name) {
@@ -1189,6 +1208,14 @@ function hydrateNameFromPackageJson(ctx, packageJson) {
1189
1208
  logger.verbose(`PrepareReleaseConfigTask: Using provided name: "${ctx.config.name}" as it is explicitly set`);
1190
1209
  return FireflyOkAsync(ctx.config.name);
1191
1210
  }
1211
+ /**
1212
+ * Hydrates the `scope` field from package.json when not provided in config.
1213
+ *
1214
+ * Cases:
1215
+ * 1. If scope is explicitly provided (key exists and value is not undefined), it is used.
1216
+ * 2. If not provided, but package.json has a scoped `name` (e.g., "@scope/name"), the scope will be extracted and returned.
1217
+ * 3. Otherwise returns undefined.
1218
+ */
1192
1219
  function hydrateScopeFromPackageJson(ctx, packageJson) {
1193
1220
  if (Object.hasOwn(ctx.config, "scope") && ctx.config.scope !== void 0) {
1194
1221
  logger.verbose(`PrepareReleaseConfigTask: Using provided scope: "${ctx.config.scope}" as it is explicitly set`);
@@ -1204,6 +1231,14 @@ function hydrateScopeFromPackageJson(ctx, packageJson) {
1204
1231
  logger.verbose("PrepareReleaseConfigTask: No scope to prepare from package.json");
1205
1232
  return FireflyOkAsync(void 0);
1206
1233
  }
1234
+ /**
1235
+ * Hydrates the `preReleaseId` field from `package.json.version` when not provided.
1236
+ *
1237
+ * Cases:
1238
+ * 1. If preReleaseId is explicitly provided and not an empty string, it is used.
1239
+ * 2. If not provided, and `package.json.version` contains a prerelease segment, the prerelease identifier will be extracted and returned.
1240
+ * 3. Otherwise the function defaults to "alpha".
1241
+ */
1207
1242
  function hydratePreReleaseIdFromPackageJson(ctx, packageJson) {
1208
1243
  if (ctx.config.preReleaseId !== void 0 && ctx.config.preReleaseId.trim() !== "") {
1209
1244
  logger.verbose(`PrepareReleaseConfigTask: Using provided preReleaseId: "${ctx.config.preReleaseId}" as it is explicitly set`);
@@ -1222,6 +1257,29 @@ function hydratePreReleaseIdFromPackageJson(ctx, packageJson) {
1222
1257
  return FireflyOkAsync("alpha");
1223
1258
  }
1224
1259
  /**
1260
+ * Hydrates branch setting from git.
1261
+ *
1262
+ * Behavior:
1263
+ * - If not inside a git repository, resolves to undefined.
1264
+ * - If a branch is explicitly provided in the config, validates it against the
1265
+ * current git branch and returns it (otherwise returns a validation error).
1266
+ * - If no branch is provided in the config, uses current git branch.
1267
+ */
1268
+ function hydrateBranch(ctx) {
1269
+ return ctx.services.git.isInsideRepository().andThen((isRepo) => {
1270
+ if (!isRepo) return FireflyOkAsync(void 0);
1271
+ return ctx.services.git.getCurrentBranch().andThen((currentBranch) => {
1272
+ if (Object.hasOwn(ctx.config, "branch") && ctx.config.branch !== void 0 && ctx.config.branch.trim() !== "") {
1273
+ if (ctx.config.branch !== currentBranch) return validationErrAsync({ message: `Configured branch "${ctx.config.branch}" does not match current git branch "${currentBranch}"` });
1274
+ logger.verbose(`PrepareReleaseConfigTask: Using provided branch: "${ctx.config.branch}" as it is explicitly set`);
1275
+ return FireflyOkAsync(ctx.config.branch);
1276
+ }
1277
+ logger.verbose(`PrepareReleaseConfigTask: Prepared branch from git: ${currentBranch}`);
1278
+ return FireflyOkAsync(currentBranch);
1279
+ });
1280
+ });
1281
+ }
1282
+ /**
1225
1283
  * Creates the Prepare Release Config Task.
1226
1284
  *
1227
1285
  * This task determines and hydrates configuration settings, by inferring values from the environment.
@@ -1230,15 +1288,17 @@ function hydratePreReleaseIdFromPackageJson(ctx, packageJson) {
1230
1288
  * 1. Detects repository owner/repo from git remote URL
1231
1289
  * 2. Extracts name and scope from package.json
1232
1290
  * 3. Extracts preReleaseId from package.json version
1291
+ * 4. Detects current git branch if not provided
1233
1292
  */
1234
1293
  function createPrepareReleaseConfigTask() {
1235
1294
  return TaskBuilder.create("prepare-release-config").description("Hydrate and prepare the release configuration").execute((ctx) => {
1236
1295
  const hydrated = {};
1237
- return zipAsync(hydrateRepository(ctx), hydrateFromPackageJson(ctx)).map(([repository, pkgData]) => {
1296
+ return zip3Async(hydrateRepository(ctx), hydrateFromPackageJson(ctx), hydrateBranch(ctx)).map(([repository, pkgData, branch]) => {
1238
1297
  if (repository) hydrated.repository = repository;
1239
1298
  if (pkgData.name) hydrated.name = pkgData.name;
1240
1299
  if (pkgData.scope) hydrated.scope = pkgData.scope;
1241
1300
  if (pkgData.preReleaseId) hydrated.preReleaseId = pkgData.preReleaseId;
1301
+ if (branch) hydrated.branch = branch;
1242
1302
  logger.verbose(`PrepareReleaseConfigTask: Hydrated config: ${JSON.stringify(hydrated)}`);
1243
1303
  return ctx.fork("hydratedConfig", hydrated);
1244
1304
  });
@@ -1454,6 +1514,7 @@ const ReleaseConfigSchema = z$1.object({
1454
1514
  name: z$1.string().optional().describe("Unscoped project name. Auto-detected from package.json."),
1455
1515
  scope: z$1.string().optional().describe("Org/user scope without '@'. Auto-detected from package.json."),
1456
1516
  base: z$1.string().default("").describe("Relative path from repository root to project root."),
1517
+ branch: z$1.string().optional().describe("Git branch to release from."),
1457
1518
  changelogPath: z$1.string().default("CHANGELOG.md").describe("Changelog file path, relative to project root."),
1458
1519
  bumpStrategy: BumpStrategySchema.describe("\"auto\" (from commits) or \"manual\" (user-specified)."),
1459
1520
  releaseType: ReleaseTypeSchema.optional().describe("The release type to bump."),
@@ -1525,7 +1586,7 @@ function defineService(definition) {
1525
1586
  */
1526
1587
  const SERVICE_DEFINITIONS = {
1527
1588
  fs: defineService({ factory: async ({ basePath }) => {
1528
- const { createFileSystemService } = await import("./filesystem.service-B_dgIoTJ.js");
1589
+ const { createFileSystemService } = await import("./filesystem.service-DdVwnqoa.js");
1529
1590
  return createFileSystemService(basePath);
1530
1591
  } }),
1531
1592
  packageJson: defineService({
@@ -1537,7 +1598,7 @@ const SERVICE_DEFINITIONS = {
1537
1598
  }
1538
1599
  }),
1539
1600
  git: defineService({ factory: async ({ basePath }) => {
1540
- const { createGitService } = await import("./git.service-C5zcZ5BB.js");
1601
+ const { createGitService } = await import("./git.service-DarjfyXF.js");
1541
1602
  return createGitService(basePath);
1542
1603
  } })
1543
1604
  };
@@ -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 { zipAsync as i, wrapPromise as n, zip3Async as r, ensureNotAsync as t };
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-alpha.8",
3
+ "version": "4.0.0-dev.fd79cb3",
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",