@williamthorsen/release-kit 15.0.2 → 16.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.
- package/.meta/changelog.json +88 -0
- package/.readyup/kits/default.js +14 -14
- package/.readyup/kits/npm-auto-publish.js +5 -5
- package/.readyup/manifest.json +14 -14
- package/CHANGELOG.md +28 -0
- package/README.md +3 -3
- package/dist/esm/applyChangelogOverrides.js +6 -6
- package/dist/esm/assertCleanWorkingTree.js +2 -2
- package/dist/esm/assertReleasesOnNpm.js +11 -11
- package/dist/esm/assertTaggedBaseline.js +5 -5
- package/dist/esm/bin/release-kit.js +16 -16
- package/dist/esm/buildChangelogEntries.d.ts +19 -19
- package/dist/esm/buildChangelogEntries.js +40 -36
- package/dist/esm/buildChangelogItem.js +24 -24
- package/dist/esm/buildDependencyGraph.js +23 -23
- package/dist/esm/buildReleasedResult.js +21 -19
- package/dist/esm/buildSyntheticChangelogEntry.js +2 -2
- package/dist/esm/bumpVersion.js +8 -8
- package/dist/esm/changelogArchive.d.ts +1 -1
- package/dist/esm/changelogArchive.js +2 -2
- package/dist/esm/changelogJsonFile.js +5 -5
- package/dist/esm/changelogJsonUtils.js +3 -3
- package/dist/esm/changelogOverrides.d.ts +5 -5
- package/dist/esm/changelogOverrides.js +23 -23
- package/dist/esm/classifyChangelogCommit.js +4 -4
- package/dist/esm/commitCommand.js +7 -7
- package/dist/esm/compareVersions.js +13 -13
- package/dist/esm/configSchema.d.ts +2 -2
- package/dist/esm/configSchema.js +1 -1
- package/dist/esm/createGithubRelease.d.ts +4 -4
- package/dist/esm/createGithubRelease.js +10 -10
- package/dist/esm/createGithubReleaseCommand.js +9 -9
- package/dist/esm/createTags.d.ts +2 -2
- package/dist/esm/createTags.js +12 -12
- package/dist/esm/decideDirectReleases.d.ts +5 -5
- package/dist/esm/decideDirectReleases.js +25 -25
- package/dist/esm/decideRelease.d.ts +1 -1
- package/dist/esm/decideRelease.js +2 -2
- package/dist/esm/deriveDirectoryConfig.d.ts +1 -1
- package/dist/esm/deriveDirectoryConfig.js +18 -18
- package/dist/esm/deriveWorkspaceConfig.js +4 -4
- package/dist/esm/detectPackageManager.js +5 -5
- package/dist/esm/detectUndeclaredTagPrefixes.js +8 -8
- package/dist/esm/enumerateReleaseWindows.d.ts +1 -1
- package/dist/esm/enumerateReleaseWindows.js +9 -9
- package/dist/esm/findTransitiveDependents.js +5 -5
- package/dist/esm/findUnroutedEntryScopes.js +11 -11
- package/dist/esm/format.d.ts +1 -1
- package/dist/esm/format.js +1 -1
- package/dist/esm/formatPrepareFiles.d.ts +3 -3
- package/dist/esm/formatPrepareFiles.js +10 -10
- package/dist/esm/formatPrepareWarnings.js +6 -6
- package/dist/esm/hasPrettierConfig.js +2 -2
- package/dist/esm/init/checks.js +7 -5
- package/dist/esm/init/detectRepoType.js +3 -3
- package/dist/esm/init/initCommand.d.ts +4 -4
- package/dist/esm/init/initCommand.js +7 -7
- package/dist/esm/init/parseJsonRecord.d.ts +1 -1
- package/dist/esm/init/parseJsonRecord.js +4 -4
- package/dist/esm/init/scaffold.d.ts +4 -4
- package/dist/esm/init/scaffold.js +18 -9
- package/dist/esm/init/templates.d.ts +10 -10
- package/dist/esm/init/templates.js +5 -5
- package/dist/esm/init/updateTemplatesCommand.d.ts +2 -2
- package/dist/esm/init/updateTemplatesCommand.js +16 -14
- package/dist/esm/injectReleaseNotesIntoReadme.d.ts +1 -1
- package/dist/esm/injectReleaseNotesIntoReadme.js +6 -6
- package/dist/esm/injectSection.js +8 -8
- package/dist/esm/loadChangelogOverrides.d.ts +1 -1
- package/dist/esm/loadChangelogOverrides.js +9 -9
- package/dist/esm/loadConfig.d.ts +3 -3
- package/dist/esm/loadConfig.js +10 -10
- package/dist/esm/loadValidatedConfig.js +4 -4
- package/dist/esm/mergeConfig.d.ts +1 -1
- package/dist/esm/mergeConfig.js +27 -27
- package/dist/esm/monorepoConfigAssertions.js +15 -15
- package/dist/esm/npmRegistry.js +4 -4
- package/dist/esm/packsPath.js +3 -3
- package/dist/esm/parseChangeRecordBlock.js +33 -33
- package/dist/esm/parseCommitMessage.js +5 -5
- package/dist/esm/planChangelogFiles.js +8 -8
- package/dist/esm/planReleaseNotesPreviews.js +10 -10
- package/dist/esm/planVersionBump.js +24 -16
- package/dist/esm/prepareArgs.d.ts +9 -9
- package/dist/esm/prepareArgs.js +11 -11
- package/dist/esm/prepareCommand.js +23 -23
- package/dist/esm/prepareComposite.d.ts +4 -4
- package/dist/esm/prepareComposite.js +16 -16
- package/dist/esm/{releasePrepareTargets.d.ts → prepareReleaseTargets.d.ts} +9 -9
- package/dist/esm/{releasePrepareTargets.js → prepareReleaseTargets.js} +40 -40
- package/dist/esm/prepareRunContext.d.ts +1 -1
- package/dist/esm/prepareRunContext.js +5 -5
- package/dist/esm/prepareTarget.d.ts +3 -3
- package/dist/esm/prepareTarget.js +41 -39
- package/dist/esm/previewTagPrefixes.js +21 -21
- package/dist/esm/propagateBumps.js +8 -8
- package/dist/esm/publish.d.ts +2 -2
- package/dist/esm/publish.js +5 -5
- package/dist/esm/publishCommand.js +20 -20
- package/dist/esm/pushCommand.js +8 -8
- package/dist/esm/pushRelease.d.ts +1 -1
- package/dist/esm/pushRelease.js +4 -4
- package/dist/esm/readChangelogSections.d.ts +1 -1
- package/dist/esm/readChangelogSections.js +16 -16
- package/dist/esm/releasePlan.js +26 -26
- package/dist/esm/renderChangelogMarkdown.d.ts +4 -4
- package/dist/esm/renderChangelogMarkdown.js +18 -15
- package/dist/esm/renderReleaseNotes.d.ts +1 -1
- package/dist/esm/renderReleaseNotes.js +16 -16
- package/dist/esm/reportPrepare.js +34 -34
- package/dist/esm/resolveCommandTags.js +9 -9
- package/dist/esm/resolveReleaseDeclaration.d.ts +2 -2
- package/dist/esm/resolveReleaseDeclaration.js +22 -22
- package/dist/esm/resolveReleaseTags.js +19 -17
- package/dist/esm/resolveReleaseTargets.js +2 -2
- package/dist/esm/showTagPrefixesCommand.js +4 -4
- package/dist/esm/sync-labels/generateCommand.d.ts +3 -3
- package/dist/esm/sync-labels/generateCommand.js +10 -10
- package/dist/esm/sync-labels/initCommand.d.ts +3 -3
- package/dist/esm/sync-labels/initCommand.js +23 -15
- package/dist/esm/sync-labels/presets.js +3 -3
- package/dist/esm/sync-labels/resolveLabels.js +13 -13
- package/dist/esm/sync-labels/syncCommand.js +2 -2
- package/dist/esm/sync-labels/templates.d.ts +4 -4
- package/dist/esm/sync-labels/templates.js +13 -40
- package/dist/esm/tagCommand.js +4 -4
- package/dist/esm/topologicalSort.d.ts +2 -2
- package/dist/esm/topologicalSort.js +7 -7
- package/dist/esm/types.d.ts +3 -3
- package/dist/esm/validateAllChangelogOverrides.js +9 -9
- package/dist/esm/validateConfig.d.ts +1 -1
- package/dist/esm/validateConfig.js +60 -50
- package/dist/esm/validateOverridesCommand.js +2 -2
- package/docs/changelogs.md +5 -5
- package/docs/configuration.md +1 -1
- package/docs/work-types.md +1 -1
- package/package.json +9 -8
- package/templates/sync-labels.yaml.template +36 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { chainError } from '@williamthorsen/toolbelt.errors/candidate';
|
|
2
2
|
import { isRepoRoot } from "./prepareTarget.js";
|
|
3
|
-
export function collect(
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
export function collect(collectedReleases, plannedRelease) {
|
|
4
|
+
collectedReleases.tags.push(plannedRelease.tag);
|
|
5
|
+
collectedReleases.writes.push(...plannedRelease.writes);
|
|
6
|
+
collectedReleases.removals.push(...plannedRelease.removals);
|
|
7
|
+
collectedReleases.modifiedFiles.push(...plannedRelease.modifiedFiles);
|
|
8
8
|
}
|
|
9
9
|
export function describeStage(target) {
|
|
10
10
|
switch (target.kind) {
|
|
@@ -10,7 +10,7 @@ export type TargetPrepareSettings = Omit<ReleaseSettings, 'releaseNotes'>;
|
|
|
10
10
|
/** One read of a target's release windows, and the untagged baseline that it found, if any. */
|
|
11
11
|
export interface TargetReading {
|
|
12
12
|
history: ReleaseHistory;
|
|
13
|
-
|
|
13
|
+
untaggedBaseline: UntaggedBaseline | undefined;
|
|
14
14
|
}
|
|
15
15
|
/** Outcome of {@link decideTargetRelease}: a release at a decided level or at an explicit version, or a skip. */
|
|
16
16
|
export type TargetDecision = {
|
|
@@ -76,10 +76,10 @@ export declare function readTargetHistory(target: ReleaseTarget, settings: Targe
|
|
|
76
76
|
export declare function describeHistoryWindow(target: ReleaseTarget): GenerateChangelogOptions;
|
|
77
77
|
/**
|
|
78
78
|
* Decides a target's direct release from its window: `setVersion` releases at that version, and otherwise the
|
|
79
|
-
* window's bump, `
|
|
79
|
+
* window's bump, `shouldForce`, and `bumpOverride` decide as {@link decideRelease} states.
|
|
80
80
|
*/
|
|
81
81
|
export declare function decideTargetRelease(target: ReleaseTarget, history: ReleaseHistory, options: {
|
|
82
|
-
|
|
82
|
+
shouldForce: boolean;
|
|
83
83
|
bumpOverride: ReleaseType | undefined;
|
|
84
84
|
setVersion: string | undefined;
|
|
85
85
|
}): TargetDecision;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { findUntaggedBaseline } from "./assertTaggedBaseline.js";
|
|
2
2
|
import { attachChangelogDiagnostics } from "./attachChangelogDiagnostics.js";
|
|
3
|
-
import {
|
|
3
|
+
import { convertToReleaseEntries, readReleaseHistory } from "./buildChangelogEntries.js";
|
|
4
4
|
import { buildPropagationEntries, buildReleasedResult } from "./buildReleasedResult.js";
|
|
5
5
|
import { applyWorkspaceOverrides } from "./changelogOverrides.js";
|
|
6
6
|
import { decideRelease } from "./decideRelease.js";
|
|
@@ -12,14 +12,14 @@ import { PROJECT_TARGET_ID } from "./resolveReleaseTargets.js";
|
|
|
12
12
|
export function readTargetHistory(target, settings) {
|
|
13
13
|
const options = describeHistoryWindow(target);
|
|
14
14
|
const history = readReleaseHistory(settings, options);
|
|
15
|
-
const
|
|
15
|
+
const untaggedBaseline = findUntaggedBaseline({
|
|
16
16
|
label: describeBaselineLabel(target),
|
|
17
17
|
packageFiles: target.versionFiles,
|
|
18
18
|
changelogPaths: [target.changelogDir],
|
|
19
19
|
tagPrefixes: options.tagPrefixes,
|
|
20
20
|
previousTag: history.previousTag,
|
|
21
21
|
}, settings);
|
|
22
|
-
return { history,
|
|
22
|
+
return { history, untaggedBaseline };
|
|
23
23
|
}
|
|
24
24
|
export function describeHistoryWindow(target) {
|
|
25
25
|
return {
|
|
@@ -29,21 +29,21 @@ export function describeHistoryWindow(target) {
|
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
31
|
export function decideTargetRelease(target, history, options) {
|
|
32
|
-
const {
|
|
32
|
+
const { shouldForce, bumpOverride, setVersion } = options;
|
|
33
33
|
if (setVersion !== undefined) {
|
|
34
34
|
return { outcome: 'release', releaseType: undefined, bumpOverride: undefined, setVersion };
|
|
35
35
|
}
|
|
36
36
|
const tag = history.previousTag;
|
|
37
|
-
const
|
|
37
|
+
const sinceClause = tag === undefined ? '(no previous release found)' : `since ${tag}`;
|
|
38
38
|
const subject = isScopeRouted(target) || target.kind === 'directory' ? ` for ${target.id}` : '';
|
|
39
39
|
const decision = decideRelease({
|
|
40
|
-
naturalBump: history.
|
|
41
|
-
commitCount: history.
|
|
42
|
-
|
|
40
|
+
naturalBump: history.unreleasedReading.bump,
|
|
41
|
+
commitCount: history.unreleasedReading.commits.length,
|
|
42
|
+
shouldForce,
|
|
43
43
|
bumpOverride,
|
|
44
44
|
skipReasons: {
|
|
45
|
-
noCommits: `No commits${subject} ${
|
|
46
|
-
noBumpWorthy: `No bump-worthy commits${subject} ${
|
|
45
|
+
noCommits: `No commits${subject} ${sinceClause}. Pass --force to release at patch. Skipping.`,
|
|
46
|
+
noBumpWorthy: `No bump-worthy commits${subject} ${sinceClause}. Pass --force to release at patch (or --force --bump=X for a different level). Skipping.`,
|
|
47
47
|
},
|
|
48
48
|
});
|
|
49
49
|
if (decision.outcome === 'skip') {
|
|
@@ -54,42 +54,42 @@ export function decideTargetRelease(target, history, options) {
|
|
|
54
54
|
export function planTargetRelease(args) {
|
|
55
55
|
const { target, settings, release, decision, history, overrideContext, sectionOrder, shouldPlanPreviews, today } = args;
|
|
56
56
|
const setVersion = decision?.setVersion;
|
|
57
|
-
const
|
|
57
|
+
const bumpPlan = setVersion === undefined
|
|
58
58
|
? planVersionBump(target.versionFiles, release.releaseType)
|
|
59
59
|
: planVersionSet(target.versionFiles, setVersion);
|
|
60
|
-
const tag = `${target.tagPrefix}${
|
|
61
|
-
const writes = [...
|
|
60
|
+
const tag = `${target.tagPrefix}${bumpPlan.newVersion}`;
|
|
61
|
+
const writes = [...bumpPlan.writes];
|
|
62
62
|
const entries = decision === undefined
|
|
63
|
-
? buildPropagationEntries(target, release,
|
|
64
|
-
:
|
|
63
|
+
? buildPropagationEntries(target, release, bumpPlan.newVersion, today, args.dependenciesHeader)
|
|
64
|
+
: convertToReleaseEntries(history, tag, today);
|
|
65
65
|
const overrideScope = describeOverrideScope(target);
|
|
66
|
-
const
|
|
67
|
-
const
|
|
68
|
-
writes.push(...
|
|
66
|
+
const appliedOverrides = applyWorkspaceOverrides(entries, overrideScope, overrideContext);
|
|
67
|
+
const changelogPlan = planChangelogFiles(target.changelogDir, appliedOverrides.entries, settings, sectionOrder);
|
|
68
|
+
writes.push(...changelogPlan.writes);
|
|
69
69
|
const warnings = [];
|
|
70
70
|
const previewFiles = [];
|
|
71
71
|
if (shouldPlanPreviews) {
|
|
72
|
-
const
|
|
72
|
+
const previewsPlan = planReleaseNotesPreviews({
|
|
73
73
|
workspacePath: target.changelogDir,
|
|
74
74
|
tag,
|
|
75
|
-
entries:
|
|
75
|
+
entries: changelogPlan.entries,
|
|
76
76
|
sectionOrder,
|
|
77
77
|
});
|
|
78
|
-
writes.push(...
|
|
79
|
-
warnings.push(...
|
|
80
|
-
previewFiles.push(...
|
|
78
|
+
writes.push(...previewsPlan.writes);
|
|
79
|
+
warnings.push(...previewsPlan.warnings);
|
|
80
|
+
previewFiles.push(...previewsPlan.writes.map((write) => write.path));
|
|
81
81
|
}
|
|
82
82
|
const releaseFields = {
|
|
83
83
|
targetId: target.id,
|
|
84
|
-
commitCount: history.
|
|
85
|
-
currentVersion:
|
|
86
|
-
newVersion:
|
|
84
|
+
commitCount: history.unreleasedReading.commits.length,
|
|
85
|
+
currentVersion: bumpPlan.currentVersion,
|
|
86
|
+
newVersion: bumpPlan.newVersion,
|
|
87
87
|
tag,
|
|
88
|
-
bumpedFiles:
|
|
89
|
-
changelogFiles:
|
|
90
|
-
...(
|
|
88
|
+
bumpedFiles: bumpPlan.writes.map((write) => write.path),
|
|
89
|
+
changelogFiles: changelogPlan.changelogFiles,
|
|
90
|
+
...(changelogPlan.removals.length > 0 && { removedChangelogFiles: changelogPlan.removals }),
|
|
91
91
|
...(previewFiles.length > 0 && { previewFiles }),
|
|
92
|
-
...(
|
|
92
|
+
...(changelogPlan.preservation !== undefined && { changelogPreservation: [changelogPlan.preservation] }),
|
|
93
93
|
...(history.previousTag !== undefined && { previousTag: history.previousTag }),
|
|
94
94
|
};
|
|
95
95
|
const result = buildReleasedResult(target, releaseFields, release, decision, history);
|
|
@@ -97,25 +97,27 @@ export function planTargetRelease(args) {
|
|
|
97
97
|
result,
|
|
98
98
|
tag,
|
|
99
99
|
writes,
|
|
100
|
-
removals:
|
|
101
|
-
modifiedFiles: [...target.versionFiles, ...
|
|
100
|
+
removals: changelogPlan.removals,
|
|
101
|
+
modifiedFiles: [...target.versionFiles, ...changelogPlan.changelogFiles, ...changelogPlan.changelogJsonFiles],
|
|
102
102
|
warnings,
|
|
103
103
|
};
|
|
104
104
|
}
|
|
105
105
|
export function buildSkippedTargetResult(target, history, skipReason) {
|
|
106
|
-
const {
|
|
106
|
+
const { unreleasedReading } = history;
|
|
107
107
|
const fields = {
|
|
108
108
|
targetId: target.id,
|
|
109
109
|
status: 'skipped',
|
|
110
|
-
commitCount:
|
|
111
|
-
parsedCommitCount:
|
|
110
|
+
commitCount: unreleasedReading.commits.length,
|
|
111
|
+
parsedCommitCount: unreleasedReading.parsedCommitCount,
|
|
112
112
|
skipReason,
|
|
113
113
|
...(history.previousTag !== undefined && { previousTag: history.previousTag }),
|
|
114
|
-
...(
|
|
114
|
+
...(unreleasedReading.unparseableCommits !== undefined && {
|
|
115
|
+
unparseableCommits: unreleasedReading.unparseableCommits,
|
|
116
|
+
}),
|
|
115
117
|
};
|
|
116
|
-
const
|
|
117
|
-
attachChangelogDiagnostics(
|
|
118
|
-
return
|
|
118
|
+
const skippedResult = labelSkippedResult(target, fields);
|
|
119
|
+
attachChangelogDiagnostics(skippedResult, unreleasedReading.diagnostics);
|
|
120
|
+
return skippedResult;
|
|
119
121
|
}
|
|
120
122
|
export function isRepoRoot(target) {
|
|
121
123
|
return target.directoryPath === '.';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { execFileSync } from 'node:child_process';
|
|
2
2
|
import { basename } from 'node:path';
|
|
3
|
-
import {
|
|
3
|
+
import { GIT_OUTPUT_LIMIT_BYTES } from '@williamthorsen/nmr-core';
|
|
4
4
|
import { describeError } from '@williamthorsen/toolbelt.errors';
|
|
5
5
|
import { DEFAULT_PROJECT_TAG_PREFIX } from "./defaults.js";
|
|
6
6
|
import { deriveDirectoryConfig } from "./deriveDirectoryConfig.js";
|
|
@@ -47,19 +47,19 @@ function buildOverrideMap(config, workspacePaths) {
|
|
|
47
47
|
return map;
|
|
48
48
|
}
|
|
49
49
|
function buildDirectoryRows(config, workspacePaths, overridesByPath) {
|
|
50
|
-
const
|
|
50
|
+
const discoveredPaths = new Set(workspacePaths);
|
|
51
51
|
return Object.entries(config?.releases ?? {}).flatMap(([name, entry]) => {
|
|
52
52
|
if (entry === false || !('path' in entry))
|
|
53
53
|
return [];
|
|
54
54
|
const directoryPath = normalizeWorkspacePath(entry.path);
|
|
55
|
-
if (
|
|
55
|
+
if (discoveredPaths.has(directoryPath))
|
|
56
56
|
return [];
|
|
57
|
-
const
|
|
57
|
+
const declaredDirectory = {
|
|
58
58
|
name,
|
|
59
59
|
path: directoryPath,
|
|
60
60
|
...(entry.tagPrefix !== undefined && { tagPrefix: entry.tagPrefix }),
|
|
61
61
|
};
|
|
62
|
-
return [buildPreviewRow(directoryPath, () => deriveDirectoryConfig(
|
|
62
|
+
return [buildPreviewRow(directoryPath, () => deriveDirectoryConfig(declaredDirectory).tagPrefix, overridesByPath)];
|
|
63
63
|
});
|
|
64
64
|
}
|
|
65
65
|
function buildPreviewRow(workspacePath, derivePrefix, overridesByPath) {
|
|
@@ -91,7 +91,7 @@ function countTagsMatching(prefix) {
|
|
|
91
91
|
try {
|
|
92
92
|
const output = execFileSync('git', ['tag', '--list', `${prefix}*`], {
|
|
93
93
|
encoding: 'utf8',
|
|
94
|
-
maxBuffer:
|
|
94
|
+
maxBuffer: GIT_OUTPUT_LIMIT_BYTES,
|
|
95
95
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
96
96
|
});
|
|
97
97
|
return output.split('\n').filter((line) => matchesTagPrefix(line.trim(), [prefix])).length;
|
|
@@ -105,12 +105,12 @@ function detectCollisions(rows) {
|
|
|
105
105
|
for (const row of rows) {
|
|
106
106
|
if (row.derivedPrefix === null)
|
|
107
107
|
continue;
|
|
108
|
-
const
|
|
109
|
-
if (
|
|
108
|
+
const existingPaths = pathsByPrefix.get(row.derivedPrefix);
|
|
109
|
+
if (existingPaths === undefined) {
|
|
110
110
|
pathsByPrefix.set(row.derivedPrefix, [row.workspacePath]);
|
|
111
111
|
}
|
|
112
112
|
else {
|
|
113
|
-
|
|
113
|
+
existingPaths.push(row.workspacePath);
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
116
|
const collisions = [];
|
|
@@ -122,27 +122,27 @@ function detectCollisions(rows) {
|
|
|
122
122
|
return collisions;
|
|
123
123
|
}
|
|
124
124
|
function collectKnownPrefixes(rows, retiredPackages, compositeTagPrefix) {
|
|
125
|
-
const
|
|
125
|
+
const knownPrefixes = new Set();
|
|
126
126
|
for (const row of rows) {
|
|
127
127
|
if (row.derivedPrefix !== null)
|
|
128
|
-
|
|
128
|
+
knownPrefixes.add(row.derivedPrefix);
|
|
129
129
|
for (const entry of row.legacyEntries) {
|
|
130
|
-
|
|
130
|
+
knownPrefixes.add(entry.prefix);
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
|
-
for (const
|
|
134
|
-
|
|
133
|
+
for (const retiredPackage of retiredPackages) {
|
|
134
|
+
knownPrefixes.add(retiredPackage.tagPrefix);
|
|
135
135
|
}
|
|
136
136
|
if (compositeTagPrefix !== undefined)
|
|
137
|
-
|
|
138
|
-
return [...
|
|
137
|
+
knownPrefixes.add(compositeTagPrefix);
|
|
138
|
+
return [...knownPrefixes];
|
|
139
139
|
}
|
|
140
140
|
function buildRetiredPreviewEntries(retiredPackages) {
|
|
141
|
-
return retiredPackages.map((
|
|
142
|
-
name:
|
|
143
|
-
tagPrefix:
|
|
144
|
-
tagCount: countTagsMatching(
|
|
145
|
-
...(
|
|
141
|
+
return retiredPackages.map((retiredPackage) => ({
|
|
142
|
+
name: retiredPackage.name,
|
|
143
|
+
tagPrefix: retiredPackage.tagPrefix,
|
|
144
|
+
tagCount: countTagsMatching(retiredPackage.tagPrefix),
|
|
145
|
+
...(retiredPackage.successor !== undefined && { successor: retiredPackage.successor }),
|
|
146
146
|
}));
|
|
147
147
|
}
|
|
148
148
|
function findCompositeTagPrefix(config) {
|
|
@@ -5,16 +5,16 @@ export function propagateBumps(directBumps, graph) {
|
|
|
5
5
|
result.set(dir, { ...entry });
|
|
6
6
|
}
|
|
7
7
|
const queue = directBumps.keys().toArray();
|
|
8
|
-
const
|
|
8
|
+
const visitedDirs = new Set();
|
|
9
9
|
while (queue.length > 0) {
|
|
10
10
|
const dir = queue.shift();
|
|
11
11
|
if (dir === undefined) {
|
|
12
12
|
break;
|
|
13
13
|
}
|
|
14
|
-
if (
|
|
14
|
+
if (visitedDirs.has(dir)) {
|
|
15
15
|
continue;
|
|
16
16
|
}
|
|
17
|
-
|
|
17
|
+
visitedDirs.add(dir);
|
|
18
18
|
const packageName = graph.dirToPackageName.get(dir);
|
|
19
19
|
if (packageName === undefined) {
|
|
20
20
|
continue;
|
|
@@ -31,19 +31,19 @@ export function propagateBumps(directBumps, graph) {
|
|
|
31
31
|
}
|
|
32
32
|
for (const dependent of dependents) {
|
|
33
33
|
const dependentDir = dependent.id;
|
|
34
|
-
const
|
|
34
|
+
const existingEntry = result.get(dependentDir);
|
|
35
35
|
const propagationInfo = { packageName, newVersion };
|
|
36
|
-
if (
|
|
36
|
+
if (existingEntry === undefined) {
|
|
37
37
|
result.set(dependentDir, {
|
|
38
38
|
releaseType: 'patch',
|
|
39
39
|
propagatedFrom: [propagationInfo],
|
|
40
40
|
});
|
|
41
41
|
}
|
|
42
42
|
else {
|
|
43
|
-
const
|
|
44
|
-
|
|
43
|
+
const existingSources = existingEntry.propagatedFrom ?? [];
|
|
44
|
+
existingEntry.propagatedFrom = [...existingSources, propagationInfo];
|
|
45
45
|
}
|
|
46
|
-
if (!
|
|
46
|
+
if (!visitedDirs.has(dependentDir)) {
|
|
47
47
|
queue.push(dependentDir);
|
|
48
48
|
}
|
|
49
49
|
}
|
package/dist/esm/publish.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { PackageManager } from './detectPackageManager.js';
|
|
2
2
|
import type { ResolvedTag } from './resolveReleaseTags.js';
|
|
3
3
|
export interface PublishOptions {
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
isDryRun: boolean;
|
|
5
|
+
shouldGenerateProvenance: boolean;
|
|
6
6
|
}
|
|
7
7
|
/** Publishes a single package by running `{pm} publish` from its workspace directory. */
|
|
8
8
|
export declare function publishPackage(resolvedTag: ResolvedTag, packageManager: PackageManager, options: PublishOptions): void;
|
package/dist/esm/publish.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { execFileSync } from 'node:child_process';
|
|
2
2
|
export function publishPackage(resolvedTag, packageManager, options) {
|
|
3
|
-
const {
|
|
3
|
+
const { isDryRun, shouldGenerateProvenance } = options;
|
|
4
4
|
const executable = resolveExecutable(packageManager);
|
|
5
|
-
const args = buildPublishArgs(packageManager, {
|
|
6
|
-
console.info(`\n${
|
|
5
|
+
const args = buildPublishArgs(packageManager, { isDryRun, shouldGenerateProvenance });
|
|
6
|
+
console.info(`\n${isDryRun ? '[dry-run] ' : ''}Running: ${executable} ${args.join(' ')} (cwd: ${resolvedTag.workspacePath})`);
|
|
7
7
|
execFileSync(executable, args, { cwd: resolvedTag.workspacePath, stdio: 'inherit' });
|
|
8
8
|
}
|
|
9
9
|
function resolveExecutable(packageManager) {
|
|
@@ -14,13 +14,13 @@ function resolveExecutable(packageManager) {
|
|
|
14
14
|
}
|
|
15
15
|
function buildPublishArgs(packageManager, options) {
|
|
16
16
|
const args = packageManager === 'yarn-berry' ? ['npm', 'publish'] : ['publish'];
|
|
17
|
-
if (options.
|
|
17
|
+
if (options.isDryRun) {
|
|
18
18
|
args.push('--dry-run');
|
|
19
19
|
}
|
|
20
20
|
if (packageManager === 'pnpm') {
|
|
21
21
|
args.push('--no-git-checks');
|
|
22
22
|
}
|
|
23
|
-
if (options.
|
|
23
|
+
if (options.shouldGenerateProvenance && packageManager !== 'yarn') {
|
|
24
24
|
args.push('--provenance');
|
|
25
25
|
}
|
|
26
26
|
return args;
|
|
@@ -17,17 +17,17 @@ import { resolveCommandTags } from "./resolveCommandTags.js";
|
|
|
17
17
|
import { resolveConfigFlag } from "./resolveConfigFlag.js";
|
|
18
18
|
const publishFlagSchema = {
|
|
19
19
|
...configFlagSchema,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
isDryRun: { long: '--dry-run', type: 'boolean' },
|
|
21
|
+
shouldSkipGitChecks: { long: '--no-git-checks', type: 'boolean' },
|
|
22
|
+
shouldGenerateProvenance: { long: '--provenance', type: 'boolean' },
|
|
23
23
|
tags: { long: '--tags', type: 'string' },
|
|
24
24
|
};
|
|
25
25
|
export async function publishCommand(argv, styles, invocationDir) {
|
|
26
|
-
const
|
|
27
|
-
const configPath = resolveConfigFlag(
|
|
28
|
-
const {
|
|
26
|
+
const parsedArgs = parseArgsOrExit(argv, publishFlagSchema);
|
|
27
|
+
const configPath = resolveConfigFlag(parsedArgs.flags.config, invocationDir);
|
|
28
|
+
const { isDryRun, shouldSkipGitChecks, shouldGenerateProvenance } = parsedArgs.flags;
|
|
29
29
|
const userConfig = await loadUsableConfig(styles.stderr, configPath);
|
|
30
|
-
if (!
|
|
30
|
+
if (!isDryRun && !shouldSkipGitChecks) {
|
|
31
31
|
try {
|
|
32
32
|
assertCleanWorkingTree();
|
|
33
33
|
}
|
|
@@ -36,7 +36,7 @@ export async function publishCommand(argv, styles, invocationDir) {
|
|
|
36
36
|
process.exit(1);
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
-
const requestedTags = parseRequestedTags(
|
|
39
|
+
const requestedTags = parseRequestedTags(parsedArgs.flags.tags);
|
|
40
40
|
const resolvedTags = resolveCommandTags(requestedTags, userConfig);
|
|
41
41
|
if (resolvedTags.length === 0) {
|
|
42
42
|
return;
|
|
@@ -49,11 +49,11 @@ export async function publishCommand(argv, styles, invocationDir) {
|
|
|
49
49
|
const packageManager = detectPackageManager();
|
|
50
50
|
const { releaseNotes, changelogJsonOutputPath, sectionOrder } = deriveReleaseNotesConfig(userConfig);
|
|
51
51
|
const shouldInject = releaseNotes.shouldInjectIntoReadme;
|
|
52
|
-
console.info(
|
|
52
|
+
console.info(isDryRun ? '[dry-run] Would publish:' : 'Publishing:');
|
|
53
53
|
for (const { tag, workspacePath } of publishableTags) {
|
|
54
54
|
console.info(` ${tag} (${workspacePath})`);
|
|
55
55
|
}
|
|
56
|
-
const
|
|
56
|
+
const publishedTags = [];
|
|
57
57
|
try {
|
|
58
58
|
for (const resolvedTag of publishableTags) {
|
|
59
59
|
let readmePath;
|
|
@@ -65,8 +65,8 @@ export async function publishCommand(argv, styles, invocationDir) {
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
try {
|
|
68
|
-
publishPackage(resolvedTag, packageManager, {
|
|
69
|
-
|
|
68
|
+
publishPackage(resolvedTag, packageManager, { isDryRun, shouldGenerateProvenance });
|
|
69
|
+
publishedTags.push(resolvedTag.tag);
|
|
70
70
|
}
|
|
71
71
|
finally {
|
|
72
72
|
if (readmePath !== undefined && originalReadme !== undefined) {
|
|
@@ -76,10 +76,10 @@ export async function publishCommand(argv, styles, invocationDir) {
|
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
catch (error) {
|
|
79
|
-
if (
|
|
79
|
+
if (publishedTags.length > 0) {
|
|
80
80
|
console.warn('Packages published before failure:');
|
|
81
|
-
for (const
|
|
82
|
-
console.warn(` ${
|
|
81
|
+
for (const tag of publishedTags) {
|
|
82
|
+
console.warn(` ${tag}`);
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
reportError(describeError(error));
|
|
@@ -87,17 +87,17 @@ export async function publishCommand(argv, styles, invocationDir) {
|
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
function filterPublishableTags(resolvedTags, isExplicit) {
|
|
90
|
-
const
|
|
91
|
-
const
|
|
90
|
+
const publishableTags = [];
|
|
91
|
+
const unpublishableTags = [];
|
|
92
92
|
for (const tag of resolvedTags) {
|
|
93
|
-
(tag.isPublishable ?
|
|
93
|
+
(tag.isPublishable ? publishableTags : unpublishableTags).push(tag);
|
|
94
94
|
}
|
|
95
95
|
if (isExplicit) {
|
|
96
|
-
for (const resolvedTag of
|
|
96
|
+
for (const resolvedTag of unpublishableTags) {
|
|
97
97
|
console.warn(formatPublishSkip(resolvedTag));
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
|
-
return
|
|
100
|
+
return publishableTags;
|
|
101
101
|
}
|
|
102
102
|
function formatPublishSkip(resolvedTag) {
|
|
103
103
|
switch (resolvedTag.kind) {
|
package/dist/esm/pushCommand.js
CHANGED
|
@@ -8,21 +8,21 @@ import { resolveCommandTags } from "./resolveCommandTags.js";
|
|
|
8
8
|
import { resolveConfigFlag } from "./resolveConfigFlag.js";
|
|
9
9
|
const pushFlagSchema = {
|
|
10
10
|
...configFlagSchema,
|
|
11
|
-
|
|
11
|
+
isDryRun: { long: '--dry-run', type: 'boolean' },
|
|
12
12
|
tags: { long: '--tags', type: 'string' },
|
|
13
13
|
tagsOnly: { long: '--tags-only', type: 'boolean' },
|
|
14
14
|
};
|
|
15
15
|
export async function pushCommand(argv, styles, invocationDir) {
|
|
16
|
-
const
|
|
17
|
-
const configPath = resolveConfigFlag(
|
|
18
|
-
const {
|
|
16
|
+
const parsedArgs = parseArgsOrExit(argv, pushFlagSchema);
|
|
17
|
+
const configPath = resolveConfigFlag(parsedArgs.flags.config, invocationDir);
|
|
18
|
+
const { isDryRun, tagsOnly } = parsedArgs.flags;
|
|
19
19
|
const userConfig = await loadUsableConfig(styles.stderr, configPath);
|
|
20
|
-
const requestedTags = parseRequestedTags(
|
|
20
|
+
const requestedTags = parseRequestedTags(parsedArgs.flags.tags);
|
|
21
21
|
const resolvedTags = resolveCommandTags(requestedTags, userConfig);
|
|
22
22
|
if (resolvedTags.length === 0) {
|
|
23
23
|
return;
|
|
24
24
|
}
|
|
25
|
-
const prefix =
|
|
25
|
+
const prefix = isDryRun ? '[dry-run] Would push' : 'Pushing';
|
|
26
26
|
if (!tagsOnly) {
|
|
27
27
|
console.info(`${prefix} branch and ${resolvedTags.length} tag(s):`);
|
|
28
28
|
}
|
|
@@ -33,8 +33,8 @@ export async function pushCommand(argv, styles, invocationDir) {
|
|
|
33
33
|
console.info(` ${tag}`);
|
|
34
34
|
}
|
|
35
35
|
try {
|
|
36
|
-
const steps = pushRelease(resolvedTags, {
|
|
37
|
-
if (
|
|
36
|
+
const steps = pushRelease(resolvedTags, { isDryRun, tagsOnly });
|
|
37
|
+
if (isDryRun) {
|
|
38
38
|
for (const step of steps) {
|
|
39
39
|
console.info(`[dry-run] ${step.command.join(' ')}`);
|
|
40
40
|
}
|
package/dist/esm/pushRelease.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { execFileSync } from 'node:child_process';
|
|
2
|
-
import {
|
|
2
|
+
import { GIT_OUTPUT_LIMIT_BYTES } from '@williamthorsen/nmr-core';
|
|
3
3
|
export function pushRelease(resolvedTags, options = {}) {
|
|
4
|
-
const {
|
|
4
|
+
const { isDryRun = false, tagsOnly = false } = options;
|
|
5
5
|
const steps = [];
|
|
6
6
|
if (!tagsOnly) {
|
|
7
7
|
const branch = execFileSync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], {
|
|
8
8
|
encoding: 'utf8',
|
|
9
|
-
maxBuffer:
|
|
9
|
+
maxBuffer: GIT_OUTPUT_LIMIT_BYTES,
|
|
10
10
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
11
11
|
}).trim();
|
|
12
12
|
const command = ['git', 'push', 'origin', branch];
|
|
@@ -16,7 +16,7 @@ export function pushRelease(resolvedTags, options = {}) {
|
|
|
16
16
|
const command = ['git', 'push', '--no-follow-tags', 'origin', tag];
|
|
17
17
|
steps.push({ type: 'tag', ref: tag, command });
|
|
18
18
|
}
|
|
19
|
-
if (!
|
|
19
|
+
if (!isDryRun) {
|
|
20
20
|
for (const step of steps) {
|
|
21
21
|
execFileSync(step.command[0], step.command.slice(1), { stdio: 'inherit' });
|
|
22
22
|
}
|
|
@@ -7,7 +7,7 @@ export interface VersionedMarkdownSection {
|
|
|
7
7
|
}
|
|
8
8
|
/** The `##` sections of a `CHANGELOG.md`, split by whether their heading names a version. */
|
|
9
9
|
export interface ChangelogMarkdownSections {
|
|
10
|
-
|
|
10
|
+
versionedSections: VersionedMarkdownSection[];
|
|
11
11
|
/** Headings of the `##` sections that do not name a version, as written. */
|
|
12
12
|
unversionedHeadings: string[];
|
|
13
13
|
}
|
|
@@ -9,14 +9,14 @@ export function planPreservedSections(changelogDir, entries) {
|
|
|
9
9
|
const sections = [];
|
|
10
10
|
const unversionedHeadings = [];
|
|
11
11
|
for (const file of files) {
|
|
12
|
-
const
|
|
13
|
-
for (const section of
|
|
12
|
+
const fileSections = readChangelogSections(file);
|
|
13
|
+
for (const section of fileSections.versionedSections) {
|
|
14
14
|
if (seenVersions.has(section.version))
|
|
15
15
|
continue;
|
|
16
16
|
seenVersions.add(section.version);
|
|
17
17
|
sections.push(section);
|
|
18
18
|
}
|
|
19
|
-
unversionedHeadings.push(...
|
|
19
|
+
unversionedHeadings.push(...fileSections.unversionedHeadings);
|
|
20
20
|
}
|
|
21
21
|
if (sections.length === 0 && unversionedHeadings.length === 0) {
|
|
22
22
|
return { sections, preservation: undefined };
|
|
@@ -32,29 +32,29 @@ export function planPreservedSections(changelogDir, entries) {
|
|
|
32
32
|
}
|
|
33
33
|
export function readChangelogSections(filePath) {
|
|
34
34
|
if (!existsSync(filePath)) {
|
|
35
|
-
return {
|
|
35
|
+
return { versionedSections: [], unversionedHeadings: [] };
|
|
36
36
|
}
|
|
37
37
|
return parseChangelogSections(readFileSync(filePath, 'utf8'));
|
|
38
38
|
}
|
|
39
39
|
export function parseChangelogSections(content) {
|
|
40
40
|
const sections = [];
|
|
41
|
-
let
|
|
41
|
+
let currentSection;
|
|
42
42
|
let fence;
|
|
43
43
|
for (const line of content.split(/\r?\n/)) {
|
|
44
44
|
if (fence === undefined) {
|
|
45
45
|
if (FOOTER_PATTERN.test(line)) {
|
|
46
|
-
|
|
46
|
+
currentSection = undefined;
|
|
47
47
|
continue;
|
|
48
48
|
}
|
|
49
49
|
if (SECTION_HEADING_PATTERN.test(line)) {
|
|
50
|
-
|
|
51
|
-
sections.push(
|
|
50
|
+
currentSection = { heading: line.trimEnd(), lines: [] };
|
|
51
|
+
sections.push(currentSection);
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
fence = updateFence(fence, line);
|
|
55
|
-
|
|
55
|
+
currentSection?.lines.push(line);
|
|
56
56
|
}
|
|
57
|
-
const
|
|
57
|
+
const versionedSections = [];
|
|
58
58
|
const unversionedHeadings = [];
|
|
59
59
|
for (const { heading, lines } of sections) {
|
|
60
60
|
const version = extractHeadingVersion(heading);
|
|
@@ -62,10 +62,10 @@ export function parseChangelogSections(content) {
|
|
|
62
62
|
unversionedHeadings.push(heading);
|
|
63
63
|
}
|
|
64
64
|
else {
|
|
65
|
-
|
|
65
|
+
versionedSections.push({ version, text: trimTrailingBlankLines(lines).join('\n') });
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
|
-
return {
|
|
68
|
+
return { versionedSections, unversionedHeadings };
|
|
69
69
|
}
|
|
70
70
|
const FOOTER_PATTERN = /^<!-- Generated by release-kit\b/;
|
|
71
71
|
const SECTION_HEADING_PATTERN = /^## /;
|
|
@@ -78,11 +78,11 @@ function extractHeadingVersion(heading) {
|
|
|
78
78
|
return semver.valid(token) ?? undefined;
|
|
79
79
|
}
|
|
80
80
|
function trimTrailingBlankLines(lines) {
|
|
81
|
-
let
|
|
82
|
-
while (
|
|
83
|
-
|
|
81
|
+
let endIndex = lines.length;
|
|
82
|
+
while (endIndex > 0 && lines[endIndex - 1]?.trim() === '') {
|
|
83
|
+
endIndex--;
|
|
84
84
|
}
|
|
85
|
-
return lines.slice(0,
|
|
85
|
+
return lines.slice(0, endIndex);
|
|
86
86
|
}
|
|
87
87
|
function updateFence(fence, line) {
|
|
88
88
|
const marker = FENCE_PATTERN.exec(line)?.[1];
|