fork-version 4.1.7 → 4.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Fork Version
2
2
 
3
+ ## [4.1.8](https://github.com/eglavin/fork-version/compare/v4.1.7...v4.1.8) (2026-04-05)
4
+
5
+
6
+ ### Docs
7
+
8
+ * update readme with details on commit parser options ([9a8ba6d](https://github.com/eglavin/fork-version/commit/9a8ba6de3dcccfdb1ae62d12792ffc39122342cd))
9
+
10
+
11
+ ### Refactor
12
+
13
+ * add detected git host name to schema ([9728a1e](https://github.com/eglavin/fork-version/commit/9728a1efb813436adef0358310ce24469e36f311))
14
+ * extract detect git host to allow expanding options ([b330727](https://github.com/eglavin/fork-version/commit/b330727d4f9d5dfafae5796c20ff57834e56de49))
15
+ * improve git host detection ([d231e6c](https://github.com/eglavin/fork-version/commit/d231e6ca1bf389869602577f843fbf996e3587e3))
16
+ * set commit parser options from detected git host ([840584f](https://github.com/eglavin/fork-version/commit/840584fefc94868457cf3c77979a795133219d64))
17
+
18
+
3
19
  ## [4.1.7](https://github.com/eglavin/fork-version/compare/v4.1.6...v4.1.7) (2026-03-08)
4
20
 
5
21
 
package/README.md CHANGED
@@ -314,12 +314,14 @@ Alternatively you can define your config using a key in your `package.json` file
314
314
  | gitTagFallback | boolean | true | If unable to find a version in the given files, fallback and attempt to use the latest git tag |
315
315
  | sign | boolean | false | Sign the commit with the systems GPG key |
316
316
  | verify | boolean | false | Run user defined git hooks before committing |
317
+ | asJson | boolean | false | Print inspected output as a parsable json string |
317
318
  | skipBump | boolean | false | Skip the bump step |
318
319
  | skipChangelog | boolean | false | Skip the changelog step |
319
320
  | skipCommit | boolean | false | Skip the commit step |
320
321
  | skipTag | boolean | false | Skip the tag step |
321
322
  | [changelogPresetConfig](#configchangelogpresetconfig) | object | {} | Override defaults from the "conventional-changelog-conventionalcommits" preset configuration |
322
323
  | releaseMessageSuffix | string | - | Add a suffix to the end of the release message |
324
+ | [commitParserOptions](#configcommitparseroptions) | object | {} | Options to pass to commits parser |
323
325
 
324
326
  ##### config.files
325
327
 
@@ -430,6 +432,35 @@ Adds a suffix to the end of the release message, useful to add a `[skip ci]` mes
430
432
  - [GitHub Actions - Skipping workflow runs](https://docs.github.com/en/actions/managing-workflow-runs/skipping-workflow-runs)
431
433
  - [Azure Devops - Skipping CI for individual pushes](https://learn.microsoft.com/en-us/azure/devops/pipelines/repos/azure-repos-git?view=azure-devops&tabs=yaml#skipping-ci-for-individual-pushes)
432
434
 
435
+ ##### config.commitParserOptions
436
+
437
+ The commit parser options allow you to configure the regex patterns used to parse commits. This is useful if your team has a specific commit message format that doesn't match the default conventional commit format.
438
+
439
+ | Property | Type | Description |
440
+ | :--------------------- | :------------- | :------------------------------------------------ |
441
+ | subjectPattern | Regex | Pattern to match commit subjects |
442
+ | mergePattern | Regex | Pattern to match merge commits |
443
+ | revertPattern | Regex | Pattern to match revert commits |
444
+ | commentPattern | Regex | Pattern to match commented out lines |
445
+ | mentionPattern | Regex | Pattern to match mentions |
446
+ | referenceActions | Array\<string> | List of action labels to match reference sections |
447
+ | referenceActionPattern | Regex | Pattern to match reference sections |
448
+ | issuePrefixes | Array\<string> | List of issue prefixes to match issue ids |
449
+ | issuePattern | Regex | Pattern to match issue references |
450
+ | noteKeywords | Array\<string> | List of keywords to match note titles |
451
+ | notePattern | Regex | Pattern to match note sections |
452
+
453
+ [View the commit parser options to see the default patterns used.](./src/commit-parser/options.ts)
454
+
455
+ If you are using one of the following Git hosts, Fork-Version will automatically use the correct commit parser options for that host:
456
+
457
+ - GitHub
458
+ - GitLab
459
+ - BitBucket
460
+ - Azure DevOps
461
+
462
+ [View the `detect-git-host` function to see how Fork-Version detects the git host.](./src/detect-git-host/detect-git-host.ts)
463
+
433
464
  ### Supported File Types
434
465
 
435
466
  - [Json Package](#json-package)
@@ -278,10 +278,10 @@ var ForkConfigSchema = zod.z.object({
278
278
  */
279
279
  verify: zod.z.boolean().describe("If true, git will run user defined git hooks before committing."),
280
280
  /**
281
- * Output result as JSON.
281
+ * Print inspected output as a parsable json string.
282
282
  * @default false
283
283
  */
284
- asJson: zod.z.boolean().describe("Output the result as JSON."),
284
+ asJson: zod.z.boolean().describe("Print inspected output as a parsable json string."),
285
285
  // Skip Steps
286
286
  //
287
287
  /**
@@ -304,17 +304,34 @@ var ForkConfigSchema = zod.z.object({
304
304
  * @default false
305
305
  */
306
306
  skipTag: zod.z.boolean().describe("Skip the tag step."),
307
+ // Parser Options
308
+ //
309
+ /**
310
+ * The detected git host:
311
+ * - `GitHub`
312
+ * - `GitLab`
313
+ * - `Bitbucket`
314
+ * - `Azure Devops`
315
+ * - Or undefined if unknown or not detected.
316
+ */
317
+ detectedGitHost: zod.z.string().optional().describe(
318
+ "The detected git host, such as GitHub, GitLab, Bitbucket, Azure Devops, or undefined if unknown or not detected."
319
+ ),
307
320
  /**
308
321
  * Override the default "conventional-changelog-conventionalcommits" preset configuration.
309
322
  */
310
- changelogPresetConfig: ChangelogPresetConfigSchema.partial().describe(
323
+ changelogPresetConfig: ChangelogPresetConfigSchema.partial().optional().describe(
311
324
  'Override the default "conventional-changelog-conventionalcommits" preset configuration.'
312
325
  ),
313
326
  /**
314
327
  * Add a suffix to the release commit message.
315
328
  * @example "[skip ci]"
316
329
  */
317
- releaseMessageSuffix: zod.z.string().optional().describe("Add a suffix to the release commit message.")
330
+ releaseMessageSuffix: zod.z.string().optional().describe("Add a suffix to the release commit message."),
331
+ /**
332
+ * Options to pass to commits parser.
333
+ */
334
+ commitParserOptions: zod.z.looseObject().optional().describe("Options to pass to commits parser.")
318
335
  });
319
336
 
320
337
  // src/utils/escape-regex.ts
@@ -591,7 +608,7 @@ ${SCISSOR}
591
608
  return splitCommits;
592
609
  }
593
610
  };
594
- function getChangelogPresetConfig(mergedConfig, cliArguments, detectedGitHost) {
611
+ function getChangelogPresetConfig(mergedConfig, cliArguments, detectedChangelogOptions) {
595
612
  const preset = {
596
613
  name: "conventionalcommits"
597
614
  };
@@ -615,8 +632,8 @@ function getChangelogPresetConfig(mergedConfig, cliArguments, detectedGitHost) {
615
632
  }
616
633
  });
617
634
  }
618
- if (detectedGitHost) {
619
- Object.entries(detectedGitHost).forEach(([key, value]) => {
635
+ if (detectedChangelogOptions) {
636
+ Object.entries(detectedChangelogOptions).forEach(([key, value]) => {
620
637
  if (value !== void 0) {
621
638
  preset[key] = value;
622
639
  }
@@ -692,41 +709,175 @@ All notable changes to this project will be documented in this file. See [fork-v
692
709
  skipBump: false,
693
710
  skipChangelog: false,
694
711
  skipCommit: false,
695
- skipTag: false,
696
- changelogPresetConfig: {}
712
+ skipTag: false
697
713
  };
698
714
 
699
- // src/config/detect-git-host.ts
700
- async function detectGitHost(path) {
701
- const remoteUrl = await new Git({ path }).getRemoteUrl();
702
- if (remoteUrl.startsWith("https://") && remoteUrl.includes("@dev.azure.com/")) {
703
- const match = /^https:\/\/(?<atorganisation>.*?)@dev.azure.com\/(?<organisation>.*?)\/(?<project>.*?)\/_git\/(?<repository>.*?)(?:\.git)?$/.exec(
715
+ // src/detect-git-host/host-github.ts
716
+ function detectGitHubOptions(remoteUrl) {
717
+ let matches = null;
718
+ if (/^https:\/\/(.*)?github\.com/.test(remoteUrl)) {
719
+ matches = /^https:\/\/(.*)?github\.com\/(?<organisation>.*?)\/(?<repository>.*?)(?:\.git)?$/.exec(
720
+ remoteUrl
721
+ );
722
+ } else if (remoteUrl.startsWith("git@github.com:")) {
723
+ matches = /^git@github\.com:(?<organisation>.*?)\/(?<repository>.*?)(?:\.git)?$/.exec(
724
+ remoteUrl
725
+ );
726
+ }
727
+ if (matches?.groups) {
728
+ const { organisation = "", repository = "" } = matches.groups;
729
+ return {
730
+ hostName: "GitHub",
731
+ changelogOptions: {
732
+ commitUrlFormat: `https://github.com/${organisation}/${repository}/commit/{{hash}}`,
733
+ compareUrlFormat: `https://github.com/${organisation}/${repository}/compare/{{previousTag}}...{{currentTag}}`,
734
+ issueUrlFormat: `https://github.com/${organisation}/${repository}/issues/{{id}}`,
735
+ issuePrefixes: ["#", "gh-"]
736
+ },
737
+ commitParserOptions: {
738
+ mergePattern: /^Merge pull request #(?<id>\d*) from (?<source>.*)/i,
739
+ issuePrefixes: ["#", "gh-"]
740
+ }
741
+ };
742
+ }
743
+ return void 0;
744
+ }
745
+
746
+ // src/detect-git-host/host-gitlab.ts
747
+ function detectGitlabOptions(remoteUrl) {
748
+ let matches = null;
749
+ if (/^https:\/\/(.*)?gitlab\.com/.test(remoteUrl)) {
750
+ matches = /^https:\/\/(.*)?gitlab\.com\/(?<organisation>.*?)\/(?<repository>.*?)(?:\.git)?$/.exec(
751
+ remoteUrl
752
+ );
753
+ } else if (remoteUrl.startsWith("git@gitlab.com:")) {
754
+ matches = /^git@gitlab\.com:(?<organisation>.*?)\/(?<repository>.*?)(?:\.git)?$/.exec(
755
+ remoteUrl
756
+ );
757
+ }
758
+ if (matches?.groups) {
759
+ const { organisation = "", repository = "" } = matches.groups;
760
+ return {
761
+ hostName: "GitLab",
762
+ changelogOptions: {
763
+ commitUrlFormat: `https://gitlab.com/${organisation}/${repository}/-/commit/{{hash}}`,
764
+ compareUrlFormat: `https://gitlab.com/${organisation}/${repository}/-/compare/{{previousTag}}...{{currentTag}}`,
765
+ issueUrlFormat: `https://gitlab.com/${organisation}/${repository}/-/issues/{{id}}`
766
+ },
767
+ commitParserOptions: {
768
+ mergePattern: /^Merge branch '(?<source>.*)' into '(.*)'/i,
769
+ // https://docs.gitlab.com/user/project/issues/managing_issues/#default-closing-pattern
770
+ referenceActions: [
771
+ "close",
772
+ "closes",
773
+ "closed",
774
+ "closing",
775
+ "fix",
776
+ "fixes",
777
+ "fixed",
778
+ "fixing",
779
+ "resolve",
780
+ "resolves",
781
+ "resolved",
782
+ "resolving",
783
+ "implement",
784
+ "implements",
785
+ "implemented",
786
+ "implementing"
787
+ ]
788
+ }
789
+ };
790
+ }
791
+ return void 0;
792
+ }
793
+
794
+ // src/detect-git-host/host-bitbucket.ts
795
+ function detectBitbucketOptions(remoteUrl) {
796
+ let matches = null;
797
+ if (/^https:\/\/(.*)?bitbucket\.(org|com)/.test(remoteUrl)) {
798
+ matches = /^https:\/\/(.*)?bitbucket\.(?<domain>org|com)\/(?<organisation>.*?)\/(?<repository>.*?)(?:\.git)?$/.exec(
799
+ remoteUrl
800
+ );
801
+ } else if (remoteUrl.startsWith("git@bitbucket.org:")) {
802
+ matches = /^git@bitbucket\.(?<domain>org|com):(?<organisation>.*?)\/(?<repository>.*?)(?:\.git)?$/.exec(
803
+ remoteUrl
804
+ );
805
+ }
806
+ if (matches?.groups) {
807
+ const { domain = "", organisation = "", repository = "" } = matches.groups;
808
+ return {
809
+ hostName: "Bitbucket",
810
+ changelogOptions: {
811
+ commitUrlFormat: `https://bitbucket.${domain}/${organisation}/${repository}/commits/{{hash}}`,
812
+ compareUrlFormat: `https://bitbucket.${domain}/${organisation}/${repository}/branches/compare/{{currentTag}}..{{previousTag}}`,
813
+ // Bitbucket doesn't have a builtin issue tracker like GitHub or GitLab, this should be overridden by the user if they want to link to issues in their changelog.
814
+ issueUrlFormat: `https://bitbucket.${domain}/${organisation}/${repository}/issues/{{id}}`
815
+ },
816
+ commitParserOptions: {
817
+ mergePattern: /^Merged in (?<source>.*) \(pull request #(?<id>\d*)\)/i
818
+ }
819
+ };
820
+ }
821
+ return void 0;
822
+ }
823
+
824
+ // src/detect-git-host/host-azure-devops.ts
825
+ function detectAzureDevopsOptions(remoteUrl) {
826
+ let matches = null;
827
+ if (/^https:\/\/(.*)?dev\.azure\.com/.test(remoteUrl)) {
828
+ matches = /^https:\/\/(.*)?dev\.azure\.com\/(?<organisation>.*?)\/(?<project>.*?)\/_git\/(?<repository>.*?)(?:\.git)?$/.exec(
704
829
  remoteUrl
705
830
  );
706
- if (match?.groups) {
707
- const { organisation = "", project = "", repository = "" } = match.groups;
708
- return {
709
- detectedGitHost: "Azure",
710
- commitUrlFormat: `{{host}}/${organisation}/${project}/_git/${repository}/commit/{{hash}}`,
711
- compareUrlFormat: `{{host}}/${organisation}/${project}/_git/${repository}/branchCompare?baseVersion=GT{{previousTag}}&targetVersion=GT{{currentTag}}`,
712
- issueUrlFormat: `{{host}}/${organisation}/${project}/_workitems/edit/{{id}}`
713
- };
714
- }
715
831
  } else if (remoteUrl.startsWith("git@ssh.dev.azure.com:")) {
716
- const match = /^git@ssh.dev.azure.com:v\d\/(?<organisation>.*?)\/(?<project>.*?)\/(?<repository>.*?)(?:\.git)?$/.exec(
832
+ matches = /^git@ssh\.dev\.azure\.com:v\d\/(?<organisation>.*?)\/(?<project>.*?)\/(?<repository>.*?)(?:\.git)?$/.exec(
717
833
  remoteUrl
718
834
  );
719
- if (match?.groups) {
720
- const { organisation = "", project = "", repository = "" } = match.groups;
721
- return {
722
- detectedGitHost: "Azure",
723
- commitUrlFormat: `{{host}}/${organisation}/${project}/_git/${repository}/commit/{{hash}}`,
724
- compareUrlFormat: `{{host}}/${organisation}/${project}/_git/${repository}/branchCompare?baseVersion=GT{{previousTag}}&targetVersion=GT{{currentTag}}`,
725
- issueUrlFormat: `{{host}}/${organisation}/${project}/_workitems/edit/{{id}}`
726
- };
835
+ }
836
+ if (matches?.groups) {
837
+ const { organisation = "", project = "", repository = "" } = matches.groups;
838
+ return {
839
+ hostName: "Azure Devops",
840
+ changelogOptions: {
841
+ commitUrlFormat: `https://dev.azure.com/${organisation}/${project}/_git/${repository}/commit/{{hash}}`,
842
+ compareUrlFormat: `https://dev.azure.com/${organisation}/${project}/_git/${repository}/branchCompare?baseVersion=GT{{previousTag}}&targetVersion=GT{{currentTag}}`,
843
+ issueUrlFormat: `https://dev.azure.com/${organisation}/${project}/_workitems/edit/{{id}}`
844
+ },
845
+ commitParserOptions: {
846
+ mergePattern: /^Merged PR (?<id>\d*): (?<source>.*)/i
847
+ }
848
+ };
849
+ }
850
+ return void 0;
851
+ }
852
+
853
+ // src/detect-git-host/detect-git-host.ts
854
+ async function detectGitHost(path) {
855
+ const remoteUrl = await new Git({ path }).getRemoteUrl();
856
+ if (remoteUrl.includes("github.com")) {
857
+ const githubOptions = detectGitHubOptions(remoteUrl);
858
+ if (githubOptions) {
859
+ return githubOptions;
860
+ }
861
+ }
862
+ if (remoteUrl.includes("gitlab.com")) {
863
+ const gitlabOptions = detectGitlabOptions(remoteUrl);
864
+ if (gitlabOptions) {
865
+ return gitlabOptions;
866
+ }
867
+ }
868
+ if (/bitbucket\.(org|com)/.test(remoteUrl)) {
869
+ const bitbucketOptions = detectBitbucketOptions(remoteUrl);
870
+ if (bitbucketOptions) {
871
+ return bitbucketOptions;
872
+ }
873
+ }
874
+ if (remoteUrl.includes("dev.azure.com")) {
875
+ const azureDevopsOptions = detectAzureDevopsOptions(remoteUrl);
876
+ if (azureDevopsOptions) {
877
+ return azureDevopsOptions;
727
878
  }
728
879
  }
729
- return null;
880
+ return void 0;
730
881
  }
731
882
  var PACKAGE_JSON_CONFIG_KEY = "fork-version";
732
883
  async function loadConfigFile(cwd) {
@@ -813,11 +964,6 @@ async function getUserConfig(cliArguments) {
813
964
  }
814
965
  const files = mergeFiles(configFile?.files, cliArguments.flags.files, globResults);
815
966
  const detectedGitHost = await detectGitHost(cwd);
816
- const changelogPresetConfig = getChangelogPresetConfig(
817
- mergedConfig,
818
- cliArguments.flags,
819
- detectedGitHost
820
- );
821
967
  let command = DEFAULT_CONFIG.command;
822
968
  if (cliArguments.input.length > 0 && cliArguments.input[0].trim()) {
823
969
  command = cliArguments.input[0].trim().toLowerCase();
@@ -838,7 +984,16 @@ async function getUserConfig(cliArguments) {
838
984
  cliArguments.flags.preReleaseTag ?? cliArguments.flags.preRelease ?? configFile.preRelease
839
985
  ),
840
986
  silent: shouldBeSilent || mergedConfig.silent,
841
- changelogPresetConfig
987
+ detectedGitHost: detectedGitHost?.hostName,
988
+ changelogPresetConfig: getChangelogPresetConfig(
989
+ mergedConfig,
990
+ cliArguments.flags,
991
+ detectedGitHost?.changelogOptions
992
+ ),
993
+ commitParserOptions: {
994
+ ...detectedGitHost?.commitParserOptions,
995
+ ...mergedConfig.commitParserOptions
996
+ }
842
997
  };
843
998
  }
844
999
  var Logger = class {
@@ -1677,7 +1832,7 @@ function cleanTag(tag, tagPrefix) {
1677
1832
 
1678
1833
  // src/process/get-commits.ts
1679
1834
  async function getCommitsSinceTag(config, logger, git) {
1680
- const commitParser = new CommitParser();
1835
+ const commitParser = new CommitParser(config.commitParserOptions);
1681
1836
  if (config.debug) commitParser.setLogger(logger);
1682
1837
  const latestTag = await git.getMostRecentTag(config.tagPrefix);
1683
1838
  if (!latestTag) {
@@ -2105,5 +2260,5 @@ exports.main = main;
2105
2260
  exports.tagChanges = tagChanges;
2106
2261
  exports.updateChangelog = updateChangelog;
2107
2262
  exports.validateConfig = validateConfig;
2108
- //# sourceMappingURL=chunk-JYQTKLHN.cjs.map
2109
- //# sourceMappingURL=chunk-JYQTKLHN.cjs.map
2263
+ //# sourceMappingURL=chunk-KRGBUNRK.cjs.map
2264
+ //# sourceMappingURL=chunk-KRGBUNRK.cjs.map