@williamthorsen/release-kit 12.0.0 → 13.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 +212 -0
- package/.readyup/kits/default.js +18 -17
- package/.readyup/kits/npm-auto-publish.js +24 -23
- package/.readyup/manifest.json +16 -11
- package/CHANGELOG.md +58 -0
- package/README.md +55 -48
- package/bin/release-kit.js +1 -1
- package/dist/esm/assertCleanWorkingTree.d.ts +1 -5
- package/dist/esm/assertTaggedBaseline.d.ts +29 -0
- package/dist/esm/assertTaggedBaseline.js +41 -0
- package/dist/esm/attachChangelogDiagnostics.d.ts +1 -1
- package/dist/esm/attachChangelogDiagnostics.js +3 -0
- package/dist/esm/bin/release-kit.js +85 -22
- package/dist/esm/buildChangelogEntries.d.ts +23 -13
- package/dist/esm/buildChangelogEntries.js +36 -17
- package/dist/esm/buildDependencyGraph.d.ts +6 -6
- package/dist/esm/buildEmptyReleaseEntry.d.ts +1 -8
- package/dist/esm/buildReleaseSummary.d.ts +2 -8
- package/dist/esm/buildSyntheticChangelogEntry.d.ts +3 -5
- package/dist/esm/buildSyntheticChangelogEntry.js +2 -2
- package/dist/esm/bumpVersion.d.ts +1 -8
- package/dist/esm/changelogJsonFile.d.ts +5 -7
- package/dist/esm/changelogJsonFile.js +2 -17
- package/dist/esm/changelogJsonUtils.d.ts +7 -10
- package/dist/esm/changelogOverrides.d.ts +59 -98
- package/dist/esm/classifyChangelogCommit.d.ts +7 -9
- package/dist/esm/classifyChangelogCommit.js +3 -2
- package/dist/esm/commitCommand.d.ts +2 -4
- package/dist/esm/compareVersions.d.ts +10 -4
- package/dist/esm/compareVersions.js +16 -0
- package/dist/esm/configFlagSchema.d.ts +1 -1
- package/dist/esm/createGithubRelease.d.ts +7 -19
- package/dist/esm/createGithubReleaseCommand.d.ts +5 -5
- package/dist/esm/createGithubReleaseCommand.js +9 -9
- package/dist/esm/createTags.d.ts +2 -3
- package/dist/esm/decideRelease.d.ts +2 -6
- package/dist/esm/defaults.d.ts +5 -24
- package/dist/esm/defaults.js +4 -5
- package/dist/esm/defineConfig.d.ts +1 -1
- package/dist/esm/deleteFileIfExists.d.ts +1 -1
- package/dist/esm/deriveReleaseNotesConfig.d.ts +20 -0
- package/dist/esm/deriveReleaseNotesConfig.js +21 -0
- package/dist/esm/deriveWorkspaceConfig.d.ts +3 -5
- package/dist/esm/detectPackageManager.d.ts +2 -4
- package/dist/esm/detectUndeclaredTagPrefixes.d.ts +4 -6
- package/dist/esm/detectUndeclaredTagPrefixes.js +1 -1
- package/dist/esm/determineBumpType.d.ts +1 -1
- package/dist/esm/discoverWorkspaces.d.ts +14 -15
- package/dist/esm/discoverWorkspaces.js +12 -12
- package/dist/esm/enterRepoRoot.d.ts +12 -0
- package/dist/esm/enterRepoRoot.js +16 -0
- package/dist/esm/enumerateReleaseWindows.d.ts +8 -8
- package/dist/esm/extractMigration.d.ts +6 -8
- package/dist/esm/findUnroutedEntryScopes.d.ts +16 -0
- package/dist/esm/findUnroutedEntryScopes.js +57 -0
- package/dist/esm/formatExcludedSkip.d.ts +3 -0
- package/dist/esm/formatExcludedSkip.js +3 -0
- package/dist/esm/formatPrivateSkip.d.ts +1 -6
- package/dist/esm/generateChangelogs.d.ts +10 -5
- package/dist/esm/glyphs.d.ts +1 -1
- package/dist/esm/help/prepareHelp.d.ts +3 -4
- package/dist/esm/help/prepareHelp.js +4 -3
- package/dist/esm/init/checks.d.ts +3 -3
- package/dist/esm/init/checks.js +4 -1
- package/dist/esm/init/detectRepoType.d.ts +2 -3
- package/dist/esm/init/hasProvenance.d.ts +2 -0
- package/dist/esm/init/hasProvenance.js +3 -0
- package/dist/esm/init/initCommand.d.ts +3 -6
- package/dist/esm/init/initCommand.js +10 -10
- package/dist/esm/init/parseJsonRecord.d.ts +1 -4
- package/dist/esm/init/scaffold.d.ts +1 -1
- package/dist/esm/init/templates.d.ts +9 -11
- package/dist/esm/init/templates.js +12 -11
- package/dist/esm/init/updateTemplatesCommand.d.ts +13 -0
- package/dist/esm/init/updateTemplatesCommand.js +64 -0
- package/dist/esm/injectReleaseNotesIntoReadme.d.ts +12 -17
- package/dist/esm/injectSection.d.ts +3 -3
- package/dist/esm/loadConfig.d.ts +16 -14
- package/dist/esm/loadConfig.js +2 -2
- package/dist/esm/loadValidatedConfig.d.ts +16 -19
- package/dist/esm/loadValidatedConfig.js +6 -1
- package/dist/esm/packsPath.d.ts +9 -9
- package/dist/esm/parseChangeRecordBlock.d.ts +2 -2
- package/dist/esm/parseCommitMessage.d.ts +17 -32
- package/dist/esm/parseCommitMessage.js +28 -37
- package/dist/esm/parseRequestedTags.d.ts +3 -3
- package/dist/esm/planReleaseNotesPreviews.d.ts +6 -6
- package/dist/esm/planVersionBump.d.ts +5 -3
- package/dist/esm/planVersionBump.js +3 -0
- package/dist/esm/prepareCommand.d.ts +4 -7
- package/dist/esm/prepareCommand.js +13 -6
- package/dist/esm/previewTagPrefixes.d.ts +8 -10
- package/dist/esm/propagateBumps.d.ts +6 -7
- package/dist/esm/publish.d.ts +1 -1
- package/dist/esm/publishCommand.d.ts +4 -3
- package/dist/esm/publishCommand.js +8 -8
- package/dist/esm/pushCommand.d.ts +4 -3
- package/dist/esm/pushCommand.js +8 -2
- package/dist/esm/pushRelease.d.ts +2 -2
- package/dist/esm/readChangelogSections.d.ts +33 -0
- package/dist/esm/readChangelogSections.js +80 -0
- package/dist/esm/releaseFiles.d.ts +5 -7
- package/dist/esm/releasePlan.d.ts +11 -13
- package/dist/esm/releasePrepare.d.ts +23 -22
- package/dist/esm/releasePrepare.js +31 -11
- package/dist/esm/releasePrepareMono.d.ts +9 -7
- package/dist/esm/releasePrepareMono.js +85 -33
- package/dist/esm/releasePrepareProject.d.ts +19 -29
- package/dist/esm/releasePrepareProject.js +31 -12
- package/dist/esm/renderChangelogMarkdown.d.ts +10 -4
- package/dist/esm/renderChangelogMarkdown.js +27 -2
- package/dist/esm/renderReleaseNotes.d.ts +3 -11
- package/dist/esm/renderReleaseNotes.js +2 -6
- package/dist/esm/reportPrepare.d.ts +4 -5
- package/dist/esm/reportPrepare.js +33 -19
- package/dist/esm/resolveCommandTags.d.ts +15 -11
- package/dist/esm/resolveCommandTags.js +35 -5
- package/dist/esm/resolveConfigFlag.d.ts +7 -0
- package/dist/esm/resolveConfigFlag.js +4 -0
- package/dist/esm/resolveReleaseTags.d.ts +6 -8
- package/dist/esm/resolveReleaseTags.js +1 -1
- package/dist/esm/resolveStylesOrExit.d.ts +2 -2
- package/dist/esm/showTagPrefixesCommand.d.ts +7 -10
- package/dist/esm/showTagPrefixesCommand.js +4 -4
- package/dist/esm/stripEmojiPrefix.d.ts +1 -0
- package/dist/esm/stripScope.d.ts +2 -2
- package/dist/esm/stripScope.js +3 -3
- package/dist/esm/sync-labels/generateCommand.d.ts +11 -10
- package/dist/esm/sync-labels/generateCommand.js +11 -8
- package/dist/esm/sync-labels/initCommand.d.ts +6 -7
- package/dist/esm/sync-labels/initCommand.js +2 -2
- package/dist/esm/sync-labels/presets.d.ts +5 -4
- package/dist/esm/sync-labels/presets.js +9 -9
- package/dist/esm/sync-labels/resolveLabels.d.ts +7 -7
- package/dist/esm/sync-labels/resolveLabels.js +1 -1
- package/dist/esm/sync-labels/retiredConfig.d.ts +4 -5
- package/dist/esm/sync-labels/syncCommand.d.ts +1 -4
- package/dist/esm/sync-labels/templates.d.ts +3 -3
- package/dist/esm/sync-labels/templates.js +3 -3
- package/dist/esm/sync-labels/typeLabels.d.ts +14 -0
- package/dist/esm/sync-labels/typeLabels.js +38 -0
- package/dist/esm/sync-labels/types.d.ts +1 -1
- package/dist/esm/tagCommand.d.ts +1 -1
- package/dist/esm/typeGuards.d.ts +2 -2
- package/dist/esm/types.d.ts +116 -91
- package/dist/esm/types.js +1 -1
- package/dist/esm/validateConfig.d.ts +2 -11
- package/dist/esm/validateConfig.js +2 -2
- package/dist/esm/validateOnlyExcludesStrandedDependents.d.ts +14 -12
- package/dist/esm/validateOverridesCommand.d.ts +17 -20
- package/dist/esm/validateOverridesCommand.js +1 -1
- package/docs/api.md +6 -6
- package/docs/changelogs.md +63 -40
- package/docs/configuration.md +29 -27
- package/docs/editorial-overrides.md +23 -23
- package/docs/labels.md +21 -19
- package/docs/project-releases.md +13 -13
- package/docs/publishing.md +5 -5
- package/docs/readiness-checks.md +3 -3
- package/docs/releasing.md +50 -25
- package/docs/work-types.md +41 -57
- package/package.json +7 -6
- package/presets/labels/common.yaml +1 -41
- package/dist/esm/resolveReleaseNotesConfig.d.ts +0 -26
- package/dist/esm/resolveReleaseNotesConfig.js +0 -29
- package/dist/esm/workTypesData.d.ts +0 -50
- package/dist/esm/workTypesData.js +0 -145
- package/schemas/label-map.json +0 -24
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import { join as joinPath } from 'node:path';
|
|
2
|
+
import { assertTaggedBaseline, findUntaggedBaseline } from "./assertTaggedBaseline.js";
|
|
2
3
|
import { attachChangelogDiagnostics } from "./attachChangelogDiagnostics.js";
|
|
3
|
-
import { readReleaseHistory,
|
|
4
|
-
import { buildEmptyReleaseEntry } from "./buildEmptyReleaseEntry.js";
|
|
4
|
+
import { readReleaseHistory, toReleaseEntries } from "./buildChangelogEntries.js";
|
|
5
5
|
import { buildReleaseSummary } from "./buildReleaseSummary.js";
|
|
6
6
|
import { mergeChangelogEntriesWithDisk, renderChangelogJson, resolveChangelogJsonPath } from "./changelogJsonFile.js";
|
|
7
7
|
import { applyChangelogOverrides, formatStaleOverrideKeyWarning, loadOverridesForScopes, } from "./changelogOverrides.js";
|
|
8
8
|
import { decideRelease } from "./decideRelease.js";
|
|
9
|
+
import { deriveSectionOrder } from "./deriveReleaseNotesConfig.js";
|
|
9
10
|
import { hasPrettierConfig } from "./hasPrettierConfig.js";
|
|
10
11
|
import { resolveWorkTypes } from "./loadConfig.js";
|
|
11
12
|
import { planReleaseNotesPreviews } from "./planReleaseNotesPreviews.js";
|
|
12
13
|
import { planVersionBump, planVersionSet } from "./planVersionBump.js";
|
|
14
|
+
import { planPreservedSections } from "./readChangelogSections.js";
|
|
13
15
|
import { renderChangelogMarkdown } from "./renderChangelogMarkdown.js";
|
|
14
|
-
import { deriveSectionOrder } from "./resolveReleaseNotesConfig.js";
|
|
15
16
|
export function releasePrepare(config, options) {
|
|
16
17
|
const { bumpOverride, force, setVersion, withReleaseNotes } = options;
|
|
17
18
|
const writes = [];
|
|
@@ -21,6 +22,15 @@ export function releasePrepare(config, options) {
|
|
|
21
22
|
}
|
|
22
23
|
const overrides = overridesResult.project;
|
|
23
24
|
const history = readReleaseHistory(config, { tagPrefixes: [config.tagPrefix] });
|
|
25
|
+
assertTaggedBaseline([
|
|
26
|
+
findUntaggedBaseline({
|
|
27
|
+
label: 'package',
|
|
28
|
+
packageFiles: config.packageFiles,
|
|
29
|
+
changelogPaths: config.changelogPaths,
|
|
30
|
+
tagPrefixes: [config.tagPrefix],
|
|
31
|
+
previousTag: history.previousTag,
|
|
32
|
+
}, config),
|
|
33
|
+
]);
|
|
24
34
|
const { commits } = history.unreleased;
|
|
25
35
|
const tag = history.previousTag;
|
|
26
36
|
const since = tag === undefined ? '(no previous release found)' : `since ${tag}`;
|
|
@@ -60,11 +70,10 @@ export function releasePrepare(config, options) {
|
|
|
60
70
|
config,
|
|
61
71
|
history,
|
|
62
72
|
newTag,
|
|
63
|
-
newVersion: bump.newVersion,
|
|
64
73
|
overrides,
|
|
65
74
|
overrideWarnings: planWarnings,
|
|
66
75
|
});
|
|
67
|
-
const { changelogFiles, changelogJsonFiles } = changelogs;
|
|
76
|
+
const { changelogFiles, changelogJsonFiles, changelogPreservation } = changelogs;
|
|
68
77
|
const previewWrites = planSinglePackagePreviews(withReleaseNotes === true, config, newTag, changelogs.entries, planWarnings);
|
|
69
78
|
writes.push(...changelogs.writes, ...previewWrites);
|
|
70
79
|
const formatCommandStr = config.formatCommand ?? (hasPrettierConfig() ? 'npx prettier --write' : undefined);
|
|
@@ -82,6 +91,7 @@ export function releasePrepare(config, options) {
|
|
|
82
91
|
bump,
|
|
83
92
|
newTag,
|
|
84
93
|
changelogFiles,
|
|
94
|
+
changelogPreservation,
|
|
85
95
|
releaseType,
|
|
86
96
|
bumpOverride: setVersion === undefined ? bumpOverride : undefined,
|
|
87
97
|
setVersion,
|
|
@@ -149,13 +159,15 @@ function buildReleasedSinglePackage(args) {
|
|
|
149
159
|
if (args.previewFiles.length > 0) {
|
|
150
160
|
released.previewFiles = args.previewFiles;
|
|
151
161
|
}
|
|
162
|
+
if (args.changelogPreservation.length > 0) {
|
|
163
|
+
released.changelogPreservation = args.changelogPreservation;
|
|
164
|
+
}
|
|
152
165
|
return released;
|
|
153
166
|
}
|
|
154
167
|
function planSinglePackageChangelogs(args) {
|
|
155
|
-
const { config, history, newTag,
|
|
156
|
-
const isEmptyRange = history.unreleased.commits.length === 0;
|
|
168
|
+
const { config, history, newTag, overrides, overrideWarnings } = args;
|
|
157
169
|
const today = new Date().toISOString().slice(0, 10);
|
|
158
|
-
const builtEntries =
|
|
170
|
+
const builtEntries = toReleaseEntries(history, newTag, today);
|
|
159
171
|
const applied = applyChangelogOverrides(builtEntries, overrides);
|
|
160
172
|
if (applied.errors.length > 0) {
|
|
161
173
|
throw new Error(`Changelog override application failed:\n - ${applied.errors.join('\n - ')}`);
|
|
@@ -170,6 +182,7 @@ function planSinglePackageChangelogs(args) {
|
|
|
170
182
|
const sectionOrder = deriveSectionOrder(resolveWorkTypes(config.workTypes));
|
|
171
183
|
const changelogFiles = [];
|
|
172
184
|
const changelogJsonFiles = [];
|
|
185
|
+
const changelogPreservation = [];
|
|
173
186
|
const writes = [];
|
|
174
187
|
let firstMergedEntries = [];
|
|
175
188
|
for (const changelogPath of config.changelogPaths) {
|
|
@@ -183,10 +196,17 @@ function planSinglePackageChangelogs(args) {
|
|
|
183
196
|
changelogJsonFiles.push(jsonPath);
|
|
184
197
|
}
|
|
185
198
|
const changelogFile = joinPath(changelogPath, 'CHANGELOG.md');
|
|
186
|
-
|
|
199
|
+
const preserved = planPreservedSections(changelogFile, mergedEntries);
|
|
200
|
+
writes.push({
|
|
201
|
+
path: changelogFile,
|
|
202
|
+
content: renderChangelogMarkdown(mergedEntries, { sectionOrder, preservedSections: preserved.sections }),
|
|
203
|
+
});
|
|
187
204
|
changelogFiles.push(changelogFile);
|
|
205
|
+
if (preserved.preservation !== undefined) {
|
|
206
|
+
changelogPreservation.push(preserved.preservation);
|
|
207
|
+
}
|
|
188
208
|
}
|
|
189
|
-
return { changelogFiles, changelogJsonFiles, entries: firstMergedEntries, writes };
|
|
209
|
+
return { changelogFiles, changelogJsonFiles, changelogPreservation, entries: firstMergedEntries, writes };
|
|
190
210
|
}
|
|
191
211
|
function planSinglePackagePreviews(withReleaseNotes, config, newTag, entries, warnings) {
|
|
192
212
|
if (!withReleaseNotes) {
|
|
@@ -200,7 +220,7 @@ function planSinglePackagePreviews(withReleaseNotes, config, newTag, entries, wa
|
|
|
200
220
|
return [];
|
|
201
221
|
}
|
|
202
222
|
const previews = planReleaseNotesPreviews({
|
|
203
|
-
workspacePath:
|
|
223
|
+
workspacePath: '.',
|
|
204
224
|
tag: newTag,
|
|
205
225
|
entries,
|
|
206
226
|
sectionOrder: deriveSectionOrder(resolveWorkTypes(config.workTypes)),
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import type { ReleasePlan } from './releasePlan.js';
|
|
2
2
|
import type { ReleasePrepareOptions } from './releasePrepare.js';
|
|
3
|
-
import type {
|
|
3
|
+
import type { MonorepoPrepareConfig } from './types.js';
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* Orchestrates release preparation for a monorepo with multiple workspaces.
|
|
6
6
|
*
|
|
7
|
-
* Phase 1:
|
|
8
|
-
* Phase 2:
|
|
9
|
-
* Phase 2b:
|
|
10
|
-
* Phase 3:
|
|
7
|
+
* Phase 1: Determines direct bumps from commits for each workspace.
|
|
8
|
+
* Phase 2: Builds the dependency graph and propagates bumps to dependents.
|
|
9
|
+
* Phase 2b: Sorts the full release set topologically.
|
|
10
|
+
* Phase 3: Plans bumps and changelogs in dependency order.
|
|
11
|
+
* Phase 3b: Plans the project release.
|
|
12
|
+
* Phase 4: Renders the format command.
|
|
11
13
|
*/
|
|
12
|
-
export declare function releasePrepareMono(config:
|
|
14
|
+
export declare function releasePrepareMono(config: MonorepoPrepareConfig, options: ReleasePrepareOptions): ReleasePlan;
|
|
@@ -1,24 +1,26 @@
|
|
|
1
1
|
import { join as joinPath } from 'node:path';
|
|
2
2
|
import { chainError } from '@williamthorsen/toolbelt.errors/candidate';
|
|
3
|
+
import { assertTaggedBaseline, findUntaggedBaseline } from "./assertTaggedBaseline.js";
|
|
3
4
|
import { attachChangelogDiagnostics } from "./attachChangelogDiagnostics.js";
|
|
4
|
-
import { readReleaseHistory,
|
|
5
|
+
import { readReleaseHistory, toReleaseEntries } from "./buildChangelogEntries.js";
|
|
5
6
|
import { buildDependencyGraph } from "./buildDependencyGraph.js";
|
|
6
|
-
import { buildEmptyReleaseEntry } from "./buildEmptyReleaseEntry.js";
|
|
7
7
|
import { buildReleaseSummary } from "./buildReleaseSummary.js";
|
|
8
8
|
import { buildSyntheticChangelogEntry } from "./buildSyntheticChangelogEntry.js";
|
|
9
9
|
import { mergeChangelogEntriesWithDisk, renderChangelogJson, resolveChangelogJsonPath } from "./changelogJsonFile.js";
|
|
10
10
|
import { applyWorkspaceOverrides, createOverrideContext, formatStaleOverrideKeyWarning, } from "./changelogOverrides.js";
|
|
11
11
|
import { decideRelease } from "./decideRelease.js";
|
|
12
|
+
import { deriveDependenciesHeader, deriveSectionOrder } from "./deriveReleaseNotesConfig.js";
|
|
12
13
|
import { detectUndeclaredTagPrefixes } from "./detectUndeclaredTagPrefixes.js";
|
|
14
|
+
import { findUnroutedEntryScopes } from "./findUnroutedEntryScopes.js";
|
|
13
15
|
import { getAllTagPrefixes } from "./generateChangelogs.js";
|
|
14
16
|
import { hasPrettierConfig } from "./hasPrettierConfig.js";
|
|
15
17
|
import { resolveWorkTypes } from "./loadConfig.js";
|
|
16
18
|
import { planReleaseNotesPreviews } from "./planReleaseNotesPreviews.js";
|
|
17
19
|
import { planVersionBump, planVersionSet } from "./planVersionBump.js";
|
|
18
20
|
import { propagateBumps } from "./propagateBumps.js";
|
|
21
|
+
import { planPreservedSections } from "./readChangelogSections.js";
|
|
19
22
|
import { releasePrepareProject } from "./releasePrepareProject.js";
|
|
20
23
|
import { renderChangelogMarkdown } from "./renderChangelogMarkdown.js";
|
|
21
|
-
import { deriveSectionOrder } from "./resolveReleaseNotesConfig.js";
|
|
22
24
|
export function releasePrepareMono(config, options) {
|
|
23
25
|
const { only, withReleaseNotes } = options;
|
|
24
26
|
const writes = [];
|
|
@@ -26,18 +28,18 @@ export function releasePrepareMono(config, options) {
|
|
|
26
28
|
if (withReleaseNotes === true && !config.changelogJson.enabled) {
|
|
27
29
|
warnings.push('--with-release-notes requires changelogJson.enabled; skipping preview generation');
|
|
28
30
|
}
|
|
29
|
-
const
|
|
31
|
+
const workTypes = resolveWorkTypes(config.workTypes);
|
|
32
|
+
const sectionOrder = deriveSectionOrder(workTypes);
|
|
33
|
+
const dependenciesHeader = deriveDependenciesHeader(workTypes);
|
|
30
34
|
const overrideContext = createOverrideContext(config.workspaces);
|
|
31
|
-
const { directBumps, directResults, skippedResults } = determineDirectBumps(config, options);
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
previousTags.set(result.workspace.dir, result.history.previousTag);
|
|
35
|
-
}
|
|
36
|
-
for (const skipped of skippedResults) {
|
|
37
|
-
previousTags.set(skipped.workspace.dir, skipped.history.previousTag);
|
|
38
|
-
}
|
|
35
|
+
const { directBumps, directResults, skippedResults, untaggedBaselines } = determineDirectBumps(config, options);
|
|
36
|
+
reportUnroutedEntryScopes([...directResults.values(), ...skippedResults], config, options);
|
|
37
|
+
const skippedHistories = new Map(skippedResults.map((skipped) => [skipped.workspace.dir, skipped.history]));
|
|
39
38
|
const graph = buildDependencyGraph(config.workspaces);
|
|
40
39
|
const fullReleaseSet = propagateBumps(directBumps, graph);
|
|
40
|
+
assertTaggedBaseline([...untaggedBaselines]
|
|
41
|
+
.filter(([dir]) => directBumps.has(dir) || !fullReleaseSet.has(dir))
|
|
42
|
+
.map(([, untagged]) => untagged));
|
|
41
43
|
const { sorted: sortedDirs, cyclicDirs } = topologicalSort(fullReleaseSet, graph);
|
|
42
44
|
if (cyclicDirs.length > 0) {
|
|
43
45
|
warnings.push(`Circular workspace dependencies detected among: ${cyclicDirs.join(', ')}. ` +
|
|
@@ -53,13 +55,14 @@ export function releasePrepareMono(config, options) {
|
|
|
53
55
|
fullReleaseSet,
|
|
54
56
|
config,
|
|
55
57
|
directResults,
|
|
56
|
-
|
|
58
|
+
skippedHistories,
|
|
57
59
|
writes,
|
|
58
60
|
warnings,
|
|
59
61
|
workspaces,
|
|
60
62
|
previewOptions,
|
|
61
63
|
overrideContext,
|
|
62
64
|
sectionOrder,
|
|
65
|
+
dependenciesHeader,
|
|
63
66
|
});
|
|
64
67
|
const configOrder = new Map(config.workspaces.map((w, i) => [w.dir, i]));
|
|
65
68
|
workspaces.sort((a, b) => {
|
|
@@ -112,12 +115,24 @@ function determineDirectBumps(config, options) {
|
|
|
112
115
|
const directBumps = new Map();
|
|
113
116
|
const directResults = new Map();
|
|
114
117
|
const skippedResults = [];
|
|
118
|
+
const untaggedBaselines = new Map();
|
|
115
119
|
const hintState = { emitted: false };
|
|
116
120
|
const knownPrefixes = config.workspaces.flatMap(getAllTagPrefixes);
|
|
117
121
|
for (const workspace of config.workspaces) {
|
|
118
122
|
const name = workspace.dir;
|
|
119
123
|
const stageLabel = workspaceStageLabel(workspace.dir);
|
|
120
|
-
const
|
|
124
|
+
const tagPrefixes = getAllTagPrefixes(workspace);
|
|
125
|
+
const history = tryStage(stageLabel, () => readReleaseHistory(config, { tagPrefixes, paths: workspace.paths, workspaceDir: workspace.dir }));
|
|
126
|
+
const untagged = tryStage(stageLabel, () => findUntaggedBaseline({
|
|
127
|
+
label: `workspace '${workspace.dir}'`,
|
|
128
|
+
packageFiles: workspace.packageFiles,
|
|
129
|
+
changelogPaths: workspace.changelogPaths,
|
|
130
|
+
tagPrefixes,
|
|
131
|
+
previousTag: history.previousTag,
|
|
132
|
+
}, config));
|
|
133
|
+
if (untagged !== undefined) {
|
|
134
|
+
untaggedBaselines.set(workspace.dir, untagged);
|
|
135
|
+
}
|
|
121
136
|
const tag = history.previousTag;
|
|
122
137
|
const since = tag === undefined ? '(no previous release found)' : `since ${tag}`;
|
|
123
138
|
if (tag === undefined) {
|
|
@@ -156,7 +171,13 @@ function determineDirectBumps(config, options) {
|
|
|
156
171
|
bumpOverride,
|
|
157
172
|
});
|
|
158
173
|
}
|
|
159
|
-
return { directBumps, directResults, skippedResults };
|
|
174
|
+
return { directBumps, directResults, skippedResults, untaggedBaselines };
|
|
175
|
+
}
|
|
176
|
+
function reportUnroutedEntryScopes(results, config, options) {
|
|
177
|
+
const findings = findUnroutedEntryScopes(results.map(({ workspace, history }) => ({ dir: workspace.dir, commits: history.unreleased.commits })), options.configuredWorkspaceDirs ?? config.workspaces.map((workspace) => workspace.dir), config.scopeAliases ?? {});
|
|
178
|
+
for (const { workspace, history } of results) {
|
|
179
|
+
history.unreleased.diagnostics.unroutedEntryScopes = findings.get(workspace.dir) ?? [];
|
|
180
|
+
}
|
|
160
181
|
}
|
|
161
182
|
function collectSkippedWorkspaces(skippedResults, fullReleaseSet) {
|
|
162
183
|
const workspaces = [];
|
|
@@ -184,7 +205,7 @@ function collectSkippedWorkspaces(skippedResults, fullReleaseSet) {
|
|
|
184
205
|
return workspaces;
|
|
185
206
|
}
|
|
186
207
|
function executeReleaseSet(args) {
|
|
187
|
-
const { sortedDirs, fullReleaseSet, config, directResults,
|
|
208
|
+
const { sortedDirs, fullReleaseSet, config, directResults, skippedHistories, writes, warnings, workspaces, previewOptions, overrideContext, sectionOrder, dependenciesHeader, } = args;
|
|
188
209
|
const tags = [];
|
|
189
210
|
const modifiedFiles = [];
|
|
190
211
|
const today = new Date().toISOString().slice(0, 10);
|
|
@@ -202,7 +223,7 @@ function executeReleaseSet(args) {
|
|
|
202
223
|
workspace,
|
|
203
224
|
releaseEntry,
|
|
204
225
|
directResult: directResults.get(dir),
|
|
205
|
-
|
|
226
|
+
skippedHistory: skippedHistories.get(dir),
|
|
206
227
|
config,
|
|
207
228
|
today,
|
|
208
229
|
tags,
|
|
@@ -213,12 +234,13 @@ function executeReleaseSet(args) {
|
|
|
213
234
|
previewOptions,
|
|
214
235
|
overrideContext,
|
|
215
236
|
sectionOrder,
|
|
237
|
+
dependenciesHeader,
|
|
216
238
|
}));
|
|
217
239
|
}
|
|
218
240
|
return { tags, modifiedFiles };
|
|
219
241
|
}
|
|
220
242
|
function executeWorkspaceRelease(args) {
|
|
221
|
-
const { dir, workspace, releaseEntry, directResult,
|
|
243
|
+
const { dir, workspace, releaseEntry, directResult, skippedHistory, config, today, tags, modifiedFiles, writes, warnings, workspaces, previewOptions, overrideContext, sectionOrder, dependenciesHeader, } = args;
|
|
222
244
|
const setVersionTarget = directResult?.setVersion;
|
|
223
245
|
const bump = setVersionTarget === undefined
|
|
224
246
|
? planVersionBump(workspace.packageFiles, releaseEntry.releaseType)
|
|
@@ -227,8 +249,8 @@ function executeWorkspaceRelease(args) {
|
|
|
227
249
|
tags.push(newTag);
|
|
228
250
|
writes.push(...bump.writes);
|
|
229
251
|
modifiedFiles.push(...workspace.packageFiles, ...workspace.changelogPaths.map((changelogPath) => joinPath(changelogPath, 'CHANGELOG.md')));
|
|
230
|
-
const
|
|
231
|
-
const { changelogFiles, previewFiles } = generateWorkspaceChangelogs({
|
|
252
|
+
const phase1History = directResult?.history ?? skippedHistory;
|
|
253
|
+
const { changelogFiles, changelogPreservation, previewFiles } = generateWorkspaceChangelogs({
|
|
232
254
|
workspace,
|
|
233
255
|
releaseEntry,
|
|
234
256
|
newTag,
|
|
@@ -242,28 +264,31 @@ function executeWorkspaceRelease(args) {
|
|
|
242
264
|
previewOptions,
|
|
243
265
|
overrideContext,
|
|
244
266
|
sectionOrder,
|
|
267
|
+
dependenciesHeader,
|
|
245
268
|
});
|
|
246
269
|
const released = {
|
|
247
270
|
name: dir,
|
|
248
271
|
status: 'released',
|
|
249
|
-
commitCount:
|
|
272
|
+
commitCount: phase1History?.unreleased.commits.length ?? 0,
|
|
250
273
|
currentVersion: bump.currentVersion,
|
|
251
274
|
newVersion: bump.newVersion,
|
|
252
275
|
tag: newTag,
|
|
253
276
|
bumpedFiles: bump.writes.map((write) => write.path),
|
|
254
277
|
changelogFiles,
|
|
255
278
|
...(previewFiles.length > 0 && { previewFiles }),
|
|
279
|
+
...(changelogPreservation.length > 0 && { changelogPreservation }),
|
|
256
280
|
};
|
|
257
281
|
attachReleasedWorkspaceOptionals(released, {
|
|
258
|
-
previousTag:
|
|
282
|
+
previousTag: phase1History?.previousTag,
|
|
259
283
|
directResult,
|
|
284
|
+
skippedHistory,
|
|
260
285
|
releaseEntry,
|
|
261
286
|
setVersionTarget,
|
|
262
287
|
});
|
|
263
288
|
workspaces.push(released);
|
|
264
289
|
}
|
|
265
290
|
function attachReleasedWorkspaceOptionals(released, args) {
|
|
266
|
-
const { previousTag, directResult, releaseEntry, setVersionTarget } = args;
|
|
291
|
+
const { previousTag, directResult, skippedHistory, releaseEntry, setVersionTarget } = args;
|
|
267
292
|
if (previousTag !== undefined) {
|
|
268
293
|
released.previousTag = previousTag;
|
|
269
294
|
}
|
|
@@ -273,6 +298,9 @@ function attachReleasedWorkspaceOptionals(released, args) {
|
|
|
273
298
|
if (directResult !== undefined) {
|
|
274
299
|
attachDirectHistory(released, directResult.history.unreleased, setVersionTarget === undefined);
|
|
275
300
|
}
|
|
301
|
+
else {
|
|
302
|
+
attachPropagatedHistory(released, skippedHistory?.unreleased);
|
|
303
|
+
}
|
|
276
304
|
if (releaseEntry.propagatedFrom !== undefined) {
|
|
277
305
|
released.propagatedFrom = releaseEntry.propagatedFrom;
|
|
278
306
|
}
|
|
@@ -293,11 +321,31 @@ function attachDirectHistory(released, unreleased, hasDecidedBump) {
|
|
|
293
321
|
}
|
|
294
322
|
attachChangelogDiagnostics(released, unreleased.diagnostics);
|
|
295
323
|
}
|
|
324
|
+
function attachPropagatedHistory(released, unreleased) {
|
|
325
|
+
released.propagatedOnly = true;
|
|
326
|
+
if (unreleased === undefined) {
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
released.commits = unreleased.commits;
|
|
330
|
+
if (unreleased.unparseableCommits !== undefined) {
|
|
331
|
+
released.unparseableCommits = unreleased.unparseableCommits;
|
|
332
|
+
}
|
|
333
|
+
attachChangelogDiagnostics(released, unreleased.diagnostics);
|
|
334
|
+
}
|
|
296
335
|
function generateWorkspaceChangelogs(args) {
|
|
297
|
-
const { workspace, releaseEntry, newTag, newVersion, history, config, today, modifiedFiles, writes, warnings, previewOptions, overrideContext, sectionOrder, } = args;
|
|
298
|
-
const entries = buildWorkspaceEntries({
|
|
336
|
+
const { workspace, releaseEntry, newTag, newVersion, history, config, today, modifiedFiles, writes, warnings, previewOptions, overrideContext, sectionOrder, dependenciesHeader, } = args;
|
|
337
|
+
const entries = buildWorkspaceEntries({
|
|
338
|
+
workspace,
|
|
339
|
+
releaseEntry,
|
|
340
|
+
newTag,
|
|
341
|
+
newVersion,
|
|
342
|
+
history,
|
|
343
|
+
today,
|
|
344
|
+
dependenciesHeader,
|
|
345
|
+
});
|
|
299
346
|
const applied = applyWorkspaceOverrides(entries, workspace.workspacePath, overrideContext);
|
|
300
347
|
const changelogFiles = [];
|
|
348
|
+
const changelogPreservation = [];
|
|
301
349
|
let firstMergedEntries;
|
|
302
350
|
for (const changelogPath of workspace.changelogPaths) {
|
|
303
351
|
const jsonPath = resolveChangelogJsonPath(config, changelogPath);
|
|
@@ -308,25 +356,29 @@ function generateWorkspaceChangelogs(args) {
|
|
|
308
356
|
firstMergedEntries ??= mergedEntries;
|
|
309
357
|
}
|
|
310
358
|
const changelogFile = joinPath(changelogPath, 'CHANGELOG.md');
|
|
311
|
-
|
|
359
|
+
const preserved = planPreservedSections(changelogFile, mergedEntries);
|
|
360
|
+
writes.push({
|
|
361
|
+
path: changelogFile,
|
|
362
|
+
content: renderChangelogMarkdown(mergedEntries, { sectionOrder, preservedSections: preserved.sections }),
|
|
363
|
+
});
|
|
312
364
|
changelogFiles.push(changelogFile);
|
|
365
|
+
if (preserved.preservation !== undefined) {
|
|
366
|
+
changelogPreservation.push(preserved.preservation);
|
|
367
|
+
}
|
|
313
368
|
}
|
|
314
369
|
const previews = planPreviews(workspace, newTag, firstMergedEntries, previewOptions, warnings);
|
|
315
370
|
writes.push(...previews);
|
|
316
|
-
return { changelogFiles, previewFiles: previews.map((write) => write.path) };
|
|
371
|
+
return { changelogFiles, changelogPreservation, previewFiles: previews.map((write) => write.path) };
|
|
317
372
|
}
|
|
318
373
|
function buildWorkspaceEntries(args) {
|
|
319
|
-
const { workspace, releaseEntry, newTag, newVersion, history, today } = args;
|
|
374
|
+
const { workspace, releaseEntry, newTag, newVersion, history, today, dependenciesHeader } = args;
|
|
320
375
|
if (history === undefined) {
|
|
321
376
|
if (releaseEntry.propagatedFrom === undefined) {
|
|
322
377
|
throw new Error(`Workspace '${workspace.dir}' has neither a direct release nor a propagation source`);
|
|
323
378
|
}
|
|
324
|
-
return [buildSyntheticChangelogEntry(releaseEntry.propagatedFrom, newVersion, today)];
|
|
325
|
-
}
|
|
326
|
-
if (history.unreleased.commits.length === 0) {
|
|
327
|
-
return [buildEmptyReleaseEntry(newVersion, today)];
|
|
379
|
+
return [buildSyntheticChangelogEntry(releaseEntry.propagatedFrom, newVersion, today, dependenciesHeader)];
|
|
328
380
|
}
|
|
329
|
-
return
|
|
381
|
+
return toReleaseEntries(history, newTag, today);
|
|
330
382
|
}
|
|
331
383
|
function planPreviews(workspace, newTag, entries, previewOptions, warnings) {
|
|
332
384
|
if (!previewOptions.enabled || entries === undefined) {
|
|
@@ -1,57 +1,47 @@
|
|
|
1
1
|
import type { PlannedWrite } from './releasePlan.js';
|
|
2
2
|
import type { ReleasePrepareOptions } from './releasePrepare.js';
|
|
3
|
-
import type { ChangelogOverride,
|
|
3
|
+
import type { ChangelogOverride, MonorepoPrepareConfig, ProjectPrepareResult } from './types.js';
|
|
4
4
|
/** Inputs to the project-release stage. */
|
|
5
5
|
export interface ReleasePrepareProjectArgs {
|
|
6
6
|
/** Resolved monorepo config; `config.project` must be defined when this function is called. */
|
|
7
|
-
config:
|
|
7
|
+
config: MonorepoPrepareConfig;
|
|
8
8
|
options: ReleasePrepareOptions;
|
|
9
9
|
/** Mutated in-place to append project-level files (root package.json, root CHANGELOG.md, root changelog.json). */
|
|
10
10
|
modifiedFiles: string[];
|
|
11
|
-
/** Mutated in-place to append every file this stage intends to write. */
|
|
11
|
+
/** Mutated in-place to append every file that this stage intends to write. */
|
|
12
12
|
writes: PlannedWrite[];
|
|
13
13
|
/** Mutated in-place to append the project tag. */
|
|
14
14
|
tags: string[];
|
|
15
15
|
/**
|
|
16
|
-
* Mutated in-place to
|
|
17
|
-
*
|
|
16
|
+
* Mutated in-place to receive the warnings that this stage raises and that are not override-specific.
|
|
17
|
+
* Defaults to a discardable sink.
|
|
18
18
|
*/
|
|
19
19
|
warnings?: string[];
|
|
20
20
|
/**
|
|
21
|
-
* Root-tier editorial overrides
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* meaning at the aggregated project tier.
|
|
21
|
+
* Root-tier editorial overrides. Defaults to an empty map. The project changelog applies only the
|
|
22
|
+
* root-tier file: Per-workspace files describe per-workspace editorial intent and are
|
|
23
|
+
* meaningless at the aggregated project tier.
|
|
25
24
|
*/
|
|
26
25
|
rootOverrides?: Map<string, ChangelogOverride>;
|
|
27
26
|
/**
|
|
28
|
-
* Mutated in-place to
|
|
29
|
-
*
|
|
30
|
-
* a discardable sink when omitted.
|
|
27
|
+
* Mutated in-place to receive override-application warnings. Stale-key warnings are not among them: Those
|
|
28
|
+
* depend on the matches of every batch, which `globalMatchedRootKeys` collects. Defaults to a discardable sink.
|
|
31
29
|
*/
|
|
32
30
|
overrideWarnings?: string[];
|
|
33
31
|
/**
|
|
34
|
-
* Mutated in-place
|
|
35
|
-
*
|
|
36
|
-
* sink when omitted.
|
|
32
|
+
* Mutated in-place to receive every root-tier override key that this stage matches, so that stale-key
|
|
33
|
+
* warnings can cover the whole run. Defaults to a discardable sink.
|
|
37
34
|
*/
|
|
38
35
|
globalMatchedRootKeys?: Set<string>;
|
|
39
36
|
}
|
|
40
37
|
/**
|
|
41
|
-
*
|
|
38
|
+
* Runs the project-level release stage: reads the history, decides the bump, and plans the root `package.json`
|
|
39
|
+
* bump, the root `CHANGELOG.md`, and optionally `changelog.json` and release-notes previews. Contributing paths
|
|
40
|
+
* come from the resolved `project.paths`, which defaults to the union of every (already-filtered) workspace's
|
|
41
|
+
* `paths`.
|
|
42
42
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* the resolved `project.paths`, which defaults to the union of every (already-filtered)
|
|
47
|
-
* workspace's `paths`.
|
|
48
|
-
*
|
|
49
|
-
* Returns a structured `{ status: 'skipped', skipReason, ... }` result when neither
|
|
50
|
-
* commits nor `--force` provide a release signal. The caller should attach the returned
|
|
51
|
-
* result to `PrepareResult.project`. `undefined` is returned only when there is no
|
|
52
|
-
* configured `project` block — handled at the call site, not here.
|
|
53
|
-
*
|
|
54
|
-
* Caller contract: `prepareCommand` rejects `--only` upstream when a project block is
|
|
55
|
-
* configured, so this orchestrator never has to reason about workspace-narrowing flags.
|
|
43
|
+
* Returns a `skipped` result when neither commits nor `--force` provide a release signal, and throws when
|
|
44
|
+
* `config.project` is undefined. A run narrowed by `--only` does not reach this stage, so it doesn't
|
|
45
|
+
* read any narrowing flag.
|
|
56
46
|
*/
|
|
57
47
|
export declare function releasePrepareProject(args: ReleasePrepareProjectArgs): ProjectPrepareResult;
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { join as joinPath } from 'node:path';
|
|
2
|
+
import { assertTaggedBaseline, findUntaggedBaseline } from "./assertTaggedBaseline.js";
|
|
2
3
|
import { attachChangelogDiagnostics } from "./attachChangelogDiagnostics.js";
|
|
3
|
-
import { readReleaseHistory,
|
|
4
|
-
import { buildEmptyReleaseEntry } from "./buildEmptyReleaseEntry.js";
|
|
4
|
+
import { readReleaseHistory, toReleaseEntries } from "./buildChangelogEntries.js";
|
|
5
5
|
import { mergeChangelogEntriesWithDisk, renderChangelogJson, resolveChangelogJsonPath } from "./changelogJsonFile.js";
|
|
6
6
|
import { applyChangelogOverrides } from "./changelogOverrides.js";
|
|
7
7
|
import { decideRelease } from "./decideRelease.js";
|
|
8
8
|
import { DEFAULT_WORK_TYPES } from "./defaults.js";
|
|
9
|
+
import { deriveSectionOrder } from "./deriveReleaseNotesConfig.js";
|
|
9
10
|
import { planReleaseNotesPreviews } from "./planReleaseNotesPreviews.js";
|
|
10
11
|
import { planVersionBump } from "./planVersionBump.js";
|
|
12
|
+
import { planPreservedSections } from "./readChangelogSections.js";
|
|
11
13
|
import { renderChangelogMarkdown } from "./renderChangelogMarkdown.js";
|
|
12
|
-
import { deriveSectionOrder } from "./resolveReleaseNotesConfig.js";
|
|
13
14
|
const ROOT_PACKAGE_FILE = './package.json';
|
|
14
15
|
const ROOT_CHANGELOG_PATH = '.';
|
|
15
16
|
export function releasePrepareProject(args) {
|
|
@@ -22,6 +23,15 @@ export function releasePrepareProject(args) {
|
|
|
22
23
|
}
|
|
23
24
|
const workTypes = config.workTypes ?? { ...DEFAULT_WORK_TYPES };
|
|
24
25
|
const history = readReleaseHistory(config, { tagPrefixes: [project.tagPrefix], paths: project.paths });
|
|
26
|
+
assertTaggedBaseline([
|
|
27
|
+
findUntaggedBaseline({
|
|
28
|
+
label: 'project',
|
|
29
|
+
packageFiles: [ROOT_PACKAGE_FILE],
|
|
30
|
+
changelogPaths: [ROOT_CHANGELOG_PATH],
|
|
31
|
+
tagPrefixes: [project.tagPrefix],
|
|
32
|
+
previousTag: history.previousTag,
|
|
33
|
+
}, config),
|
|
34
|
+
]);
|
|
25
35
|
const { commits, diagnostics, parsedCommitCount, unparseableCommits } = history.unreleased;
|
|
26
36
|
const tag = history.previousTag;
|
|
27
37
|
const since = tag === undefined ? '(no previous release found)' : `since ${tag}`;
|
|
@@ -59,7 +69,6 @@ export function releasePrepareProject(args) {
|
|
|
59
69
|
config,
|
|
60
70
|
history,
|
|
61
71
|
newTag,
|
|
62
|
-
newVersion: bump.newVersion,
|
|
63
72
|
rootOverrides,
|
|
64
73
|
overrideWarnings,
|
|
65
74
|
globalMatchedRootKeys,
|
|
@@ -95,6 +104,9 @@ export function releasePrepareProject(args) {
|
|
|
95
104
|
if (previewFiles.length > 0) {
|
|
96
105
|
result.previewFiles = previewFiles;
|
|
97
106
|
}
|
|
107
|
+
if (changelogs.changelogPreservation.length > 0) {
|
|
108
|
+
result.changelogPreservation = changelogs.changelogPreservation;
|
|
109
|
+
}
|
|
98
110
|
if (tag !== undefined) {
|
|
99
111
|
result.previousTag = tag;
|
|
100
112
|
}
|
|
@@ -116,10 +128,9 @@ function resolveOptionalOverrideArgs(args) {
|
|
|
116
128
|
};
|
|
117
129
|
}
|
|
118
130
|
function planProjectChangelogs(args) {
|
|
119
|
-
const { config, history, newTag,
|
|
120
|
-
const isEmptyRange = history.unreleased.commits.length === 0;
|
|
131
|
+
const { config, history, newTag, rootOverrides, overrideWarnings, globalMatchedRootKeys } = args;
|
|
121
132
|
const today = new Date().toISOString().slice(0, 10);
|
|
122
|
-
const builtEntries =
|
|
133
|
+
const builtEntries = toReleaseEntries(history, newTag, today);
|
|
123
134
|
const applied = applyChangelogOverrides(builtEntries, rootOverrides);
|
|
124
135
|
if (applied.errors.length > 0) {
|
|
125
136
|
throw new Error(`Changelog override application failed:\n - ${applied.errors.join('\n - ')}`);
|
|
@@ -130,9 +141,7 @@ function planProjectChangelogs(args) {
|
|
|
130
141
|
}
|
|
131
142
|
const changelogJsonPath = resolveChangelogJsonPath(config, ROOT_CHANGELOG_PATH);
|
|
132
143
|
const sectionOrder = deriveSectionOrder(config.workTypes ?? { ...DEFAULT_WORK_TYPES });
|
|
133
|
-
const renderEntries =
|
|
134
|
-
? mergeChangelogEntriesWithDisk(changelogJsonPath, applied.entries)
|
|
135
|
-
: applied.entries;
|
|
144
|
+
const renderEntries = mergeChangelogEntriesWithDisk(changelogJsonPath, applied.entries);
|
|
136
145
|
const writes = [];
|
|
137
146
|
const changelogJsonFiles = [];
|
|
138
147
|
if (config.changelogJson.enabled) {
|
|
@@ -140,6 +149,16 @@ function planProjectChangelogs(args) {
|
|
|
140
149
|
changelogJsonFiles.push(changelogJsonPath);
|
|
141
150
|
}
|
|
142
151
|
const changelogFile = joinPath(ROOT_CHANGELOG_PATH, 'CHANGELOG.md');
|
|
143
|
-
|
|
144
|
-
|
|
152
|
+
const preserved = planPreservedSections(changelogFile, renderEntries);
|
|
153
|
+
writes.push({
|
|
154
|
+
path: changelogFile,
|
|
155
|
+
content: renderChangelogMarkdown(renderEntries, { sectionOrder, preservedSections: preserved.sections }),
|
|
156
|
+
});
|
|
157
|
+
return {
|
|
158
|
+
changelogFiles: [changelogFile],
|
|
159
|
+
changelogJsonFiles,
|
|
160
|
+
changelogPreservation: preserved.preservation === undefined ? [] : [preserved.preservation],
|
|
161
|
+
entries: renderEntries,
|
|
162
|
+
writes,
|
|
163
|
+
};
|
|
145
164
|
}
|
|
@@ -1,22 +1,28 @@
|
|
|
1
|
+
import type { VersionedMarkdownSection } from './readChangelogSections.js';
|
|
1
2
|
import type { ChangelogEntry } from './types.js';
|
|
2
3
|
/** Options for `renderChangelogMarkdown`. */
|
|
3
4
|
export interface RenderChangelogMarkdownOptions {
|
|
4
|
-
/** Section titles in canonical order; passed through to `
|
|
5
|
+
/** Section titles in canonical order; passed through to `renderReleaseNotesSingle`. */
|
|
5
6
|
sectionOrder?: string[];
|
|
7
|
+
/**
|
|
8
|
+
* Sections of the existing `CHANGELOG.md` to keep verbatim, interleaved by version among the rendered entries. A
|
|
9
|
+
* section's version must not also be an entry's version.
|
|
10
|
+
*/
|
|
11
|
+
preservedSections?: readonly VersionedMarkdownSection[];
|
|
6
12
|
}
|
|
7
13
|
/**
|
|
8
|
-
*
|
|
14
|
+
* Renders `ChangelogEntry[]` into a complete `CHANGELOG.md`-shaped string.
|
|
9
15
|
*
|
|
10
16
|
* Format:
|
|
11
17
|
* `# Changelog`
|
|
12
18
|
* blank line
|
|
13
19
|
* `All notable changes …`
|
|
14
20
|
* blank line
|
|
15
|
-
* per-entry sections (delegated to `
|
|
21
|
+
* per-entry sections (delegated to `renderReleaseNotesSingle`), with preserved sections interleaved by version
|
|
16
22
|
* blank line
|
|
17
23
|
* footer comment
|
|
18
24
|
*
|
|
19
25
|
* Entries are rendered in the order provided; the caller sorts (typically newest-first via
|
|
20
|
-
* `
|
|
26
|
+
* `compareVersionsDescending`).
|
|
21
27
|
*/
|
|
22
28
|
export declare function renderChangelogMarkdown(entries: ChangelogEntry[], options?: RenderChangelogMarkdownOptions): string;
|