@williamthorsen/release-kit 15.0.2 → 16.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.meta/changelog.json +88 -0
- package/.readyup/kits/default.js +14 -14
- package/.readyup/kits/npm-auto-publish.js +5 -5
- package/.readyup/manifest.json +14 -14
- package/CHANGELOG.md +28 -0
- package/README.md +3 -3
- package/dist/esm/applyChangelogOverrides.js +6 -6
- package/dist/esm/assertCleanWorkingTree.js +2 -2
- package/dist/esm/assertReleasesOnNpm.js +11 -11
- package/dist/esm/assertTaggedBaseline.js +5 -5
- package/dist/esm/bin/release-kit.js +16 -16
- package/dist/esm/buildChangelogEntries.d.ts +19 -19
- package/dist/esm/buildChangelogEntries.js +40 -36
- package/dist/esm/buildChangelogItem.js +24 -24
- package/dist/esm/buildDependencyGraph.js +23 -23
- package/dist/esm/buildReleasedResult.js +21 -19
- package/dist/esm/buildSyntheticChangelogEntry.js +2 -2
- package/dist/esm/bumpVersion.js +8 -8
- package/dist/esm/changelogArchive.d.ts +1 -1
- package/dist/esm/changelogArchive.js +2 -2
- package/dist/esm/changelogJsonFile.js +5 -5
- package/dist/esm/changelogJsonUtils.js +3 -3
- package/dist/esm/changelogOverrides.d.ts +5 -5
- package/dist/esm/changelogOverrides.js +23 -23
- package/dist/esm/classifyChangelogCommit.js +4 -4
- package/dist/esm/commitCommand.js +7 -7
- package/dist/esm/compareVersions.js +13 -13
- package/dist/esm/configSchema.d.ts +2 -2
- package/dist/esm/configSchema.js +1 -1
- package/dist/esm/createGithubRelease.d.ts +4 -4
- package/dist/esm/createGithubRelease.js +10 -10
- package/dist/esm/createGithubReleaseCommand.js +9 -9
- package/dist/esm/createTags.d.ts +2 -2
- package/dist/esm/createTags.js +12 -12
- package/dist/esm/decideDirectReleases.d.ts +5 -5
- package/dist/esm/decideDirectReleases.js +25 -25
- package/dist/esm/decideRelease.d.ts +1 -1
- package/dist/esm/decideRelease.js +2 -2
- package/dist/esm/deriveDirectoryConfig.d.ts +1 -1
- package/dist/esm/deriveDirectoryConfig.js +18 -18
- package/dist/esm/deriveWorkspaceConfig.js +4 -4
- package/dist/esm/detectPackageManager.js +5 -5
- package/dist/esm/detectUndeclaredTagPrefixes.js +8 -8
- package/dist/esm/enumerateReleaseWindows.d.ts +1 -1
- package/dist/esm/enumerateReleaseWindows.js +9 -9
- package/dist/esm/findTransitiveDependents.js +5 -5
- package/dist/esm/findUnroutedEntryScopes.js +11 -11
- package/dist/esm/format.d.ts +1 -1
- package/dist/esm/format.js +1 -1
- package/dist/esm/formatPrepareFiles.d.ts +3 -3
- package/dist/esm/formatPrepareFiles.js +10 -10
- package/dist/esm/formatPrepareWarnings.js +6 -6
- package/dist/esm/hasPrettierConfig.js +2 -2
- package/dist/esm/init/checks.js +7 -5
- package/dist/esm/init/detectRepoType.js +3 -3
- package/dist/esm/init/initCommand.d.ts +4 -4
- package/dist/esm/init/initCommand.js +7 -7
- package/dist/esm/init/parseJsonRecord.d.ts +1 -1
- package/dist/esm/init/parseJsonRecord.js +4 -4
- package/dist/esm/init/scaffold.d.ts +4 -4
- package/dist/esm/init/scaffold.js +18 -9
- package/dist/esm/init/templates.d.ts +10 -10
- package/dist/esm/init/templates.js +5 -5
- package/dist/esm/init/updateTemplatesCommand.d.ts +2 -2
- package/dist/esm/init/updateTemplatesCommand.js +16 -14
- package/dist/esm/injectReleaseNotesIntoReadme.d.ts +1 -1
- package/dist/esm/injectReleaseNotesIntoReadme.js +6 -6
- package/dist/esm/injectSection.js +8 -8
- package/dist/esm/loadChangelogOverrides.d.ts +1 -1
- package/dist/esm/loadChangelogOverrides.js +9 -9
- package/dist/esm/loadConfig.d.ts +3 -3
- package/dist/esm/loadConfig.js +10 -10
- package/dist/esm/loadValidatedConfig.js +4 -4
- package/dist/esm/mergeConfig.d.ts +1 -1
- package/dist/esm/mergeConfig.js +27 -27
- package/dist/esm/monorepoConfigAssertions.js +15 -15
- package/dist/esm/npmRegistry.js +4 -4
- package/dist/esm/packsPath.js +3 -3
- package/dist/esm/parseChangeRecordBlock.js +33 -33
- package/dist/esm/parseCommitMessage.js +5 -5
- package/dist/esm/planChangelogFiles.js +8 -8
- package/dist/esm/planReleaseNotesPreviews.js +10 -10
- package/dist/esm/planVersionBump.js +24 -16
- package/dist/esm/prepareArgs.d.ts +9 -9
- package/dist/esm/prepareArgs.js +11 -11
- package/dist/esm/prepareCommand.js +23 -23
- package/dist/esm/prepareComposite.d.ts +4 -4
- package/dist/esm/prepareComposite.js +16 -16
- package/dist/esm/{releasePrepareTargets.d.ts → prepareReleaseTargets.d.ts} +9 -9
- package/dist/esm/{releasePrepareTargets.js → prepareReleaseTargets.js} +40 -40
- package/dist/esm/prepareRunContext.d.ts +1 -1
- package/dist/esm/prepareRunContext.js +5 -5
- package/dist/esm/prepareTarget.d.ts +3 -3
- package/dist/esm/prepareTarget.js +41 -39
- package/dist/esm/previewTagPrefixes.js +21 -21
- package/dist/esm/propagateBumps.js +8 -8
- package/dist/esm/publish.d.ts +2 -2
- package/dist/esm/publish.js +5 -5
- package/dist/esm/publishCommand.js +20 -20
- package/dist/esm/pushCommand.js +8 -8
- package/dist/esm/pushRelease.d.ts +1 -1
- package/dist/esm/pushRelease.js +4 -4
- package/dist/esm/readChangelogSections.d.ts +1 -1
- package/dist/esm/readChangelogSections.js +16 -16
- package/dist/esm/releasePlan.js +26 -26
- package/dist/esm/renderChangelogMarkdown.d.ts +4 -4
- package/dist/esm/renderChangelogMarkdown.js +18 -15
- package/dist/esm/renderReleaseNotes.d.ts +1 -1
- package/dist/esm/renderReleaseNotes.js +16 -16
- package/dist/esm/reportPrepare.js +34 -34
- package/dist/esm/resolveCommandTags.js +9 -9
- package/dist/esm/resolveReleaseDeclaration.d.ts +2 -2
- package/dist/esm/resolveReleaseDeclaration.js +22 -22
- package/dist/esm/resolveReleaseTags.js +19 -17
- package/dist/esm/resolveReleaseTargets.js +2 -2
- package/dist/esm/showTagPrefixesCommand.js +4 -4
- package/dist/esm/sync-labels/generateCommand.d.ts +3 -3
- package/dist/esm/sync-labels/generateCommand.js +10 -10
- package/dist/esm/sync-labels/initCommand.d.ts +3 -3
- package/dist/esm/sync-labels/initCommand.js +23 -15
- package/dist/esm/sync-labels/presets.js +3 -3
- package/dist/esm/sync-labels/resolveLabels.js +13 -13
- package/dist/esm/sync-labels/syncCommand.js +2 -2
- package/dist/esm/sync-labels/templates.d.ts +4 -4
- package/dist/esm/sync-labels/templates.js +13 -40
- package/dist/esm/tagCommand.js +4 -4
- package/dist/esm/topologicalSort.d.ts +2 -2
- package/dist/esm/topologicalSort.js +7 -7
- package/dist/esm/types.d.ts +3 -3
- package/dist/esm/validateAllChangelogOverrides.js +9 -9
- package/dist/esm/validateConfig.d.ts +1 -1
- package/dist/esm/validateConfig.js +60 -50
- package/dist/esm/validateOverridesCommand.js +2 -2
- package/docs/changelogs.md +5 -5
- package/docs/configuration.md +1 -1
- package/docs/work-types.md +1 -1
- package/package.json +9 -8
- package/templates/sync-labels.yaml.template +36 -0
|
@@ -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
|
};
|
|
@@ -18,16 +18,16 @@ export function loadChangelogOverrides(path) {
|
|
|
18
18
|
errors: [`Failed to read override file ${path}: ${describeError(error)}`],
|
|
19
19
|
};
|
|
20
20
|
}
|
|
21
|
-
let
|
|
21
|
+
let parsedJson;
|
|
22
22
|
try {
|
|
23
|
-
|
|
23
|
+
parsedJson = JSON.parse(content);
|
|
24
24
|
}
|
|
25
25
|
catch (error) {
|
|
26
26
|
return {
|
|
27
27
|
errors: [`Failed to parse override file ${path}: ${describeError(error)}`],
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
|
-
const result = validateChangelogOverrides(
|
|
30
|
+
const result = validateChangelogOverrides(parsedJson);
|
|
31
31
|
if (result.errors.length > 0) {
|
|
32
32
|
return { errors: result.errors };
|
|
33
33
|
}
|
|
@@ -41,14 +41,14 @@ export function parseOverrideKey(key) {
|
|
|
41
41
|
}
|
|
42
42
|
return { hashPrefix: key.slice(0, separatorIndex), entry: Number(key.slice(separatorIndex + 1)) };
|
|
43
43
|
}
|
|
44
|
-
export function validateChangelogOverrides(
|
|
44
|
+
export function validateChangelogOverrides(rawValue) {
|
|
45
45
|
const overrides = new Map();
|
|
46
46
|
const errors = [];
|
|
47
|
-
if (!isRecord(
|
|
47
|
+
if (!isRecord(rawValue)) {
|
|
48
48
|
errors.push('Override file: top-level value must be an object keyed by commit hash');
|
|
49
49
|
return { overrides, errors };
|
|
50
50
|
}
|
|
51
|
-
for (const [key, rawEntry] of Object.entries(
|
|
51
|
+
for (const [key, rawEntry] of Object.entries(rawValue)) {
|
|
52
52
|
if (key === SCHEMA_KEY) {
|
|
53
53
|
if (typeof rawEntry !== 'string') {
|
|
54
54
|
errors.push(`Override file: '${SCHEMA_KEY}' must be a string`);
|
|
@@ -59,9 +59,9 @@ export function validateChangelogOverrides(raw) {
|
|
|
59
59
|
errors.push(`overrides['${key}']: key must be a lowercase hex commit hash or prefix, optionally followed by ':<n>'`);
|
|
60
60
|
continue;
|
|
61
61
|
}
|
|
62
|
-
const
|
|
63
|
-
if (
|
|
64
|
-
overrides.set(key,
|
|
62
|
+
const validatedOverride = validateSingleOverride(key, rawEntry, errors);
|
|
63
|
+
if (validatedOverride !== undefined) {
|
|
64
|
+
overrides.set(key, validatedOverride);
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
return { overrides, errors };
|
package/dist/esm/loadConfig.d.ts
CHANGED
|
@@ -3,13 +3,13 @@ export declare const ROOT_PACKAGE_JSON_PATH = "package.json";
|
|
|
3
3
|
/**
|
|
4
4
|
* Reads the root `package.json` and returns its `version` field.
|
|
5
5
|
*
|
|
6
|
-
* Returns `{
|
|
7
|
-
* when the file exists but does not have a `version` field, and `{
|
|
6
|
+
* Returns `{ doesExist: false }` when the file is missing, `{ doesExist: true, version: undefined }`
|
|
7
|
+
* when the file exists but does not have a `version` field, and `{ doesExist: true, version }`
|
|
8
8
|
* when both are present; `mergeMonorepoConfig` decides whether the situation is an error.
|
|
9
9
|
* Throws when the file cannot be read or parsed.
|
|
10
10
|
*/
|
|
11
11
|
export declare function readRootPackageVersion(): {
|
|
12
|
-
|
|
12
|
+
doesExist: boolean;
|
|
13
13
|
version: string | undefined;
|
|
14
14
|
};
|
|
15
15
|
/** The path where the consumer-facing config file is expected. */
|
package/dist/esm/loadConfig.js
CHANGED
|
@@ -15,7 +15,7 @@ export const ROOT_PACKAGE_JSON_PATH = 'package.json';
|
|
|
15
15
|
export function readRootPackageVersion() {
|
|
16
16
|
const absolutePath = path.resolve(process.cwd(), ROOT_PACKAGE_JSON_PATH);
|
|
17
17
|
if (!existsSync(absolutePath)) {
|
|
18
|
-
return {
|
|
18
|
+
return { doesExist: false, version: undefined };
|
|
19
19
|
}
|
|
20
20
|
let contents;
|
|
21
21
|
try {
|
|
@@ -24,17 +24,17 @@ export function readRootPackageVersion() {
|
|
|
24
24
|
catch (error) {
|
|
25
25
|
throw chainError(`Failed to read root ${ROOT_PACKAGE_JSON_PATH}`, error);
|
|
26
26
|
}
|
|
27
|
-
let
|
|
27
|
+
let parsedJson;
|
|
28
28
|
try {
|
|
29
|
-
|
|
29
|
+
parsedJson = JSON.parse(contents);
|
|
30
30
|
}
|
|
31
31
|
catch (error) {
|
|
32
32
|
throw chainError(`Failed to parse root ${ROOT_PACKAGE_JSON_PATH}`, error);
|
|
33
33
|
}
|
|
34
|
-
if (!isRecord(
|
|
35
|
-
return {
|
|
34
|
+
if (!isRecord(parsedJson)) {
|
|
35
|
+
return { doesExist: true, version: undefined };
|
|
36
36
|
}
|
|
37
|
-
return {
|
|
37
|
+
return { doesExist: true, version: typeof parsedJson['version'] === 'string' ? parsedJson['version'] : undefined };
|
|
38
38
|
}
|
|
39
39
|
export const CONFIG_FILE_PATH = '.config/release-kit.config.ts';
|
|
40
40
|
export async function loadConfig(configPath) {
|
|
@@ -45,10 +45,10 @@ export async function loadConfig(configPath) {
|
|
|
45
45
|
}
|
|
46
46
|
throw new Error(`Config file not found: ${absoluteConfigPath}`);
|
|
47
47
|
}
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
if (
|
|
48
|
+
const importedModule = await import(__rewriteRelativeImportExtension(pathToFileURL(absoluteConfigPath).href));
|
|
49
|
+
const resolvedConfig = isRecord(importedModule) ? (importedModule['default'] ?? importedModule['config']) : undefined;
|
|
50
|
+
if (resolvedConfig === undefined) {
|
|
51
51
|
throw new Error('Config file must have a default export or a named `config` export (e.g., `export default { ... }` or `export const config = { ... }`)');
|
|
52
52
|
}
|
|
53
|
-
return
|
|
53
|
+
return resolvedConfig;
|
|
54
54
|
}
|
|
@@ -4,17 +4,17 @@ import { CONFIG_FILE_PATH, loadConfig } from "./loadConfig.js";
|
|
|
4
4
|
import { validateConfig } from "./validateConfig.js";
|
|
5
5
|
export async function loadValidatedConfig(configPath) {
|
|
6
6
|
const configFilePath = configPath ?? CONFIG_FILE_PATH;
|
|
7
|
-
let
|
|
7
|
+
let rawConfig;
|
|
8
8
|
try {
|
|
9
|
-
|
|
9
|
+
rawConfig = await loadConfig(configPath);
|
|
10
10
|
}
|
|
11
11
|
catch (error) {
|
|
12
12
|
return { status: 'invalid', configFilePath, problem: { kind: 'load', message: describeError(error) } };
|
|
13
13
|
}
|
|
14
|
-
if (
|
|
14
|
+
if (rawConfig === undefined) {
|
|
15
15
|
return { status: 'missing', configFilePath };
|
|
16
16
|
}
|
|
17
|
-
const { config, errors, warnings } = validateConfig(
|
|
17
|
+
const { config, errors, warnings } = validateConfig(rawConfig);
|
|
18
18
|
if (errors.length > 0) {
|
|
19
19
|
return { status: 'invalid', configFilePath, problem: { kind: 'validation', errors } };
|
|
20
20
|
}
|
package/dist/esm/mergeConfig.js
CHANGED
|
@@ -5,10 +5,10 @@ import { ROOT_PACKAGE_JSON_PATH } from "./loadConfig.js";
|
|
|
5
5
|
import { assertLegacyIdentityDoesNotMatchCurrent, assertNoSharedVersionFiles, assertNoTagPrefixCollisions, assertRetiredPackagesDoNotCollideWithActive, assertUniqueTagPrefixes, } from "./monorepoConfigAssertions.js";
|
|
6
6
|
import { resolveReleaseDeclaration } from "./resolveReleaseDeclaration.js";
|
|
7
7
|
export function mergeMonorepoConfig(discoveredPaths, userConfig, rootPackage) {
|
|
8
|
-
const
|
|
9
|
-
assertUniqueTagPrefixes(
|
|
10
|
-
const {
|
|
11
|
-
const directories = declaredDirectories.map((
|
|
8
|
+
const discoveredWorkspaces = discoveredPaths.map((workspacePath) => deriveWorkspaceConfig(workspacePath));
|
|
9
|
+
assertUniqueTagPrefixes(discoveredWorkspaces);
|
|
10
|
+
const { retainedWorkspaces: workspaces, excludedWorkspaces, directories: declaredDirectories, composite: declaredComposite, } = resolveReleaseDeclaration(discoveredWorkspaces, userConfig);
|
|
11
|
+
const directories = declaredDirectories.map((declaredDirectory) => deriveDirectoryConfig(declaredDirectory));
|
|
12
12
|
for (const workspace of workspaces) {
|
|
13
13
|
if (workspace.legacyIdentities !== undefined) {
|
|
14
14
|
assertLegacyIdentityDoesNotMatchCurrent(workspace.dir, workspace.name, workspace.tagPrefix, workspace.legacyIdentities);
|
|
@@ -17,13 +17,13 @@ export function mergeMonorepoConfig(discoveredPaths, userConfig, rootPackage) {
|
|
|
17
17
|
if (userConfig?.retiredPackages !== undefined) {
|
|
18
18
|
assertRetiredPackagesDoNotCollideWithActive(workspaces, userConfig.retiredPackages);
|
|
19
19
|
}
|
|
20
|
-
const
|
|
20
|
+
const projectConfig = resolveProjectConfig(declaredComposite, rootPackage, workspaces);
|
|
21
21
|
const workTypes = resolveWorkTypes(userConfig?.workTypes);
|
|
22
22
|
const versionPatterns = userConfig?.versionPatterns === undefined ? { ...DEFAULT_VERSION_PATTERNS } : { ...userConfig.versionPatterns };
|
|
23
23
|
const changelogJson = mergeChangelogJsonConfig(userConfig?.changelogJson);
|
|
24
24
|
const releaseNotes = mergeReleaseNotesConfig(userConfig?.releaseNotes);
|
|
25
|
-
assertNoSharedVersionFiles(workspaces, directories,
|
|
26
|
-
assertNoTagPrefixCollisions(workspaces, directories, userConfig?.retiredPackages,
|
|
25
|
+
assertNoSharedVersionFiles(workspaces, directories, projectConfig);
|
|
26
|
+
assertNoTagPrefixCollisions(workspaces, directories, userConfig?.retiredPackages, projectConfig);
|
|
27
27
|
const result = {
|
|
28
28
|
workspaces,
|
|
29
29
|
workTypes,
|
|
@@ -31,14 +31,14 @@ export function mergeMonorepoConfig(discoveredPaths, userConfig, rootPackage) {
|
|
|
31
31
|
changelogJson,
|
|
32
32
|
releaseNotes,
|
|
33
33
|
};
|
|
34
|
-
if (
|
|
35
|
-
result.excludedWorkspaces =
|
|
34
|
+
if (excludedWorkspaces.length > 0) {
|
|
35
|
+
result.excludedWorkspaces = excludedWorkspaces;
|
|
36
36
|
}
|
|
37
37
|
if (directories.length > 0) {
|
|
38
38
|
result.directories = directories;
|
|
39
39
|
}
|
|
40
|
-
if (
|
|
41
|
-
result.project =
|
|
40
|
+
if (projectConfig !== undefined) {
|
|
41
|
+
result.project = projectConfig;
|
|
42
42
|
}
|
|
43
43
|
applyOptionalPassthroughFields(result, userConfig);
|
|
44
44
|
return result;
|
|
@@ -80,39 +80,39 @@ function applyOptionalPassthroughFields(result, userConfig) {
|
|
|
80
80
|
result.breakingPolicies = userConfig.breakingPolicies;
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
|
-
function mergeChangelogJsonConfig(
|
|
84
|
-
if (
|
|
83
|
+
function mergeChangelogJsonConfig(partialConfig) {
|
|
84
|
+
if (partialConfig === undefined) {
|
|
85
85
|
return { ...DEFAULT_CHANGELOG_JSON_CONFIG };
|
|
86
86
|
}
|
|
87
87
|
return {
|
|
88
|
-
enabled:
|
|
89
|
-
outputPath:
|
|
90
|
-
devOnlySections:
|
|
88
|
+
enabled: partialConfig.enabled ?? DEFAULT_CHANGELOG_JSON_CONFIG.enabled,
|
|
89
|
+
outputPath: partialConfig.outputPath ?? DEFAULT_CHANGELOG_JSON_CONFIG.outputPath,
|
|
90
|
+
devOnlySections: partialConfig.devOnlySections ?? [...DEFAULT_CHANGELOG_JSON_CONFIG.devOnlySections],
|
|
91
91
|
};
|
|
92
92
|
}
|
|
93
|
-
function mergeReleaseNotesConfig(
|
|
94
|
-
if (
|
|
93
|
+
function mergeReleaseNotesConfig(partialConfig) {
|
|
94
|
+
if (partialConfig === undefined) {
|
|
95
95
|
return { ...DEFAULT_RELEASE_NOTES_CONFIG };
|
|
96
96
|
}
|
|
97
97
|
return {
|
|
98
|
-
shouldInjectIntoReadme:
|
|
98
|
+
shouldInjectIntoReadme: partialConfig.shouldInjectIntoReadme ?? DEFAULT_RELEASE_NOTES_CONFIG.shouldInjectIntoReadme,
|
|
99
99
|
};
|
|
100
100
|
}
|
|
101
|
-
function resolveProjectConfig(
|
|
102
|
-
if (
|
|
101
|
+
function resolveProjectConfig(declaredComposite, rootPackage, workspaces) {
|
|
102
|
+
if (declaredComposite === undefined) {
|
|
103
103
|
return undefined;
|
|
104
104
|
}
|
|
105
|
-
const subject =
|
|
106
|
-
if (rootPackage === undefined || !rootPackage.
|
|
105
|
+
const subject = declaredComposite.name === undefined ? 'project block' : `composite release '${declaredComposite.name}'`;
|
|
106
|
+
if (rootPackage === undefined || !rootPackage.doesExist) {
|
|
107
107
|
throw new Error(`${subject} requires a root ${ROOT_PACKAGE_JSON_PATH}; create one with a 'version' field at the repo root`);
|
|
108
108
|
}
|
|
109
109
|
if (rootPackage.version === undefined) {
|
|
110
110
|
throw new Error(`${subject} requires root ${ROOT_PACKAGE_JSON_PATH} to have a 'version' field; add a 'version' field to the root package.json`);
|
|
111
111
|
}
|
|
112
112
|
return {
|
|
113
|
-
paths:
|
|
114
|
-
tagPrefix:
|
|
115
|
-
...(
|
|
116
|
-
...(
|
|
113
|
+
paths: declaredComposite.paths ?? workspaces.flatMap((workspace) => workspace.paths),
|
|
114
|
+
tagPrefix: declaredComposite.tagPrefix ?? DEFAULT_PROJECT_TAG_PREFIX,
|
|
115
|
+
...(declaredComposite.name !== undefined && { name: declaredComposite.name }),
|
|
116
|
+
...(declaredComposite.members !== undefined && { members: declaredComposite.members }),
|
|
117
117
|
};
|
|
118
118
|
}
|
|
@@ -63,10 +63,10 @@ export function assertNoTagPrefixCollisions(workspaces, directories, retiredPack
|
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
const retiredEntries = (retiredPackages ?? []).entries();
|
|
66
|
-
for (const [index,
|
|
66
|
+
for (const [index, retiredPackage] of retiredEntries) {
|
|
67
67
|
sources.push({
|
|
68
|
-
prefix:
|
|
69
|
-
label: `retiredPackages entry (name='${
|
|
68
|
+
prefix: retiredPackage.tagPrefix,
|
|
69
|
+
label: `retiredPackages entry (name='${retiredPackage.name}')`,
|
|
70
70
|
owner: `retired:${index}`,
|
|
71
71
|
});
|
|
72
72
|
}
|
|
@@ -77,10 +77,10 @@ export function assertNoTagPrefixCollisions(workspaces, directories, retiredPack
|
|
|
77
77
|
owner: 'project',
|
|
78
78
|
});
|
|
79
79
|
}
|
|
80
|
-
for (let
|
|
81
|
-
for (let
|
|
82
|
-
const a = sources[
|
|
83
|
-
const b = sources[
|
|
80
|
+
for (let aIndex = 0; aIndex < sources.length; aIndex++) {
|
|
81
|
+
for (let bIndex = aIndex + 1; bIndex < sources.length; bIndex++) {
|
|
82
|
+
const a = sources[aIndex];
|
|
83
|
+
const b = sources[bIndex];
|
|
84
84
|
if (a === undefined || b === undefined || a.owner === b.owner)
|
|
85
85
|
continue;
|
|
86
86
|
if (isPrefixCollision(a.prefix, b.prefix)) {
|
|
@@ -96,23 +96,23 @@ export function assertRetiredPackagesDoNotCollideWithActive(workspaces, retiredP
|
|
|
96
96
|
for (const workspace of workspaces) {
|
|
97
97
|
workspaceByDerivedPrefix.set(workspace.tagPrefix, workspace);
|
|
98
98
|
}
|
|
99
|
-
for (const
|
|
100
|
-
const
|
|
101
|
-
if (
|
|
102
|
-
throw new Error(`retiredPackages: tagPrefix '${
|
|
103
|
-
`(derived prefix '${
|
|
99
|
+
for (const retiredPackage of retiredPackages) {
|
|
100
|
+
const activeWorkspace = workspaceByDerivedPrefix.get(retiredPackage.tagPrefix);
|
|
101
|
+
if (activeWorkspace !== undefined) {
|
|
102
|
+
throw new Error(`retiredPackages: tagPrefix '${retiredPackage.tagPrefix}' collides with active workspace '${activeWorkspace.dir}' ` +
|
|
103
|
+
`(derived prefix '${activeWorkspace.tagPrefix}'). A retired package's tagPrefix cannot belong to an active workspace.`);
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
export function assertUniqueTagPrefixes(workspaces) {
|
|
108
108
|
const pathsByPrefix = new Map();
|
|
109
109
|
for (const workspace of workspaces) {
|
|
110
|
-
const
|
|
111
|
-
if (
|
|
110
|
+
const existingPaths = pathsByPrefix.get(workspace.tagPrefix);
|
|
111
|
+
if (existingPaths === undefined) {
|
|
112
112
|
pathsByPrefix.set(workspace.tagPrefix, [workspace.workspacePath]);
|
|
113
113
|
}
|
|
114
114
|
else {
|
|
115
|
-
|
|
115
|
+
existingPaths.push(workspace.workspacePath);
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
118
|
for (const [prefix, paths] of pathsByPrefix) {
|
package/dist/esm/npmRegistry.js
CHANGED
|
@@ -34,17 +34,17 @@ export function lookUpNpmPackage(packageName, registry) {
|
|
|
34
34
|
return classifyNpmPackageLookup(runNpmJson(args));
|
|
35
35
|
}
|
|
36
36
|
export function readNpmError(stdout) {
|
|
37
|
-
let
|
|
37
|
+
let parsedJson;
|
|
38
38
|
try {
|
|
39
|
-
|
|
39
|
+
parsedJson = JSON.parse(stdout);
|
|
40
40
|
}
|
|
41
41
|
catch {
|
|
42
42
|
return undefined;
|
|
43
43
|
}
|
|
44
|
-
if (!isRecord(
|
|
44
|
+
if (!isRecord(parsedJson) || !isRecord(parsedJson['error']) || typeof parsedJson['error']['code'] !== 'string') {
|
|
45
45
|
return undefined;
|
|
46
46
|
}
|
|
47
|
-
const { code, summary } =
|
|
47
|
+
const { code, summary } = parsedJson['error'];
|
|
48
48
|
return { code, summary: typeof summary === 'string' ? summary : '' };
|
|
49
49
|
}
|
|
50
50
|
export function runNpmJson(args) {
|
package/dist/esm/packsPath.js
CHANGED
|
@@ -11,10 +11,10 @@ const GLOB_TOKEN_PATTERN = /\*\*\/|\*\*|\*|\?|[^*?]+/g;
|
|
|
11
11
|
function compileEntry(entry) {
|
|
12
12
|
if (entry.startsWith('!'))
|
|
13
13
|
return undefined;
|
|
14
|
-
const
|
|
15
|
-
if (
|
|
14
|
+
const normalizedEntry = entry.replace(/^\.?\//, '').replace(/\/+$/, '');
|
|
15
|
+
if (normalizedEntry === '')
|
|
16
16
|
return undefined;
|
|
17
|
-
return new RegExp(`^${translateGlob(
|
|
17
|
+
return new RegExp(`^${translateGlob(normalizedEntry)}$`);
|
|
18
18
|
}
|
|
19
19
|
function isStringArray(value) {
|
|
20
20
|
return Array.isArray(value) && value.every((entry) => typeof entry === 'string');
|
|
@@ -6,10 +6,10 @@ export function parseChangeRecordBlock(message) {
|
|
|
6
6
|
if (fence === undefined) {
|
|
7
7
|
return { kind: 'absent' };
|
|
8
8
|
}
|
|
9
|
-
if (fence.
|
|
9
|
+
if (fence.closeIndex === undefined) {
|
|
10
10
|
return { kind: 'malformed', reason: 'the block opens but never closes' };
|
|
11
11
|
}
|
|
12
|
-
const document = parseDocument(lines.slice(fence.
|
|
12
|
+
const document = parseDocument(lines.slice(fence.openIndex + 1, fence.closeIndex).join('\n'));
|
|
13
13
|
const [error] = document.errors;
|
|
14
14
|
if (error !== undefined) {
|
|
15
15
|
const detail = (error.message.split('\n', 1)[0] ?? '').replace(/:$/, '');
|
|
@@ -21,60 +21,60 @@ export function stripChangeRecordBlocks(message) {
|
|
|
21
21
|
const lines = message.split(/\r?\n/);
|
|
22
22
|
const fences = findFences(lines);
|
|
23
23
|
return lines
|
|
24
|
-
.filter((_line, index) => fences.every((fence) => index < fence.
|
|
24
|
+
.filter((_line, index) => fences.every((fence) => index < fence.openIndex || index > (fence.closeIndex ?? lines.length)))
|
|
25
25
|
.join('\n');
|
|
26
26
|
}
|
|
27
27
|
const FENCE = '```';
|
|
28
28
|
function findFences(lines) {
|
|
29
29
|
const fences = [];
|
|
30
|
-
let
|
|
30
|
+
let openIndex;
|
|
31
31
|
for (const [index, line] of lines.entries()) {
|
|
32
|
-
if (
|
|
32
|
+
if (openIndex === undefined) {
|
|
33
33
|
if (line.trim() === `${FENCE}${INFO_STRING}`) {
|
|
34
|
-
|
|
34
|
+
openIndex = index;
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
else if (line.trim() === FENCE) {
|
|
38
|
-
fences.push({
|
|
39
|
-
|
|
38
|
+
fences.push({ closeIndex: index, openIndex });
|
|
39
|
+
openIndex = undefined;
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
|
-
if (
|
|
43
|
-
fences.push({
|
|
42
|
+
if (openIndex !== undefined) {
|
|
43
|
+
fences.push({ openIndex });
|
|
44
44
|
}
|
|
45
45
|
return fences;
|
|
46
46
|
}
|
|
47
47
|
const INFO_STRING = 'change-record';
|
|
48
48
|
function readEntry(item, index) {
|
|
49
|
-
const
|
|
49
|
+
const entryPath = `entries[${index}]`;
|
|
50
50
|
if (!isRecord(item)) {
|
|
51
|
-
return { reason: `\`${
|
|
51
|
+
return { reason: `\`${entryPath}\` is not a mapping` };
|
|
52
52
|
}
|
|
53
53
|
const { breaking, migration, scopes } = item;
|
|
54
54
|
if (breaking !== undefined && breaking !== null && typeof breaking !== 'boolean') {
|
|
55
|
-
return { reason: `\`${
|
|
55
|
+
return { reason: `\`${entryPath}.breaking\` is not a boolean` };
|
|
56
56
|
}
|
|
57
57
|
if (migration !== undefined && migration !== null && typeof migration !== 'string') {
|
|
58
|
-
return { reason: `\`${
|
|
58
|
+
return { reason: `\`${entryPath}.migration\` is not a string` };
|
|
59
59
|
}
|
|
60
60
|
if (scopes !== undefined && scopes !== null && !Array.isArray(scopes)) {
|
|
61
|
-
return { reason: `\`${
|
|
61
|
+
return { reason: `\`${entryPath}.scopes\` is not a list` };
|
|
62
62
|
}
|
|
63
63
|
const declaredScopes = scopes ?? [];
|
|
64
64
|
const readScopes = [];
|
|
65
65
|
for (const [position, scope] of declaredScopes.entries()) {
|
|
66
66
|
if (typeof scope !== 'string') {
|
|
67
|
-
return { reason: `\`${
|
|
67
|
+
return { reason: `\`${entryPath}.scopes[${position}]\` is not a string` };
|
|
68
68
|
}
|
|
69
69
|
readScopes.push(scope.trim());
|
|
70
70
|
}
|
|
71
|
-
const
|
|
72
|
-
if ('reason' in
|
|
73
|
-
return
|
|
71
|
+
const typeResult = readRequiredString(item, entryPath, 'type');
|
|
72
|
+
if ('reason' in typeResult) {
|
|
73
|
+
return typeResult;
|
|
74
74
|
}
|
|
75
|
-
const
|
|
76
|
-
if ('reason' in
|
|
77
|
-
return
|
|
75
|
+
const textResult = readRequiredString(item, entryPath, 'text');
|
|
76
|
+
if ('reason' in textResult) {
|
|
77
|
+
return textResult;
|
|
78
78
|
}
|
|
79
79
|
const trimmedMigration = migration?.trim();
|
|
80
80
|
return {
|
|
@@ -82,8 +82,8 @@ function readEntry(item, index) {
|
|
|
82
82
|
breaking: breaking === true,
|
|
83
83
|
...(trimmedMigration !== undefined && trimmedMigration !== '' && { migration: trimmedMigration }),
|
|
84
84
|
scopes: readScopes,
|
|
85
|
-
text:
|
|
86
|
-
type:
|
|
85
|
+
text: textResult.value,
|
|
86
|
+
type: typeResult.value,
|
|
87
87
|
},
|
|
88
88
|
};
|
|
89
89
|
}
|
|
@@ -106,11 +106,11 @@ function readPayload(payload) {
|
|
|
106
106
|
return { kind: 'malformed', reason: '`entries` is not a list' };
|
|
107
107
|
}
|
|
108
108
|
for (const [index, item] of entries.entries()) {
|
|
109
|
-
const
|
|
110
|
-
if ('reason' in
|
|
111
|
-
return { kind: 'malformed', reason:
|
|
109
|
+
const readResult = readEntry(item, index);
|
|
110
|
+
if ('reason' in readResult) {
|
|
111
|
+
return { kind: 'malformed', reason: readResult.reason };
|
|
112
112
|
}
|
|
113
|
-
readEntries.push(
|
|
113
|
+
readEntries.push(readResult.entry);
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
116
|
const trimmedTicketRef = ticketRef?.trim();
|
|
@@ -121,14 +121,14 @@ function readPayload(payload) {
|
|
|
121
121
|
...(trimmedTicketRef !== undefined && trimmedTicketRef !== '' && { ticketRef: trimmedTicketRef }),
|
|
122
122
|
};
|
|
123
123
|
}
|
|
124
|
-
function readRequiredString(item,
|
|
124
|
+
function readRequiredString(item, entryPath, name) {
|
|
125
125
|
const value = item[name];
|
|
126
126
|
if (value === undefined || value === null) {
|
|
127
|
-
return { reason: `\`${
|
|
127
|
+
return { reason: `\`${entryPath}.${name}\` is missing` };
|
|
128
128
|
}
|
|
129
129
|
if (typeof value !== 'string') {
|
|
130
|
-
return { reason: `\`${
|
|
130
|
+
return { reason: `\`${entryPath}.${name}\` is not a string` };
|
|
131
131
|
}
|
|
132
|
-
const
|
|
133
|
-
return
|
|
132
|
+
const trimmedValue = value.trim();
|
|
133
|
+
return trimmedValue === '' ? { reason: `\`${entryPath}.${name}\` is blank` } : { value: trimmedValue };
|
|
134
134
|
}
|
|
@@ -30,7 +30,7 @@ export function parseCommitMessage(message, hash, workTypes, scopeAliases, optio
|
|
|
30
30
|
};
|
|
31
31
|
}
|
|
32
32
|
export function parseSubject(subject, workTypes) {
|
|
33
|
-
const taxonomy =
|
|
33
|
+
const taxonomy = adaptToTaxonomy(workTypes);
|
|
34
34
|
for (const nodes of SUBJECT_TEMPLATES) {
|
|
35
35
|
const record = parse(nodes, subject, taxonomy);
|
|
36
36
|
if (record !== undefined) {
|
|
@@ -54,14 +54,14 @@ export function evaluateBreakingPolicy(inputs) {
|
|
|
54
54
|
return hasPrefixBreaking || hasFooterBreaking;
|
|
55
55
|
}
|
|
56
56
|
export function resolveType(rawType, workTypes) {
|
|
57
|
-
const
|
|
57
|
+
const loweredType = rawType.toLowerCase();
|
|
58
58
|
for (const [key, config] of Object.entries(workTypes)) {
|
|
59
|
-
if (key ===
|
|
59
|
+
if (key === loweredType) {
|
|
60
60
|
return key;
|
|
61
61
|
}
|
|
62
62
|
if (config.aliases !== undefined) {
|
|
63
63
|
for (const alias of config.aliases) {
|
|
64
|
-
if (alias ===
|
|
64
|
+
if (alias === loweredType) {
|
|
65
65
|
return key;
|
|
66
66
|
}
|
|
67
67
|
}
|
|
@@ -69,7 +69,7 @@ export function resolveType(rawType, workTypes) {
|
|
|
69
69
|
}
|
|
70
70
|
return undefined;
|
|
71
71
|
}
|
|
72
|
-
function
|
|
72
|
+
function adaptToTaxonomy(workTypes) {
|
|
73
73
|
return {
|
|
74
74
|
tiers: [],
|
|
75
75
|
types: Object.entries(workTypes).map(([key, config]) => ({ aliases: config.aliases ?? [], key, tier: '' })),
|
|
@@ -13,16 +13,16 @@ export function planChangelogFiles(changelogDir, newEntries, settings, sectionOr
|
|
|
13
13
|
changelogJsonFiles.push(jsonPath);
|
|
14
14
|
}
|
|
15
15
|
const changelogFile = joinPath(changelogDir, 'CHANGELOG.md');
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const
|
|
16
|
+
const preservedPlan = planPreservedSections(changelogDir, entries);
|
|
17
|
+
const keptVersionCount = settings.changelogMarkdown?.keptVersionCount;
|
|
18
|
+
const renderedFiles = renderChangelogFiles(entries, {
|
|
19
19
|
sectionOrder,
|
|
20
|
-
preservedSections:
|
|
21
|
-
...(
|
|
20
|
+
preservedSections: preservedPlan.sections,
|
|
21
|
+
...(keptVersionCount !== undefined && { keptVersionCount }),
|
|
22
22
|
});
|
|
23
|
-
writes.push({ path: changelogFile, content:
|
|
23
|
+
writes.push({ path: changelogFile, content: renderedFiles.main });
|
|
24
24
|
const archiveFiles = [];
|
|
25
|
-
for (const { major, content } of
|
|
25
|
+
for (const { major, content } of renderedFiles.archives) {
|
|
26
26
|
const path = joinPath(changelogDir, describeArchivePath(major));
|
|
27
27
|
writes.push({ path, content });
|
|
28
28
|
archiveFiles.push(path);
|
|
@@ -34,7 +34,7 @@ export function planChangelogFiles(changelogDir, newEntries, settings, sectionOr
|
|
|
34
34
|
changelogFiles: [changelogFile, ...archiveFiles],
|
|
35
35
|
changelogJsonFiles,
|
|
36
36
|
entries,
|
|
37
|
-
preservation:
|
|
37
|
+
preservation: preservedPlan.preservation,
|
|
38
38
|
removals,
|
|
39
39
|
writes,
|
|
40
40
|
};
|