@williamthorsen/release-kit 11.0.0 → 13.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.meta/changelog.json +274 -2
- package/.readyup/kits/default.js +18 -33
- package/.readyup/kits/npm-auto-publish.js +24 -23
- package/.readyup/manifest.json +16 -11
- package/CHANGELOG.md +98 -0
- package/README.md +57 -69
- package/bin/release-kit.js +1 -1
- package/dist/esm/assertCleanWorkingTree.d.ts +1 -5
- package/dist/esm/assertTaggedBaseline.d.ts +29 -0
- package/dist/esm/assertTaggedBaseline.js +41 -0
- package/dist/esm/attachChangelogDiagnostics.d.ts +4 -0
- package/dist/esm/attachChangelogDiagnostics.js +14 -0
- package/dist/esm/bin/release-kit.js +88 -24
- package/dist/esm/buildChangelogEntries.d.ts +69 -17
- package/dist/esm/buildChangelogEntries.js +222 -120
- package/dist/esm/buildDependencyGraph.d.ts +6 -6
- package/dist/esm/buildEmptyReleaseEntry.d.ts +1 -8
- package/dist/esm/buildReleaseSummary.d.ts +2 -8
- package/dist/esm/buildReleaseSummary.js +2 -2
- package/dist/esm/buildSyntheticChangelogEntry.d.ts +3 -5
- package/dist/esm/buildSyntheticChangelogEntry.js +2 -2
- package/dist/esm/bumpVersion.d.ts +1 -8
- package/dist/esm/changelogJsonFile.d.ts +5 -7
- package/dist/esm/changelogJsonFile.js +2 -17
- package/dist/esm/changelogJsonUtils.d.ts +7 -10
- package/dist/esm/changelogOverrides.d.ts +79 -100
- package/dist/esm/changelogOverrides.js +138 -58
- package/dist/esm/classifyChangelogCommit.d.ts +36 -0
- package/dist/esm/classifyChangelogCommit.js +34 -0
- package/dist/esm/commitCommand.d.ts +2 -4
- package/dist/esm/compareVersions.d.ts +10 -4
- package/dist/esm/compareVersions.js +16 -0
- package/dist/esm/configFlagSchema.d.ts +1 -1
- package/dist/esm/createGithubRelease.d.ts +7 -19
- package/dist/esm/createGithubReleaseCommand.d.ts +5 -5
- package/dist/esm/createGithubReleaseCommand.js +9 -9
- package/dist/esm/createTags.d.ts +2 -3
- package/dist/esm/decideRelease.d.ts +11 -41
- package/dist/esm/decideRelease.js +5 -27
- package/dist/esm/defaults.d.ts +5 -24
- package/dist/esm/defaults.js +7 -5
- package/dist/esm/defineConfig.d.ts +1 -1
- package/dist/esm/deleteFileIfExists.d.ts +1 -1
- package/dist/esm/deriveReleaseNotesConfig.d.ts +20 -0
- package/dist/esm/deriveReleaseNotesConfig.js +21 -0
- package/dist/esm/deriveWorkspaceConfig.d.ts +3 -5
- package/dist/esm/detectPackageManager.d.ts +2 -4
- package/dist/esm/detectUndeclaredTagPrefixes.d.ts +4 -6
- package/dist/esm/detectUndeclaredTagPrefixes.js +1 -1
- package/dist/esm/determineBumpType.d.ts +11 -11
- package/dist/esm/determineBumpType.js +6 -7
- package/dist/esm/discoverWorkspaces.d.ts +14 -15
- package/dist/esm/discoverWorkspaces.js +12 -12
- package/dist/esm/enterRepoRoot.d.ts +12 -0
- package/dist/esm/enterRepoRoot.js +16 -0
- package/dist/esm/enumerateReleaseWindows.d.ts +50 -0
- package/dist/esm/enumerateReleaseWindows.js +124 -0
- package/dist/esm/extractMigration.d.ts +6 -8
- package/dist/esm/findUnroutedEntryScopes.d.ts +16 -0
- package/dist/esm/findUnroutedEntryScopes.js +57 -0
- package/dist/esm/formatExcludedSkip.d.ts +3 -0
- package/dist/esm/formatExcludedSkip.js +3 -0
- package/dist/esm/formatPrivateSkip.d.ts +1 -6
- package/dist/esm/generateChangelogs.d.ts +13 -26
- package/dist/esm/generateChangelogs.js +0 -14
- package/dist/esm/glyphs.d.ts +2 -2
- package/dist/esm/help/prepareHelp.d.ts +3 -4
- package/dist/esm/help/prepareHelp.js +7 -8
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/init/checks.d.ts +3 -3
- package/dist/esm/init/checks.js +4 -1
- package/dist/esm/init/detectRepoType.d.ts +2 -3
- package/dist/esm/init/hasProvenance.d.ts +2 -0
- package/dist/esm/init/hasProvenance.js +3 -0
- package/dist/esm/init/initCommand.d.ts +3 -6
- package/dist/esm/init/initCommand.js +11 -11
- package/dist/esm/init/parseJsonRecord.d.ts +1 -4
- package/dist/esm/init/scaffold.d.ts +1 -3
- package/dist/esm/init/scaffold.js +2 -30
- package/dist/esm/init/templates.d.ts +9 -11
- package/dist/esm/init/templates.js +12 -11
- package/dist/esm/init/updateTemplatesCommand.d.ts +13 -0
- package/dist/esm/init/updateTemplatesCommand.js +64 -0
- package/dist/esm/injectReleaseNotesIntoReadme.d.ts +12 -17
- package/dist/esm/injectSection.d.ts +3 -3
- package/dist/esm/loadConfig.d.ts +16 -14
- package/dist/esm/loadConfig.js +2 -5
- package/dist/esm/loadValidatedConfig.d.ts +16 -19
- package/dist/esm/loadValidatedConfig.js +6 -1
- package/dist/esm/packsPath.d.ts +9 -9
- package/dist/esm/parseChangeRecordBlock.d.ts +37 -0
- package/dist/esm/parseChangeRecordBlock.js +134 -0
- package/dist/esm/parseCommitMessage.d.ts +42 -32
- package/dist/esm/parseCommitMessage.js +33 -41
- package/dist/esm/parseRequestedTags.d.ts +3 -3
- package/dist/esm/planReleaseNotesPreviews.d.ts +6 -6
- package/dist/esm/planVersionBump.d.ts +5 -3
- package/dist/esm/planVersionBump.js +3 -0
- package/dist/esm/prepareCommand.d.ts +4 -7
- package/dist/esm/prepareCommand.js +17 -18
- package/dist/esm/previewTagPrefixes.d.ts +8 -10
- package/dist/esm/propagateBumps.d.ts +6 -7
- package/dist/esm/publish.d.ts +1 -1
- package/dist/esm/publishCommand.d.ts +4 -3
- package/dist/esm/publishCommand.js +8 -8
- package/dist/esm/pushCommand.d.ts +4 -3
- package/dist/esm/pushCommand.js +8 -2
- package/dist/esm/pushRelease.d.ts +2 -2
- package/dist/esm/readChangelogSections.d.ts +33 -0
- package/dist/esm/readChangelogSections.js +80 -0
- package/dist/esm/releaseFiles.d.ts +5 -7
- package/dist/esm/releasePlan.d.ts +11 -13
- package/dist/esm/releasePrepare.d.ts +25 -25
- package/dist/esm/releasePrepare.js +80 -80
- package/dist/esm/releasePrepareMono.d.ts +9 -7
- package/dist/esm/releasePrepareMono.js +114 -99
- package/dist/esm/releasePrepareProject.d.ts +19 -29
- package/dist/esm/releasePrepareProject.js +46 -45
- package/dist/esm/renderChangelogMarkdown.d.ts +10 -4
- package/dist/esm/renderChangelogMarkdown.js +27 -2
- package/dist/esm/renderReleaseNotes.d.ts +3 -11
- package/dist/esm/renderReleaseNotes.js +2 -6
- package/dist/esm/reportPrepare.d.ts +4 -5
- package/dist/esm/reportPrepare.js +67 -42
- package/dist/esm/resolveCommandTags.d.ts +15 -11
- package/dist/esm/resolveCommandTags.js +35 -5
- package/dist/esm/resolveConfigFlag.d.ts +7 -0
- package/dist/esm/resolveConfigFlag.js +4 -0
- package/dist/esm/resolveReleaseTags.d.ts +6 -8
- package/dist/esm/resolveReleaseTags.js +1 -1
- package/dist/esm/resolveStylesOrExit.d.ts +2 -2
- package/dist/esm/showTagPrefixesCommand.d.ts +7 -10
- package/dist/esm/showTagPrefixesCommand.js +4 -4
- package/dist/esm/stripEmojiPrefix.d.ts +1 -0
- package/dist/esm/stripScope.d.ts +2 -2
- package/dist/esm/stripScope.js +3 -3
- package/dist/esm/sync-labels/generateCommand.d.ts +11 -10
- package/dist/esm/sync-labels/generateCommand.js +11 -8
- package/dist/esm/sync-labels/initCommand.d.ts +6 -7
- package/dist/esm/sync-labels/initCommand.js +2 -2
- package/dist/esm/sync-labels/presets.d.ts +5 -4
- package/dist/esm/sync-labels/presets.js +9 -9
- package/dist/esm/sync-labels/resolveLabels.d.ts +7 -7
- package/dist/esm/sync-labels/resolveLabels.js +1 -1
- package/dist/esm/sync-labels/retiredConfig.d.ts +4 -5
- package/dist/esm/sync-labels/syncCommand.d.ts +1 -4
- package/dist/esm/sync-labels/templates.d.ts +3 -3
- package/dist/esm/sync-labels/templates.js +3 -3
- package/dist/esm/sync-labels/typeLabels.d.ts +14 -0
- package/dist/esm/sync-labels/typeLabels.js +38 -0
- package/dist/esm/sync-labels/types.d.ts +1 -1
- package/dist/esm/tagCommand.d.ts +1 -1
- package/dist/esm/typeGuards.d.ts +2 -2
- package/dist/esm/types.d.ts +185 -116
- package/dist/esm/types.js +2 -2
- package/dist/esm/validateConfig.d.ts +2 -11
- package/dist/esm/validateConfig.js +5 -1
- package/dist/esm/validateOnlyExcludesStrandedDependents.d.ts +14 -12
- package/dist/esm/validateOverridesCommand.d.ts +19 -21
- package/dist/esm/validateOverridesCommand.js +16 -23
- package/docs/api.md +6 -6
- package/docs/changelogs.md +90 -28
- package/docs/configuration.md +30 -29
- package/docs/editorial-overrides.md +90 -31
- package/docs/labels.md +21 -19
- package/docs/project-releases.md +14 -14
- package/docs/publishing.md +5 -5
- package/docs/readiness-checks.md +3 -3
- package/docs/releasing.md +54 -24
- package/docs/work-types.md +46 -58
- package/package.json +7 -7
- package/presets/labels/common.yaml +1 -41
- package/schemas/changelog-overrides.json +39 -0
- package/cliff.toml.template +0 -65
- package/dist/esm/collectPolicyViolations.d.ts +0 -15
- package/dist/esm/collectPolicyViolations.js +0 -12
- package/dist/esm/determineBumpFromCommits.d.ts +0 -17
- package/dist/esm/determineBumpFromCommits.js +0 -28
- package/dist/esm/getCommitsSinceTarget.d.ts +0 -21
- package/dist/esm/getCommitsSinceTarget.js +0 -66
- package/dist/esm/resolveCliffConfigPath.d.ts +0 -11
- package/dist/esm/resolveCliffConfigPath.js +0 -20
- package/dist/esm/resolveReleaseNotesConfig.d.ts +0 -26
- package/dist/esm/resolveReleaseNotesConfig.js +0 -29
- package/dist/esm/runGitCliff.d.ts +0 -38
- package/dist/esm/runGitCliff.js +0 -25
- package/dist/esm/workTypesData.d.ts +0 -50
- package/dist/esm/workTypesData.js +0 -145
- package/schemas/label-map.json +0 -24
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import type { ChangelogEntry, ChangelogOverride, WorkspaceConfig } from './types.js';
|
|
2
|
+
/** Known fields on a single override entry; presence of any other field is a validation error. */
|
|
3
|
+
export declare const KNOWN_OVERRIDE_FIELDS: Set<string>;
|
|
4
|
+
/** Form of an override key: a lowercase hex commit hash or prefix, optionally followed by `:<n>`, a 1-based entry position. */
|
|
5
|
+
export declare const OVERRIDE_KEY_PATTERN: RegExp;
|
|
2
6
|
/** Result of loading an override file: either parsed overrides or a list of structured errors. */
|
|
3
7
|
export type LoadChangelogOverridesResult = {
|
|
4
8
|
overrides: Map<string, ChangelogOverride>;
|
|
@@ -6,55 +10,47 @@ export type LoadChangelogOverridesResult = {
|
|
|
6
10
|
errors: string[];
|
|
7
11
|
};
|
|
8
12
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* - Missing file resolves to an empty map (no-op default; matches "absent file → unchanged behavior").
|
|
12
|
-
* - Malformed JSON, wrong top-level shape, or any per-entry validation failure surfaces as
|
|
13
|
-
* structured errors. Callers decide how to surface them.
|
|
14
|
-
*
|
|
15
|
-
* Returns either `{ overrides: Map }` on success or `{ errors: string[] }` on failure. Pure
|
|
16
|
-
* except for the single file read; performs no other I/O.
|
|
13
|
+
* Loads and validates the editorial overrides file at `path`. A missing file yields an empty map; an unreadable file,
|
|
14
|
+
* malformed JSON, a wrong top-level shape, or any per-entry validation failure yields errors.
|
|
17
15
|
*/
|
|
18
16
|
export declare function loadChangelogOverrides(path: string): LoadChangelogOverridesResult;
|
|
19
17
|
/**
|
|
20
|
-
*
|
|
18
|
+
* Validates a parsed override record, returning the valid overrides and an error message for each problem.
|
|
21
19
|
*
|
|
22
|
-
* Each error names the offending key (e.g. `overrides['abc']: 'audience' must be one of …`)
|
|
23
|
-
*
|
|
20
|
+
* Each error names the offending key (e.g. `overrides['abc']: 'audience' must be one of …`) so that the user can find
|
|
21
|
+
* it in the override file.
|
|
24
22
|
*/
|
|
25
23
|
export declare function validateChangelogOverrides(raw: unknown): {
|
|
26
24
|
overrides: Map<string, ChangelogOverride>;
|
|
27
25
|
errors: string[];
|
|
28
26
|
};
|
|
29
|
-
/**
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
/** Splits a valid override key into its hash prefix and, for an ordinal key, its 1-based entry position. */
|
|
28
|
+
export declare function parseOverrideKey(key: string): {
|
|
29
|
+
hashPrefix: string;
|
|
30
|
+
entry?: number;
|
|
31
|
+
};
|
|
32
|
+
/** Formats the warning for an override key that did not match any item in the changelog. */
|
|
34
33
|
export declare function formatStaleOverrideKeyWarning(key: string): string;
|
|
35
34
|
/**
|
|
36
|
-
*
|
|
35
|
+
* Applies overrides to changelog entries, returning new entries without mutating the input.
|
|
37
36
|
*
|
|
38
|
-
*
|
|
39
|
-
* -
|
|
40
|
-
* -
|
|
41
|
-
*
|
|
37
|
+
* Each key's hash prefix is matched against the distinct `ChangelogItem.hash` values:
|
|
38
|
+
* - No match: The key is unmatched in this batch, and this function doesn't emit a warning.
|
|
39
|
+
* - One match: A bare key resolves to every item of that commit, and an ordinal key `<hash>:<n>` to the items whose
|
|
40
|
+
* `entry` is `n`. A key that doesn't resolve to any item is unmatched, so an ordinal key on a title-derived item
|
|
41
|
+
* goes stale.
|
|
42
|
+
* - Several matches: an error (ambiguous prefix).
|
|
42
43
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* may target a commit that lives in another workspace, so the per-batch zero-match signal is
|
|
46
|
-
* insufficient on its own. Single-package and monorepo orchestrators format warnings using
|
|
47
|
-
* `formatStaleOverrideKeyWarning` after aggregating `matchedKeys` across all apply calls.
|
|
44
|
+
* Two more conditions are errors, and the keys involved apply nowhere: a bare key that sets `description` or `body` on a
|
|
45
|
+
* commit with several items, and two keys that resolve to the same item.
|
|
48
46
|
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* - `'all'` and `'dev'` are validated out before reaching the applier.
|
|
47
|
+
* `matchedKeys` lists the keys that resolved to at least one item without error. The caller computes stale-key
|
|
48
|
+
* warnings, because in a monorepo a key may target a commit in another workspace: A key unmatched in one batch is not
|
|
49
|
+
* necessarily stale.
|
|
53
50
|
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
* transformed entries so the caller decides whether to abort or log-and-continue.
|
|
51
|
+
* An override whose audience is `'skip'` removes its item, and a section left empty is dropped; an entry left without
|
|
52
|
+
* sections is kept. An item without a `hash`, such as a synthetic propagation item, passes through unmatched. Errors
|
|
53
|
+
* are returned rather than thrown, and the caller decides whether to abort.
|
|
58
54
|
*/
|
|
59
55
|
export declare function applyChangelogOverrides(entries: ChangelogEntry[], overrides: Map<string, ChangelogOverride>): {
|
|
60
56
|
entries: ChangelogEntry[];
|
|
@@ -63,10 +59,8 @@ export declare function applyChangelogOverrides(entries: ChangelogEntry[], overr
|
|
|
63
59
|
matchedKeys: string[];
|
|
64
60
|
};
|
|
65
61
|
/**
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* `scopeRoot` is the directory at which a scope's other artifacts live (e.g., `'.'` for the
|
|
69
|
-
* project, `'packages/foo'` for a workspace). The returned path is repo-relative.
|
|
62
|
+
* Resolves the conventional override-file path for a scope root: the directory in which a scope's other artifacts live
|
|
63
|
+
* (e.g., `'.'` for the project, `'packages/foo'` for a workspace). The returned path is repo-relative.
|
|
70
64
|
*/
|
|
71
65
|
export declare function resolveOverridePath(scopeRoot: string): string;
|
|
72
66
|
/** Result of {@link loadOverridesForScopes}: per-scope maps plus accumulated load/validation errors. */
|
|
@@ -79,40 +73,27 @@ export interface LoadOverridesForScopesResult {
|
|
|
79
73
|
errors: string[];
|
|
80
74
|
}
|
|
81
75
|
/**
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
* aggregates errors across all files (rather than throwing on the first failure) so a
|
|
86
|
-
* consumer who edits multiple files at once sees every problem in one report. Missing files
|
|
87
|
-
* resolve to empty maps — matches the existing single-file behavior.
|
|
88
|
-
*
|
|
89
|
-
* The caller is expected to surface a combined error when `errors.length > 0` and abort the
|
|
90
|
-
* release before any workspace begins writing.
|
|
76
|
+
* Loads and validates the override file of every requested scope, collecting the errors of all files rather than
|
|
77
|
+
* stopping at the first, so that a user who edits several files sees every problem in one report. A missing file
|
|
78
|
+
* yields an empty map.
|
|
91
79
|
*/
|
|
92
80
|
export declare function loadOverridesForScopes(scopes: {
|
|
93
81
|
project?: string;
|
|
94
82
|
workspaces?: string[];
|
|
95
83
|
}): LoadOverridesForScopesResult;
|
|
96
84
|
/**
|
|
97
|
-
*
|
|
85
|
+
* Composes root and workspace override maps into the effective map for one workspace, without mutating either.
|
|
98
86
|
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
* fall through to the existing ambiguous-prefix error in {@link applyChangelogOverrides}.
|
|
103
|
-
*
|
|
104
|
-
* Pure: never mutates inputs.
|
|
87
|
+
* A workspace key identical to a root key replaces the root entry entirely, without a field-level merge. Distinct keys
|
|
88
|
+
* that resolve to the same item do not shadow each other here: {@link applyChangelogOverrides} reports them as
|
|
89
|
+
* overlapping.
|
|
105
90
|
*/
|
|
106
91
|
export declare function composeOverrides(rootEntries: Map<string, ChangelogOverride>, workspaceEntries: Map<string, ChangelogOverride> | undefined): Map<string, ChangelogOverride>;
|
|
107
92
|
/**
|
|
108
|
-
*
|
|
109
|
-
* sites. Bundles the loaded per-scope maps with the run-scoped warning aggregators so each
|
|
110
|
-
* call site can both consume the maps it needs and report into the same warning channel.
|
|
93
|
+
* The loaded per-scope override maps and the run's warning aggregators, shared by every apply of a prepare run.
|
|
111
94
|
*
|
|
112
|
-
* `globalMatchedRootKeys`
|
|
113
|
-
*
|
|
114
|
-
* stale-key semantics are local (a workspace key that doesn't match in its own workspace is
|
|
115
|
-
* unambiguously stale and is warned immediately, not aggregated to end-of-run).
|
|
95
|
+
* `globalMatchedRootKeys` contains the root keys matched in any apply. Workspace keys are not added: A workspace key
|
|
96
|
+
* that matches nothing in its own workspace is stale, and it is warned about at once rather than at the end of the run.
|
|
116
97
|
*/
|
|
117
98
|
export interface OverrideContext {
|
|
118
99
|
project: Map<string, ChangelogOverride>;
|
|
@@ -121,18 +102,25 @@ export interface OverrideContext {
|
|
|
121
102
|
globalMatchedRootKeys: Set<string>;
|
|
122
103
|
}
|
|
123
104
|
/**
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
* is a bug, and we want the prepare run to fail before any workspace begins writing.
|
|
105
|
+
* Loads and validates the override files of the root and every workspace, and bundles them with empty warning
|
|
106
|
+
* aggregators. Throws if any file fails to load, so that a malformed checked-in override file stops `prepare` before
|
|
107
|
+
* any workspace writes.
|
|
128
108
|
*/
|
|
129
109
|
export declare function createOverrideContext(workspaces: WorkspaceConfig[]): OverrideContext;
|
|
110
|
+
/** A changelog item as override matching sees it. `entry` is absent for a title-derived item. */
|
|
111
|
+
export interface OverrideTargetItem {
|
|
112
|
+
hash: string;
|
|
113
|
+
entry?: number;
|
|
114
|
+
}
|
|
130
115
|
/** Per-scope input to {@link validateAllChangelogOverrides}. */
|
|
131
116
|
export interface ChangelogOverrideScope {
|
|
132
|
-
/**
|
|
117
|
+
/**
|
|
118
|
+
* Path to the override file, used to load the file and to attribute findings. A relative path resolves against the
|
|
119
|
+
* process working directory.
|
|
120
|
+
*/
|
|
133
121
|
filePath: string;
|
|
134
|
-
/**
|
|
135
|
-
|
|
122
|
+
/** Items in this scope's history window. Each override key is matched against these. */
|
|
123
|
+
items: readonly OverrideTargetItem[];
|
|
136
124
|
}
|
|
137
125
|
/** Inputs to {@link validateAllChangelogOverrides}. */
|
|
138
126
|
export interface ValidateAllChangelogOverridesInputs {
|
|
@@ -141,56 +129,47 @@ export interface ValidateAllChangelogOverridesInputs {
|
|
|
141
129
|
*
|
|
142
130
|
* The file at `filePath` is loaded once and used in two ways:
|
|
143
131
|
* - Its overrides are composed into every workspace's apply (root-tier overrides apply globally).
|
|
144
|
-
* - When `
|
|
132
|
+
* - When `items` is provided, the project map is also applied directly to those items
|
|
145
133
|
* (project release in monorepo mode, or the package's history in single-package mode).
|
|
146
134
|
*
|
|
147
|
-
* Omit when
|
|
135
|
+
* Omit when the project file doesn't exist.
|
|
148
136
|
*/
|
|
149
137
|
project?: {
|
|
150
138
|
filePath: string;
|
|
151
|
-
|
|
139
|
+
items?: readonly OverrideTargetItem[];
|
|
152
140
|
};
|
|
153
|
-
/** Per-workspace scopes. Each workspace's file applies only to its own
|
|
141
|
+
/** Per-workspace scopes. Each workspace's file applies only to its own items. */
|
|
154
142
|
workspaces?: readonly ChangelogOverrideScope[];
|
|
155
143
|
}
|
|
156
|
-
/**
|
|
144
|
+
/**
|
|
145
|
+
* Result of {@link validateAllChangelogOverrides}: aggregated errors and warnings, each prefixed with the path of the
|
|
146
|
+
* file to which it pertains.
|
|
147
|
+
*/
|
|
157
148
|
export interface ValidateAllChangelogOverridesResult {
|
|
158
149
|
errors: string[];
|
|
159
150
|
warnings: string[];
|
|
160
151
|
}
|
|
161
152
|
/**
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
153
|
+
* Validates every override file against the items of its scopes and returns the aggregated findings. It reads the
|
|
154
|
+
* override files but doesn't collect any items: The caller supplies each scope's items.
|
|
155
|
+
*
|
|
156
|
+
* Items built by `buildChangelogEntries`, as `release-kit prepare` builds them, yield the matches that `prepare`
|
|
157
|
+
* computes, tier asymmetry included: A workspace-tier key is stale when it matches nothing in its own workspace, and a
|
|
158
|
+
* root-tier key only when it matches nothing in any scope, the project release window included.
|
|
165
159
|
*
|
|
166
|
-
*
|
|
167
|
-
* `hashes` is built by `buildChangelogEntries` — the same path `release-kit prepare` walks —
|
|
168
|
-
* so the match-set is byte-equal to what `prepare` would compute. The tier asymmetry is part
|
|
169
|
-
* of that contract: workspace-tier keys are stale if they don't match in their own workspace;
|
|
170
|
-
* root-tier keys are stale only if they don't match in any scope (no workspace AND not the
|
|
171
|
-
* project release window). Library callers that construct `inputs` directly are responsible
|
|
172
|
-
* for supplying the same hash universes if they want this guarantee.
|
|
160
|
+
* Every returned string is prefixed with the path of the override file to which it pertains.
|
|
173
161
|
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
162
|
+
* A relative `filePath`, in any scope, resolves against the process working directory, not against the repo root.
|
|
163
|
+
* A caller running from elsewhere passes absolute paths or changes directory first.
|
|
176
164
|
*/
|
|
177
165
|
export declare function validateAllChangelogOverrides(inputs: ValidateAllChangelogOverridesInputs): ValidateAllChangelogOverridesResult;
|
|
178
166
|
/**
|
|
179
|
-
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
* The composed map is applied in a single {@link applyChangelogOverrides} call. Matched keys
|
|
183
|
-
* are demultiplexed by source via `Map.has` lookups on the original (uncomposed) maps so the
|
|
184
|
-
* stale-key semantics stay tier-aware:
|
|
185
|
-
*
|
|
186
|
-
* - Workspace-sourced keys (those present in the per-workspace map, regardless of whether
|
|
187
|
-
* the root map also has the same byte-equal key) that did NOT match are unambiguously
|
|
188
|
-
* stale in their own apply context — push an immediate stale warning naming the key.
|
|
189
|
-
* - Root-sourced matched keys (present in root, absent from this workspace's map) are added
|
|
190
|
-
* to `globalMatchedRootKeys` so the orchestrator's end-of-run loop can dedupe across
|
|
191
|
-
* batches and warn only on root keys that matched nowhere.
|
|
167
|
+
* Applies the composed root and workspace override map to a workspace's changelog entries, and records stale keys by
|
|
168
|
+
* tier.
|
|
192
169
|
*
|
|
193
|
-
*
|
|
194
|
-
*
|
|
170
|
+
* A workspace key that matched nothing, whether or not the root map has the same key, is stale, and it is warned about
|
|
171
|
+
* at once. The function adds each root key that matched without being shadowed to `globalMatchedRootKeys`, from which
|
|
172
|
+
* the caller warns, at the end of the run, about the root keys that matched nowhere. Throws if applying reports any
|
|
173
|
+
* error, such as an ambiguous prefix.
|
|
195
174
|
*/
|
|
196
175
|
export declare function applyWorkspaceOverrides(newEntries: ChangelogEntry[], workspacePath: string, overrideContext: OverrideContext): ReturnType<typeof applyChangelogOverrides>;
|
|
@@ -6,7 +6,9 @@ import { isRecord } from "./typeGuards.js";
|
|
|
6
6
|
const OVERRIDES_FILENAME = '.meta/changelog-overrides.json';
|
|
7
7
|
const VALID_AUDIENCE_VALUES = new Set(['all', 'dev', 'skip']);
|
|
8
8
|
const V1_SUPPORTED_AUDIENCE_VALUES = new Set(['skip']);
|
|
9
|
-
const KNOWN_OVERRIDE_FIELDS = new Set(['audience', 'description', 'body', 'breaking']);
|
|
9
|
+
export const KNOWN_OVERRIDE_FIELDS = new Set(['audience', 'description', 'body', 'breaking']);
|
|
10
|
+
export const OVERRIDE_KEY_PATTERN = /^[0-9a-f]+(:[1-9][0-9]*)?$/;
|
|
11
|
+
const SCHEMA_KEY = '$schema';
|
|
10
12
|
export function loadChangelogOverrides(path) {
|
|
11
13
|
if (!existsSync(path)) {
|
|
12
14
|
return { overrides: new Map() };
|
|
@@ -43,8 +45,14 @@ export function validateChangelogOverrides(raw) {
|
|
|
43
45
|
return { overrides, errors };
|
|
44
46
|
}
|
|
45
47
|
for (const [key, rawEntry] of Object.entries(raw)) {
|
|
46
|
-
if (key ===
|
|
47
|
-
|
|
48
|
+
if (key === SCHEMA_KEY) {
|
|
49
|
+
if (typeof rawEntry !== 'string') {
|
|
50
|
+
errors.push(`Override file: '${SCHEMA_KEY}' must be a string`);
|
|
51
|
+
}
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (!OVERRIDE_KEY_PATTERN.test(key)) {
|
|
55
|
+
errors.push(`overrides['${key}']: key must be a lowercase hex commit hash or prefix, optionally followed by ':<n>'`);
|
|
48
56
|
continue;
|
|
49
57
|
}
|
|
50
58
|
const validated = validateSingleOverride(key, rawEntry, errors);
|
|
@@ -54,6 +62,13 @@ export function validateChangelogOverrides(raw) {
|
|
|
54
62
|
}
|
|
55
63
|
return { overrides, errors };
|
|
56
64
|
}
|
|
65
|
+
export function parseOverrideKey(key) {
|
|
66
|
+
const separatorIndex = key.indexOf(':');
|
|
67
|
+
if (separatorIndex === -1) {
|
|
68
|
+
return { hashPrefix: key };
|
|
69
|
+
}
|
|
70
|
+
return { hashPrefix: key.slice(0, separatorIndex), entry: Number(key.slice(separatorIndex + 1)) };
|
|
71
|
+
}
|
|
57
72
|
function validateSingleOverride(key, rawEntry, errors) {
|
|
58
73
|
if (!isRecord(rawEntry)) {
|
|
59
74
|
errors.push(`overrides['${key}']: must be an object`);
|
|
@@ -125,53 +140,27 @@ function validateAudience(key, value, errors) {
|
|
|
125
140
|
return 'skip';
|
|
126
141
|
}
|
|
127
142
|
export function formatStaleOverrideKeyWarning(key) {
|
|
128
|
-
return `Override key '${key}' did not match any
|
|
143
|
+
return `Override key '${key}' did not match any item in the changelog (likely a stale reference)`;
|
|
129
144
|
}
|
|
130
145
|
export function applyChangelogOverrides(entries, overrides) {
|
|
131
146
|
const warnings = [];
|
|
132
|
-
const errors = [];
|
|
133
|
-
const matchedKeys = [];
|
|
134
147
|
if (overrides.size === 0) {
|
|
135
|
-
return { entries: entries.map(cloneEntry), warnings, errors, matchedKeys };
|
|
136
|
-
}
|
|
137
|
-
const allHashes = [];
|
|
138
|
-
for (const entry of entries) {
|
|
139
|
-
for (const section of entry.sections) {
|
|
140
|
-
for (const item of section.items) {
|
|
141
|
-
if (item.hash !== undefined) {
|
|
142
|
-
allHashes.push(item.hash);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
148
|
+
return { entries: entries.map(cloneEntry), warnings, errors: [], matchedKeys: [] };
|
|
146
149
|
}
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
if (matches.length === 0) {
|
|
151
|
-
continue;
|
|
152
|
-
}
|
|
153
|
-
if (matches.length > 1) {
|
|
154
|
-
errors.push(`Override key '${overrideKey}' is ambiguous: matches multiple commits (${matches.join(', ')}). ` +
|
|
155
|
-
'Use a longer prefix or the full commit hash.');
|
|
156
|
-
continue;
|
|
157
|
-
}
|
|
158
|
-
keyToMatchedHashes.set(overrideKey, matches);
|
|
159
|
-
matchedKeys.push(overrideKey);
|
|
160
|
-
}
|
|
161
|
-
const hashToOverride = new Map();
|
|
162
|
-
for (const [overrideKey, matchedHashes] of keyToMatchedHashes) {
|
|
150
|
+
const { errors, itemIdToKey } = resolveOverrideKeys(indexEntryPositions(entries), overrides);
|
|
151
|
+
const itemIdToOverride = new Map();
|
|
152
|
+
for (const [itemId, overrideKey] of itemIdToKey) {
|
|
163
153
|
const override = overrides.get(overrideKey);
|
|
164
|
-
if (override
|
|
165
|
-
|
|
166
|
-
for (const hash of matchedHashes) {
|
|
167
|
-
hashToOverride.set(hash, override);
|
|
154
|
+
if (override !== undefined) {
|
|
155
|
+
itemIdToOverride.set(itemId, override);
|
|
168
156
|
}
|
|
169
157
|
}
|
|
158
|
+
const matchedKeys = [...new Set(itemIdToKey.values())];
|
|
170
159
|
const transformedEntries = [];
|
|
171
160
|
for (const entry of entries) {
|
|
172
161
|
const transformedSections = [];
|
|
173
162
|
for (const section of entry.sections) {
|
|
174
|
-
const transformedItems = applyOverridesToItems(section.items,
|
|
163
|
+
const transformedItems = applyOverridesToItems(section.items, itemIdToOverride);
|
|
175
164
|
if (transformedItems.length === 0) {
|
|
176
165
|
continue;
|
|
177
166
|
}
|
|
@@ -181,14 +170,93 @@ export function applyChangelogOverrides(entries, overrides) {
|
|
|
181
170
|
}
|
|
182
171
|
return { entries: transformedEntries, warnings, errors, matchedKeys };
|
|
183
172
|
}
|
|
184
|
-
function
|
|
173
|
+
function resolveOverrideKeys(positionsByHash, overrides) {
|
|
174
|
+
const errors = [];
|
|
175
|
+
const failedKeys = new Set();
|
|
176
|
+
const itemIdToKey = new Map();
|
|
177
|
+
for (const [overrideKey, override] of overrides) {
|
|
178
|
+
const resolution = resolveOverrideKey(overrideKey, positionsByHash);
|
|
179
|
+
if (resolution.kind === 'ambiguous') {
|
|
180
|
+
errors.push(`Override key '${overrideKey}' is ambiguous: matches multiple commits (${resolution.hashes.join(', ')}). ` +
|
|
181
|
+
'Use a longer prefix or the full commit hash.');
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
if (resolution.kind === 'none') {
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
const { hash, positions } = resolution;
|
|
188
|
+
if (parseOverrideKey(overrideKey).entry === undefined && positions.length > 1) {
|
|
189
|
+
const fieldsSet = ['description', 'body'].filter((field) => override[field] !== undefined);
|
|
190
|
+
if (fieldsSet.length > 0) {
|
|
191
|
+
const ordinalKeys = positions.map((position) => `${overrideKey}:${position}`).join(', ');
|
|
192
|
+
errors.push(`Override key '${overrideKey}' sets ${fieldsSet.join(' and ')} on a commit with several items; use ${ordinalKeys}`);
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
for (const position of positions) {
|
|
197
|
+
const itemId = formatItemId(hash, position);
|
|
198
|
+
const claimingKey = itemIdToKey.get(itemId);
|
|
199
|
+
if (claimingKey === undefined) {
|
|
200
|
+
itemIdToKey.set(itemId, overrideKey);
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
const target = position === undefined ? `commit ${hash}` : `the item at ${hash}:${position}`;
|
|
204
|
+
errors.push(`Override keys '${claimingKey}' and '${overrideKey}' both match ${target}; keep one`);
|
|
205
|
+
failedKeys.add(claimingKey);
|
|
206
|
+
failedKeys.add(overrideKey);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
for (const [itemId, overrideKey] of itemIdToKey) {
|
|
210
|
+
if (failedKeys.has(overrideKey)) {
|
|
211
|
+
itemIdToKey.delete(itemId);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return { errors, itemIdToKey };
|
|
215
|
+
}
|
|
216
|
+
function resolveOverrideKey(overrideKey, positionsByHash) {
|
|
217
|
+
const { hashPrefix, entry } = parseOverrideKey(overrideKey);
|
|
218
|
+
const hashes = positionsByHash
|
|
219
|
+
.keys()
|
|
220
|
+
.filter((hash) => hash.startsWith(hashPrefix))
|
|
221
|
+
.toArray();
|
|
222
|
+
const [hash] = hashes;
|
|
223
|
+
if (hash === undefined) {
|
|
224
|
+
return { kind: 'none' };
|
|
225
|
+
}
|
|
226
|
+
if (hashes.length > 1) {
|
|
227
|
+
return { kind: 'ambiguous', hashes };
|
|
228
|
+
}
|
|
229
|
+
const available = [...(positionsByHash.get(hash) ?? [])];
|
|
230
|
+
const positions = entry === undefined
|
|
231
|
+
? available.toSorted((left, right) => (left ?? 0) - (right ?? 0))
|
|
232
|
+
: available.filter((position) => position === entry);
|
|
233
|
+
return positions.length === 0 ? { kind: 'none' } : { kind: 'items', hash, positions };
|
|
234
|
+
}
|
|
235
|
+
function indexEntryPositions(entries) {
|
|
236
|
+
return indexItemPositions(entries.flatMap((entry) => entry.sections.flatMap((section) => section.items)));
|
|
237
|
+
}
|
|
238
|
+
function indexItemPositions(items) {
|
|
239
|
+
const positionsByHash = new Map();
|
|
240
|
+
for (const item of items) {
|
|
241
|
+
if (item.hash === undefined)
|
|
242
|
+
continue;
|
|
243
|
+
const positions = positionsByHash.get(item.hash) ?? new Set();
|
|
244
|
+
positions.add(item.entry);
|
|
245
|
+
positionsByHash.set(item.hash, positions);
|
|
246
|
+
}
|
|
247
|
+
return positionsByHash;
|
|
248
|
+
}
|
|
249
|
+
function formatItemId(hash, entry) {
|
|
250
|
+
return entry === undefined ? hash : `${hash}:${entry}`;
|
|
251
|
+
}
|
|
252
|
+
function applyOverridesToItems(items, itemIdToOverride) {
|
|
185
253
|
const result = [];
|
|
186
254
|
for (const item of items) {
|
|
187
255
|
if (item.hash === undefined) {
|
|
188
256
|
result.push(cloneItem(item));
|
|
189
257
|
continue;
|
|
190
258
|
}
|
|
191
|
-
const override =
|
|
259
|
+
const override = itemIdToOverride.get(formatItemId(item.hash, item.entry));
|
|
192
260
|
if (override === undefined) {
|
|
193
261
|
result.push(cloneItem(item));
|
|
194
262
|
continue;
|
|
@@ -207,6 +275,8 @@ function applyOverrideToItem(item, override) {
|
|
|
207
275
|
}
|
|
208
276
|
if (override.body !== undefined) {
|
|
209
277
|
result.body = override.body;
|
|
278
|
+
}
|
|
279
|
+
if (override.body !== undefined && item.entry === undefined) {
|
|
210
280
|
const migration = extractMigration(override.body);
|
|
211
281
|
if (migration === undefined) {
|
|
212
282
|
delete result.migration;
|
|
@@ -288,7 +358,7 @@ export function validateAllChangelogOverrides(inputs) {
|
|
|
288
358
|
const projectMap = loadScopeMap(projectFilePath, errors);
|
|
289
359
|
const workspaceMaps = (inputs.workspaces ?? []).map((scope) => ({
|
|
290
360
|
filePath: scope.filePath,
|
|
291
|
-
|
|
361
|
+
items: scope.items,
|
|
292
362
|
map: loadScopeMap(scope.filePath, errors),
|
|
293
363
|
}));
|
|
294
364
|
const globalMatchedRootKeys = new Set();
|
|
@@ -302,9 +372,9 @@ export function validateAllChangelogOverrides(inputs) {
|
|
|
302
372
|
globalMatchedRootKeys,
|
|
303
373
|
});
|
|
304
374
|
}
|
|
305
|
-
const
|
|
306
|
-
if (projectFilePath !== undefined &&
|
|
307
|
-
processProjectScope({ projectFilePath, projectMap,
|
|
375
|
+
const projectItems = inputs.project?.items;
|
|
376
|
+
if (projectFilePath !== undefined && projectItems !== undefined) {
|
|
377
|
+
processProjectScope({ projectFilePath, projectMap, projectItems, errors, globalMatchedRootKeys });
|
|
308
378
|
}
|
|
309
379
|
if (projectFilePath !== undefined) {
|
|
310
380
|
collectRootStaleWarnings(projectFilePath, projectMap, globalMatchedRootKeys, warnings);
|
|
@@ -313,39 +383,49 @@ export function validateAllChangelogOverrides(inputs) {
|
|
|
313
383
|
}
|
|
314
384
|
function processWorkspaceScope(args) {
|
|
315
385
|
const { workspace, projectFilePath, projectMap, errors, warnings, globalMatchedRootKeys } = args;
|
|
316
|
-
const { filePath,
|
|
317
|
-
const
|
|
386
|
+
const { filePath, items, map } = workspace;
|
|
387
|
+
const validationEntries = makeValidationEntries(items);
|
|
388
|
+
const positionsByHash = indexItemPositions(items);
|
|
389
|
+
const workspaceApplied = applyChangelogOverrides(validationEntries, map);
|
|
318
390
|
for (const message of workspaceApplied.errors) {
|
|
319
391
|
errors.push(prefixWithFilePath(filePath, message));
|
|
320
392
|
}
|
|
321
393
|
if (projectFilePath !== undefined && projectMap.size > 0) {
|
|
322
394
|
const projectMinusShadowed = filterShadowedKeys(projectMap, map);
|
|
323
|
-
const projectApplied = applyChangelogOverrides(
|
|
395
|
+
const projectApplied = applyChangelogOverrides(validationEntries, projectMinusShadowed);
|
|
324
396
|
for (const message of projectApplied.errors) {
|
|
325
397
|
errors.push(prefixWithFilePath(projectFilePath, message));
|
|
326
398
|
}
|
|
399
|
+
const perFileErrors = new Set([...workspaceApplied.errors, ...projectApplied.errors]);
|
|
400
|
+
const composedApplied = applyChangelogOverrides(validationEntries, composeOverrides(projectMap, map));
|
|
401
|
+
for (const message of composedApplied.errors) {
|
|
402
|
+
if (!perFileErrors.has(message)) {
|
|
403
|
+
errors.push(prefixWithFilePath(filePath, message));
|
|
404
|
+
}
|
|
405
|
+
}
|
|
327
406
|
}
|
|
328
407
|
for (const key of map.keys()) {
|
|
329
|
-
if (!hasAnyMatch(key,
|
|
408
|
+
if (!hasAnyMatch(key, positionsByHash)) {
|
|
330
409
|
warnings.push(formatWorkspaceStaleWarning(filePath, key));
|
|
331
410
|
}
|
|
332
411
|
}
|
|
333
412
|
for (const key of projectMap.keys()) {
|
|
334
413
|
if (map.has(key))
|
|
335
414
|
continue;
|
|
336
|
-
if (hasAnyMatch(key,
|
|
415
|
+
if (hasAnyMatch(key, positionsByHash)) {
|
|
337
416
|
globalMatchedRootKeys.add(key);
|
|
338
417
|
}
|
|
339
418
|
}
|
|
340
419
|
}
|
|
341
420
|
function processProjectScope(args) {
|
|
342
|
-
const { projectFilePath, projectMap,
|
|
343
|
-
const applied = applyChangelogOverrides(makeValidationEntries(
|
|
421
|
+
const { projectFilePath, projectMap, projectItems, errors, globalMatchedRootKeys } = args;
|
|
422
|
+
const applied = applyChangelogOverrides(makeValidationEntries(projectItems), projectMap);
|
|
344
423
|
for (const message of applied.errors) {
|
|
345
424
|
errors.push(prefixWithFilePath(projectFilePath, message));
|
|
346
425
|
}
|
|
426
|
+
const positionsByHash = indexItemPositions(projectItems);
|
|
347
427
|
for (const key of projectMap.keys()) {
|
|
348
|
-
if (hasAnyMatch(key,
|
|
428
|
+
if (hasAnyMatch(key, positionsByHash)) {
|
|
349
429
|
globalMatchedRootKeys.add(key);
|
|
350
430
|
}
|
|
351
431
|
}
|
|
@@ -357,8 +437,8 @@ function collectRootStaleWarnings(projectFilePath, projectMap, globalMatchedRoot
|
|
|
357
437
|
}
|
|
358
438
|
}
|
|
359
439
|
}
|
|
360
|
-
function hasAnyMatch(key,
|
|
361
|
-
return
|
|
440
|
+
function hasAnyMatch(key, positionsByHash) {
|
|
441
|
+
return resolveOverrideKey(key, positionsByHash).kind !== 'none';
|
|
362
442
|
}
|
|
363
443
|
function filterShadowedKeys(projectMap, workspaceMap) {
|
|
364
444
|
const result = new Map();
|
|
@@ -382,7 +462,7 @@ function loadScopeMap(filePath, errors) {
|
|
|
382
462
|
}
|
|
383
463
|
return result.overrides;
|
|
384
464
|
}
|
|
385
|
-
function makeValidationEntries(
|
|
465
|
+
function makeValidationEntries(items) {
|
|
386
466
|
return [
|
|
387
467
|
{
|
|
388
468
|
version: '0.0.0',
|
|
@@ -391,7 +471,7 @@ function makeValidationEntries(hashes) {
|
|
|
391
471
|
{
|
|
392
472
|
title: 'Validation',
|
|
393
473
|
audience: 'all',
|
|
394
|
-
items:
|
|
474
|
+
items: items.map((item) => ({ ...item, description: '' })),
|
|
395
475
|
},
|
|
396
476
|
],
|
|
397
477
|
},
|
|
@@ -401,10 +481,10 @@ function prefixWithFilePath(filePath, message) {
|
|
|
401
481
|
return `${filePath}: ${message}`;
|
|
402
482
|
}
|
|
403
483
|
function formatWorkspaceStaleWarning(filePath, key) {
|
|
404
|
-
return `${filePath}: Override key '${key}' did not match any
|
|
484
|
+
return `${filePath}: Override key '${key}' did not match any item in this workspace's history (likely a stale reference)`;
|
|
405
485
|
}
|
|
406
486
|
function formatRootStaleWarning(filePath, key) {
|
|
407
|
-
return `${filePath}: Override key '${key}' did not match any
|
|
487
|
+
return `${filePath}: Override key '${key}' did not match any item in any scope (likely a stale reference)`;
|
|
408
488
|
}
|
|
409
489
|
export function applyWorkspaceOverrides(newEntries, workspacePath, overrideContext) {
|
|
410
490
|
const { project, perWorkspace, overrideWarnings, globalMatchedRootKeys } = overrideContext;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type ParseCommitMessageOptions } from './parseCommitMessage.js';
|
|
2
|
+
import type { Commit, WorkTypeConfig } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* How a commit's title places it in a changelog: under a section header, excluded by design, or unreadable.
|
|
5
|
+
*
|
|
6
|
+
* `breaking` is the parser's flag under the breaking policies passed in, which a `BREAKING CHANGE:` footer can set.
|
|
7
|
+
*/
|
|
8
|
+
export type ChangelogClassification = {
|
|
9
|
+
kind: 'header';
|
|
10
|
+
header: string;
|
|
11
|
+
type: string;
|
|
12
|
+
breaking: boolean;
|
|
13
|
+
} | {
|
|
14
|
+
kind: 'excluded';
|
|
15
|
+
} | {
|
|
16
|
+
kind: 'unparseable';
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Classifies a commit by its title.
|
|
20
|
+
*
|
|
21
|
+
* Four gates decide, in order: A `release:` or `Merge` subject is excluded; a subject without a ticket-ID prefix is
|
|
22
|
+
* unparseable; a type that `parseCommitMessage` cannot resolve against `workTypes` is unparseable; and a type that
|
|
23
|
+
* `workTypes` excludes from the changelog is excluded. A commit that passes all four takes the header that its type
|
|
24
|
+
* declares.
|
|
25
|
+
*
|
|
26
|
+
* The function passes `options` to the parse, so a policy violation is reported for every ticketed commit whose type
|
|
27
|
+
* resolves, excluded types included.
|
|
28
|
+
*/
|
|
29
|
+
export declare function classifyChangelogCommit(commit: Pick<Commit, 'hash' | 'message'>, workTypes: Record<string, WorkTypeConfig>, options?: ParseCommitMessageOptions): ChangelogClassification;
|
|
30
|
+
/**
|
|
31
|
+
* Reports whether a subject belongs to a commit that is never included in a changelog: a `release:` commit, which
|
|
32
|
+
* records version bumps, or a git merge commit, whose content the merged commits already report.
|
|
33
|
+
*/
|
|
34
|
+
export declare function isNonChangeSubject(subject: string): boolean;
|
|
35
|
+
/** Reports whether a subject belongs to a `release:` commit, which records version bumps rather than a change. */
|
|
36
|
+
export declare function isReleaseSubject(subject: string): boolean;
|