@williamthorsen/release-kit 15.0.3 → 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 +66 -0
- package/.readyup/kits/default.js +13 -13
- package/.readyup/kits/npm-auto-publish.js +4 -4
- package/.readyup/manifest.json +12 -12
- package/CHANGELOG.md +19 -0
- package/README.md +7 -1
- package/dist/esm/applyChangelogOverrides.js +6 -6
- 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 +3 -3
- 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 +8 -8
- 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 +6 -6
- package/dist/esm/enumerateReleaseWindows.d.ts +1 -1
- package/dist/esm/enumerateReleaseWindows.js +7 -7
- 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 +5 -3
- 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 +15 -15
- 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 +14 -12
- 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 +19 -19
- 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 +2 -2
- package/dist/esm/readChangelogSections.d.ts +1 -1
- package/dist/esm/readChangelogSections.js +16 -16
- package/dist/esm/releasePlan.js +25 -25
- 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 +17 -15
- 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 +15 -15
- package/dist/esm/sync-labels/presets.js +3 -3
- package/dist/esm/sync-labels/resolveLabels.js +13 -13
- package/dist/esm/sync-labels/templates.d.ts +2 -2
- package/dist/esm/sync-labels/templates.js +1 -1
- 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 +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export function findTransitiveDependents(graph, startDirs) {
|
|
2
|
-
const
|
|
3
|
-
const queue = [...
|
|
2
|
+
const foundDirs = new Set(startDirs);
|
|
3
|
+
const queue = [...foundDirs];
|
|
4
4
|
while (queue.length > 0) {
|
|
5
5
|
const dir = queue.shift();
|
|
6
6
|
if (dir === undefined)
|
|
@@ -10,11 +10,11 @@ export function findTransitiveDependents(graph, startDirs) {
|
|
|
10
10
|
continue;
|
|
11
11
|
const dependents = graph.dependentsOf.get(packageName) ?? [];
|
|
12
12
|
for (const dependent of dependents) {
|
|
13
|
-
if (
|
|
13
|
+
if (foundDirs.has(dependent.id))
|
|
14
14
|
continue;
|
|
15
|
-
|
|
15
|
+
foundDirs.add(dependent.id);
|
|
16
16
|
queue.push(dependent.id);
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
|
-
return
|
|
19
|
+
return foundDirs;
|
|
20
20
|
}
|
|
@@ -28,11 +28,11 @@ function findCommitUnroutedScopes(commit, windowDirs, unreadDirs, isRootReserved
|
|
|
28
28
|
for (const [index, entry] of reading.entries.entries()) {
|
|
29
29
|
const scopes = new Set(entry.scopes);
|
|
30
30
|
for (const scope of scopes) {
|
|
31
|
-
const
|
|
32
|
-
const isRouted =
|
|
33
|
-
windowDirs.has(
|
|
34
|
-
unreadDirs.has(
|
|
35
|
-
(
|
|
31
|
+
const resolvedScope = scopeAliases[scope] ?? scope;
|
|
32
|
+
const isRouted = resolvedScope === '*' ||
|
|
33
|
+
windowDirs.has(resolvedScope) ||
|
|
34
|
+
unreadDirs.has(resolvedScope) ||
|
|
35
|
+
(resolvedScope === 'root' && isRootReserved);
|
|
36
36
|
if (!isRouted) {
|
|
37
37
|
findings.push({ commitHash: commit.hash, commitSubject: commit.subject, entryPosition: index + 1, scope });
|
|
38
38
|
}
|
|
@@ -41,17 +41,17 @@ function findCommitUnroutedScopes(commit, windowDirs, unreadDirs, isRootReserved
|
|
|
41
41
|
return findings;
|
|
42
42
|
}
|
|
43
43
|
function indexCommits(windows) {
|
|
44
|
-
const
|
|
44
|
+
const commitsByHash = new Map();
|
|
45
45
|
for (const window of windows) {
|
|
46
46
|
for (const commit of window.commits) {
|
|
47
|
-
const
|
|
48
|
-
if (
|
|
49
|
-
|
|
47
|
+
const indexedEntry = commitsByHash.get(commit.hash);
|
|
48
|
+
if (indexedEntry === undefined) {
|
|
49
|
+
commitsByHash.set(commit.hash, { commit, windowDirs: new Set([window.dir]) });
|
|
50
50
|
}
|
|
51
51
|
else {
|
|
52
|
-
|
|
52
|
+
indexedEntry.windowDirs.add(window.dir);
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
|
-
return
|
|
56
|
+
return commitsByHash;
|
|
57
57
|
}
|
package/dist/esm/format.d.ts
CHANGED
|
@@ -3,4 +3,4 @@ export declare function bold(text: string, stream?: NodeJS.WritableStream): stri
|
|
|
3
3
|
/** Styles text dim, returning it unstyled for a stream that cannot render color. */
|
|
4
4
|
export declare function dim(text: string, stream?: NodeJS.WritableStream): string;
|
|
5
5
|
/** Renders a section header for separating workspaces in CLI output. */
|
|
6
|
-
export declare function
|
|
6
|
+
export declare function renderSectionHeader(name: string): string;
|
package/dist/esm/format.js
CHANGED
|
@@ -5,6 +5,6 @@ export function bold(text, stream = process.stdout) {
|
|
|
5
5
|
export function dim(text, stream = process.stdout) {
|
|
6
6
|
return styleText('dim', text, { stream });
|
|
7
7
|
}
|
|
8
|
-
export function
|
|
8
|
+
export function renderSectionHeader(name) {
|
|
9
9
|
return `━━━ ${name} ━━━`;
|
|
10
10
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { type OutputStyle } from '@williamthorsen/nmr-core';
|
|
2
2
|
import type { ReleasedPackageResult } from './types.js';
|
|
3
3
|
/** Appends bump file detail lines. */
|
|
4
|
-
export declare function formatBumpFiles(lines: string[], workspace: Pick<ReleasedPackageResult, 'bumpedFiles'>,
|
|
4
|
+
export declare function formatBumpFiles(lines: string[], workspace: Pick<ReleasedPackageResult, 'bumpedFiles'>, isDryRun: boolean, indent?: string): void;
|
|
5
5
|
/**
|
|
6
6
|
* Appends a line per generated changelog file, each followed by the versions kept from the existing changelog and a
|
|
7
7
|
* warning naming the sections dropped for lacking a version, then a line per removed changelog archive file.
|
|
8
8
|
*/
|
|
9
|
-
export declare function formatChangelogFiles(lines: string[], release: Pick<ReleasedPackageResult, 'changelogFiles' | 'changelogPreservation' | 'removedChangelogFiles'>,
|
|
9
|
+
export declare function formatChangelogFiles(lines: string[], release: Pick<ReleasedPackageResult, 'changelogFiles' | 'changelogPreservation' | 'removedChangelogFiles'>, isDryRun: boolean, style: OutputStyle, indent?: string): void;
|
|
10
10
|
/** Appends release-notes preview file lines, which are present only under `--with-release-notes`. */
|
|
11
|
-
export declare function formatPreviewFiles(lines: string[], release: Pick<ReleasedPackageResult, 'previewFiles'>,
|
|
11
|
+
export declare function formatPreviewFiles(lines: string[], release: Pick<ReleasedPackageResult, 'previewFiles'>, isDryRun: boolean, indent?: string): void;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { formatStatusLine } from '@williamthorsen/nmr-core';
|
|
2
2
|
import { dim } from "./format.js";
|
|
3
|
-
export function formatBumpFiles(lines, workspace,
|
|
3
|
+
export function formatBumpFiles(lines, workspace, isDryRun, indent = '') {
|
|
4
4
|
for (const file of workspace.bumpedFiles) {
|
|
5
|
-
if (
|
|
5
|
+
if (isDryRun) {
|
|
6
6
|
lines.push(dim(`${indent} [dry-run] Would bump ${file}`));
|
|
7
7
|
}
|
|
8
8
|
else {
|
|
@@ -10,9 +10,9 @@ export function formatBumpFiles(lines, workspace, dryRun, indent = '') {
|
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
|
-
export function formatChangelogFiles(lines, release,
|
|
13
|
+
export function formatChangelogFiles(lines, release, isDryRun, style, indent = '') {
|
|
14
14
|
for (const file of release.changelogFiles) {
|
|
15
|
-
if (
|
|
15
|
+
if (isDryRun) {
|
|
16
16
|
lines.push(dim(`${indent} [dry-run] Would generate changelog: ${file}`));
|
|
17
17
|
}
|
|
18
18
|
else {
|
|
@@ -25,16 +25,16 @@ export function formatChangelogFiles(lines, release, dryRun, style, indent = '')
|
|
|
25
25
|
if (preservation.preservedVersions.length > 0) {
|
|
26
26
|
lines.push(dim(`${indent} Kept from the existing changelog: ${preservation.preservedVersions.join(', ')}`));
|
|
27
27
|
}
|
|
28
|
-
const
|
|
29
|
-
if (
|
|
28
|
+
const droppedHeadings = preservation.droppedUnversionedHeadings;
|
|
29
|
+
if (droppedHeadings.length === 0) {
|
|
30
30
|
continue;
|
|
31
31
|
}
|
|
32
|
-
const message = `Dropped ${
|
|
32
|
+
const message = `Dropped ${droppedHeadings.length} section${droppedHeadings.length === 1 ? '' : 's'} without a version: ${droppedHeadings.join(', ')}`;
|
|
33
33
|
lines.push(`${indent} ${formatStatusLine(style, 'warning', message)}`);
|
|
34
34
|
}
|
|
35
35
|
const removedFiles = release.removedChangelogFiles ?? [];
|
|
36
36
|
for (const file of removedFiles) {
|
|
37
|
-
if (
|
|
37
|
+
if (isDryRun) {
|
|
38
38
|
lines.push(dim(`${indent} [dry-run] Would remove changelog: ${file}`));
|
|
39
39
|
}
|
|
40
40
|
else {
|
|
@@ -42,10 +42,10 @@ export function formatChangelogFiles(lines, release, dryRun, style, indent = '')
|
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
|
-
export function formatPreviewFiles(lines, release,
|
|
45
|
+
export function formatPreviewFiles(lines, release, isDryRun, indent = '') {
|
|
46
46
|
const previewFiles = release.previewFiles ?? [];
|
|
47
47
|
for (const file of previewFiles) {
|
|
48
|
-
if (
|
|
48
|
+
if (isDryRun) {
|
|
49
49
|
lines.push(dim(`${indent} [dry-run] Would write ${file}`));
|
|
50
50
|
}
|
|
51
51
|
else {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { formatStatusLine, truncateToWidth } from '@williamthorsen/nmr-core';
|
|
2
|
-
const
|
|
2
|
+
const SUBJECT_BUDGET_COLUMNS = 72;
|
|
3
3
|
export function formatChangeRecordWarnings(lines, release, style, indent = '') {
|
|
4
4
|
const { malformedBlocks = [], undeclaredEntryTypes = [], unroutedEntryScopes = [] } = release;
|
|
5
5
|
if (malformedBlocks.length > 0) {
|
|
@@ -45,13 +45,13 @@ export function formatPolicyViolations(lines, violations, style, indent = '') {
|
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
export function formatUnparseableWarning(lines, release, style, indent = '') {
|
|
48
|
-
const
|
|
49
|
-
if (
|
|
48
|
+
const unparseableCommits = release.unparseableCommits;
|
|
49
|
+
if (unparseableCommits === undefined || unparseableCommits.length === 0) {
|
|
50
50
|
return;
|
|
51
51
|
}
|
|
52
|
-
const count =
|
|
52
|
+
const count = unparseableCommits.length;
|
|
53
53
|
lines.push(`${indent} ${formatStatusLine(style, 'warning', `${count} commit${count === 1 ? '' : 's'} could not be parsed`)}`);
|
|
54
|
-
for (const commit of
|
|
54
|
+
for (const commit of unparseableCommits) {
|
|
55
55
|
const shortHash = commit.hash.slice(0, 7);
|
|
56
56
|
const truncatedSubject = truncateSubject(commit.subject);
|
|
57
57
|
lines.push(`${indent} · ${shortHash} ${truncatedSubject}`);
|
|
@@ -68,5 +68,5 @@ export function formatWarnings(lines, result, style) {
|
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
function truncateSubject(subject) {
|
|
71
|
-
return truncateToWidth(subject, { width:
|
|
71
|
+
return truncateToWidth(subject, { width: SUBJECT_BUDGET_COLUMNS });
|
|
72
72
|
}
|
|
@@ -15,8 +15,8 @@ function hasPrettierKeyInPackageJson(packageJsonPath) {
|
|
|
15
15
|
return false;
|
|
16
16
|
}
|
|
17
17
|
try {
|
|
18
|
-
const
|
|
19
|
-
return isRecord(
|
|
18
|
+
const parsedJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
|
19
|
+
return isRecord(parsedJson) && 'prettier' in parsedJson;
|
|
20
20
|
}
|
|
21
21
|
catch {
|
|
22
22
|
return false;
|
package/dist/esm/init/checks.js
CHANGED
|
@@ -24,9 +24,11 @@ export function usesPnpm() {
|
|
|
24
24
|
if (existsSync('pnpm-lock.yaml')) {
|
|
25
25
|
return { ok: true };
|
|
26
26
|
}
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
if (
|
|
27
|
+
const manifestJson = readFileSync('package.json', 'utf8');
|
|
28
|
+
const packageJson = parseJsonRecord(manifestJson);
|
|
29
|
+
if (packageJson !== undefined &&
|
|
30
|
+
typeof packageJson['packageManager'] === 'string' &&
|
|
31
|
+
packageJson['packageManager'].startsWith('pnpm')) {
|
|
30
32
|
return { ok: true };
|
|
31
33
|
}
|
|
32
34
|
return {
|
|
@@ -5,9 +5,9 @@ export function detectRepoType() {
|
|
|
5
5
|
return 'monorepo';
|
|
6
6
|
}
|
|
7
7
|
if (existsSync('package.json')) {
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
if (
|
|
8
|
+
const manifestJson = readFileSync('package.json', 'utf8');
|
|
9
|
+
const packageJson = parseJsonRecord(manifestJson);
|
|
10
|
+
if (packageJson !== undefined && Array.isArray(packageJson['workspaces'])) {
|
|
11
11
|
return 'monorepo';
|
|
12
12
|
}
|
|
13
13
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { type StreamStyles } from '@williamthorsen/nmr-core';
|
|
2
2
|
interface InitOptions {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
isDryRun: boolean;
|
|
4
|
+
shouldForce: boolean;
|
|
5
5
|
styles: StreamStyles;
|
|
6
|
-
|
|
6
|
+
shouldScaffoldConfig: boolean;
|
|
7
7
|
}
|
|
8
8
|
/** Runs the eligibility checks, stopping at the first failure, and reports whether all passed. */
|
|
9
9
|
export declare function checkEligibility(styles: StreamStyles): boolean;
|
|
10
10
|
/** Runs the `release-kit init` command and returns the process exit code. */
|
|
11
|
-
export declare function initCommand({
|
|
11
|
+
export declare function initCommand({ isDryRun, shouldForce, styles, shouldScaffoldConfig }: InitOptions): number;
|
|
12
12
|
export {};
|
|
@@ -10,8 +10,8 @@ export function checkEligibility(styles) {
|
|
|
10
10
|
runRequiredCheck('package.json found', hasPackageJson(), styles) &&
|
|
11
11
|
runRequiredCheck('pnpm detected', usesPnpm(), styles));
|
|
12
12
|
}
|
|
13
|
-
export function initCommand({
|
|
14
|
-
if (
|
|
13
|
+
export function initCommand({ isDryRun, shouldForce, styles, shouldScaffoldConfig }) {
|
|
14
|
+
if (isDryRun) {
|
|
15
15
|
console.info('[dry-run mode]');
|
|
16
16
|
}
|
|
17
17
|
let eligible;
|
|
@@ -43,25 +43,25 @@ export function initCommand({ dryRun, force, styles, withConfig }) {
|
|
|
43
43
|
}
|
|
44
44
|
let results;
|
|
45
45
|
try {
|
|
46
|
-
results = scaffoldFiles({ repoType,
|
|
46
|
+
results = scaffoldFiles({ repoType, isDryRun, shouldOverwrite: shouldForce, publishable, shouldScaffoldConfig });
|
|
47
47
|
}
|
|
48
48
|
catch (error) {
|
|
49
49
|
printError(`Failed to scaffold files: ${describeError(error)}`, styles.stderr);
|
|
50
50
|
return 1;
|
|
51
51
|
}
|
|
52
52
|
for (const result of results) {
|
|
53
|
-
reportWriteResult(result,
|
|
53
|
+
reportWriteResult(result, isDryRun, styles);
|
|
54
54
|
}
|
|
55
55
|
if (results.some((r) => r.outcome === 'failed')) {
|
|
56
56
|
return 1;
|
|
57
57
|
}
|
|
58
58
|
printStep('Next steps');
|
|
59
|
-
console.info(`\n${formatNextSteps({ publishable,
|
|
59
|
+
console.info(`\n${formatNextSteps({ publishable, shouldScaffoldConfig })}\n`);
|
|
60
60
|
return 0;
|
|
61
61
|
}
|
|
62
|
-
function formatNextSteps({ publishable,
|
|
62
|
+
function formatNextSteps({ publishable, shouldScaffoldConfig, }) {
|
|
63
63
|
const steps = [
|
|
64
|
-
|
|
64
|
+
shouldScaffoldConfig
|
|
65
65
|
? '(Optional) Customize .config/release-kit.config.ts.'
|
|
66
66
|
: '(Optional) Run again with --with-config to scaffold config files.',
|
|
67
67
|
...(publishable ? ['If this is a private repo, remove provenance: true from .github/workflows/publish.yaml.'] : []),
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Parses a JSON string, returning the result if it is a plain object and `undefined` otherwise. */
|
|
2
|
-
export declare function parseJsonRecord(
|
|
2
|
+
export declare function parseJsonRecord(jsonText: string): Record<string, unknown> | undefined;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { isRecord } from "../typeGuards.js";
|
|
2
|
-
export function parseJsonRecord(
|
|
3
|
-
let
|
|
2
|
+
export function parseJsonRecord(jsonText) {
|
|
3
|
+
let parsedJson;
|
|
4
4
|
try {
|
|
5
|
-
|
|
5
|
+
parsedJson = JSON.parse(jsonText);
|
|
6
6
|
}
|
|
7
7
|
catch {
|
|
8
8
|
return undefined;
|
|
9
9
|
}
|
|
10
|
-
return isRecord(
|
|
10
|
+
return isRecord(parsedJson) ? parsedJson : undefined;
|
|
11
11
|
}
|
|
@@ -2,15 +2,15 @@ import { type WriteResult } from '@williamthorsen/nmr-core';
|
|
|
2
2
|
import type { RepoType } from './detectRepoType.js';
|
|
3
3
|
interface ScaffoldOptions {
|
|
4
4
|
repoType: RepoType;
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
isDryRun: boolean;
|
|
6
|
+
shouldOverwrite: boolean;
|
|
7
7
|
publishable: boolean;
|
|
8
|
-
|
|
8
|
+
shouldScaffoldConfig: boolean;
|
|
9
9
|
}
|
|
10
10
|
export declare const CREATE_GITHUB_RELEASE_WORKFLOW_PATH = ".github/workflows/create-github-release.yaml";
|
|
11
11
|
export declare const PUBLISH_WORKFLOW_PATH = ".github/workflows/publish.yaml";
|
|
12
12
|
/** The workflows that act only on publishable packages, which a repo whose packages are all private does not get. */
|
|
13
13
|
export declare const PUBLISHING_WORKFLOW_PATHS: readonly [".github/workflows/create-github-release.yaml", ".github/workflows/publish.yaml"];
|
|
14
14
|
/** Scaffolds release-kit files for the target repo, returning a result for each file attempted. */
|
|
15
|
-
export declare function scaffoldFiles({ repoType,
|
|
15
|
+
export declare function scaffoldFiles({ repoType, isDryRun, shouldOverwrite, publishable, shouldScaffoldConfig, }: ScaffoldOptions): WriteResult[];
|
|
16
16
|
export {};
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
import { writeFileWithCheck } from '@williamthorsen/nmr-core';
|
|
2
|
-
import {
|
|
2
|
+
import { renderCreateGithubReleaseWorkflow, renderPublishWorkflow, renderReleaseConfigScript, renderReleaseWorkflow, } from "./templates.js";
|
|
3
3
|
export const CREATE_GITHUB_RELEASE_WORKFLOW_PATH = '.github/workflows/create-github-release.yaml';
|
|
4
4
|
export const PUBLISH_WORKFLOW_PATH = '.github/workflows/publish.yaml';
|
|
5
5
|
export const PUBLISHING_WORKFLOW_PATHS = [CREATE_GITHUB_RELEASE_WORKFLOW_PATH, PUBLISH_WORKFLOW_PATH];
|
|
6
|
-
export function scaffoldFiles({ repoType,
|
|
6
|
+
export function scaffoldFiles({ repoType, isDryRun, shouldOverwrite, publishable, shouldScaffoldConfig, }) {
|
|
7
7
|
const results = [];
|
|
8
8
|
if (publishable) {
|
|
9
|
-
results.push(writeFileWithCheck(CREATE_GITHUB_RELEASE_WORKFLOW_PATH,
|
|
10
|
-
isDryRun
|
|
11
|
-
shouldOverwrite
|
|
12
|
-
}), writeFileWithCheck(PUBLISH_WORKFLOW_PATH,
|
|
13
|
-
isDryRun
|
|
14
|
-
shouldOverwrite
|
|
9
|
+
results.push(writeFileWithCheck(CREATE_GITHUB_RELEASE_WORKFLOW_PATH, renderCreateGithubReleaseWorkflow(repoType), {
|
|
10
|
+
isDryRun,
|
|
11
|
+
shouldOverwrite,
|
|
12
|
+
}), writeFileWithCheck(PUBLISH_WORKFLOW_PATH, renderPublishWorkflow(repoType), {
|
|
13
|
+
isDryRun,
|
|
14
|
+
shouldOverwrite,
|
|
15
15
|
}));
|
|
16
16
|
}
|
|
17
|
-
results.push(writeFileWithCheck('.github/workflows/release.yaml',
|
|
18
|
-
isDryRun
|
|
19
|
-
shouldOverwrite
|
|
17
|
+
results.push(writeFileWithCheck('.github/workflows/release.yaml', renderReleaseWorkflow(repoType), {
|
|
18
|
+
isDryRun,
|
|
19
|
+
shouldOverwrite,
|
|
20
20
|
}));
|
|
21
|
-
if (
|
|
22
|
-
results.push(writeFileWithCheck('.config/release-kit.config.ts',
|
|
23
|
-
isDryRun
|
|
24
|
-
shouldOverwrite
|
|
21
|
+
if (shouldScaffoldConfig) {
|
|
22
|
+
results.push(writeFileWithCheck('.config/release-kit.config.ts', renderReleaseConfigScript(repoType), {
|
|
23
|
+
isDryRun,
|
|
24
|
+
shouldOverwrite,
|
|
25
25
|
}));
|
|
26
26
|
}
|
|
27
27
|
return results;
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import type { RepoType } from './detectRepoType.js';
|
|
2
|
-
/**
|
|
3
|
-
export declare function
|
|
2
|
+
/** Renders the `.config/release-kit.config.ts` starter config, with commented-out options to customize. */
|
|
3
|
+
export declare function renderReleaseConfigScript(repoType: RepoType): string;
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* Renders the publish.yaml GitHub Actions entry-point workflow.
|
|
6
6
|
*
|
|
7
7
|
* The caller's `permissions` block caps what the reusable workflow receives, so it must grant the `id-token: write`
|
|
8
|
-
* that OIDC publishing needs. `
|
|
8
|
+
* that OIDC publishing needs. `shouldGenerateProvenance: false` omits the provenance input, which a private repo cannot use.
|
|
9
9
|
*/
|
|
10
|
-
export declare function
|
|
11
|
-
|
|
10
|
+
export declare function renderPublishWorkflow(repoType: RepoType, { shouldGenerateProvenance }?: {
|
|
11
|
+
shouldGenerateProvenance?: boolean;
|
|
12
12
|
}): string;
|
|
13
|
-
/**
|
|
14
|
-
export declare function
|
|
15
|
-
/**
|
|
16
|
-
export declare function
|
|
13
|
+
/** Renders the create-github-release.yaml GitHub Actions caller workflow. */
|
|
14
|
+
export declare function renderCreateGithubReleaseWorkflow(repoType: RepoType): string;
|
|
15
|
+
/** Renders the release.yaml GitHub Actions workflow. */
|
|
16
|
+
export declare function renderReleaseWorkflow(repoType: RepoType): string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export function
|
|
1
|
+
export function renderReleaseConfigScript(repoType) {
|
|
2
2
|
if (repoType === 'monorepo') {
|
|
3
3
|
return `import { defineConfig } from '@williamthorsen/release-kit/config';
|
|
4
4
|
|
|
@@ -39,7 +39,7 @@ export default defineConfig({
|
|
|
39
39
|
});
|
|
40
40
|
`;
|
|
41
41
|
}
|
|
42
|
-
export function
|
|
42
|
+
export function renderPublishWorkflow(repoType, { shouldGenerateProvenance = true } = {}) {
|
|
43
43
|
const tagPattern = repoType === 'monorepo' ? "'*-v[0-9]*.[0-9]*.[0-9]*'" : "'v[0-9]*.[0-9]*.[0-9]*'";
|
|
44
44
|
return `# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
|
|
45
45
|
name: Publish
|
|
@@ -57,10 +57,10 @@ jobs:
|
|
|
57
57
|
publish:
|
|
58
58
|
uses: williamthorsen/node-monorepo-tools/.github/workflows/publish.reusable.yaml@workflow/publish-v1
|
|
59
59
|
with:
|
|
60
|
-
${
|
|
60
|
+
${shouldGenerateProvenance ? ' provenance: true\n' : ''} tags: \${{ github.ref_name }}
|
|
61
61
|
`;
|
|
62
62
|
}
|
|
63
|
-
export function
|
|
63
|
+
export function renderCreateGithubReleaseWorkflow(repoType) {
|
|
64
64
|
const tagPattern = repoType === 'monorepo' ? "'*-v[0-9]*.[0-9]*.[0-9]*'" : "'v[0-9]*.[0-9]*.[0-9]*'";
|
|
65
65
|
return `# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
|
|
66
66
|
name: Create GitHub release
|
|
@@ -80,7 +80,7 @@ jobs:
|
|
|
80
80
|
tag: \${{ github.ref_name }}
|
|
81
81
|
`;
|
|
82
82
|
}
|
|
83
|
-
export function
|
|
83
|
+
export function renderReleaseWorkflow(repoType) {
|
|
84
84
|
if (repoType === 'monorepo') {
|
|
85
85
|
return `# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
|
|
86
86
|
name: Release
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type StreamStyles } from '@williamthorsen/nmr-core';
|
|
2
2
|
interface UpdateTemplatesOptions {
|
|
3
|
-
|
|
3
|
+
isDryRun: boolean;
|
|
4
4
|
styles: StreamStyles;
|
|
5
5
|
}
|
|
6
6
|
/**
|
|
@@ -10,5 +10,5 @@ interface UpdateTemplatesOptions {
|
|
|
10
10
|
* `sync-labels.yaml` is refreshed only when it exists, as are the publishing workflows in a repo whose packages are
|
|
11
11
|
* all private. Config files are never read or written.
|
|
12
12
|
*/
|
|
13
|
-
export declare function updateTemplatesCommand({
|
|
13
|
+
export declare function updateTemplatesCommand({ isDryRun, styles }: UpdateTemplatesOptions): number;
|
|
14
14
|
export {};
|
|
@@ -7,10 +7,10 @@ import { hasProvenance } from "./hasProvenance.js";
|
|
|
7
7
|
import { formatPrivateWorkflowSkip, hasPublishablePackage } from "./hasPublishablePackage.js";
|
|
8
8
|
import { checkEligibility } from "./initCommand.js";
|
|
9
9
|
import { CREATE_GITHUB_RELEASE_WORKFLOW_PATH, PUBLISH_WORKFLOW_PATH, PUBLISHING_WORKFLOW_PATHS } from "./scaffold.js";
|
|
10
|
-
import {
|
|
10
|
+
import { renderCreateGithubReleaseWorkflow, renderPublishWorkflow, renderReleaseWorkflow } from "./templates.js";
|
|
11
11
|
const SYNC_LABELS_WORKFLOW_PATH = '.github/workflows/sync-labels.yaml';
|
|
12
|
-
export function updateTemplatesCommand({
|
|
13
|
-
if (
|
|
12
|
+
export function updateTemplatesCommand({ isDryRun, styles }) {
|
|
13
|
+
if (isDryRun) {
|
|
14
14
|
console.info('[dry-run mode]');
|
|
15
15
|
}
|
|
16
16
|
let eligible;
|
|
@@ -36,32 +36,34 @@ export function updateTemplatesCommand({ dryRun, styles }) {
|
|
|
36
36
|
printStep('Updating workflows');
|
|
37
37
|
let results;
|
|
38
38
|
try {
|
|
39
|
-
const { files,
|
|
40
|
-
for (const filePath of
|
|
39
|
+
const { files, skippedPaths } = buildManagedFiles(repoType, hasPublishablePackage());
|
|
40
|
+
for (const filePath of skippedPaths) {
|
|
41
41
|
printSkip(formatPrivateWorkflowSkip(filePath), styles.stdout);
|
|
42
42
|
}
|
|
43
|
-
results = files.map(([filePath, content]) => updateManagedFile(filePath, content, { isDryRun
|
|
43
|
+
results = files.map(([filePath, content]) => updateManagedFile(filePath, content, { isDryRun }));
|
|
44
44
|
}
|
|
45
45
|
catch (error) {
|
|
46
46
|
printError(`Failed to render workflows: ${describeError(error)}`, styles.stderr);
|
|
47
47
|
return 1;
|
|
48
48
|
}
|
|
49
49
|
for (const result of results) {
|
|
50
|
-
reportTemplateUpdate(result,
|
|
50
|
+
reportTemplateUpdate(result, isDryRun, styles);
|
|
51
51
|
}
|
|
52
52
|
return results.some((result) => result.outcome === 'failed') ? 1 : 0;
|
|
53
53
|
}
|
|
54
54
|
function buildManagedFiles(repoType, publishable) {
|
|
55
|
-
const
|
|
55
|
+
const skippedPaths = publishable
|
|
56
|
+
? []
|
|
57
|
+
: PUBLISHING_WORKFLOW_PATHS.filter((filePath) => !existsSync(filePath));
|
|
56
58
|
const files = [
|
|
57
|
-
[CREATE_GITHUB_RELEASE_WORKFLOW_PATH,
|
|
58
|
-
[PUBLISH_WORKFLOW_PATH,
|
|
59
|
-
['.github/workflows/release.yaml',
|
|
59
|
+
[CREATE_GITHUB_RELEASE_WORKFLOW_PATH, renderCreateGithubReleaseWorkflow(repoType)],
|
|
60
|
+
[PUBLISH_WORKFLOW_PATH, renderPublishWorkflow(repoType, { shouldGenerateProvenance: readProvenanceSetting() })],
|
|
61
|
+
['.github/workflows/release.yaml', renderReleaseWorkflow(repoType)],
|
|
60
62
|
];
|
|
61
63
|
if (existsSync(SYNC_LABELS_WORKFLOW_PATH)) {
|
|
62
64
|
files.push([SYNC_LABELS_WORKFLOW_PATH, readSyncLabelsWorkflowTemplate()]);
|
|
63
65
|
}
|
|
64
|
-
return { files: files.filter(([filePath]) => !
|
|
66
|
+
return { files: files.filter(([filePath]) => !skippedPaths.includes(filePath)), skippedPaths };
|
|
65
67
|
}
|
|
66
68
|
function readProvenanceSetting() {
|
|
67
69
|
if (!existsSync(PUBLISH_WORKFLOW_PATH))
|
|
@@ -16,7 +16,7 @@ export type RenderInjectedReadmeSkipReason = 'no-entry' | 'empty-body';
|
|
|
16
16
|
/** Discriminated outcome of rendering release notes for a tag. */
|
|
17
17
|
export type RenderInjectedReadmeResult = {
|
|
18
18
|
status: 'rendered';
|
|
19
|
-
|
|
19
|
+
renderedReadme: RenderedInjectedReadme;
|
|
20
20
|
} | {
|
|
21
21
|
status: 'skipped';
|
|
22
22
|
reason: RenderInjectedReadmeSkipReason;
|
|
@@ -11,7 +11,7 @@ export function renderInjectedReadmeFromEntries(readme, entries, tag, sectionOrd
|
|
|
11
11
|
}
|
|
12
12
|
const renderedSections = renderReleaseNotesSingle(entry, {
|
|
13
13
|
filter: matchesAudience('all'),
|
|
14
|
-
|
|
14
|
+
shouldIncludeHeading: false,
|
|
15
15
|
...(sectionOrder !== undefined && { sectionOrder }),
|
|
16
16
|
});
|
|
17
17
|
if (renderedSections.trimEnd().length === 0) {
|
|
@@ -20,7 +20,7 @@ export function renderInjectedReadmeFromEntries(readme, entries, tag, sectionOrd
|
|
|
20
20
|
const labeledHeading = `## Release notes — v${version} (${entry.date})`;
|
|
21
21
|
const releaseNotesMarkdown = `${labeledHeading}\n\n${renderedSections.trimEnd()}`;
|
|
22
22
|
const injectedReadme = injectSection(readme, 'release-notes', releaseNotesMarkdown);
|
|
23
|
-
return { status: 'rendered',
|
|
23
|
+
return { status: 'rendered', renderedReadme: { injectedReadme, releaseNotesMarkdown } };
|
|
24
24
|
}
|
|
25
25
|
export function renderInjectedReadme(readme, changelogJsonPath, tag, sectionOrder) {
|
|
26
26
|
if (!existsSync(changelogJsonPath)) {
|
|
@@ -37,15 +37,15 @@ export function renderInjectedReadme(readme, changelogJsonPath, tag, sectionOrde
|
|
|
37
37
|
console.warn(`Warning: ${describeRenderSkip(result.reason, result.version)}; skipping README injection`);
|
|
38
38
|
return undefined;
|
|
39
39
|
}
|
|
40
|
-
return result.
|
|
40
|
+
return result.renderedReadme;
|
|
41
41
|
}
|
|
42
42
|
export function injectReleaseNotesIntoReadme(readmePath, changelogJsonPath, tag, sectionOrder) {
|
|
43
43
|
const originalReadme = readFileSync(readmePath, 'utf8');
|
|
44
|
-
const
|
|
45
|
-
if (
|
|
44
|
+
const renderResult = renderInjectedReadme(originalReadme, changelogJsonPath, tag, sectionOrder);
|
|
45
|
+
if (renderResult === undefined) {
|
|
46
46
|
return undefined;
|
|
47
47
|
}
|
|
48
|
-
writeFileSync(readmePath,
|
|
48
|
+
writeFileSync(readmePath, renderResult.injectedReadme, 'utf8');
|
|
49
49
|
return originalReadme;
|
|
50
50
|
}
|
|
51
51
|
export function resolveReadmePath(workspacePath) {
|
|
@@ -5,16 +5,16 @@ function closeMarker(key) {
|
|
|
5
5
|
return `<!-- /section:${key} -->`;
|
|
6
6
|
}
|
|
7
7
|
export function injectSection(content, key, injection) {
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const openIndex = content.indexOf(
|
|
11
|
-
const closeIndex = content.indexOf(
|
|
8
|
+
const openComment = openMarker(key);
|
|
9
|
+
const closeComment = closeMarker(key);
|
|
10
|
+
const openIndex = content.indexOf(openComment);
|
|
11
|
+
const closeIndex = content.indexOf(closeComment);
|
|
12
12
|
if (openIndex !== -1 && closeIndex !== -1 && closeIndex > openIndex) {
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
return `${
|
|
13
|
+
const contentBefore = content.slice(0, openIndex + openComment.length);
|
|
14
|
+
const contentAfter = content.slice(closeIndex);
|
|
15
|
+
return `${contentBefore}\n${injection}\n${contentAfter}`;
|
|
16
16
|
}
|
|
17
|
-
const section = `${
|
|
17
|
+
const section = `${openComment}\n${injection}\n${closeComment}`;
|
|
18
18
|
if (content.length === 0) {
|
|
19
19
|
return `${section}\n`;
|
|
20
20
|
}
|
|
@@ -25,7 +25,7 @@ export declare function parseOverrideKey(key: string): {
|
|
|
25
25
|
* Each error names the offending key (e.g. `overrides['abc']: 'audience' must be one of …`) so that the user can find
|
|
26
26
|
* it in the override file.
|
|
27
27
|
*/
|
|
28
|
-
export declare function validateChangelogOverrides(
|
|
28
|
+
export declare function validateChangelogOverrides(rawValue: unknown): {
|
|
29
29
|
overrides: Map<string, ChangelogOverride>;
|
|
30
30
|
errors: string[];
|
|
31
31
|
};
|