fork-version 4.1.9 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/cli.d.ts +1 -1
  3. package/dist/cli.js +54 -193
  4. package/dist/commands/inspect.d.ts +9 -0
  5. package/dist/commands/inspect.js +41 -0
  6. package/dist/commands/main.d.ts +16 -0
  7. package/dist/commands/main.js +30 -0
  8. package/dist/commands/validate-config.d.ts +6 -0
  9. package/dist/commands/validate-config.js +11 -0
  10. package/dist/commit-parser/commit-parser.d.ts +114 -0
  11. package/dist/commit-parser/commit-parser.js +327 -0
  12. package/dist/commit-parser/filter-reverted-commits.d.ts +17 -0
  13. package/dist/commit-parser/filter-reverted-commits.js +34 -0
  14. package/dist/commit-parser/options.d.ts +74 -0
  15. package/dist/commit-parser/options.js +70 -0
  16. package/dist/commit-parser/parser-error.js +14 -0
  17. package/dist/commit-parser/types.d.ts +53 -0
  18. package/dist/config/changelog-preset-config.js +41 -0
  19. package/dist/config/cli-arguments.d.ts +109 -0
  20. package/dist/config/cli-arguments.js +141 -0
  21. package/dist/config/defaults.js +38 -0
  22. package/dist/config/define-config.d.ts +9 -0
  23. package/dist/config/define-config.js +9 -0
  24. package/dist/config/load-config.js +45 -0
  25. package/dist/config/merge-files.js +12 -0
  26. package/dist/config/schema.d.ts +50 -0
  27. package/dist/config/schema.js +61 -0
  28. package/dist/config/types.d.ts +279 -0
  29. package/dist/config/user-config.d.ts +6 -0
  30. package/dist/config/user-config.js +50 -0
  31. package/dist/detect-git-host/detect-git-host.js +35 -0
  32. package/dist/detect-git-host/host-azure-devops.js +28 -0
  33. package/dist/detect-git-host/host-bitbucket.js +28 -0
  34. package/dist/detect-git-host/host-github.js +32 -0
  35. package/dist/detect-git-host/host-gitlab.js +48 -0
  36. package/dist/files/arm-bicep.js +44 -0
  37. package/dist/files/file-manager.d.ts +47 -0
  38. package/dist/files/file-manager.js +65 -0
  39. package/dist/files/install-shield-ism.js +59 -0
  40. package/dist/files/json-package.js +68 -0
  41. package/dist/files/ms-build-project.js +59 -0
  42. package/dist/files/plain-text.js +35 -0
  43. package/dist/files/yaml-package.js +61 -0
  44. package/dist/index.d.ts +21 -646
  45. package/dist/index.js +19 -10
  46. package/dist/process/changelog.d.ts +7 -0
  47. package/dist/process/changelog.js +69 -0
  48. package/dist/process/commit.d.ts +9 -0
  49. package/dist/process/commit.js +22 -0
  50. package/dist/process/get-commits.d.ts +14 -0
  51. package/dist/process/get-commits.js +25 -0
  52. package/dist/process/get-current-version.d.ts +13 -0
  53. package/dist/process/get-current-version.js +35 -0
  54. package/dist/process/get-next-version.d.ts +21 -0
  55. package/dist/process/get-next-version.js +72 -0
  56. package/dist/process/tag.d.ts +8 -0
  57. package/dist/process/tag.js +15 -0
  58. package/dist/services/git.d.ts +141 -0
  59. package/dist/services/git.js +236 -0
  60. package/dist/services/logger.d.ts +18 -0
  61. package/dist/services/logger.js +35 -0
  62. package/dist/utils/clean-tag.js +21 -0
  63. package/dist/utils/escape-regex.js +17 -0
  64. package/dist/utils/file-state.js +19 -0
  65. package/dist/utils/format-commit-message.js +13 -0
  66. package/dist/utils/parse-regexp-string.js +31 -0
  67. package/dist/utils/release-type.js +47 -0
  68. package/dist/utils/trim-string-array.js +20 -0
  69. package/package.json +11 -29
  70. package/dist/chunk-KRGBUNRK.cjs +0 -2264
  71. package/dist/chunk-KRGBUNRK.cjs.map +0 -1
  72. package/dist/chunk-X4NB24VR.js +0 -2220
  73. package/dist/chunk-X4NB24VR.js.map +0 -1
  74. package/dist/cli.cjs +0 -205
  75. package/dist/cli.cjs.map +0 -1
  76. package/dist/cli.d.cts +0 -1
  77. package/dist/cli.js.map +0 -1
  78. package/dist/index.cjs +0 -80
  79. package/dist/index.cjs.map +0 -1
  80. package/dist/index.d.cts +0 -646
  81. package/dist/index.js.map +0 -1
