@exadev/semantic-release-workspace 2.1.0 → 2.2.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.
- package/README.md +8 -2
- package/dist/cli.js +23 -4
- package/dist/index.cjs +22 -3
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +22 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ One orchestrator run, five stages:
|
|
|
14
14
|
|
|
15
15
|
1. **Workspace discovery.** Reads the `packages` globs from `pnpm-workspace.yaml` and every matched package's `package.json` (`dependencies`, `devDependencies`, `peerDependencies`, `optionalDependencies`), building the inter-package dependency graph keyed by package name. Packages must live in subdirectories (a package at the workspace root touches every commit and cannot be path-scoped) and names must be unique. This stage also resolves the workspace root's own path relative to the git repository's toplevel (`git rev-parse --show-prefix`), because `git log --name-only` always reports changed paths relative to that toplevel, not to `pnpm-workspace.yaml`'s own directory -- the two differ whenever the workspace is nested inside a larger repository, and every package's commit filtering is scoped against the repository-relative path, not the workspace-relative one, so nested workspaces are path-scoped correctly rather than silently matching nothing.
|
|
16
16
|
2. **Topological release ordering.** Kahn's algorithm over the discovered graph, so a package only releases after every workspace sibling it depends on has already released in this run. Ties are broken alphabetically within each dependency layer, so the same workspace always produces the same order. A dependency cycle has no valid order at all — the run fails loudly, naming the loop (`x -> y -> x`), rather than picking one of the wrong answers and publishing a package whose sibling dependency points at a version that does not exist yet.
|
|
17
|
-
3. **Per-package scoped release.** For each package in order, the orchestrator calls semantic-release's programmatic API (`require('semantic-release')`, not the CLI) with `cwd` set to the package's directory, `tagFormat`
|
|
17
|
+
3. **Per-package scoped release.** For each package in order, the orchestrator calls semantic-release's programmatic API (`require('semantic-release')`, not the CLI) with `cwd` set to the package's directory, `tagFormat` resolved from the `tagFormat` option (default `'${name}@${version}'`) so each package's tags stay distinct in the one shared tag namespace, and inline `analyzeCommits`/`generateNotes` plugins. Each wrapper runs one `git log --name-only --no-renames` pass over the same release range semantic-release already analysed (from the package's last matching tag to `HEAD`, or the whole history for a first release), maps every commit to the paths it changed, and filters the commit list down to commits touching the package's own directory **before delegating to the real @semantic-release/commit-analyzer and @semantic-release/release-notes-generator**. Conventional-commit parsing and changelog formatting stay entirely inside the standard plugins — the orchestrator only scopes what they see.
|
|
18
18
|
4. **Cross-package manifest bumping** — the heart of the design, covered in its own section below.
|
|
19
19
|
5. **Standard plugins do the publishing.** @semantic-release/npm, @semantic-release/github, @semantic-release/changelog, and @semantic-release/git run per package exactly as in a single-package repository, scoped by `cwd`. The orchestrator coordinates and sequences them; it does not reimplement npm publishing, GitHub release creation, or changelog file writing.
|
|
20
20
|
|
|
@@ -66,7 +66,13 @@ Everything above describes `commitStrategy: 'per-package'`, the default: unchang
|
|
|
66
66
|
| Default publish plugins | `DEFAULT_PUBLISH_PLUGINS` (changelog, npm, github, git) | `SINGLE_COMMIT_DEFAULT_PUBLISH_PLUGINS` — the same list minus git |
|
|
67
67
|
| Crash recovery | A bump commit already sitting in git history (from this run or an earlier one) is recognised via a machine-parseable trailer, so a run that resumes after a partial push still forces the right dependent releases | Not needed: either the whole combined commit lands and pushes, or the run fails before touching git at all, so there is never a partial push to recover from |
|
|
68
68
|
|
|
69
|
-
Everything about *what* releases (topological order, forced-patch dependents, dependency-range classification, path-scoped commit analysis, unsupported-range rejection) is identical between the two modes — `commitStrategy` only changes how the result is committed, tagged, and pushed.
|
|
69
|
+
Everything about *what* releases (topological order, forced-patch dependents, dependency-range classification, path-scoped commit analysis, unsupported-range rejection) is identical between the two modes — `commitStrategy` only changes how the result is committed, tagged, and pushed. ## Tag format
|
|
70
|
+
|
|
71
|
+
Each package's release tag comes from the `tagFormat` option, a lodash template with `${name}` and `${version}` placeholders, defaulting to `'${name}@${version}'`. Set it via the `tagFormat` field in a `--config` file or the `tagFormat` option to `releaseWorkspace()`. The template must contain `${version}` and may contain `${name}`; anything else is rejected before any package releases.
|
|
72
|
+
|
|
73
|
+
Override it when the tags are consumed as refs outside git: GitHub Actions pins composite actions as `owner/repo/path@ref`, and GitHub's workflow parser rejects a ref containing `@` -- so a repository of actions sets `'${name}-v${version}'` and every workflow pins `...@<action>-v<major>`. Note that switching an existing repository's format starts a fresh tag namespace: semantic-release will not see prior releases recorded under the old format, so rename existing tags to the new template as part of the switch.
|
|
74
|
+
|
|
75
|
+
Set it via the `--commit-strategy <mode>` CLI flag, the `commitStrategy` field in a `--config` file, or the `commitStrategy` option to `releaseWorkspace()`; omit it and nothing changes.
|
|
70
76
|
|
|
71
77
|
`'single'` mode still runs each package's own configured publish plugins afterward (npm publish with provenance, GitHub releases), scoped per package exactly as `'per-package'` mode does — it just runs their `verifyConditions`/`publish`/`success` steps directly against the already-committed-and-tagged repository state, since by that point semantic-release's own top-level orchestrator would misread the tag this mode already created as an existing release. `addChannel` and `fail` are not called in this mode (pre-release channel promotion and posting an automated failure comment/issue, respectively) — a deliberate scope boundary, not a silent gap: raise an issue if your workflow needs them.
|
|
72
78
|
|
package/dist/cli.js
CHANGED
|
@@ -14,7 +14,7 @@ import { generateNotes } from "@semantic-release/release-notes-generator";
|
|
|
14
14
|
import semanticRelease from "semantic-release";
|
|
15
15
|
import { pathToFileURL } from "node:url";
|
|
16
16
|
//#region package.json
|
|
17
|
-
var version = "2.
|
|
17
|
+
var version = "2.2.0";
|
|
18
18
|
//#endregion
|
|
19
19
|
//#region src/errors.ts
|
|
20
20
|
/**
|
|
@@ -59,6 +59,21 @@ var PnpmCommandError = class extends WorkspaceReleaseError {
|
|
|
59
59
|
super(`pnpm install --lockfile-only failed in ${cwd}: ${detail}`);
|
|
60
60
|
}
|
|
61
61
|
};
|
|
62
|
+
/**
|
|
63
|
+
* Validate a caller-supplied tagFormat once per run, before any package releases. The template must contain `${version}` (semantic-release interpolates it; without it every package would compute the same tag and overwrite its predecessor) and may contain `${name}`, which the orchestrator substitutes per package. Any other `${...}` token is a typo or a placeholder semantic-release does not support in tagFormat, so it is rejected here rather than released as a literal into a tag name.
|
|
64
|
+
*/
|
|
65
|
+
function validateTagFormat(tagFormat) {
|
|
66
|
+
if (!tagFormat.includes("${version}")) throw new ReleaseConfigurationError(`tagFormat must contain '\${version}' so each package's release tag carries its version; got: ${tagFormat}`);
|
|
67
|
+
const unknown = [...tagFormat.matchAll(/\$\{([^}]*)\}/g)].map((match) => match[1] ?? "").filter((token) => token !== "name" && token !== "version").filter((token) => token !== "");
|
|
68
|
+
if (unknown.length > 0) throw new ReleaseConfigurationError(`tagFormat supports only the '\${name}' and '\${version}' placeholders; unknown token(s): ${unknown.map((token) => `\${${token}}`).join(", ")}`);
|
|
69
|
+
return tagFormat;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Substitute `${name}` for one package. Called per package at release time; the returned template still carries the literal `${version}` for semantic-release to interpolate, exactly as the default `name@version` format always has.
|
|
73
|
+
*/
|
|
74
|
+
function formatTagForPackage(tagFormat, name) {
|
|
75
|
+
return tagFormat.replaceAll("${name}", name);
|
|
76
|
+
}
|
|
62
77
|
//#endregion
|
|
63
78
|
//#region src/exec-file.ts
|
|
64
79
|
/**
|
|
@@ -880,6 +895,7 @@ async function releaseWorkspaceSingleCommit(options) {
|
|
|
880
895
|
});
|
|
881
896
|
const analyzeCommitsConfig = options.analyzeCommits ?? {};
|
|
882
897
|
const generateNotesConfig = options.generateNotes ?? {};
|
|
898
|
+
const tagFormat = validateTagFormat(options.tagFormat ?? "${name}@${version}");
|
|
883
899
|
const capturedCommits = /* @__PURE__ */ new Map();
|
|
884
900
|
const captured = {
|
|
885
901
|
branch: void 0,
|
|
@@ -893,6 +909,7 @@ async function releaseWorkspaceSingleCommit(options) {
|
|
|
893
909
|
const bumpsForThisPackage = pendingBumps.get(name) ?? [];
|
|
894
910
|
pendingBumps.delete(name);
|
|
895
911
|
const nextRelease = await analysePackage(pkg, {
|
|
912
|
+
tagFormat,
|
|
896
913
|
resolvedPlugins: mustGet(resolvedPlugins, name, "publish plugins"),
|
|
897
914
|
analyzeCommitsConfig,
|
|
898
915
|
generateNotesConfig,
|
|
@@ -1015,7 +1032,7 @@ async function analysePackage(pkg, options) {
|
|
|
1015
1032
|
onCommitsResolved: options.onCommitsResolved
|
|
1016
1033
|
});
|
|
1017
1034
|
const semanticReleaseOptions = {
|
|
1018
|
-
tagFormat:
|
|
1035
|
+
tagFormat: formatTagForPackage(options.tagFormat, pkg.name),
|
|
1019
1036
|
plugins: options.resolvedPlugins,
|
|
1020
1037
|
dryRun: true,
|
|
1021
1038
|
async analyzeCommits(pluginConfig, context) {
|
|
@@ -1163,6 +1180,7 @@ async function releaseWorkspace(options = {}) {
|
|
|
1163
1180
|
order,
|
|
1164
1181
|
packages: (await runReleaseLoop(graph, order, workspace, dryRun, log, async (pkg, bumpsForThisPackage) => {
|
|
1165
1182
|
const result = await runPackageRelease(pkg, {
|
|
1183
|
+
tagFormat: validateTagFormat(options.tagFormat ?? "${name}@${version}"),
|
|
1166
1184
|
publishPlugins: mustGet(publishPlugins, pkg.name, "publish plugins"),
|
|
1167
1185
|
analyzeCommitsConfig,
|
|
1168
1186
|
generateNotesConfig,
|
|
@@ -1244,7 +1262,7 @@ async function runPackageRelease(pkg, options) {
|
|
|
1244
1262
|
bumps: { bumpsFor: () => options.bumpsForThisPackage }
|
|
1245
1263
|
});
|
|
1246
1264
|
const semanticReleaseOptions = {
|
|
1247
|
-
tagFormat:
|
|
1265
|
+
tagFormat: formatTagForPackage(options.tagFormat, pkg.name),
|
|
1248
1266
|
plugins: options.publishPlugins,
|
|
1249
1267
|
analyzeCommits: scoped.analyzeCommits,
|
|
1250
1268
|
generateNotes: scoped.generateNotes
|
|
@@ -1331,6 +1349,7 @@ async function detachWorkspaceRelease(options) {
|
|
|
1331
1349
|
analyzeCommitsConfig,
|
|
1332
1350
|
generateNotesConfig,
|
|
1333
1351
|
bumpsForThisPackage,
|
|
1352
|
+
tagFormat: validateTagFormat(options.tagFormat ?? "${name}@${version}"),
|
|
1334
1353
|
dryRun,
|
|
1335
1354
|
env,
|
|
1336
1355
|
branches: options.branches
|
|
@@ -1373,7 +1392,7 @@ async function runPackageDetach(pkg, options) {
|
|
|
1373
1392
|
bumps: { bumpsFor: () => options.bumpsForThisPackage }
|
|
1374
1393
|
});
|
|
1375
1394
|
const cliOptions = {
|
|
1376
|
-
tagFormat:
|
|
1395
|
+
tagFormat: formatTagForPackage(options.tagFormat, pkg.name),
|
|
1377
1396
|
plugins: options.publishPlugins,
|
|
1378
1397
|
analyzeCommits: scoped.analyzeCommits,
|
|
1379
1398
|
generateNotes: scoped.generateNotes
|
package/dist/index.cjs
CHANGED
|
@@ -857,6 +857,21 @@ async function regenerateLockfile(options) {
|
|
|
857
857
|
throw new PnpmCommandError(options.cwd, detail);
|
|
858
858
|
}
|
|
859
859
|
}
|
|
860
|
+
/**
|
|
861
|
+
* Validate a caller-supplied tagFormat once per run, before any package releases. The template must contain `${version}` (semantic-release interpolates it; without it every package would compute the same tag and overwrite its predecessor) and may contain `${name}`, which the orchestrator substitutes per package. Any other `${...}` token is a typo or a placeholder semantic-release does not support in tagFormat, so it is rejected here rather than released as a literal into a tag name.
|
|
862
|
+
*/
|
|
863
|
+
function validateTagFormat(tagFormat) {
|
|
864
|
+
if (!tagFormat.includes("${version}")) throw new ReleaseConfigurationError(`tagFormat must contain '\${version}' so each package's release tag carries its version; got: ${tagFormat}`);
|
|
865
|
+
const unknown = [...tagFormat.matchAll(/\$\{([^}]*)\}/g)].map((match) => match[1] ?? "").filter((token) => token !== "name" && token !== "version").filter((token) => token !== "");
|
|
866
|
+
if (unknown.length > 0) throw new ReleaseConfigurationError(`tagFormat supports only the '\${name}' and '\${version}' placeholders; unknown token(s): ${unknown.map((token) => `\${${token}}`).join(", ")}`);
|
|
867
|
+
return tagFormat;
|
|
868
|
+
}
|
|
869
|
+
/**
|
|
870
|
+
* Substitute `${name}` for one package. Called per package at release time; the returned template still carries the literal `${version}` for semantic-release to interpolate, exactly as the default `name@version` format always has.
|
|
871
|
+
*/
|
|
872
|
+
function formatTagForPackage(tagFormat, name) {
|
|
873
|
+
return tagFormat.replaceAll("${name}", name);
|
|
874
|
+
}
|
|
860
875
|
//#endregion
|
|
861
876
|
//#region src/single-commit-release.ts
|
|
862
877
|
/**
|
|
@@ -893,6 +908,7 @@ async function releaseWorkspaceSingleCommit(options) {
|
|
|
893
908
|
});
|
|
894
909
|
const analyzeCommitsConfig = options.analyzeCommits ?? {};
|
|
895
910
|
const generateNotesConfig = options.generateNotes ?? {};
|
|
911
|
+
const tagFormat = validateTagFormat(options.tagFormat ?? "${name}@${version}");
|
|
896
912
|
const capturedCommits = /* @__PURE__ */ new Map();
|
|
897
913
|
const captured = {
|
|
898
914
|
branch: void 0,
|
|
@@ -906,6 +922,7 @@ async function releaseWorkspaceSingleCommit(options) {
|
|
|
906
922
|
const bumpsForThisPackage = pendingBumps.get(name) ?? [];
|
|
907
923
|
pendingBumps.delete(name);
|
|
908
924
|
const nextRelease = await analysePackage(pkg, {
|
|
925
|
+
tagFormat,
|
|
909
926
|
resolvedPlugins: mustGet(resolvedPlugins, name, "publish plugins"),
|
|
910
927
|
analyzeCommitsConfig,
|
|
911
928
|
generateNotesConfig,
|
|
@@ -1028,7 +1045,7 @@ async function analysePackage(pkg, options) {
|
|
|
1028
1045
|
onCommitsResolved: options.onCommitsResolved
|
|
1029
1046
|
});
|
|
1030
1047
|
const semanticReleaseOptions = {
|
|
1031
|
-
tagFormat:
|
|
1048
|
+
tagFormat: formatTagForPackage(options.tagFormat, pkg.name),
|
|
1032
1049
|
plugins: options.resolvedPlugins,
|
|
1033
1050
|
dryRun: true,
|
|
1034
1051
|
async analyzeCommits(pluginConfig, context) {
|
|
@@ -1171,6 +1188,7 @@ async function detachWorkspaceRelease(options) {
|
|
|
1171
1188
|
analyzeCommitsConfig,
|
|
1172
1189
|
generateNotesConfig,
|
|
1173
1190
|
bumpsForThisPackage,
|
|
1191
|
+
tagFormat: validateTagFormat(options.tagFormat ?? "${name}@${version}"),
|
|
1174
1192
|
dryRun,
|
|
1175
1193
|
env,
|
|
1176
1194
|
branches: options.branches
|
|
@@ -1213,7 +1231,7 @@ async function runPackageDetach(pkg, options) {
|
|
|
1213
1231
|
bumps: { bumpsFor: () => options.bumpsForThisPackage }
|
|
1214
1232
|
});
|
|
1215
1233
|
const cliOptions = {
|
|
1216
|
-
tagFormat:
|
|
1234
|
+
tagFormat: formatTagForPackage(options.tagFormat, pkg.name),
|
|
1217
1235
|
plugins: options.publishPlugins,
|
|
1218
1236
|
analyzeCommits: scoped.analyzeCommits,
|
|
1219
1237
|
generateNotes: scoped.generateNotes
|
|
@@ -1310,6 +1328,7 @@ async function releaseWorkspace(options = {}) {
|
|
|
1310
1328
|
order,
|
|
1311
1329
|
packages: (await runReleaseLoop(graph, order, workspace, dryRun, log, async (pkg, bumpsForThisPackage) => {
|
|
1312
1330
|
const result = await runPackageRelease(pkg, {
|
|
1331
|
+
tagFormat: validateTagFormat(options.tagFormat ?? "${name}@${version}"),
|
|
1313
1332
|
publishPlugins: mustGet(publishPlugins, pkg.name, "publish plugins"),
|
|
1314
1333
|
analyzeCommitsConfig,
|
|
1315
1334
|
generateNotesConfig,
|
|
@@ -1391,7 +1410,7 @@ async function runPackageRelease(pkg, options) {
|
|
|
1391
1410
|
bumps: { bumpsFor: () => options.bumpsForThisPackage }
|
|
1392
1411
|
});
|
|
1393
1412
|
const semanticReleaseOptions = {
|
|
1394
|
-
tagFormat:
|
|
1413
|
+
tagFormat: formatTagForPackage(options.tagFormat, pkg.name),
|
|
1395
1414
|
plugins: options.publishPlugins,
|
|
1396
1415
|
analyzeCommits: scoped.analyzeCommits,
|
|
1397
1416
|
generateNotes: scoped.generateNotes
|
package/dist/index.d.cts
CHANGED
|
@@ -260,6 +260,14 @@ interface ReleaseWorkspaceOptions {
|
|
|
260
260
|
* Opt-in, orthogonal to `commitStrategy` -- it governs *when* publish/success run relative to tag+push, not *how many commits* the release makes. When `true`, each package's release is tagged and pushed via `@exadev/release-gate`'s `detachRelease` but never published: `WorkspaceReleaseOutcome.detached` carries the state `resumeWorkspaceRelease` needs to finish publishing later, from the same process or a different one, once an external gate confirms the release should actually go out. Rejected outright in combination with `commitStrategy: 'single'` -- `single-commit-release.ts`'s tag/publish machinery is entirely bespoke and never goes through semantic-release's own `run()`, so it has no insertion point for `release-gate`'s primitives. Defaults to `false`, today's exact existing behaviour.
|
|
261
261
|
*/
|
|
262
262
|
readonly gatePublish?: boolean;
|
|
263
|
+
/**
|
|
264
|
+
* Lodash template for each package's release tag, with `${name}` and `${version}` placeholders.
|
|
265
|
+
* Defaults to `'${name}@${version}'`. Override it when the tags double as refs consumed outside
|
|
266
|
+
* git: GitHub Actions pins composite actions as `owner/repo/path@ref`, and GitHub's workflow
|
|
267
|
+
* parser rejects a ref containing `@`, so a repository of actions sets `'${name}-v${version}'`
|
|
268
|
+
* and pins `...@<action>-v1`. Validated once per run by `validateTagFormat`.
|
|
269
|
+
*/
|
|
270
|
+
readonly tagFormat?: string;
|
|
263
271
|
}
|
|
264
272
|
/** One dependency-range change applied to a dependent package's manifest during the run, attached to the dependent's own outcome. */
|
|
265
273
|
interface AppliedDependencyBump extends DependencyBump {
|
package/dist/index.d.ts
CHANGED
|
@@ -260,6 +260,14 @@ interface ReleaseWorkspaceOptions {
|
|
|
260
260
|
* Opt-in, orthogonal to `commitStrategy` -- it governs *when* publish/success run relative to tag+push, not *how many commits* the release makes. When `true`, each package's release is tagged and pushed via `@exadev/release-gate`'s `detachRelease` but never published: `WorkspaceReleaseOutcome.detached` carries the state `resumeWorkspaceRelease` needs to finish publishing later, from the same process or a different one, once an external gate confirms the release should actually go out. Rejected outright in combination with `commitStrategy: 'single'` -- `single-commit-release.ts`'s tag/publish machinery is entirely bespoke and never goes through semantic-release's own `run()`, so it has no insertion point for `release-gate`'s primitives. Defaults to `false`, today's exact existing behaviour.
|
|
261
261
|
*/
|
|
262
262
|
readonly gatePublish?: boolean;
|
|
263
|
+
/**
|
|
264
|
+
* Lodash template for each package's release tag, with `${name}` and `${version}` placeholders.
|
|
265
|
+
* Defaults to `'${name}@${version}'`. Override it when the tags double as refs consumed outside
|
|
266
|
+
* git: GitHub Actions pins composite actions as `owner/repo/path@ref`, and GitHub's workflow
|
|
267
|
+
* parser rejects a ref containing `@`, so a repository of actions sets `'${name}-v${version}'`
|
|
268
|
+
* and pins `...@<action>-v1`. Validated once per run by `validateTagFormat`.
|
|
269
|
+
*/
|
|
270
|
+
readonly tagFormat?: string;
|
|
263
271
|
}
|
|
264
272
|
/** One dependency-range change applied to a dependent package's manifest during the run, attached to the dependent's own outcome. */
|
|
265
273
|
interface AppliedDependencyBump extends DependencyBump {
|
package/dist/index.js
CHANGED
|
@@ -832,6 +832,21 @@ async function regenerateLockfile(options) {
|
|
|
832
832
|
throw new PnpmCommandError(options.cwd, detail);
|
|
833
833
|
}
|
|
834
834
|
}
|
|
835
|
+
/**
|
|
836
|
+
* Validate a caller-supplied tagFormat once per run, before any package releases. The template must contain `${version}` (semantic-release interpolates it; without it every package would compute the same tag and overwrite its predecessor) and may contain `${name}`, which the orchestrator substitutes per package. Any other `${...}` token is a typo or a placeholder semantic-release does not support in tagFormat, so it is rejected here rather than released as a literal into a tag name.
|
|
837
|
+
*/
|
|
838
|
+
function validateTagFormat(tagFormat) {
|
|
839
|
+
if (!tagFormat.includes("${version}")) throw new ReleaseConfigurationError(`tagFormat must contain '\${version}' so each package's release tag carries its version; got: ${tagFormat}`);
|
|
840
|
+
const unknown = [...tagFormat.matchAll(/\$\{([^}]*)\}/g)].map((match) => match[1] ?? "").filter((token) => token !== "name" && token !== "version").filter((token) => token !== "");
|
|
841
|
+
if (unknown.length > 0) throw new ReleaseConfigurationError(`tagFormat supports only the '\${name}' and '\${version}' placeholders; unknown token(s): ${unknown.map((token) => `\${${token}}`).join(", ")}`);
|
|
842
|
+
return tagFormat;
|
|
843
|
+
}
|
|
844
|
+
/**
|
|
845
|
+
* Substitute `${name}` for one package. Called per package at release time; the returned template still carries the literal `${version}` for semantic-release to interpolate, exactly as the default `name@version` format always has.
|
|
846
|
+
*/
|
|
847
|
+
function formatTagForPackage(tagFormat, name) {
|
|
848
|
+
return tagFormat.replaceAll("${name}", name);
|
|
849
|
+
}
|
|
835
850
|
//#endregion
|
|
836
851
|
//#region src/single-commit-release.ts
|
|
837
852
|
/**
|
|
@@ -868,6 +883,7 @@ async function releaseWorkspaceSingleCommit(options) {
|
|
|
868
883
|
});
|
|
869
884
|
const analyzeCommitsConfig = options.analyzeCommits ?? {};
|
|
870
885
|
const generateNotesConfig = options.generateNotes ?? {};
|
|
886
|
+
const tagFormat = validateTagFormat(options.tagFormat ?? "${name}@${version}");
|
|
871
887
|
const capturedCommits = /* @__PURE__ */ new Map();
|
|
872
888
|
const captured = {
|
|
873
889
|
branch: void 0,
|
|
@@ -881,6 +897,7 @@ async function releaseWorkspaceSingleCommit(options) {
|
|
|
881
897
|
const bumpsForThisPackage = pendingBumps.get(name) ?? [];
|
|
882
898
|
pendingBumps.delete(name);
|
|
883
899
|
const nextRelease = await analysePackage(pkg, {
|
|
900
|
+
tagFormat,
|
|
884
901
|
resolvedPlugins: mustGet(resolvedPlugins, name, "publish plugins"),
|
|
885
902
|
analyzeCommitsConfig,
|
|
886
903
|
generateNotesConfig,
|
|
@@ -1003,7 +1020,7 @@ async function analysePackage(pkg, options) {
|
|
|
1003
1020
|
onCommitsResolved: options.onCommitsResolved
|
|
1004
1021
|
});
|
|
1005
1022
|
const semanticReleaseOptions = {
|
|
1006
|
-
tagFormat:
|
|
1023
|
+
tagFormat: formatTagForPackage(options.tagFormat, pkg.name),
|
|
1007
1024
|
plugins: options.resolvedPlugins,
|
|
1008
1025
|
dryRun: true,
|
|
1009
1026
|
async analyzeCommits(pluginConfig, context) {
|
|
@@ -1146,6 +1163,7 @@ async function detachWorkspaceRelease(options) {
|
|
|
1146
1163
|
analyzeCommitsConfig,
|
|
1147
1164
|
generateNotesConfig,
|
|
1148
1165
|
bumpsForThisPackage,
|
|
1166
|
+
tagFormat: validateTagFormat(options.tagFormat ?? "${name}@${version}"),
|
|
1149
1167
|
dryRun,
|
|
1150
1168
|
env,
|
|
1151
1169
|
branches: options.branches
|
|
@@ -1188,7 +1206,7 @@ async function runPackageDetach(pkg, options) {
|
|
|
1188
1206
|
bumps: { bumpsFor: () => options.bumpsForThisPackage }
|
|
1189
1207
|
});
|
|
1190
1208
|
const cliOptions = {
|
|
1191
|
-
tagFormat:
|
|
1209
|
+
tagFormat: formatTagForPackage(options.tagFormat, pkg.name),
|
|
1192
1210
|
plugins: options.publishPlugins,
|
|
1193
1211
|
analyzeCommits: scoped.analyzeCommits,
|
|
1194
1212
|
generateNotes: scoped.generateNotes
|
|
@@ -1285,6 +1303,7 @@ async function releaseWorkspace(options = {}) {
|
|
|
1285
1303
|
order,
|
|
1286
1304
|
packages: (await runReleaseLoop(graph, order, workspace, dryRun, log, async (pkg, bumpsForThisPackage) => {
|
|
1287
1305
|
const result = await runPackageRelease(pkg, {
|
|
1306
|
+
tagFormat: validateTagFormat(options.tagFormat ?? "${name}@${version}"),
|
|
1288
1307
|
publishPlugins: mustGet(publishPlugins, pkg.name, "publish plugins"),
|
|
1289
1308
|
analyzeCommitsConfig,
|
|
1290
1309
|
generateNotesConfig,
|
|
@@ -1366,7 +1385,7 @@ async function runPackageRelease(pkg, options) {
|
|
|
1366
1385
|
bumps: { bumpsFor: () => options.bumpsForThisPackage }
|
|
1367
1386
|
});
|
|
1368
1387
|
const semanticReleaseOptions = {
|
|
1369
|
-
tagFormat:
|
|
1388
|
+
tagFormat: formatTagForPackage(options.tagFormat, pkg.name),
|
|
1370
1389
|
plugins: options.publishPlugins,
|
|
1371
1390
|
analyzeCommits: scoped.analyzeCommits,
|
|
1372
1391
|
generateNotes: scoped.generateNotes
|
package/package.json
CHANGED