@williamthorsen/release-kit 14.2.1 → 14.2.3
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 +77 -0
- package/.readyup/kits/default.js +142 -152
- package/.readyup/kits/npm-auto-publish.js +183 -184
- package/.readyup/manifest.json +83 -9
- package/CHANGELOG.md +24 -0
- package/README.md +7 -1
- package/dist/esm/applyChangelogOverrides.d.ts +50 -0
- package/dist/esm/applyChangelogOverrides.js +162 -0
- package/dist/esm/attachChangelogDiagnostics.d.ts +1 -1
- package/dist/esm/bin/release-kit.js +6 -238
- package/dist/esm/buildChangelogEntries.d.ts +20 -31
- package/dist/esm/buildChangelogEntries.js +71 -188
- package/dist/esm/buildChangelogItem.d.ts +56 -0
- package/dist/esm/buildChangelogItem.js +119 -0
- package/dist/esm/buildReleasedResult.d.ts +20 -0
- package/dist/esm/buildReleasedResult.js +78 -0
- package/dist/esm/changelogJsonUtils.d.ts +1 -1
- package/dist/esm/changelogOverrides.d.ts +29 -143
- package/dist/esm/changelogOverrides.js +35 -467
- package/dist/esm/configSchema.d.ts +225 -0
- package/dist/esm/configSchema.js +103 -0
- package/dist/esm/createGithubReleaseCommand.js +4 -3
- package/dist/esm/decideDirectReleases.d.ts +30 -0
- package/dist/esm/decideDirectReleases.js +66 -0
- package/dist/esm/defaults.js +1 -4
- package/dist/esm/defineConfig.d.ts +2 -2
- package/dist/esm/deriveReleaseNotesConfig.d.ts +2 -1
- package/dist/esm/deriveReleaseNotesConfig.js +1 -1
- package/dist/esm/determineBumpType.js +4 -3
- package/dist/esm/enumerateReleaseWindows.js +4 -4
- package/dist/esm/formatPrepareFiles.d.ts +11 -0
- package/dist/esm/formatPrepareFiles.js +55 -0
- package/dist/esm/formatPrepareWarnings.d.ts +26 -0
- package/dist/esm/formatPrepareWarnings.js +72 -0
- package/dist/esm/help/initHelp.d.ts +4 -0
- package/dist/esm/help/initHelp.js +31 -0
- package/dist/esm/help/overridesHelp.d.ts +4 -0
- package/dist/esm/help/overridesHelp.js +32 -0
- package/dist/esm/help/releaseStepsHelp.d.ts +12 -0
- package/dist/esm/help/releaseStepsHelp.js +91 -0
- package/dist/esm/help/syncLabelsHelp.d.ts +8 -0
- package/dist/esm/help/syncLabelsHelp.js +55 -0
- package/dist/esm/help/usage.d.ts +2 -0
- package/dist/esm/help/usage.js +29 -0
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/init/initCommand.js +3 -7
- package/dist/esm/loadChangelogOverrides.d.ts +31 -0
- package/dist/esm/loadChangelogOverrides.js +138 -0
- package/dist/esm/loadConfig.d.ts +0 -40
- package/dist/esm/loadConfig.js +0 -242
- package/dist/esm/loadValidatedConfig.d.ts +1 -1
- package/dist/esm/mergeConfig.d.ts +41 -0
- package/dist/esm/mergeConfig.js +118 -0
- package/dist/esm/monorepoConfigAssertions.d.ts +49 -0
- package/dist/esm/monorepoConfigAssertions.js +126 -0
- package/dist/esm/planChangelogFiles.d.ts +16 -0
- package/dist/esm/planChangelogFiles.js +41 -0
- package/dist/esm/prepareArgs.d.ts +55 -0
- package/dist/esm/prepareArgs.js +69 -0
- package/dist/esm/prepareCommand.d.ts +0 -48
- package/dist/esm/prepareCommand.js +11 -77
- package/dist/esm/prepareComposite.d.ts +16 -0
- package/dist/esm/prepareComposite.js +39 -0
- package/dist/esm/prepareRunContext.d.ts +38 -0
- package/dist/esm/prepareRunContext.js +39 -0
- package/dist/esm/prepareTarget.d.ts +2 -7
- package/dist/esm/prepareTarget.js +2 -118
- package/dist/esm/previewTagPrefixes.d.ts +1 -1
- package/dist/esm/releasePrepareTargets.js +13 -207
- package/dist/esm/renderReleaseNotes.js +6 -5
- package/dist/esm/reportPrepare.js +3 -123
- package/dist/esm/resolveCommandTags.d.ts +1 -1
- package/dist/esm/resolveCommandTags.js +2 -1
- package/dist/esm/resolveReleaseDeclaration.d.ts +2 -1
- package/dist/esm/resolveReleaseTargets.d.ts +2 -1
- package/dist/esm/resolveReleaseTargets.js +2 -1
- package/dist/esm/stripScope.js +4 -3
- package/dist/esm/sync-labels/generateCommand.d.ts +1 -1
- package/dist/esm/sync-labels/resolveLabels.d.ts +1 -1
- package/dist/esm/topologicalSort.d.ts +12 -0
- package/dist/esm/topologicalSort.js +60 -0
- package/dist/esm/types.d.ts +1 -225
- package/dist/esm/types.js +1 -103
- package/dist/esm/validateAllChangelogOverrides.d.ts +56 -0
- package/dist/esm/validateAllChangelogOverrides.js +138 -0
- package/dist/esm/validateConfig.d.ts +1 -1
- package/dist/esm/validateConfig.js +7 -9
- package/dist/esm/validateOverridesCommand.d.ts +1 -1
- package/dist/esm/validateOverridesCommand.js +2 -1
- package/package.json +4 -4
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Schema for a single historical identity snapshot for a workspace.
|
|
4
|
+
*
|
|
5
|
+
* Captures what the package looked like at some earlier point: the full npm `name`
|
|
6
|
+
* (e.g., `'@williamthorsen/nmr-core'`) and the `tagPrefix` under which tags were
|
|
7
|
+
* published (e.g., `'core-v'`).
|
|
8
|
+
*/
|
|
9
|
+
export declare const legacyIdentitySchema: z.ZodObject<{
|
|
10
|
+
name: z.ZodString;
|
|
11
|
+
tagPrefix: z.ZodString;
|
|
12
|
+
}, z.core.$strict>;
|
|
13
|
+
/**
|
|
14
|
+
* A single historical identity snapshot for a workspace. Both fields are required, because a full
|
|
15
|
+
* tuple stays unambiguous across any number of renames.
|
|
16
|
+
*/
|
|
17
|
+
export type LegacyIdentity = z.infer<typeof legacyIdentitySchema>;
|
|
18
|
+
/**
|
|
19
|
+
* Schema for a package that once lived in this repo but has since been extracted or removed.
|
|
20
|
+
*
|
|
21
|
+
* Unlike `legacyIdentitySchema`, retired packages are never consulted for baseline lookup
|
|
22
|
+
* or changelog attribution; they acknowledge historical tag prefixes and suppress
|
|
23
|
+
* undeclared-candidate warnings.
|
|
24
|
+
*/
|
|
25
|
+
export declare const retiredPackageSchema: z.ZodObject<{
|
|
26
|
+
name: z.ZodString;
|
|
27
|
+
tagPrefix: z.ZodString;
|
|
28
|
+
successor: z.ZodOptional<z.ZodString>;
|
|
29
|
+
}, z.core.$strict>;
|
|
30
|
+
/** A package that once lived in this repo but has since been extracted or removed. */
|
|
31
|
+
export type RetiredPackage = z.infer<typeof retiredPackageSchema>;
|
|
32
|
+
/** Schema for a single workspace override entry in the config file. */
|
|
33
|
+
export declare const workspaceOverrideSchema: z.ZodObject<{
|
|
34
|
+
dir: z.ZodString;
|
|
35
|
+
shouldExclude: z.ZodOptional<z.ZodBoolean>;
|
|
36
|
+
legacyIdentities: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
37
|
+
name: z.ZodString;
|
|
38
|
+
tagPrefix: z.ZodString;
|
|
39
|
+
}, z.core.$strict>>>;
|
|
40
|
+
}, z.core.$strict>;
|
|
41
|
+
/** Override for a single workspace in the config file. Matches a discovered workspace by `dir`. */
|
|
42
|
+
export type WorkspaceOverride = z.infer<typeof workspaceOverrideSchema>;
|
|
43
|
+
/** Schema for the optional `project` block. */
|
|
44
|
+
export declare const projectConfigSchema: z.ZodObject<{
|
|
45
|
+
paths: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
46
|
+
tagPrefix: z.ZodOptional<z.ZodString>;
|
|
47
|
+
}, z.core.$strict>;
|
|
48
|
+
/** Consumer-facing project-release config (`project` block). Empty object opts in to project releases. */
|
|
49
|
+
export type ProjectConfig = z.infer<typeof projectConfigSchema>;
|
|
50
|
+
/**
|
|
51
|
+
* Schema for a `releases` entry that names the target at `path`: the discovered workspace there, or otherwise the
|
|
52
|
+
* directory, whose `tagPrefix` defaults to its basename followed by `-v`.
|
|
53
|
+
*/
|
|
54
|
+
export declare const pathReleaseSchema: z.ZodObject<{
|
|
55
|
+
path: z.ZodString;
|
|
56
|
+
tagPrefix: z.ZodOptional<z.ZodString>;
|
|
57
|
+
legacyIdentities: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
58
|
+
name: z.ZodString;
|
|
59
|
+
tagPrefix: z.ZodString;
|
|
60
|
+
}, z.core.$strict>>>;
|
|
61
|
+
}, z.core.$strict>;
|
|
62
|
+
/** A `releases` entry that names the discovered workspace or the directory at `path`. */
|
|
63
|
+
export type PathRelease = z.infer<typeof pathReleaseSchema>;
|
|
64
|
+
/** Schema for a `releases` entry that declares a composite of the named targets. */
|
|
65
|
+
export declare const compositeReleaseSchema: z.ZodObject<{
|
|
66
|
+
includes: z.ZodArray<z.ZodString>;
|
|
67
|
+
tagPrefix: z.ZodOptional<z.ZodString>;
|
|
68
|
+
}, z.core.$strict>;
|
|
69
|
+
/** A `releases` entry that declares a composite of the named targets, versioned by the root `package.json`. */
|
|
70
|
+
export type CompositeRelease = z.infer<typeof compositeReleaseSchema>;
|
|
71
|
+
/**
|
|
72
|
+
* Schema for one `releases` entry: `false` excludes the discovered workspace of that name, and the object shapes name
|
|
73
|
+
* a workspace or a directory, or declare the composite. `validateConfig` relies on this branch order to report a failed entry.
|
|
74
|
+
*/
|
|
75
|
+
export declare const releaseEntrySchema: z.ZodUnion<readonly [z.ZodLiteral<false>, z.ZodObject<{
|
|
76
|
+
path: z.ZodString;
|
|
77
|
+
tagPrefix: z.ZodOptional<z.ZodString>;
|
|
78
|
+
legacyIdentities: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
79
|
+
name: z.ZodString;
|
|
80
|
+
tagPrefix: z.ZodString;
|
|
81
|
+
}, z.core.$strict>>>;
|
|
82
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
83
|
+
includes: z.ZodArray<z.ZodString>;
|
|
84
|
+
tagPrefix: z.ZodOptional<z.ZodString>;
|
|
85
|
+
}, z.core.$strict>]>;
|
|
86
|
+
/** One `releases` entry, keyed in the config by the target's name. */
|
|
87
|
+
export type ReleaseEntry = z.infer<typeof releaseEntrySchema>;
|
|
88
|
+
/** Schema for the optional `changelogJson` block (input shape, all fields optional). */
|
|
89
|
+
export declare const changelogJsonInputSchema: z.ZodObject<{
|
|
90
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
91
|
+
outputPath: z.ZodOptional<z.ZodString>;
|
|
92
|
+
devOnlySections: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
93
|
+
}, z.core.$strict>;
|
|
94
|
+
/** Schema for the optional `changelogMarkdown` block (input shape, all fields optional). */
|
|
95
|
+
export declare const changelogMarkdownInputSchema: z.ZodObject<{
|
|
96
|
+
keepVersions: z.ZodOptional<z.ZodNumber>;
|
|
97
|
+
}, z.core.$strict>;
|
|
98
|
+
/** Schema for the optional `releaseNotes` block (input shape, all fields optional). */
|
|
99
|
+
export declare const releaseNotesInputSchema: z.ZodObject<{
|
|
100
|
+
shouldInjectIntoReadme: z.ZodOptional<z.ZodBoolean>;
|
|
101
|
+
}, z.core.$strict>;
|
|
102
|
+
/** Schema for a single `workTypes` entry. */
|
|
103
|
+
export declare const workTypeConfigSchema: z.ZodObject<{
|
|
104
|
+
header: z.ZodString;
|
|
105
|
+
aliases: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
106
|
+
excludedFromChangelog: z.ZodOptional<z.ZodBoolean>;
|
|
107
|
+
}, z.core.$strict>;
|
|
108
|
+
/** Schema for the `versionPatterns` block. Both arrays are required when the field is provided. */
|
|
109
|
+
export declare const versionPatternsSchema: z.ZodObject<{
|
|
110
|
+
major: z.ZodArray<z.ZodString>;
|
|
111
|
+
minor: z.ZodArray<z.ZodString>;
|
|
112
|
+
}, z.core.$strict>;
|
|
113
|
+
/** Schema for a single `breakingPolicies` value. */
|
|
114
|
+
export declare const breakingPolicyValueSchema: z.ZodEnum<{
|
|
115
|
+
optional: "optional";
|
|
116
|
+
forbidden: "forbidden";
|
|
117
|
+
}>;
|
|
118
|
+
/** Schema for a single label's spec in the `repoLabels.labels` record. */
|
|
119
|
+
export declare const labelSpecSchema: z.ZodObject<{
|
|
120
|
+
color: z.ZodString;
|
|
121
|
+
description: z.ZodOptional<z.ZodString>;
|
|
122
|
+
aliases: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
123
|
+
archived: z.ZodOptional<z.ZodLiteral<true>>;
|
|
124
|
+
}, z.core.$strict>;
|
|
125
|
+
/**
|
|
126
|
+
* A label's color, optional description, optional aliases, and optional archived mark; the name is the record key in
|
|
127
|
+
* `repoLabels.labels`. An omitted description resolves to empty, which the generated labels file declares explicitly
|
|
128
|
+
* so that a sync clears whatever description the label has on the repo. Each alias names an existing label that the
|
|
129
|
+
* sync renames to this one in place, keeping it on the issues and pull requests that have it. `archived: true` retires
|
|
130
|
+
* the label: The sync archives it, keeping it on the issues and pull requests that have it.
|
|
131
|
+
*/
|
|
132
|
+
export type LabelSpec = z.infer<typeof labelSpecSchema>;
|
|
133
|
+
/**
|
|
134
|
+
* Schema for the optional `repoLabels` block, which declares the repository's label registry (the labels defined on
|
|
135
|
+
* the GitHub repo, distinct from labels applied to PRs and issues).
|
|
136
|
+
*
|
|
137
|
+
* Resolution is an ordered fold with last-writer-wins: presets in `extends` order, then the `labels` record,
|
|
138
|
+
* in which an entry adds a label, replaces one that an earlier layer defined, or removes it (`null`). Names match
|
|
139
|
+
* case-insensitively, as GitHub matches them, and the replacing layer's spelling wins.
|
|
140
|
+
* Three misstatements are resolve-time errors (`resolveLabels`), not schema errors: `labels` keys that differ only in
|
|
141
|
+
* case, a `null` naming a label not defined by any earlier layer, and an alias that names a resolved label or repeats
|
|
142
|
+
* another alias.
|
|
143
|
+
*/
|
|
144
|
+
export declare const repoLabelsSchema: z.ZodObject<{
|
|
145
|
+
extends: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
146
|
+
labels: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNullable<z.ZodObject<{
|
|
147
|
+
color: z.ZodString;
|
|
148
|
+
description: z.ZodOptional<z.ZodString>;
|
|
149
|
+
aliases: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
150
|
+
archived: z.ZodOptional<z.ZodLiteral<true>>;
|
|
151
|
+
}, z.core.$strict>>>>;
|
|
152
|
+
}, z.core.$strict>;
|
|
153
|
+
/** Consumer-facing `repoLabels` block: bundled presets to extend plus per-name adjustments. */
|
|
154
|
+
export type RepoLabelsConfig = z.infer<typeof repoLabelsSchema>;
|
|
155
|
+
/** Schema for the consumer-facing config file shape (`.config/release-kit.config.ts`). */
|
|
156
|
+
export declare const releaseKitConfigSchema: z.ZodObject<{
|
|
157
|
+
breakingPolicies: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEnum<{
|
|
158
|
+
optional: "optional";
|
|
159
|
+
forbidden: "forbidden";
|
|
160
|
+
}>>>;
|
|
161
|
+
changelogJson: z.ZodOptional<z.ZodObject<{
|
|
162
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
163
|
+
outputPath: z.ZodOptional<z.ZodString>;
|
|
164
|
+
devOnlySections: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
165
|
+
}, z.core.$strict>>;
|
|
166
|
+
changelogMarkdown: z.ZodOptional<z.ZodObject<{
|
|
167
|
+
keepVersions: z.ZodOptional<z.ZodNumber>;
|
|
168
|
+
}, z.core.$strict>>;
|
|
169
|
+
formatCommand: z.ZodOptional<z.ZodString>;
|
|
170
|
+
project: z.ZodOptional<z.ZodObject<{
|
|
171
|
+
paths: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
172
|
+
tagPrefix: z.ZodOptional<z.ZodString>;
|
|
173
|
+
}, z.core.$strict>>;
|
|
174
|
+
releaseNotes: z.ZodOptional<z.ZodObject<{
|
|
175
|
+
shouldInjectIntoReadme: z.ZodOptional<z.ZodBoolean>;
|
|
176
|
+
}, z.core.$strict>>;
|
|
177
|
+
releases: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodLiteral<false>, z.ZodObject<{
|
|
178
|
+
path: z.ZodString;
|
|
179
|
+
tagPrefix: z.ZodOptional<z.ZodString>;
|
|
180
|
+
legacyIdentities: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
181
|
+
name: z.ZodString;
|
|
182
|
+
tagPrefix: z.ZodString;
|
|
183
|
+
}, z.core.$strict>>>;
|
|
184
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
185
|
+
includes: z.ZodArray<z.ZodString>;
|
|
186
|
+
tagPrefix: z.ZodOptional<z.ZodString>;
|
|
187
|
+
}, z.core.$strict>]>>>;
|
|
188
|
+
repoLabels: z.ZodOptional<z.ZodObject<{
|
|
189
|
+
extends: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
190
|
+
labels: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNullable<z.ZodObject<{
|
|
191
|
+
color: z.ZodString;
|
|
192
|
+
description: z.ZodOptional<z.ZodString>;
|
|
193
|
+
aliases: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
194
|
+
archived: z.ZodOptional<z.ZodLiteral<true>>;
|
|
195
|
+
}, z.core.$strict>>>>;
|
|
196
|
+
}, z.core.$strict>>;
|
|
197
|
+
retiredPackages: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
198
|
+
name: z.ZodString;
|
|
199
|
+
tagPrefix: z.ZodString;
|
|
200
|
+
successor: z.ZodOptional<z.ZodString>;
|
|
201
|
+
}, z.core.$strict>>>;
|
|
202
|
+
scopeAliases: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
203
|
+
versionPatterns: z.ZodOptional<z.ZodObject<{
|
|
204
|
+
major: z.ZodArray<z.ZodString>;
|
|
205
|
+
minor: z.ZodArray<z.ZodString>;
|
|
206
|
+
}, z.core.$strict>>;
|
|
207
|
+
workspaces: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
208
|
+
dir: z.ZodString;
|
|
209
|
+
shouldExclude: z.ZodOptional<z.ZodBoolean>;
|
|
210
|
+
legacyIdentities: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
211
|
+
name: z.ZodString;
|
|
212
|
+
tagPrefix: z.ZodString;
|
|
213
|
+
}, z.core.$strict>>>;
|
|
214
|
+
}, z.core.$strict>>>;
|
|
215
|
+
workTypes: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
216
|
+
header: z.ZodString;
|
|
217
|
+
aliases: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
218
|
+
excludedFromChangelog: z.ZodOptional<z.ZodBoolean>;
|
|
219
|
+
}, z.core.$strict>>>;
|
|
220
|
+
}, z.core.$strict>;
|
|
221
|
+
/**
|
|
222
|
+
* Consumer-facing config file shape (`.config/release-kit.config.ts`).
|
|
223
|
+
* All fields are optional; defaults are applied during config merging.
|
|
224
|
+
*/
|
|
225
|
+
export type ReleaseKitConfig = z.infer<typeof releaseKitConfigSchema>;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const legacyIdentitySchema = z
|
|
3
|
+
.object({
|
|
4
|
+
name: z.string().min(1),
|
|
5
|
+
tagPrefix: z.string().min(1),
|
|
6
|
+
})
|
|
7
|
+
.strict();
|
|
8
|
+
export const retiredPackageSchema = z
|
|
9
|
+
.object({
|
|
10
|
+
name: z.string().min(1),
|
|
11
|
+
tagPrefix: z.string().min(1),
|
|
12
|
+
successor: z.string().min(1).optional(),
|
|
13
|
+
})
|
|
14
|
+
.strict();
|
|
15
|
+
export const workspaceOverrideSchema = z
|
|
16
|
+
.object({
|
|
17
|
+
dir: z.string().min(1),
|
|
18
|
+
shouldExclude: z.boolean().optional(),
|
|
19
|
+
legacyIdentities: z.array(legacyIdentitySchema).optional(),
|
|
20
|
+
})
|
|
21
|
+
.strict();
|
|
22
|
+
export const projectConfigSchema = z
|
|
23
|
+
.object({
|
|
24
|
+
paths: z.array(z.string().min(1)).min(1).optional(),
|
|
25
|
+
tagPrefix: z.string().min(1).optional(),
|
|
26
|
+
})
|
|
27
|
+
.strict();
|
|
28
|
+
export const pathReleaseSchema = z
|
|
29
|
+
.object({
|
|
30
|
+
path: z.string().min(1),
|
|
31
|
+
tagPrefix: z.string().min(1).optional(),
|
|
32
|
+
legacyIdentities: z.array(legacyIdentitySchema).optional(),
|
|
33
|
+
})
|
|
34
|
+
.strict();
|
|
35
|
+
export const compositeReleaseSchema = z
|
|
36
|
+
.object({
|
|
37
|
+
includes: z.array(z.string().min(1)).min(1),
|
|
38
|
+
tagPrefix: z.string().min(1).optional(),
|
|
39
|
+
})
|
|
40
|
+
.strict();
|
|
41
|
+
export const releaseEntrySchema = z.union([z.literal(false), pathReleaseSchema, compositeReleaseSchema]);
|
|
42
|
+
export const changelogJsonInputSchema = z
|
|
43
|
+
.object({
|
|
44
|
+
enabled: z.boolean().optional(),
|
|
45
|
+
outputPath: z.string().optional(),
|
|
46
|
+
devOnlySections: z.array(z.string()).optional(),
|
|
47
|
+
})
|
|
48
|
+
.strict();
|
|
49
|
+
export const changelogMarkdownInputSchema = z
|
|
50
|
+
.object({
|
|
51
|
+
keepVersions: z.number().int().min(1).optional(),
|
|
52
|
+
})
|
|
53
|
+
.strict();
|
|
54
|
+
export const releaseNotesInputSchema = z
|
|
55
|
+
.object({
|
|
56
|
+
shouldInjectIntoReadme: z.boolean().optional(),
|
|
57
|
+
})
|
|
58
|
+
.strict();
|
|
59
|
+
export const workTypeConfigSchema = z
|
|
60
|
+
.object({
|
|
61
|
+
header: z.string(),
|
|
62
|
+
aliases: z.array(z.string()).optional(),
|
|
63
|
+
excludedFromChangelog: z.boolean().optional(),
|
|
64
|
+
})
|
|
65
|
+
.strict();
|
|
66
|
+
export const versionPatternsSchema = z
|
|
67
|
+
.object({
|
|
68
|
+
major: z.array(z.string()),
|
|
69
|
+
minor: z.array(z.string()),
|
|
70
|
+
})
|
|
71
|
+
.strict();
|
|
72
|
+
export const breakingPolicyValueSchema = z.enum(['forbidden', 'optional']);
|
|
73
|
+
export const labelSpecSchema = z
|
|
74
|
+
.object({
|
|
75
|
+
color: z.string().min(1),
|
|
76
|
+
description: z.string().optional(),
|
|
77
|
+
aliases: z.array(z.string().min(1)).min(1).optional(),
|
|
78
|
+
archived: z.literal(true).optional(),
|
|
79
|
+
})
|
|
80
|
+
.strict();
|
|
81
|
+
export const repoLabelsSchema = z
|
|
82
|
+
.object({
|
|
83
|
+
extends: z.array(z.string().min(1)).optional(),
|
|
84
|
+
labels: z.record(z.string().min(1), labelSpecSchema.nullable()).optional(),
|
|
85
|
+
})
|
|
86
|
+
.strict();
|
|
87
|
+
export const releaseKitConfigSchema = z
|
|
88
|
+
.object({
|
|
89
|
+
breakingPolicies: z.record(z.string(), breakingPolicyValueSchema).optional(),
|
|
90
|
+
changelogJson: changelogJsonInputSchema.optional(),
|
|
91
|
+
changelogMarkdown: changelogMarkdownInputSchema.optional(),
|
|
92
|
+
formatCommand: z.string().min(1).optional(),
|
|
93
|
+
project: projectConfigSchema.optional(),
|
|
94
|
+
releaseNotes: releaseNotesInputSchema.optional(),
|
|
95
|
+
releases: z.record(z.string().min(1), releaseEntrySchema).optional(),
|
|
96
|
+
repoLabels: repoLabelsSchema.optional(),
|
|
97
|
+
retiredPackages: z.array(retiredPackageSchema).optional(),
|
|
98
|
+
scopeAliases: z.record(z.string(), z.string()).optional(),
|
|
99
|
+
versionPatterns: versionPatternsSchema.optional(),
|
|
100
|
+
workspaces: z.array(workspaceOverrideSchema).optional(),
|
|
101
|
+
workTypes: z.record(z.string(), workTypeConfigSchema).optional(),
|
|
102
|
+
})
|
|
103
|
+
.strict();
|
|
@@ -38,10 +38,11 @@ export async function createGithubReleaseCommand(argv, styles, invocationDir) {
|
|
|
38
38
|
reportError(`Failed to create GitHub Releases: ${describeError(error)}`);
|
|
39
39
|
process.exit(1);
|
|
40
40
|
}
|
|
41
|
-
if (outcome.skipped.length
|
|
42
|
-
|
|
43
|
-
console.info(`Skipped ${outcome.skipped.length} tag(s) without releasable content: ${formatted}.`);
|
|
41
|
+
if (outcome.skipped.length === 0) {
|
|
42
|
+
return;
|
|
44
43
|
}
|
|
44
|
+
const formatted = outcome.skipped.map((s) => `${s.tag} (${s.reason})`).join(', ');
|
|
45
|
+
console.info(`Skipped ${outcome.skipped.length} tag(s) without releasable content: ${formatted}.`);
|
|
45
46
|
}
|
|
46
47
|
function isReleasable(resolvedTag) {
|
|
47
48
|
return resolvedTag.kind !== 'package' || resolvedTag.isPublishable;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { UntaggedBaseline } from './assertTaggedBaseline.js';
|
|
2
|
+
import type { ReleaseHistory } from './buildChangelogEntries.js';
|
|
3
|
+
import { type MemberTarget } from './prepareRunContext.js';
|
|
4
|
+
import { type TargetDecision, type TargetPrepareSettings } from './prepareTarget.js';
|
|
5
|
+
import type { ReleaseEntry } from './propagateBumps.js';
|
|
6
|
+
import type { ReleaseType } from './types.js';
|
|
7
|
+
/** The direct releases of the planned package targets, with the reads from which they were decided. */
|
|
8
|
+
export interface DirectReleases {
|
|
9
|
+
readings: Map<string, ReleaseHistory>;
|
|
10
|
+
decisions: Map<string, TargetDecision>;
|
|
11
|
+
/** The bumps from which propagation starts: one per target whose decision releases. */
|
|
12
|
+
bumps: Map<string, ReleaseEntry>;
|
|
13
|
+
untaggedBaselines: Map<string, UntaggedBaseline>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Reads each planned package and directory target's history and decides its direct release. `force` applies only to
|
|
17
|
+
* the targets from which the release starts.
|
|
18
|
+
*/
|
|
19
|
+
export declare function decideDirectReleases(planned: readonly MemberTarget[], settings: TargetPrepareSettings, options: {
|
|
20
|
+
force?: boolean;
|
|
21
|
+
bumpOverride?: ReleaseType;
|
|
22
|
+
setVersions?: ReadonlyMap<string, string>;
|
|
23
|
+
}, startIds: ReadonlySet<string>): DirectReleases;
|
|
24
|
+
/**
|
|
25
|
+
* Records on each planned workspace's and directory's history the entry scopes that route nowhere in its unreleased
|
|
26
|
+
* window, which only a pass across every target's window can find. The windows go to the finder with the releasing
|
|
27
|
+
* targets first, in planned order, which sets the order of each target's findings. The repo-root directory target
|
|
28
|
+
* renders every entry in its window, so it records none, but its window still routes the scope that names it.
|
|
29
|
+
*/
|
|
30
|
+
export declare function reportUnroutedEntryScopes(planned: readonly MemberTarget[], direct: DirectReleases, settings: TargetPrepareSettings, memberTargets: readonly MemberTarget[]): void;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { detectUndeclaredTagPrefixes } from "./detectUndeclaredTagPrefixes.js";
|
|
2
|
+
import { findUnroutedEntryScopes } from "./findUnroutedEntryScopes.js";
|
|
3
|
+
import { getAllTagPrefixes } from "./generateChangelogs.js";
|
|
4
|
+
import { describeStage, isRepoRootTarget, readHistory, runStage } from "./prepareRunContext.js";
|
|
5
|
+
import { decideTargetRelease, readTargetHistory, } from "./prepareTarget.js";
|
|
6
|
+
export function decideDirectReleases(planned, settings, options, startIds) {
|
|
7
|
+
const { force, bumpOverride, setVersions } = options;
|
|
8
|
+
const direct = {
|
|
9
|
+
readings: new Map(),
|
|
10
|
+
decisions: new Map(),
|
|
11
|
+
bumps: new Map(),
|
|
12
|
+
untaggedBaselines: new Map(),
|
|
13
|
+
};
|
|
14
|
+
const hintState = { emitted: false };
|
|
15
|
+
const knownPrefixes = planned.flatMap(getAllTagPrefixes);
|
|
16
|
+
for (const target of planned) {
|
|
17
|
+
const { history, untagged } = runStage(describeStage(target), () => readTargetHistory(target, settings));
|
|
18
|
+
direct.readings.set(target.id, history);
|
|
19
|
+
if (untagged !== undefined) {
|
|
20
|
+
direct.untaggedBaselines.set(target.id, untagged);
|
|
21
|
+
}
|
|
22
|
+
if (history.previousTag === undefined && target.kind === 'package' && target.isWorkspace) {
|
|
23
|
+
maybeEmitBaselineHint(target, knownPrefixes, hintState);
|
|
24
|
+
}
|
|
25
|
+
const setVersion = setVersions?.get(target.id);
|
|
26
|
+
const decision = decideTargetRelease(target, history, {
|
|
27
|
+
force: force === true && startIds.has(target.id),
|
|
28
|
+
bumpOverride,
|
|
29
|
+
setVersion,
|
|
30
|
+
});
|
|
31
|
+
direct.decisions.set(target.id, decision);
|
|
32
|
+
if (decision.outcome === 'skip') {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
direct.bumps.set(target.id, decision.setVersion === undefined
|
|
36
|
+
? { releaseType: decision.releaseType }
|
|
37
|
+
: { releaseType: 'patch', newVersionOverride: decision.setVersion });
|
|
38
|
+
}
|
|
39
|
+
return direct;
|
|
40
|
+
}
|
|
41
|
+
export function reportUnroutedEntryScopes(planned, direct, settings, memberTargets) {
|
|
42
|
+
const releasing = planned.filter((target) => direct.decisions.get(target.id)?.outcome === 'release');
|
|
43
|
+
const windows = [...releasing, ...planned.filter((target) => !releasing.includes(target))].map((target) => ({
|
|
44
|
+
target,
|
|
45
|
+
history: readHistory(direct.readings, target),
|
|
46
|
+
}));
|
|
47
|
+
const findings = findUnroutedEntryScopes(windows.map(({ target, history }) => ({ dir: target.id, commits: history.unreleased.commits })), memberTargets.map((target) => target.id), settings.scopeAliases ?? {});
|
|
48
|
+
for (const { target, history } of windows) {
|
|
49
|
+
history.unreleased.diagnostics.unroutedEntryScopes = isRepoRootTarget(target)
|
|
50
|
+
? []
|
|
51
|
+
: (findings.get(target.id) ?? []);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function maybeEmitBaselineHint(target, knownPrefixes, state) {
|
|
55
|
+
if (state.emitted || (target.legacyIdentities?.length ?? 0) > 0)
|
|
56
|
+
return;
|
|
57
|
+
const candidates = detectUndeclaredTagPrefixes(knownPrefixes);
|
|
58
|
+
if (candidates.length === 0)
|
|
59
|
+
return;
|
|
60
|
+
const totalTags = candidates.reduce((sum, candidate) => sum + candidate.tagCount, 0);
|
|
61
|
+
const example = candidates[0]?.exampleTags[0] ?? `${candidates[0]?.prefix ?? ''}?`;
|
|
62
|
+
process.stderr.write(`Hint: no baseline tag found for ${target.id} under '${target.tagPrefix}', but ` +
|
|
63
|
+
`${totalTags} candidate-shaped tags exist (e.g., ${example}). ` +
|
|
64
|
+
"Run 'release-kit show-tag-prefixes' to check for undeclared legacy prefixes.\n");
|
|
65
|
+
state.emitted = true;
|
|
66
|
+
}
|
package/dist/esm/defaults.js
CHANGED
|
@@ -22,10 +22,7 @@ function deriveDefaultWorkTypes() {
|
|
|
22
22
|
function deriveDevOnlySections() {
|
|
23
23
|
const sections = [];
|
|
24
24
|
for (const entry of CANONICAL_TAXONOMY.types) {
|
|
25
|
-
if (!DEV_ONLY_TIERS.has(entry.tier)) {
|
|
26
|
-
continue;
|
|
27
|
-
}
|
|
28
|
-
if (entry.excludedFromChangelog === true) {
|
|
25
|
+
if (!DEV_ONLY_TIERS.has(entry.tier) || entry.excludedFromChangelog === true) {
|
|
29
26
|
continue;
|
|
30
27
|
}
|
|
31
28
|
sections.push(composeHeader(entry));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { ReleaseKitConfig } from './
|
|
2
|
-
export type { LabelSpec, ReleaseKitConfig, RepoLabelsConfig } from './
|
|
1
|
+
import type { ReleaseKitConfig } from './configSchema.js';
|
|
2
|
+
export type { LabelSpec, ReleaseKitConfig, RepoLabelsConfig } from './configSchema.js';
|
|
3
3
|
/**
|
|
4
4
|
* Returns a configuration unchanged, typing it as a `ReleaseKitConfig`.
|
|
5
5
|
*
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { ReleaseKitConfig
|
|
1
|
+
import type { ReleaseKitConfig } from './configSchema.js';
|
|
2
|
+
import type { ReleaseNotesConfig } from './types.js';
|
|
2
3
|
export interface ResolvedReleaseNotesConfig {
|
|
3
4
|
releaseNotes: ReleaseNotesConfig;
|
|
4
5
|
changelogJsonOutputPath: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DEFAULT_CHANGELOG_JSON_CONFIG, DEFAULT_RELEASE_NOTES_CONFIG } from "./defaults.js";
|
|
2
|
-
import { resolveWorkTypes } from "./
|
|
2
|
+
import { resolveWorkTypes } from "./mergeConfig.js";
|
|
3
3
|
export function deriveDependenciesHeader(workTypes) {
|
|
4
4
|
const header = workTypes['deps']?.header;
|
|
5
5
|
if (header === undefined) {
|
|
@@ -25,10 +25,11 @@ export function determineBumpType(changes, workTypes, versionPatterns) {
|
|
|
25
25
|
bump = 'patch';
|
|
26
26
|
}
|
|
27
27
|
const priority = RELEASE_PRIORITY[bump];
|
|
28
|
-
if (priority
|
|
29
|
-
|
|
30
|
-
result = bump;
|
|
28
|
+
if (priority <= highestPriority) {
|
|
29
|
+
continue;
|
|
31
30
|
}
|
|
31
|
+
highestPriority = priority;
|
|
32
|
+
result = bump;
|
|
32
33
|
}
|
|
33
34
|
return result;
|
|
34
35
|
}
|
|
@@ -94,10 +94,10 @@ function readTagBoundaries(tagPrefixes, positionByHash) {
|
|
|
94
94
|
const boundaries = [];
|
|
95
95
|
for (const line of output.split('\n')) {
|
|
96
96
|
const [tag, creatorDate, objectName, dereferencedName] = line.split(FIELD_SEPARATOR);
|
|
97
|
-
if (tag === undefined ||
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
97
|
+
if (tag === undefined ||
|
|
98
|
+
creatorDate === undefined ||
|
|
99
|
+
objectName === undefined ||
|
|
100
|
+
!matchesTagPrefix(tag, tagPrefixes)) {
|
|
101
101
|
continue;
|
|
102
102
|
}
|
|
103
103
|
const hash = dereferencedName || objectName;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type OutputStyle } from '@williamthorsen/nmr-core';
|
|
2
|
+
import type { ReleasedPackageResult } from './types.js';
|
|
3
|
+
/** Appends bump file detail lines. */
|
|
4
|
+
export declare function formatBumpFiles(lines: string[], workspace: Pick<ReleasedPackageResult, 'bumpedFiles'>, dryRun: boolean, indent?: string): void;
|
|
5
|
+
/**
|
|
6
|
+
* Appends a line per generated changelog file, each followed by the versions kept from the existing changelog and a
|
|
7
|
+
* warning naming the sections dropped for lacking a version, then a line per removed changelog archive file.
|
|
8
|
+
*/
|
|
9
|
+
export declare function formatChangelogFiles(lines: string[], release: Pick<ReleasedPackageResult, 'changelogFiles' | 'changelogPreservation' | 'removedChangelogFiles'>, dryRun: boolean, style: OutputStyle, indent?: string): void;
|
|
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'>, dryRun: boolean, indent?: string): void;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { formatStatusLine } from '@williamthorsen/nmr-core';
|
|
2
|
+
import { dim } from "./format.js";
|
|
3
|
+
export function formatBumpFiles(lines, workspace, dryRun, indent = '') {
|
|
4
|
+
for (const file of workspace.bumpedFiles) {
|
|
5
|
+
if (dryRun) {
|
|
6
|
+
lines.push(dim(`${indent} [dry-run] Would bump ${file}`));
|
|
7
|
+
}
|
|
8
|
+
else {
|
|
9
|
+
lines.push(dim(`${indent} Bumped ${file}`));
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export function formatChangelogFiles(lines, release, dryRun, style, indent = '') {
|
|
14
|
+
for (const file of release.changelogFiles) {
|
|
15
|
+
if (dryRun) {
|
|
16
|
+
lines.push(dim(`${indent} [dry-run] Would generate changelog: ${file}`));
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
lines.push(dim(`${indent} Generating changelog: ${file}`));
|
|
20
|
+
}
|
|
21
|
+
const preservation = release.changelogPreservation?.find((candidate) => candidate.file === file);
|
|
22
|
+
if (preservation === undefined) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (preservation.preservedVersions.length > 0) {
|
|
26
|
+
lines.push(dim(`${indent} Kept from the existing changelog: ${preservation.preservedVersions.join(', ')}`));
|
|
27
|
+
}
|
|
28
|
+
const dropped = preservation.droppedUnversionedHeadings;
|
|
29
|
+
if (dropped.length === 0) {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
const message = `Dropped ${dropped.length} section${dropped.length === 1 ? '' : 's'} without a version: ${dropped.join(', ')}`;
|
|
33
|
+
lines.push(`${indent} ${formatStatusLine(style, 'warning', message)}`);
|
|
34
|
+
}
|
|
35
|
+
const removedFiles = release.removedChangelogFiles ?? [];
|
|
36
|
+
for (const file of removedFiles) {
|
|
37
|
+
if (dryRun) {
|
|
38
|
+
lines.push(dim(`${indent} [dry-run] Would remove changelog: ${file}`));
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
lines.push(dim(`${indent} Removing changelog: ${file}`));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export function formatPreviewFiles(lines, release, dryRun, indent = '') {
|
|
46
|
+
const previewFiles = release.previewFiles ?? [];
|
|
47
|
+
for (const file of previewFiles) {
|
|
48
|
+
if (dryRun) {
|
|
49
|
+
lines.push(dim(`${indent} [dry-run] Would write ${file}`));
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
lines.push(dim(`${indent} Wrote ${file}`));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type OutputStyle } from '@williamthorsen/nmr-core';
|
|
2
|
+
import type { PolicyViolation, PrepareResult, ReleasedPackageResult } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Appends warning lines for the change-record blocks that could not be read, the entries whose type is undeclared, and
|
|
5
|
+
* the entry scopes that don't match any workspace in the commit's window.
|
|
6
|
+
*
|
|
7
|
+
* `indent` follows the same convention as {@link formatUnparseableWarning}.
|
|
8
|
+
*/
|
|
9
|
+
export declare function formatChangeRecordWarnings(lines: string[], release: Pick<ReleasedPackageResult, 'malformedBlocks' | 'undeclaredEntryTypes' | 'unroutedEntryScopes'>, style: OutputStyle, indent?: string): void;
|
|
10
|
+
/**
|
|
11
|
+
* Appends policy-violation lines when applicable: one header line plus one bullet per violation.
|
|
12
|
+
*
|
|
13
|
+
* `indent` follows the same convention as {@link formatUnparseableWarning}.
|
|
14
|
+
*/
|
|
15
|
+
export declare function formatPolicyViolations(lines: string[], violations: PolicyViolation[] | undefined, style: OutputStyle, indent?: string): void;
|
|
16
|
+
/**
|
|
17
|
+
* Appends unparseable commit warning lines when applicable.
|
|
18
|
+
*
|
|
19
|
+
* `indent` is an additional outer indent prepended to both the header and bullet lines; base
|
|
20
|
+
* spacing (2 spaces for the header, 4 for bullets) is encoded in the format strings, so the
|
|
21
|
+
* caller passes only the section-level indent (e.g., `''` for single-package, `' '` for
|
|
22
|
+
* multi-workspace).
|
|
23
|
+
*/
|
|
24
|
+
export declare function formatUnparseableWarning(lines: string[], release: Pick<ReleasedPackageResult, 'unparseableCommits'>, style: OutputStyle, indent?: string): void;
|
|
25
|
+
/** Appends warning lines when the prepare result includes warnings. */
|
|
26
|
+
export declare function formatWarnings(lines: string[], result: PrepareResult, style: OutputStyle): void;
|