@@ -0,0 +1,279 @@
1
+ import { getCliArguments } from "./cli-arguments.js";
2
+ import { ParserOptions } from "../commit-parser/options.js";
3
+
4
+ //#region src/config/types.d.ts
5
+ interface ChangelogPresetConfigType {
6
+ /**
7
+ * The type of commit message.
8
+ * @example "feat", "fix", "chore", etc..
9
+ */
10
+ type: string;
11
+ /**
12
+ * The scope of the commit message.
13
+ */
14
+ scope?: string;
15
+ /**
16
+ * The section of the `CHANGELOG` the commit should show up in.
17
+ */
18
+ section?: string;
19
+ /**
20
+ * Should show in the generated changelog message?
21
+ */
22
+ hidden?: boolean;
23
+ }
24
+ interface ChangelogPresetConfig {
25
+ /**
26
+ * List of explicitly supported commit message types.
27
+ */
28
+ types: ChangelogPresetConfigType[];
29
+ /**
30
+ * A URL representing a specific commit at a hash.
31
+ * @default "{{host}}/{{owner}}/{{repository}}/commit/{{hash}}"
32
+ */
33
+ commitUrlFormat: string;
34
+ /**
35
+ * A URL representing the comparison between two git SHAs.
36
+ * @default "{{host}}/{{owner}}/{{repository}}/compare/{{previousTag}}...{{currentTag}}"
37
+ */
38
+ compareUrlFormat: string;
39
+ /**
40
+ * A URL representing the issue format (allowing a different URL format to be swapped in
41
+ * for Gitlab, Bitbucket, etc).
42
+ * @default "{{host}}/{{owner}}/{{repository}}/issues/{{id}}"
43
+ */
44
+ issueUrlFormat: string;
45
+ /**
46
+ * A URL representing a user's profile on GitHub, Gitlab, etc. This URL is used
47
+ * for substituting @eglavin with https://github.com/eglavin in commit messages.
48
+ * @default "{{host}}/{{user}}"
49
+ */
50
+ userUrlFormat: string;
51
+ /**
52
+ * A string to be used to format the auto-generated release commit message.
53
+ * @default "chore(release): {{currentTag}}"
54
+ */
55
+ releaseCommitMessageFormat: string;
56
+ /**
57
+ * List of prefixes used to detect references to issues.
58
+ * @default ["#"]
59
+ */
60
+ issuePrefixes: string[];
61
+ }
62
+ interface ForkConfig {
63
+ /**
64
+ * The command to run, can be one of the following:
65
+ *
66
+ * - `main` - Bumps the version, update files, generate changelog, commit, and tag.
67
+ * - `inspect-version` - Prints the current version and exits.
68
+ * - `inspect-tag` - Prints the current git tag and exits.
69
+ * - `inspect` - Prints the current version and git tag and exits.
70
+ * - `validate-config` - Validates the configuration and exits.
71
+ *
72
+ * @default "main"
73
+ */
74
+ command: "main" | "inspect" | "inspect-version" | "inspect-tag" | "validate-config";
75
+ /**
76
+ * If set, Fork-Version will print the current version and exit.
77
+ * @default false
78
+ *
79
+ * @deprecated Set the `inspect-version` command instead.
80
+ */
81
+ inspectVersion?: boolean;
82
+ /**
83
+ * List of the files to be updated.
84
+ * @default
85
+ * ```js
86
+ * ["bower.json", "deno.json", "deno.jsonc", "jsr.json", "jsr.jsonc", "manifest.json", "npm-shrinkwrap.json", "package-lock.json", "package.json"]
87
+ * ```
88
+ */
89
+ files: string[];
90
+ /**
91
+ * Glob pattern to match files to be updated.
92
+ *
93
+ * Internally we're using [glob](https://github.com/isaacs/node-glob) to match files.
94
+ *
95
+ * Read more about the pattern syntax [here](https://github.com/isaacs/node-glob/tree/v10.3.12?tab=readme-ov-file#glob-primer).
96
+ *
97
+ * @default undefined
98
+ * @example "*.json"
99
+ */
100
+ glob?: string;
101
+ /**
102
+ * The path Fork-Version will run from.
103
+ * @default
104
+ * ```js
105
+ * process.cwd()
106
+ * ```
107
+ */
108
+ path: string;
109
+ /**
110
+ * Name of the changelog file.
111
+ * @default "CHANGELOG.md"
112
+ */
113
+ changelog: string;
114
+ /**
115
+ * The header text for the changelog.
116
+ * @default
117
+ * ```markdown
118
+ * # Changelog
119
+ *
120
+ * All notable changes to this project will be documented in this file. See [fork-version](https://github.com/eglavin/fork-version) for commit guidelines.
121
+ * ```
122
+ */
123
+ header: string;
124
+ /**
125
+ * Specify a prefix for the created tag.
126
+ *
127
+ * For instance if your version tag is prefixed by "version/" instead of "v" you have to specify
128
+ * `tagPrefix: "version/"`.
129
+ *
130
+ * `tagPrefix` can also be used for a monorepo environment where you might want to deploy
131
+ * multiple package from the same repository. In this case you can specify a prefix for
132
+ * each package:
133
+ *
134
+ * | Example Value | Tag Created |
135
+ * |:-------------------------|:------------------------------|
136
+ * | "" | `1.2.3` |
137
+ * | "version/" | `version/1.2.3` |
138
+ * | "@eglavin/fork-version-" | `@eglavin/fork-version-1.2.3` |
139
+ *
140
+ * @example "", "version/", "@eglavin/fork-version-"
141
+ * @default "v"
142
+ */
143
+ tagPrefix: string;
144
+ /**
145
+ * Make a pre-release with optional label if given value is a string.
146
+ *
147
+ * | Example Value | Produced Version |
148
+ * |:--------------|:-----------------|
149
+ * | true | `1.2.3-0` |
150
+ * | "alpha" | `1.2.3-alpha-0` |
151
+ * | "beta" | `1.2.3-beta-0` |
152
+ *
153
+ * @example true, "alpha", "beta", "rc"
154
+ * @default undefined
155
+ */
156
+ preRelease?: string | boolean;
157
+ /**
158
+ * If set, Fork-Version will use this version instead of trying to determine one.
159
+ * @example "1.0.0"
160
+ * @default undefined
161
+ */
162
+ currentVersion?: string;
163
+ /**
164
+ * If set, Fork-Version will attempt to update to this version, instead of incrementing using "conventional-commit".
165
+ * @example "2.0.0"
166
+ * @default undefined
167
+ */
168
+ nextVersion?: string;
169
+ /**
170
+ * Release as increments the version by the specified level. Overrides the default behaviour of "conventional-commit".
171
+ * @example "major", "minor", "patch"
172
+ * @default undefined
173
+ */
174
+ releaseAs?: "major" | "minor" | "patch";
175
+ /**
176
+ * Don't throw an error if multiple versions are found in the given files.
177
+ * @default true
178
+ */
179
+ allowMultipleVersions: boolean;
180
+ /**
181
+ * Commit all changes, not just files updated by Fork-Version.
182
+ * @default false
183
+ */
184
+ commitAll: boolean;
185
+ /**
186
+ * By default the conventional-changelog spec will only add commit types of `feat` and `fix` to the generated changelog.
187
+ * If this flag is set, all [default commit types](https://github.com/conventional-changelog/conventional-changelog-config-spec/blob/238093090c14bd7d5151eb5316e635623ce633f9/versions/2.2.0/schema.json#L18)
188
+ * will be added to the changelog.
189
+ * @default false
190
+ */
191
+ changelogAll: boolean;
192
+ /**
193
+ * Output debug information.
194
+ * @default false
195
+ */
196
+ debug: boolean;
197
+ /**
198
+ * No output will be written to disk or committed.
199
+ * @default false
200
+ */
201
+ dryRun: boolean;
202
+ /**
203
+ * Run without logging to the terminal.
204
+ * @default false
205
+ */
206
+ silent: boolean;
207
+ /**
208
+ * If unable to find a version in the given files, fallback and attempt to use the latest git tag.
209
+ * @default true
210
+ */
211
+ gitTagFallback: boolean;
212
+ /**
213
+ * If true, git will sign the commit with the systems GPG key.
214
+ * @see {@link https://git-scm.com/docs/git-commit#Documentation/git-commit.txt--Sltkeyidgt Git - GPG Sign Commits}
215
+ * @default false
216
+ */
217
+ sign: boolean;
218
+ /**
219
+ * If true, git will run user defined git hooks before committing.
220
+ * @see {@link https://git-scm.com/docs/githooks Git - Git Hooks}
221
+ * @default false
222
+ */
223
+ verify: boolean;
224
+ /**
225
+ * Print inspected output as a parsable json string.
226
+ * @default false
227
+ */
228
+ asJson: boolean;
229
+ /**
230
+ * Skip the bump step.
231
+ * @default false
232
+ */
233
+ skipBump: boolean;
234
+ /**
235
+ * Skip the changelog step.
236
+ * @default false
237
+ */
238
+ skipChangelog: boolean;
239
+ /**
240
+ * Skip the commit step.
241
+ * @default false
242
+ */
243
+ skipCommit: boolean;
244
+ /**
245
+ * Skip the tag step.
246
+ * @default false
247
+ */
248
+ skipTag: boolean;
249
+ /**
250
+ * The detected git host:
251
+ * - `GitHub`
252
+ * - `GitLab`
253
+ * - `Bitbucket`
254
+ * - `Azure Devops`
255
+ * - Or undefined if unknown or not detected.
256
+ */
257
+ detectedGitHost?: string;
258
+ /**
259
+ * Override the default "conventional-changelog-conventionalcommits" preset configuration.
260
+ */
261
+ changelogPresetConfig?: Partial<ChangelogPresetConfig>;
262
+ /**
263
+ * Add a suffix to the release commit message.
264
+ * @example "[skip ci]"
265
+ */
266
+ releaseMessageSuffix?: string;
267
+ /**
268
+ * Options to pass to commits parser.
269
+ */
270
+ commitParserOptions?: Partial<ParserOptions>;
271
+ }
272
+ type Config = Partial<ForkConfig>;
273
+ type CLIArguments = ReturnType<typeof getCliArguments>;
274
+ interface ForkVersionCLIArgs {
275
+ input: CLIArguments["input"];
276
+ flags: Partial<CLIArguments["flags"]>;
277
+ }
278
+ //#endregion
279
+ export { ChangelogPresetConfig, ChangelogPresetConfigType, Config, ForkConfig, ForkVersionCLIArgs };
@@ -0,0 +1,6 @@
1
+ import { ForkConfig, ForkVersionCLIArgs } from "./types.js";
2
+
3
+ //#region src/config/user-config.d.ts
4
+ declare function getUserConfig(cliArguments: ForkVersionCLIArgs): Promise<ForkConfig>;
5
+ //#endregion
6
+ export { getUserConfig };
@@ -0,0 +1,50 @@
1
+ import { getChangelogPresetConfig } from "./changelog-preset-config.js";
2
+ import { DEFAULT_CONFIG } from "./defaults.js";
3
+ import { detectGitHost } from "../detect-git-host/detect-git-host.js";
4
+ import { loadConfigFile } from "./load-config.js";
5
+ import { mergeFiles } from "./merge-files.js";
6
+ import { join, resolve } from "node:path";
7
+ import { glob } from "node:fs/promises";
8
+ //#region src/config/user-config.ts
9
+ async function getUserConfig(cliArguments) {
10
+ const cwd = cliArguments.flags.path ? resolve(cliArguments.flags.path) : process.cwd();
11
+ const configFile = await loadConfigFile(cwd);
12
+ const mergedConfig = {
13
+ ...DEFAULT_CONFIG,
14
+ ...configFile,
15
+ ...cliArguments.flags
16
+ };
17
+ const globResults = [];
18
+ if (mergedConfig.glob) {
19
+ const IGNORE_LIST = new Set(["node_modules", ".git"]);
20
+ const entries = glob(mergedConfig.glob, {
21
+ cwd,
22
+ withFileTypes: true,
23
+ exclude: (entry) => IGNORE_LIST.has(entry.name)
24
+ });
25
+ for await (const entry of entries) if (entry.isFile()) globResults.push(join(entry.parentPath, entry.name));
26
+ }
27
+ const files = mergeFiles(configFile?.files, cliArguments.flags.files, globResults);
28
+ const detectedGitHost = await detectGitHost(cwd);
29
+ let command = DEFAULT_CONFIG.command;
30
+ if (cliArguments.input.length > 0 && cliArguments.input[0].trim()) command = cliArguments.input[0].trim().toLowerCase();
31
+ else if (mergedConfig.command.trim()) command = mergedConfig.command.trim().toLowerCase();
32
+ if (mergedConfig.inspectVersion) command = "inspect-version";
33
+ const shouldBeSilent = ![DEFAULT_CONFIG.command].includes(command);
34
+ return {
35
+ ...mergedConfig,
36
+ command,
37
+ files,
38
+ path: cwd,
39
+ preRelease: cliArguments.flags.preReleaseTag ?? cliArguments.flags.preRelease ?? configFile.preRelease,
40
+ silent: shouldBeSilent || mergedConfig.silent,
41
+ detectedGitHost: detectedGitHost?.hostName,
42
+ changelogPresetConfig: getChangelogPresetConfig(mergedConfig, cliArguments.flags, detectedGitHost?.changelogOptions),
43
+ commitParserOptions: {
44
+ ...detectedGitHost?.commitParserOptions,
45
+ ...mergedConfig.commitParserOptions
46
+ }
47
+ };
48
+ }
49
+ //#endregion
50
+ export { getUserConfig };
@@ -0,0 +1,35 @@
1
+ import { Git } from "../services/git.js";
2
+ import { detectGitHubOptions } from "./host-github.js";
3
+ import { detectGitlabOptions } from "./host-gitlab.js";
4
+ import { detectBitbucketOptions } from "./host-bitbucket.js";
5
+ import { detectAzureDevopsOptions } from "./host-azure-devops.js";
6
+ //#region src/detect-git-host/detect-git-host.ts
7
+ /**
8
+ * Detects the Git hosting service based on the remote URL of the Git repository at the given path.
9
+ *
10
+ * Supports `GitHub`, `GitLab`, `Bitbucket`, and `Azure DevOps`.
11
+ *
12
+ * @param path - The file system path to the Git repository.
13
+ * @returns A promise that resolves to a DetectedGitHost object if a supported host is detected, or undefined if no supported host is found.
14
+ */
15
+ async function detectGitHost(path) {
16
+ const remoteUrl = await new Git({ path }).getRemoteUrl();
17
+ if (remoteUrl.includes("github.com")) {
18
+ const githubOptions = detectGitHubOptions(remoteUrl);
19
+ if (githubOptions) return githubOptions;
20
+ }
21
+ if (remoteUrl.includes("gitlab.com")) {
22
+ const gitlabOptions = detectGitlabOptions(remoteUrl);
23
+ if (gitlabOptions) return gitlabOptions;
24
+ }
25
+ if (/bitbucket\.(org|com)/.test(remoteUrl)) {
26
+ const bitbucketOptions = detectBitbucketOptions(remoteUrl);
27
+ if (bitbucketOptions) return bitbucketOptions;
28
+ }
29
+ if (remoteUrl.includes("dev.azure.com")) {
30
+ const azureDevopsOptions = detectAzureDevopsOptions(remoteUrl);
31
+ if (azureDevopsOptions) return azureDevopsOptions;
32
+ }
33
+ }
34
+ //#endregion
35
+ export { detectGitHost };
@@ -0,0 +1,28 @@
1
+ //#region src/detect-git-host/host-azure-devops.ts
2
+ /**
3
+ * A checked out Azure Devops remote URL looks like one of these:
4
+ *
5
+ * | Checkout Type | Remote URL |
6
+ * |:------------- |:----------------------------------------------------------------------------------------- |
7
+ * | HTTPS | `https://{{ORGANISATION}}@dev.azure.com/{{ORGANISATION}}/{{PROJECT}}/_git/{{REPOSITORY}}` |
8
+ * | SSH | `git@ssh.dev.azure.com:v3/{{ORGANISATION}}/{{PROJECT}}/{{REPOSITORY}}` |
9
+ */
10
+ function detectAzureDevopsOptions(remoteUrl) {
11
+ let matches = null;
12
+ if (/^https:\/\/(.*)?dev\.azure\.com/.test(remoteUrl)) matches = /^https:\/\/(.*)?dev\.azure\.com\/(?<organisation>.*?)\/(?<project>.*?)\/_git\/(?<repository>.*?)(?:\.git)?$/.exec(remoteUrl);
13
+ else if (remoteUrl.startsWith("git@ssh.dev.azure.com:")) matches = /^git@ssh\.dev\.azure\.com:v\d\/(?<organisation>.*?)\/(?<project>.*?)\/(?<repository>.*?)(?:\.git)?$/.exec(remoteUrl);
14
+ if (matches?.groups) {
15
+ const { organisation = "", project = "", repository = "" } = matches.groups;
16
+ return {
17
+ hostName: "Azure Devops",
18
+ changelogOptions: {
19
+ commitUrlFormat: `https://dev.azure.com/${organisation}/${project}/_git/${repository}/commit/{{hash}}`,
20
+ compareUrlFormat: `https://dev.azure.com/${organisation}/${project}/_git/${repository}/branchCompare?baseVersion=GT{{previousTag}}&targetVersion=GT{{currentTag}}`,
21
+ issueUrlFormat: `https://dev.azure.com/${organisation}/${project}/_workitems/edit/{{id}}`
22
+ },
23
+ commitParserOptions: { mergePattern: /^Merged PR (?<id>\d*): (?<source>.*)/i }
24
+ };
25
+ }
26
+ }
27
+ //#endregion
28
+ export { detectAzureDevopsOptions };
@@ -0,0 +1,28 @@
1
+ //#region src/detect-git-host/host-bitbucket.ts
2
+ /**
3
+ * A checked out Bitbucket remote URL looks like one of these:
4
+ *
5
+ * | Checkout Type | Remote URL |
6
+ * |:------------- |:------------------------------------------------------------------------- |
7
+ * | HTTPS | `https://{{WORKSPACE}}@bitbucket.org/{{ORGANISATION}}/{{REPOSITORY}}.git` |
8
+ * | SSH | `git@bitbucket.org:{{ORGANISATION}}/{{REPOSITORY}}.git` |
9
+ */
10
+ function detectBitbucketOptions(remoteUrl) {
11
+ let matches = null;
12
+ if (/^https:\/\/(.*)?bitbucket\.(org|com)/.test(remoteUrl)) matches = /^https:\/\/(.*)?bitbucket\.(?<domain>org|com)\/(?<organisation>.*?)\/(?<repository>.*?)(?:\.git)?$/.exec(remoteUrl);
13
+ else if (remoteUrl.startsWith("git@bitbucket.org:")) matches = /^git@bitbucket\.(?<domain>org|com):(?<organisation>.*?)\/(?<repository>.*?)(?:\.git)?$/.exec(remoteUrl);
14
+ if (matches?.groups) {
15
+ const { domain = "", organisation = "", repository = "" } = matches.groups;
16
+ return {
17
+ hostName: "Bitbucket",
18
+ changelogOptions: {
19
+ commitUrlFormat: `https://bitbucket.${domain}/${organisation}/${repository}/commits/{{hash}}`,
20
+ compareUrlFormat: `https://bitbucket.${domain}/${organisation}/${repository}/branches/compare/{{currentTag}}..{{previousTag}}`,
21
+ issueUrlFormat: `https://bitbucket.${domain}/${organisation}/${repository}/issues/{{id}}`
22
+ },
23
+ commitParserOptions: { mergePattern: /^Merged in (?<source>.*) \(pull request #(?<id>\d*)\)/i }
24
+ };
25
+ }
26
+ }
27
+ //#endregion
28
+ export { detectBitbucketOptions };
@@ -0,0 +1,32 @@
1
+ //#region src/detect-git-host/host-github.ts
2
+ /**
3
+ * A checked out GitHub remote URL looks like one of these:
4
+ *
5
+ * | Checkout Type | Remote URL |
6
+ * |:------------- |:-------------------------------------------------------- |
7
+ * | HTTPS | `https://github.com/{{ORGANISATION}}/{{REPOSITORY}}.git` |
8
+ * | SSH | `git@github.com:{{ORGANISATION}}/{{REPOSITORY}}.git` |
9
+ */
10
+ function detectGitHubOptions(remoteUrl) {
11
+ let matches = null;
12
+ if (/^https:\/\/(.*)?github\.com/.test(remoteUrl)) matches = /^https:\/\/(.*)?github\.com\/(?<organisation>.*?)\/(?<repository>.*?)(?:\.git)?$/.exec(remoteUrl);
13
+ else if (remoteUrl.startsWith("git@github.com:")) matches = /^git@github\.com:(?<organisation>.*?)\/(?<repository>.*?)(?:\.git)?$/.exec(remoteUrl);
14
+ if (matches?.groups) {
15
+ const { organisation = "", repository = "" } = matches.groups;
16
+ return {
17
+ hostName: "GitHub",
18
+ changelogOptions: {
19
+ commitUrlFormat: `https://github.com/${organisation}/${repository}/commit/{{hash}}`,
20
+ compareUrlFormat: `https://github.com/${organisation}/${repository}/compare/{{previousTag}}...{{currentTag}}`,
21
+ issueUrlFormat: `https://github.com/${organisation}/${repository}/issues/{{id}}`,
22
+ issuePrefixes: ["#", "gh-"]
23
+ },
24
+ commitParserOptions: {
25
+ mergePattern: /^Merge pull request #(?<id>\d*) from (?<source>.*)/i,
26
+ issuePrefixes: ["#", "gh-"]
27
+ }
28
+ };
29
+ }
30
+ }
31
+ //#endregion
32
+ export { detectGitHubOptions };
@@ -0,0 +1,48 @@
1
+ //#region src/detect-git-host/host-gitlab.ts
2
+ /**
3
+ * A checked out GitLab remote URL looks like one of these:
4
+ *
5
+ * | Checkout Type | Remote URL |
6
+ * |:------------- |:-------------------------------------------------------- |
7
+ * | HTTPS | `https://gitlab.com/{{ORGANISATION}}/{{REPOSITORY}}.git` |
8
+ * | SSH | `git@gitlab.com:{{ORGANISATION}}/{{REPOSITORY}}.git` |
9
+ */
10
+ function detectGitlabOptions(remoteUrl) {
11
+ let matches = null;
12
+ if (/^https:\/\/(.*)?gitlab\.com/.test(remoteUrl)) matches = /^https:\/\/(.*)?gitlab\.com\/(?<organisation>.*?)\/(?<repository>.*?)(?:\.git)?$/.exec(remoteUrl);
13
+ else if (remoteUrl.startsWith("git@gitlab.com:")) matches = /^git@gitlab\.com:(?<organisation>.*?)\/(?<repository>.*?)(?:\.git)?$/.exec(remoteUrl);
14
+ if (matches?.groups) {
15
+ const { organisation = "", repository = "" } = matches.groups;
16
+ return {
17
+ hostName: "GitLab",
18
+ changelogOptions: {
19
+ commitUrlFormat: `https://gitlab.com/${organisation}/${repository}/-/commit/{{hash}}`,
20
+ compareUrlFormat: `https://gitlab.com/${organisation}/${repository}/-/compare/{{previousTag}}...{{currentTag}}`,
21
+ issueUrlFormat: `https://gitlab.com/${organisation}/${repository}/-/issues/{{id}}`
22
+ },
23
+ commitParserOptions: {
24
+ mergePattern: /^Merge branch '(?<source>.*)' into '(.*)'/i,
25
+ referenceActions: [
26
+ "close",
27
+ "closes",
28
+ "closed",
29
+ "closing",
30
+ "fix",
31
+ "fixes",
32
+ "fixed",
33
+ "fixing",
34
+ "resolve",
35
+ "resolves",
36
+ "resolved",
37
+ "resolving",
38
+ "implement",
39
+ "implements",
40
+ "implemented",
41
+ "implementing"
42
+ ]
43
+ }
44
+ };
45
+ }
46
+ }
47
+ //#endregion
48
+ export { detectGitlabOptions };
@@ -0,0 +1,44 @@
1
+ import { basename } from "node:path";
2
+ import { readFileSync, writeFileSync } from "node:fs";
3
+ //#region src/files/arm-bicep.ts
4
+ /**
5
+ * An ARM bicep file with metadata and variable called contentVersion.
6
+ *
7
+ * @example
8
+ * ```bicep
9
+ * metadata contentVersion = '1.2.3.4'
10
+ * var contentVersion string = '1.2.3.4'
11
+ * ```
12
+ */
13
+ var ARMBicep = class {
14
+ #logger;
15
+ constructor(logger) {
16
+ this.#logger = logger;
17
+ }
18
+ /** https://regex101.com/r/Lriphb/2 */
19
+ #metadataRegex = /(metadata contentVersion *= *['"])(?<version>[^'"]+)(['"])/;
20
+ /** https://regex101.com/r/iKCTF9/1 */
21
+ #varRegex = /(var contentVersion(?: string)? *= *['"])(?<version>[^'"]+)(['"])/;
22
+ read(filePath) {
23
+ const fileName = basename(filePath);
24
+ const fileContents = readFileSync(filePath, "utf8");
25
+ const metadataMatch = this.#metadataRegex.exec(fileContents);
26
+ const varMatch = this.#varRegex.exec(fileContents);
27
+ if (metadataMatch?.groups?.version && varMatch?.groups?.version) return {
28
+ name: fileName,
29
+ path: filePath,
30
+ version: metadataMatch.groups.version
31
+ };
32
+ if (!metadataMatch) this.#logger.warn(`[File Manager] Missing 'metadata contentVersion' in bicep file: ${fileName}`);
33
+ if (!varMatch) this.#logger.warn(`[File Manager] Missing 'var contentVersion' in bicep file: ${fileName}`);
34
+ }
35
+ write(fileState, newVersion) {
36
+ const updatedContent = readFileSync(fileState.path, "utf8").replace(this.#metadataRegex, `$1${newVersion}$3`).replace(this.#varRegex, `$1${newVersion}$3`);
37
+ writeFileSync(fileState.path, updatedContent, "utf8");
38
+ }
39
+ isSupportedFile(fileName) {
40
+ return fileName.endsWith(".bicep");
41
+ }
42
+ };
43
+ //#endregion
44
+ export { ARMBicep };
@@ -0,0 +1,47 @@
1
+ import { ForkConfig } from "../config/types.js";
2
+ import { Logger } from "../services/logger.js";
3
+
4
+ //#region src/files/file-manager.d.ts
5
+ interface FileState {
6
+ name: string;
7
+ path: string;
8
+ version: string;
9
+ [other: string]: unknown;
10
+ }
11
+ interface IFileManager {
12
+ read(fileName: string): FileState | undefined;
13
+ write(fileState: FileState, newVersion: string): void;
14
+ isSupportedFile(fileName: string): boolean;
15
+ }
16
+ declare class FileManager {
17
+ #private;
18
+ constructor(config: ForkConfig, logger: Logger);
19
+ /**
20
+ * Get the state from the given file name.
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * fileManager.read("package.json");
25
+ * ```
26
+ *
27
+ * @returns
28
+ * ```json
29
+ * { "name": "package.json", "path": "/path/to/package.json", "version": "1.2.3", "isPrivate": true }
30
+ * ```
31
+ */
32
+ read(pathOrName: string): FileState | undefined;
33
+ /**
34
+ * Write the new version to the given file.
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * fileManager.write(
39
+ * { name: "package.json", path: "/path/to/package.json", version: "1.2.2" },
40
+ * "1.2.3"
41
+ * );
42
+ * ```
43
+ */
44
+ write(fileState: FileState, newVersion: string): void;
45
+ }
46
+ //#endregion
47
+ export { FileManager, FileState, IFileManager };
@@ -0,0 +1,65 @@
1
+ import { fileExists } from "../utils/file-state.js";
2
+ import { JSONPackage } from "./json-package.js";
3
+ import { YAMLPackage } from "./yaml-package.js";
4
+ import { PlainText } from "./plain-text.js";
5
+ import { MSBuildProject } from "./ms-build-project.js";
6
+ import { ARMBicep } from "./arm-bicep.js";
7
+ import { InstallShieldISM } from "./install-shield-ism.js";
8
+ import { isAbsolute, resolve } from "node:path";
9
+ //#region src/files/file-manager.ts
10
+ var FileManager = class {
11
+ #config;
12
+ #logger;
13
+ #fileManagers = [];
14
+ constructor(config, logger) {
15
+ this.#config = config;
16
+ this.#logger = logger;
17
+ this.#fileManagers = [
18
+ new JSONPackage(logger),
19
+ new YAMLPackage(logger),
20
+ new PlainText(logger),
21
+ new MSBuildProject(logger),
22
+ new ARMBicep(logger),
23
+ new InstallShieldISM(logger)
24
+ ];
25
+ }
26
+ /**
27
+ * Get the state from the given file name.
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * fileManager.read("package.json");
32
+ * ```
33
+ *
34
+ * @returns
35
+ * ```json
36
+ * { "name": "package.json", "path": "/path/to/package.json", "version": "1.2.3", "isPrivate": true }
37
+ * ```
38
+ */
39
+ read(pathOrName) {
40
+ const _fileName = pathOrName.toLowerCase();
41
+ const filePath = isAbsolute(pathOrName) ? pathOrName : resolve(this.#config.path, pathOrName);
42
+ if (!fileExists(filePath)) return;
43
+ for (const fileManager of this.#fileManagers) if (fileManager.isSupportedFile(_fileName)) return fileManager.read(filePath);
44
+ this.#logger.error(`[File Manager] Unsupported file: ${pathOrName}`);
45
+ }
46
+ /**
47
+ * Write the new version to the given file.
48
+ *
49
+ * @example
50
+ * ```ts
51
+ * fileManager.write(
52
+ * { name: "package.json", path: "/path/to/package.json", version: "1.2.2" },
53
+ * "1.2.3"
54
+ * );
55
+ * ```
56
+ */
57
+ write(fileState, newVersion) {
58
+ if (this.#config.dryRun) return;
59
+ const _fileName = fileState.name.toLowerCase();
60
+ for (const fileManager of this.#fileManagers) if (fileManager.isSupportedFile(_fileName)) return fileManager.write(fileState, newVersion);
61
+ this.#logger.error(`[File Manager] Unsupported file: ${fileState.path}`);
62
+ }
63
+ };
64
+ //#endregion
65
+ export { FileManager };