@williamthorsen/release-kit 10.2.1 ā 10.3.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/.readyup/kits/default.js +78 -55
- package/.readyup/kits/npm-auto-publish.js +169 -57
- package/.readyup/manifest.json +6 -6
- package/CHANGELOG.md +54 -0
- package/README.md +18 -6
- package/bin/release-kit.js +1 -1
- package/dist/esm/bin/release-kit.js +4 -4
- package/dist/esm/buildChangelogEntries.js +17 -15
- package/dist/esm/buildDependencyGraph.js +6 -2
- package/dist/esm/buildReleaseSummary.d.ts +1 -1
- package/dist/esm/changelogJsonFile.d.ts +1 -3
- package/dist/esm/changelogJsonFile.js +4 -18
- package/dist/esm/changelogJsonUtils.js +7 -7
- package/dist/esm/changelogOverrides.js +13 -12
- package/dist/esm/checkWorkTypesDrift.js +1 -1
- package/dist/esm/commitCommand.js +3 -13
- package/dist/esm/createTags.js +3 -14
- package/dist/esm/deriveWorkspaceConfig.js +3 -3
- package/dist/esm/detectPackageManager.js +2 -2
- package/dist/esm/detectUndeclaredTagPrefixes.js +1 -1
- package/dist/esm/discoverWorkspaces.js +1 -1
- package/dist/esm/getCommitsSinceTarget.js +2 -2
- package/dist/esm/help/prepareHelp.d.ts +1 -1
- package/dist/esm/help/prepareHelp.js +2 -2
- package/dist/esm/init/checks.js +1 -1
- package/dist/esm/init/detectRepoType.js +1 -1
- package/dist/esm/injectReleaseNotesIntoReadme.d.ts +2 -0
- package/dist/esm/injectReleaseNotesIntoReadme.js +13 -10
- package/dist/esm/loadConfig.js +8 -6
- package/dist/esm/planReleaseNotesPreviews.d.ts +13 -0
- package/dist/esm/planReleaseNotesPreviews.js +43 -0
- package/dist/esm/planVersionBump.d.ts +9 -0
- package/dist/esm/planVersionBump.js +54 -0
- package/dist/esm/prepareCommand.d.ts +0 -4
- package/dist/esm/prepareCommand.js +51 -45
- package/dist/esm/propagateBumps.js +1 -1
- package/dist/esm/releaseFiles.d.ts +4 -0
- package/dist/esm/releaseFiles.js +34 -0
- package/dist/esm/releasePlan.d.ts +10 -0
- package/dist/esm/releasePlan.js +53 -0
- package/dist/esm/releasePrepare.d.ts +3 -3
- package/dist/esm/releasePrepare.js +53 -54
- package/dist/esm/releasePrepareMono.d.ts +3 -2
- package/dist/esm/releasePrepareMono.js +50 -53
- package/dist/esm/releasePrepareProject.d.ts +3 -0
- package/dist/esm/releasePrepareProject.js +33 -37
- package/dist/esm/renderChangelogMarkdown.d.ts +0 -7
- package/dist/esm/renderChangelogMarkdown.js +0 -13
- package/dist/esm/reportPrepare.d.ts +5 -1
- package/dist/esm/reportPrepare.js +37 -17
- package/dist/esm/sync-labels/generateCommand.js +4 -2
- package/dist/esm/sync-labels/presets.js +5 -5
- package/dist/esm/sync-labels/resolveLabels.js +5 -3
- package/dist/esm/syncWorkTypes.js +1 -1
- package/dist/esm/types.d.ts +4 -9
- package/dist/esm/validateConfig.js +11 -11
- package/dist/esm/workTypesData.d.ts +1 -1
- package/dist/esm/workTypesUtils.js +1 -1
- package/package.json +3 -3
- package/dist/esm/bumpAllVersions.d.ts +0 -3
- package/dist/esm/bumpAllVersions.js +0 -61
- package/dist/esm/writeReleaseNotesPreviews.d.ts +0 -18
- package/dist/esm/writeReleaseNotesPreviews.js +0 -63
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { join as joinPath } from 'node:path';
|
|
2
2
|
import { buildChangelogEntries } from "./buildChangelogEntries.js";
|
|
3
3
|
import { buildDependencyGraph } from "./buildDependencyGraph.js";
|
|
4
4
|
import { buildEmptyReleaseEntry } from "./buildEmptyReleaseEntry.js";
|
|
5
|
+
import { buildReleaseSummary } from "./buildReleaseSummary.js";
|
|
5
6
|
import { buildSyntheticChangelogEntry } from "./buildSyntheticChangelogEntry.js";
|
|
6
|
-
import {
|
|
7
|
-
import { mergeChangelogEntriesWithDisk, resolveChangelogJsonPath, upsertChangelogJsonAndReturn, } from "./changelogJsonFile.js";
|
|
7
|
+
import { mergeChangelogEntriesWithDisk, renderChangelogJson, resolveChangelogJsonPath } from "./changelogJsonFile.js";
|
|
8
8
|
import { applyWorkspaceOverrides, createOverrideContext, formatStaleOverrideKeyWarning, } from "./changelogOverrides.js";
|
|
9
9
|
import { createPolicyViolationCollector } from "./collectPolicyViolations.js";
|
|
10
10
|
import { isForwardVersion } from "./compareVersions.js";
|
|
@@ -15,15 +15,17 @@ import { buildTagPattern, getAllTagPrefixes } from "./generateChangelogs.js";
|
|
|
15
15
|
import { getCommitsSinceTarget } from "./getCommitsSinceTarget.js";
|
|
16
16
|
import { hasPrettierConfig } from "./hasPrettierConfig.js";
|
|
17
17
|
import { resolveWorkTypes } from "./loadConfig.js";
|
|
18
|
+
import { planReleaseNotesPreviews } from "./planReleaseNotesPreviews.js";
|
|
19
|
+
import { planVersionBump, planVersionSet } from "./planVersionBump.js";
|
|
18
20
|
import { propagateBumps } from "./propagateBumps.js";
|
|
19
21
|
import { readCurrentVersion } from "./readCurrentVersion.js";
|
|
20
22
|
import { releasePrepareProject } from "./releasePrepareProject.js";
|
|
21
|
-
import {
|
|
23
|
+
import { renderChangelogMarkdown } from "./renderChangelogMarkdown.js";
|
|
22
24
|
import { deriveSectionOrder } from "./resolveReleaseNotesConfig.js";
|
|
23
25
|
import { refreshGitCliffCache } from "./runGitCliff.js";
|
|
24
|
-
import { writeReleaseNotesPreviews } from "./writeReleaseNotesPreviews.js";
|
|
25
26
|
export function releasePrepareMono(config, options) {
|
|
26
|
-
const {
|
|
27
|
+
const { withReleaseNotes } = options;
|
|
28
|
+
const writes = [];
|
|
27
29
|
if (withReleaseNotes === true && !config.changelogJson.enabled) {
|
|
28
30
|
console.warn('Warning: --with-release-notes requires changelogJson.enabled; skipping preview generation');
|
|
29
31
|
}
|
|
@@ -59,7 +61,8 @@ export function releasePrepareMono(config, options) {
|
|
|
59
61
|
config,
|
|
60
62
|
directResults,
|
|
61
63
|
previousTags,
|
|
62
|
-
|
|
64
|
+
writes,
|
|
65
|
+
warnings,
|
|
63
66
|
workspaces,
|
|
64
67
|
previewOptions,
|
|
65
68
|
overrideContext,
|
|
@@ -77,13 +80,15 @@ export function releasePrepareMono(config, options) {
|
|
|
77
80
|
config,
|
|
78
81
|
options,
|
|
79
82
|
modifiedFiles,
|
|
83
|
+
writes,
|
|
80
84
|
tags,
|
|
85
|
+
warnings,
|
|
81
86
|
rootOverrides: overrideContext.project,
|
|
82
87
|
overrideWarnings: overrideContext.overrideWarnings,
|
|
83
88
|
globalMatchedRootKeys: overrideContext.globalMatchedRootKeys,
|
|
84
89
|
}));
|
|
85
90
|
}
|
|
86
|
-
const formatCommand =
|
|
91
|
+
const formatCommand = planFormatCommand(config, tags, modifiedFiles);
|
|
87
92
|
for (const overrideKey of overrideContext.project.keys()) {
|
|
88
93
|
if (!overrideContext.globalMatchedRootKeys.has(overrideKey)) {
|
|
89
94
|
overrideContext.overrideWarnings.push(formatStaleOverrideKeyWarning(overrideKey));
|
|
@@ -93,8 +98,9 @@ export function releasePrepareMono(config, options) {
|
|
|
93
98
|
return {
|
|
94
99
|
workspaces,
|
|
95
100
|
tags,
|
|
101
|
+
writes,
|
|
102
|
+
summary: buildReleaseSummary({ workspaces, ...(project !== undefined && { project }) }),
|
|
96
103
|
formatCommand,
|
|
97
|
-
dryRun,
|
|
98
104
|
...(allWarnings.length > 0 && { warnings: allWarnings }),
|
|
99
105
|
...(project !== undefined && { project }),
|
|
100
106
|
};
|
|
@@ -221,7 +227,7 @@ function collectSkippedWorkspaces(skippedResults, fullReleaseSet) {
|
|
|
221
227
|
return workspaces;
|
|
222
228
|
}
|
|
223
229
|
function executeReleaseSet(args) {
|
|
224
|
-
const { sortedDirs, fullReleaseSet, config, directResults, previousTags,
|
|
230
|
+
const { sortedDirs, fullReleaseSet, config, directResults, previousTags, writes, warnings, workspaces, previewOptions, overrideContext, sectionOrder, } = args;
|
|
225
231
|
const tags = [];
|
|
226
232
|
const modifiedFiles = [];
|
|
227
233
|
const today = new Date().toISOString().slice(0, 10);
|
|
@@ -241,10 +247,11 @@ function executeReleaseSet(args) {
|
|
|
241
247
|
directResult: directResults.get(dir),
|
|
242
248
|
previousTags,
|
|
243
249
|
config,
|
|
244
|
-
dryRun,
|
|
245
250
|
today,
|
|
246
251
|
tags,
|
|
247
252
|
modifiedFiles,
|
|
253
|
+
writes,
|
|
254
|
+
warnings,
|
|
248
255
|
workspaces,
|
|
249
256
|
previewOptions,
|
|
250
257
|
overrideContext,
|
|
@@ -254,17 +261,18 @@ function executeReleaseSet(args) {
|
|
|
254
261
|
return { tags, modifiedFiles };
|
|
255
262
|
}
|
|
256
263
|
function executeWorkspaceRelease(args) {
|
|
257
|
-
const { dir, workspace, releaseEntry, directResult, previousTags, config,
|
|
264
|
+
const { dir, workspace, releaseEntry, directResult, previousTags, config, today, tags, modifiedFiles, writes, warnings, workspaces, previewOptions, overrideContext, sectionOrder, } = args;
|
|
258
265
|
const setVersionTarget = directResult?.setVersion;
|
|
259
266
|
const bump = setVersionTarget === undefined
|
|
260
|
-
?
|
|
261
|
-
:
|
|
267
|
+
? planVersionBump(workspace.packageFiles, releaseEntry.releaseType)
|
|
268
|
+
: planVersionSet(workspace.packageFiles, setVersionTarget);
|
|
262
269
|
const newTag = `${workspace.tagPrefix}${bump.newVersion}`;
|
|
263
270
|
tags.push(newTag);
|
|
264
|
-
|
|
271
|
+
writes.push(...bump.writes);
|
|
272
|
+
modifiedFiles.push(...workspace.packageFiles, ...workspace.changelogPaths.map((changelogPath) => joinPath(changelogPath, 'CHANGELOG.md')));
|
|
265
273
|
const isPropagationOnly = directResult === undefined;
|
|
266
274
|
const isEmptyRange = directResult !== undefined && directResult.commits.length === 0;
|
|
267
|
-
const changelogFiles = generateWorkspaceChangelogs({
|
|
275
|
+
const { changelogFiles, previewFiles } = generateWorkspaceChangelogs({
|
|
268
276
|
workspace,
|
|
269
277
|
releaseEntry,
|
|
270
278
|
newTag,
|
|
@@ -272,9 +280,10 @@ function executeWorkspaceRelease(args) {
|
|
|
272
280
|
isPropagationOnly,
|
|
273
281
|
isEmptyRange,
|
|
274
282
|
config,
|
|
275
|
-
dryRun,
|
|
276
283
|
today,
|
|
277
284
|
modifiedFiles,
|
|
285
|
+
writes,
|
|
286
|
+
warnings,
|
|
278
287
|
previewOptions,
|
|
279
288
|
overrideContext,
|
|
280
289
|
sectionOrder,
|
|
@@ -286,8 +295,9 @@ function executeWorkspaceRelease(args) {
|
|
|
286
295
|
currentVersion: bump.currentVersion,
|
|
287
296
|
newVersion: bump.newVersion,
|
|
288
297
|
tag: newTag,
|
|
289
|
-
bumpedFiles: bump.
|
|
298
|
+
bumpedFiles: bump.writes.map((write) => write.path),
|
|
290
299
|
changelogFiles,
|
|
300
|
+
...(previewFiles.length > 0 && { previewFiles }),
|
|
291
301
|
};
|
|
292
302
|
attachReleasedWorkspaceOptionals(released, {
|
|
293
303
|
previousTag: directResult?.tag ?? previousTags.get(dir),
|
|
@@ -328,7 +338,7 @@ function attachReleasedWorkspaceOptionals(released, args) {
|
|
|
328
338
|
}
|
|
329
339
|
}
|
|
330
340
|
function generateWorkspaceChangelogs(args) {
|
|
331
|
-
const { workspace, releaseEntry, newTag, newVersion, isPropagationOnly, isEmptyRange, config,
|
|
341
|
+
const { workspace, releaseEntry, newTag, newVersion, isPropagationOnly, isEmptyRange, config, today, modifiedFiles, writes, warnings, previewOptions, overrideContext, sectionOrder, } = args;
|
|
332
342
|
const newEntries = buildWorkspaceEntries({
|
|
333
343
|
workspace,
|
|
334
344
|
releaseEntry,
|
|
@@ -341,26 +351,22 @@ function generateWorkspaceChangelogs(args) {
|
|
|
341
351
|
});
|
|
342
352
|
const applied = applyWorkspaceOverrides(newEntries, workspace.workspacePath, overrideContext);
|
|
343
353
|
const changelogFiles = [];
|
|
344
|
-
let
|
|
354
|
+
let firstMergedEntries;
|
|
345
355
|
for (const changelogPath of workspace.changelogPaths) {
|
|
346
356
|
const jsonPath = resolveChangelogJsonPath(config, changelogPath);
|
|
347
|
-
const
|
|
348
|
-
const mergedEntries = shouldWriteJson
|
|
349
|
-
? upsertChangelogJsonAndReturn(jsonPath, applied.entries)
|
|
350
|
-
: mergeChangelogEntriesWithDisk(jsonPath, applied.entries);
|
|
357
|
+
const mergedEntries = mergeChangelogEntriesWithDisk(jsonPath, applied.entries);
|
|
351
358
|
if (config.changelogJson.enabled) {
|
|
359
|
+
writes.push({ path: jsonPath, content: renderChangelogJson(mergedEntries) });
|
|
352
360
|
modifiedFiles.push(jsonPath);
|
|
353
|
-
|
|
361
|
+
firstMergedEntries ??= mergedEntries;
|
|
354
362
|
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
sectionOrder,
|
|
359
|
-
dryRun,
|
|
360
|
-
}));
|
|
363
|
+
const changelogFile = joinPath(changelogPath, 'CHANGELOG.md');
|
|
364
|
+
writes.push({ path: changelogFile, content: renderChangelogMarkdown(mergedEntries, { sectionOrder }) });
|
|
365
|
+
changelogFiles.push(changelogFile);
|
|
361
366
|
}
|
|
362
|
-
|
|
363
|
-
|
|
367
|
+
const previews = planPreviews(workspace, newTag, firstMergedEntries, previewOptions, warnings);
|
|
368
|
+
writes.push(...previews);
|
|
369
|
+
return { changelogFiles, previewFiles: previews.map((write) => write.path) };
|
|
364
370
|
}
|
|
365
371
|
function buildWorkspaceEntries(args) {
|
|
366
372
|
const { workspace, releaseEntry, newTag, newVersion, isPropagationOnly, isEmptyRange, config, today } = args;
|
|
@@ -373,35 +379,25 @@ function buildWorkspaceEntries(args) {
|
|
|
373
379
|
const tagPattern = buildTagPattern(getAllTagPrefixes(workspace));
|
|
374
380
|
return buildChangelogEntries(config, newTag, { tagPattern, includePaths: workspace.paths });
|
|
375
381
|
}
|
|
376
|
-
function
|
|
377
|
-
if (!previewOptions.enabled ||
|
|
378
|
-
return;
|
|
382
|
+
function planPreviews(workspace, newTag, entries, previewOptions, warnings) {
|
|
383
|
+
if (!previewOptions.enabled || entries === undefined) {
|
|
384
|
+
return [];
|
|
379
385
|
}
|
|
380
|
-
|
|
386
|
+
const previews = planReleaseNotesPreviews({
|
|
381
387
|
workspacePath: workspace.workspacePath,
|
|
382
388
|
tag: newTag,
|
|
383
|
-
|
|
389
|
+
entries,
|
|
384
390
|
sectionOrder: previewOptions.sectionOrder,
|
|
385
|
-
dryRun,
|
|
386
391
|
});
|
|
392
|
+
warnings.push(...previews.warnings);
|
|
393
|
+
return previews.writes;
|
|
387
394
|
}
|
|
388
|
-
function
|
|
395
|
+
function planFormatCommand(config, tags, modifiedFiles) {
|
|
389
396
|
const formatCommandStr = config.formatCommand ?? (hasPrettierConfig() ? 'npx prettier --write' : undefined);
|
|
390
397
|
if (tags.length === 0 || formatCommandStr === undefined) {
|
|
391
398
|
return undefined;
|
|
392
399
|
}
|
|
393
|
-
|
|
394
|
-
if (dryRun) {
|
|
395
|
-
return { command: fullCommand, executed: false, files: modifiedFiles };
|
|
396
|
-
}
|
|
397
|
-
try {
|
|
398
|
-
execSync(fullCommand, { stdio: 'inherit' });
|
|
399
|
-
}
|
|
400
|
-
catch (error) {
|
|
401
|
-
const baseMessage = error instanceof Error ? error.message : String(error);
|
|
402
|
-
throw new Error(`format stage: ${baseMessage} (command: '${fullCommand}')`, { cause: error });
|
|
403
|
-
}
|
|
404
|
-
return { command: fullCommand, executed: true, files: modifiedFiles };
|
|
400
|
+
return { command: `${formatCommandStr} ${modifiedFiles.join(' ')}`, files: modifiedFiles };
|
|
405
401
|
}
|
|
406
402
|
function findWorkspace(workspaces, dir) {
|
|
407
403
|
return workspaces.find((w) => w.dir === dir);
|
|
@@ -476,7 +472,8 @@ function topologicalSort(releaseSet, graph) {
|
|
|
476
472
|
break;
|
|
477
473
|
}
|
|
478
474
|
sorted.push(dir);
|
|
479
|
-
|
|
475
|
+
const dependents = forwardEdges.get(dir) ?? [];
|
|
476
|
+
for (const dependent of dependents) {
|
|
480
477
|
const newDegree = (inDegree.get(dependent) ?? 1) - 1;
|
|
481
478
|
inDegree.set(dependent, newDegree);
|
|
482
479
|
if (newDegree === 0) {
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
import type { PlannedWrite } from './releasePlan.js';
|
|
1
2
|
import type { ReleasePrepareOptions } from './releasePrepare.js';
|
|
2
3
|
import type { ChangelogOverride, MonorepoReleaseConfig, ProjectPrepareResult } from './types.js';
|
|
3
4
|
export interface ReleasePrepareProjectArgs {
|
|
4
5
|
config: MonorepoReleaseConfig;
|
|
5
6
|
options: ReleasePrepareOptions;
|
|
6
7
|
modifiedFiles: string[];
|
|
8
|
+
writes: PlannedWrite[];
|
|
7
9
|
tags: string[];
|
|
10
|
+
warnings?: string[];
|
|
8
11
|
rootOverrides?: Map<string, ChangelogOverride>;
|
|
9
12
|
overrideWarnings?: string[];
|
|
10
13
|
globalMatchedRootKeys?: Set<string>;
|
|
@@ -1,22 +1,23 @@
|
|
|
1
|
+
import { join as joinPath } from 'node:path';
|
|
1
2
|
import { buildChangelogEntries } from "./buildChangelogEntries.js";
|
|
2
3
|
import { buildEmptyReleaseEntry } from "./buildEmptyReleaseEntry.js";
|
|
3
|
-
import {
|
|
4
|
-
import { mergeChangelogEntriesWithDisk, resolveChangelogJsonPath, writeChangelogJson } from "./changelogJsonFile.js";
|
|
4
|
+
import { mergeChangelogEntriesWithDisk, renderChangelogJson, resolveChangelogJsonPath } from "./changelogJsonFile.js";
|
|
5
5
|
import { applyChangelogOverrides } from "./changelogOverrides.js";
|
|
6
6
|
import { createPolicyViolationCollector } from "./collectPolicyViolations.js";
|
|
7
7
|
import { decideRelease } from "./decideRelease.js";
|
|
8
8
|
import { DEFAULT_BREAKING_POLICIES, DEFAULT_VERSION_PATTERNS, DEFAULT_WORK_TYPES } from "./defaults.js";
|
|
9
9
|
import { buildTagPattern } from "./generateChangelogs.js";
|
|
10
10
|
import { getCommitsSinceTarget } from "./getCommitsSinceTarget.js";
|
|
11
|
-
import {
|
|
11
|
+
import { planReleaseNotesPreviews } from "./planReleaseNotesPreviews.js";
|
|
12
|
+
import { planVersionBump } from "./planVersionBump.js";
|
|
13
|
+
import { renderChangelogMarkdown } from "./renderChangelogMarkdown.js";
|
|
12
14
|
import { deriveSectionOrder } from "./resolveReleaseNotesConfig.js";
|
|
13
|
-
import { writeReleaseNotesPreviews } from "./writeReleaseNotesPreviews.js";
|
|
14
15
|
const ROOT_PACKAGE_FILE = './package.json';
|
|
15
16
|
const ROOT_CHANGELOG_PATH = '.';
|
|
16
17
|
export function releasePrepareProject(args) {
|
|
17
|
-
const { config, options, modifiedFiles, tags } = args;
|
|
18
|
-
const { rootOverrides, overrideWarnings, globalMatchedRootKeys } = resolveOptionalOverrideArgs(args);
|
|
19
|
-
const {
|
|
18
|
+
const { config, options, modifiedFiles, writes, tags } = args;
|
|
19
|
+
const { rootOverrides, overrideWarnings, globalMatchedRootKeys, warnings } = resolveOptionalOverrideArgs(args);
|
|
20
|
+
const { bumpOverride, withReleaseNotes, force } = options;
|
|
20
21
|
const project = config.project;
|
|
21
22
|
if (project === undefined) {
|
|
22
23
|
throw new Error('releasePrepareProject called without a configured project block');
|
|
@@ -62,30 +63,33 @@ export function releasePrepareProject(args) {
|
|
|
62
63
|
return skipped;
|
|
63
64
|
}
|
|
64
65
|
const { releaseType, parsedCommitCount, unparseableCommits } = decision;
|
|
65
|
-
const bump =
|
|
66
|
+
const bump = planVersionBump([ROOT_PACKAGE_FILE], releaseType);
|
|
67
|
+
writes.push(...bump.writes);
|
|
66
68
|
const newTag = `${project.tagPrefix}${bump.newVersion}`;
|
|
67
|
-
const
|
|
69
|
+
const changelogs = planProjectChangelogs({
|
|
68
70
|
config,
|
|
69
71
|
project,
|
|
70
72
|
commits,
|
|
71
73
|
contributingPaths,
|
|
72
74
|
newTag,
|
|
73
75
|
newVersion: bump.newVersion,
|
|
74
|
-
dryRun,
|
|
75
76
|
rootOverrides,
|
|
76
77
|
overrideWarnings,
|
|
77
78
|
globalMatchedRootKeys,
|
|
78
79
|
});
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
const { changelogFiles, changelogJsonFiles } = changelogs;
|
|
81
|
+
writes.push(...changelogs.writes);
|
|
82
|
+
const previewFiles = [];
|
|
83
|
+
if (withReleaseNotes === true && config.changelogJson.enabled && changelogJsonFiles.length > 0) {
|
|
84
|
+
const previews = planReleaseNotesPreviews({
|
|
83
85
|
workspacePath: ROOT_CHANGELOG_PATH,
|
|
84
86
|
tag: newTag,
|
|
85
|
-
|
|
86
|
-
sectionOrder,
|
|
87
|
-
dryRun,
|
|
87
|
+
entries: changelogs.entries,
|
|
88
|
+
sectionOrder: deriveSectionOrder(workTypes),
|
|
88
89
|
});
|
|
90
|
+
writes.push(...previews.writes);
|
|
91
|
+
warnings.push(...previews.warnings);
|
|
92
|
+
previewFiles.push(...previews.writes.map((write) => write.path));
|
|
89
93
|
}
|
|
90
94
|
tags.push(newTag);
|
|
91
95
|
modifiedFiles.push(ROOT_PACKAGE_FILE, ...changelogFiles, ...changelogJsonFiles);
|
|
@@ -97,10 +101,13 @@ export function releasePrepareProject(args) {
|
|
|
97
101
|
currentVersion: bump.currentVersion,
|
|
98
102
|
newVersion: bump.newVersion,
|
|
99
103
|
tag: newTag,
|
|
100
|
-
bumpedFiles: bump.
|
|
104
|
+
bumpedFiles: bump.writes.map((write) => write.path),
|
|
101
105
|
changelogFiles,
|
|
102
106
|
commits,
|
|
103
107
|
};
|
|
108
|
+
if (previewFiles.length > 0) {
|
|
109
|
+
result.previewFiles = previewFiles;
|
|
110
|
+
}
|
|
104
111
|
if (tag !== undefined) {
|
|
105
112
|
result.previousTag = tag;
|
|
106
113
|
}
|
|
@@ -120,10 +127,11 @@ function resolveOptionalOverrideArgs(args) {
|
|
|
120
127
|
rootOverrides: args.rootOverrides ?? new Map(),
|
|
121
128
|
overrideWarnings: args.overrideWarnings ?? [],
|
|
122
129
|
globalMatchedRootKeys: args.globalMatchedRootKeys ?? new Set(),
|
|
130
|
+
warnings: args.warnings ?? [],
|
|
123
131
|
};
|
|
124
132
|
}
|
|
125
|
-
function
|
|
126
|
-
const { config, project, commits, contributingPaths, newTag, newVersion,
|
|
133
|
+
function planProjectChangelogs(args) {
|
|
134
|
+
const { config, project, commits, contributingPaths, newTag, newVersion, rootOverrides, overrideWarnings, globalMatchedRootKeys, } = args;
|
|
127
135
|
const isEmptyRange = commits.length === 0;
|
|
128
136
|
const today = new Date().toISOString().slice(0, 10);
|
|
129
137
|
const tagPattern = buildTagPattern([project.tagPrefix]);
|
|
@@ -143,25 +151,13 @@ function writeProjectChangelogs(args) {
|
|
|
143
151
|
const renderEntries = isEmptyRange
|
|
144
152
|
? mergeChangelogEntriesWithDisk(changelogJsonPath, applied.entries)
|
|
145
153
|
: applied.entries;
|
|
146
|
-
|
|
147
|
-
if (isEmptyRange) {
|
|
148
|
-
writeChangelogJson(changelogJsonPath, renderEntries);
|
|
149
|
-
}
|
|
150
|
-
else {
|
|
151
|
-
writeChangelogJson(changelogJsonPath, applied.entries);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
const changelogFiles = [
|
|
155
|
-
writeChangelogMarkdown({
|
|
156
|
-
changelogPath: ROOT_CHANGELOG_PATH,
|
|
157
|
-
entries: renderEntries,
|
|
158
|
-
sectionOrder,
|
|
159
|
-
dryRun,
|
|
160
|
-
}),
|
|
161
|
-
];
|
|
154
|
+
const writes = [];
|
|
162
155
|
const changelogJsonFiles = [];
|
|
163
156
|
if (config.changelogJson.enabled) {
|
|
157
|
+
writes.push({ path: changelogJsonPath, content: renderChangelogJson(renderEntries) });
|
|
164
158
|
changelogJsonFiles.push(changelogJsonPath);
|
|
165
159
|
}
|
|
166
|
-
|
|
160
|
+
const changelogFile = joinPath(ROOT_CHANGELOG_PATH, 'CHANGELOG.md');
|
|
161
|
+
writes.push({ path: changelogFile, content: renderChangelogMarkdown(renderEntries, { sectionOrder }) });
|
|
162
|
+
return { changelogFiles: [changelogFile], changelogJsonFiles, entries: renderEntries, writes };
|
|
167
163
|
}
|
|
@@ -3,10 +3,3 @@ export interface RenderChangelogMarkdownOptions {
|
|
|
3
3
|
sectionOrder?: string[];
|
|
4
4
|
}
|
|
5
5
|
export declare function renderChangelogMarkdown(entries: ChangelogEntry[], options?: RenderChangelogMarkdownOptions): string;
|
|
6
|
-
export interface WriteChangelogMarkdownParams {
|
|
7
|
-
changelogPath: string;
|
|
8
|
-
entries: ChangelogEntry[];
|
|
9
|
-
sectionOrder?: string[];
|
|
10
|
-
dryRun?: boolean;
|
|
11
|
-
}
|
|
12
|
-
export declare function writeChangelogMarkdown(params: WriteChangelogMarkdownParams): string;
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import { dirname, join as joinPath } from 'node:path';
|
|
3
1
|
import { renderReleaseNotesMulti } from "./renderReleaseNotes.js";
|
|
4
2
|
const CHANGELOG_HEADER = `# Changelog
|
|
5
3
|
|
|
@@ -15,14 +13,3 @@ export function renderChangelogMarkdown(entries, options) {
|
|
|
15
13
|
parts.push(CHANGELOG_FOOTER);
|
|
16
14
|
return parts.join('\n\n') + '\n';
|
|
17
15
|
}
|
|
18
|
-
export function writeChangelogMarkdown(params) {
|
|
19
|
-
const { changelogPath, entries, sectionOrder, dryRun = false } = params;
|
|
20
|
-
const filePath = joinPath(changelogPath, 'CHANGELOG.md');
|
|
21
|
-
if (dryRun) {
|
|
22
|
-
return filePath;
|
|
23
|
-
}
|
|
24
|
-
const rendered = renderChangelogMarkdown(entries, sectionOrder !== undefined ? { sectionOrder } : undefined);
|
|
25
|
-
mkdirSync(dirname(filePath), { recursive: true });
|
|
26
|
-
writeFileSync(filePath, rendered, 'utf8');
|
|
27
|
-
return filePath;
|
|
28
|
-
}
|
|
@@ -1,2 +1,6 @@
|
|
|
1
1
|
import type { PrepareResult } from './types.js';
|
|
2
|
-
export
|
|
2
|
+
export interface ReportPrepareOptions {
|
|
3
|
+
applied: boolean;
|
|
4
|
+
formatError?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function reportPrepare(plan: PrepareResult, options: ReportPrepareOptions): string;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { bold, dim, sectionHeader } from "./format.js";
|
|
2
|
-
export function reportPrepare(
|
|
3
|
-
const isMultiWorkspace =
|
|
2
|
+
export function reportPrepare(plan, options) {
|
|
3
|
+
const isMultiWorkspace = plan.workspaces.some((w) => w.name !== undefined) || plan.project !== undefined;
|
|
4
4
|
if (isMultiWorkspace) {
|
|
5
|
-
return formatMultiWorkspace(
|
|
5
|
+
return formatMultiWorkspace(plan, options);
|
|
6
6
|
}
|
|
7
|
-
return formatSingleWorkspace(
|
|
7
|
+
return formatSingleWorkspace(plan, options);
|
|
8
8
|
}
|
|
9
|
-
function formatSingleWorkspace(result) {
|
|
9
|
+
function formatSingleWorkspace(result, options) {
|
|
10
|
+
const dryRun = !options.applied;
|
|
10
11
|
const lines = [];
|
|
11
12
|
const workspace = result.workspaces[0];
|
|
12
13
|
if (workspace === undefined) {
|
|
@@ -41,22 +42,25 @@ function formatSingleWorkspace(result) {
|
|
|
41
42
|
else if (workspace.releaseType !== undefined) {
|
|
42
43
|
lines.push(`š¦ ${workspace.currentVersion} ā ${bold(workspace.newVersion)} (${workspace.releaseType})`);
|
|
43
44
|
}
|
|
44
|
-
formatBumpFiles(lines, workspace,
|
|
45
|
+
formatBumpFiles(lines, workspace, dryRun);
|
|
45
46
|
lines.push(dim('Generating changelogs...'));
|
|
46
|
-
formatChangelogFiles(lines, workspace,
|
|
47
|
-
|
|
47
|
+
formatChangelogFiles(lines, workspace, dryRun);
|
|
48
|
+
formatPreviewFiles(lines, workspace, dryRun);
|
|
49
|
+
formatFormatCommand(lines, result, options);
|
|
50
|
+
formatWarnings(lines, result);
|
|
48
51
|
lines.push(`ā
Release preparation complete.`, ` š·ļø ${bold(workspace.tag)}`);
|
|
49
52
|
return lines.join('\n');
|
|
50
53
|
}
|
|
51
|
-
function formatMultiWorkspace(result) {
|
|
54
|
+
function formatMultiWorkspace(result, options) {
|
|
55
|
+
const dryRun = !options.applied;
|
|
52
56
|
const lines = [];
|
|
53
57
|
for (const workspace of result.workspaces) {
|
|
54
|
-
formatWorkspaceSection(lines, workspace,
|
|
58
|
+
formatWorkspaceSection(lines, workspace, dryRun);
|
|
55
59
|
}
|
|
56
60
|
if (result.project !== undefined) {
|
|
57
|
-
formatProjectSection(lines, result.project,
|
|
61
|
+
formatProjectSection(lines, result.project, dryRun);
|
|
58
62
|
}
|
|
59
|
-
formatFormatCommand(lines, result);
|
|
63
|
+
formatFormatCommand(lines, result, options);
|
|
60
64
|
formatWarnings(lines, result);
|
|
61
65
|
if (result.tags.length > 0) {
|
|
62
66
|
lines.push(`\nā
Release preparation complete.`);
|
|
@@ -104,6 +108,7 @@ function formatProjectSection(lines, project, dryRun) {
|
|
|
104
108
|
lines.push(dim(` Generating changelog: ${file}`));
|
|
105
109
|
}
|
|
106
110
|
}
|
|
111
|
+
formatPreviewFiles(lines, project, dryRun, ' ');
|
|
107
112
|
lines.push(` š·ļø ${bold(tag)}`);
|
|
108
113
|
}
|
|
109
114
|
function formatProjectUnparseable(lines, project) {
|
|
@@ -141,6 +146,7 @@ function formatWorkspaceSection(lines, workspace, dryRun) {
|
|
|
141
146
|
formatBumpFiles(lines, workspace, dryRun, ' ');
|
|
142
147
|
lines.push(dim(' Generating changelogs...'));
|
|
143
148
|
formatChangelogFiles(lines, workspace, dryRun, ' ');
|
|
149
|
+
formatPreviewFiles(lines, workspace, dryRun, ' ');
|
|
144
150
|
lines.push(` š·ļø ${bold(workspace.tag)}`);
|
|
145
151
|
}
|
|
146
152
|
function formatCommitSummary(lines, workspace, propagatedFrom, isPropagatedOnly) {
|
|
@@ -195,6 +201,17 @@ function formatChangelogFiles(lines, workspace, dryRun, indent = '') {
|
|
|
195
201
|
}
|
|
196
202
|
}
|
|
197
203
|
}
|
|
204
|
+
function formatPreviewFiles(lines, release, dryRun, indent = '') {
|
|
205
|
+
const previewFiles = release.previewFiles ?? [];
|
|
206
|
+
for (const file of previewFiles) {
|
|
207
|
+
if (dryRun) {
|
|
208
|
+
lines.push(dim(`${indent} [dry-run] Would write ${file}`));
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
lines.push(dim(`${indent} Wrote ${file}`));
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
198
215
|
function formatUnparseableWarning(lines, workspace, indent = '') {
|
|
199
216
|
const unparseable = workspace.unparseableCommits;
|
|
200
217
|
if (unparseable === undefined || unparseable.length === 0) {
|
|
@@ -240,14 +257,17 @@ function formatWarnings(lines, result) {
|
|
|
240
257
|
lines.push(`ā ļø ${warning}`);
|
|
241
258
|
}
|
|
242
259
|
}
|
|
243
|
-
function formatFormatCommand(lines, result) {
|
|
260
|
+
function formatFormatCommand(lines, result, options) {
|
|
244
261
|
if (result.formatCommand === undefined) {
|
|
245
262
|
return;
|
|
246
263
|
}
|
|
247
|
-
if (
|
|
248
|
-
lines.push(dim(`\n Running format command: ${result.formatCommand.command}`));
|
|
249
|
-
}
|
|
250
|
-
else {
|
|
264
|
+
if (!options.applied) {
|
|
251
265
|
lines.push(dim(`\n [dry-run] Would run format command: ${result.formatCommand.command}`));
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
if (options.formatError === undefined) {
|
|
269
|
+
lines.push(dim(`\n Running format command: ${result.formatCommand.command}`));
|
|
270
|
+
return;
|
|
252
271
|
}
|
|
272
|
+
lines.push(`\n ā ļø Format command failed: ${result.formatCommand.command}`, ` ${options.formatError}`);
|
|
253
273
|
}
|
|
@@ -10,7 +10,8 @@ import { checkRetiredSyncLabelsConfig } from "./retiredConfig.js";
|
|
|
10
10
|
export const LABELS_OUTPUT_PATH = '.github/labels.yaml';
|
|
11
11
|
export function formatLabelsYaml(labels, presetHashes) {
|
|
12
12
|
const headerLines = ['# Generated by release-kit sync-labels ā do not edit.', `# Source: ${CONFIG_FILE_PATH}`];
|
|
13
|
-
|
|
13
|
+
const sortedPresetHashes = [...presetHashes].sort(([a], [b]) => a.localeCompare(b));
|
|
14
|
+
for (const [name, hash] of sortedPresetHashes) {
|
|
14
15
|
headerLines.push(`# ${name} preset hash: ${hash}`);
|
|
15
16
|
}
|
|
16
17
|
const declared = labels.map((label) => ({ ...label, description: label.description ?? '' }));
|
|
@@ -50,7 +51,8 @@ export async function generateCommand({ check = false } = {}) {
|
|
|
50
51
|
return 1;
|
|
51
52
|
}
|
|
52
53
|
const presetHashes = new Map();
|
|
53
|
-
|
|
54
|
+
const presetNames = repoLabels.extends ?? [];
|
|
55
|
+
for (const presetName of presetNames) {
|
|
54
56
|
presetHashes.set(presetName, hashPresetFile(presetName));
|
|
55
57
|
}
|
|
56
58
|
const content = formatLabelsYaml(labels, presetHashes);
|
|
@@ -23,7 +23,7 @@ export function loadPreset(presetName) {
|
|
|
23
23
|
}
|
|
24
24
|
catch (error) {
|
|
25
25
|
const message = error instanceof Error ? error.message : String(error);
|
|
26
|
-
throw new Error(`Failed to read preset "${presetName}": ${message}
|
|
26
|
+
throw new Error(`Failed to read preset "${presetName}": ${message}`, { cause: error });
|
|
27
27
|
}
|
|
28
28
|
const parsed = parse(content);
|
|
29
29
|
if (!Array.isArray(parsed)) {
|
|
@@ -34,13 +34,13 @@ export function loadPreset(presetName) {
|
|
|
34
34
|
if (!isRecord(entry)) {
|
|
35
35
|
throw new Error(`Preset "${presetName}" contains an invalid label entry: ${JSON.stringify(entry)}`);
|
|
36
36
|
}
|
|
37
|
-
const { description } = entry;
|
|
38
|
-
if (typeof
|
|
39
|
-
typeof
|
|
37
|
+
const { color, description, name } = entry;
|
|
38
|
+
if (typeof name !== 'string' ||
|
|
39
|
+
typeof color !== 'string' ||
|
|
40
40
|
(description !== undefined && typeof description !== 'string')) {
|
|
41
41
|
throw new TypeError(`Preset "${presetName}" contains a label with invalid fields: ${JSON.stringify(entry)}`);
|
|
42
42
|
}
|
|
43
|
-
labels.push({ name
|
|
43
|
+
labels.push({ name, color, ...(description !== undefined && { description }) });
|
|
44
44
|
}
|
|
45
45
|
return labels;
|
|
46
46
|
}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { loadPreset } from "./presets.js";
|
|
2
2
|
export function resolveLabels(config) {
|
|
3
3
|
const resolved = new Map();
|
|
4
|
-
|
|
4
|
+
const presetNames = config.extends ?? [];
|
|
5
|
+
for (const presetName of presetNames) {
|
|
5
6
|
for (const label of loadPreset(presetName)) {
|
|
6
7
|
resolved.set(label.name, label);
|
|
7
8
|
}
|
|
8
9
|
}
|
|
9
|
-
|
|
10
|
+
const labelEntries = Object.entries(config.labels ?? {});
|
|
11
|
+
for (const [name, spec] of labelEntries) {
|
|
10
12
|
if (spec === null) {
|
|
11
13
|
if (!resolved.has(name)) {
|
|
12
14
|
throw new Error(`Label '${name}' is set to null (remove), but no preset in 'extends' defines it. Fix the name or delete the entry.`);
|
|
@@ -21,7 +23,7 @@ export function resolveLabels(config) {
|
|
|
21
23
|
});
|
|
22
24
|
}
|
|
23
25
|
}
|
|
24
|
-
return sortLabels(
|
|
26
|
+
return sortLabels(resolved.values().toArray());
|
|
25
27
|
}
|
|
26
28
|
function sortLabels(labels) {
|
|
27
29
|
return [...labels].sort((a, b) => a.name.localeCompare(b.name));
|
|
@@ -20,7 +20,7 @@ function extractLocalSchemaUrl(content) {
|
|
|
20
20
|
if (!isRecord(parsed)) {
|
|
21
21
|
return undefined;
|
|
22
22
|
}
|
|
23
|
-
const schema = parsed
|
|
23
|
+
const schema = parsed['$schema'];
|
|
24
24
|
return typeof schema === 'string' ? schema : undefined;
|
|
25
25
|
}
|
|
26
26
|
export async function syncWorkTypes(dependencies = {}) {
|