@wpelevator/wp-release 0.6.0 → 0.6.1
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/README.md +2 -2
- package/dist/changeset-release.d.ts +2 -0
- package/dist/changeset-release.js +18 -12
- package/dist/cli.js +24 -0
- package/dist/commands/changeset-args.d.ts +4 -0
- package/dist/commands/changeset-args.js +5 -0
- package/dist/commands/changeset-tag.d.ts +3 -0
- package/dist/commands/changeset-tag.js +5 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -37,7 +37,7 @@ npx wp-release --help
|
|
|
37
37
|
| `wp-release changeset-version [options]` | Apply version bumps and changelog entries. |
|
|
38
38
|
| `wp-release changeset-tag [options]` | Create missing package release tags. |
|
|
39
39
|
|
|
40
|
-
Run `npx wp-release <command> --help` for the options of each command. Every command reads the plugin or theme directory from the first argument or `--source-dir`, defaulting to the current directory, and prints its result as JSON with `--json`.
|
|
40
|
+
Run `npx wp-release <command> --help` for the options of each command. Every command reads the plugin or theme directory from the first argument or `--source-dir`, defaulting to the current directory, and prints its result as JSON with `--json`. In GitHub Actions, `--github-output` sets the result as JSON to the `result` output of the step instead, for later steps and jobs to read with `fromJSON( steps.<id>.outputs.result )`.
|
|
41
41
|
|
|
42
42
|
### GitHub Actions annotations and job summaries
|
|
43
43
|
|
|
@@ -127,7 +127,7 @@ Add release notes in a feature PR with `npx wp-release changeset-add --package @
|
|
|
127
127
|
|
|
128
128
|
On the release branch, preview with `changeset-version --dry-run`, then run `changeset-version` to update version targets and changelogs. By default, new Markdown entries go before the first version heading; `changelogInsertAfter` sets a literal insertion marker for `CHANGELOG.md` and, with `readmeChangelog`, the plugin readme. Put the marker in both files; a missing marker is an error. Without a marker, plugin readmes use the `== Changelog ==` heading. Failed updates are rolled back for safe retries.
|
|
129
129
|
|
|
130
|
-
After merging the release PR, `changeset-tag --since <merge-commit>^1 --push` pushes tags only for packages changed by that release. Add `--github-release` to create missing GitHub Releases; it requires `--push`. For initial adoption, preview all missing tags with `changeset-tag --dry-run` (without `--since`), then push if needed. Tag pushes need Git write credentials; GitHub Releases need authenticated `gh`.
|
|
130
|
+
After merging the release PR, `changeset-tag --since <merge-commit>^1 --push` pushes tags only for packages changed by that release. It pushes one tag at a time because GitHub doesn't trigger workflows for a push of more than three tags. Add `--github-release` to create missing GitHub Releases; it requires `--push`. For initial adoption, preview all missing tags with `changeset-tag --dry-run` (without `--since`), then push if needed. To release each package with a separate workflow instead, `changeset-tag --since <merge-commit>^1 --untagged --github-output` lists the releases that don't have a tag yet, without creating any. Tag pushes need Git write credentials; GitHub Releases need authenticated `gh`.
|
|
131
131
|
|
|
132
132
|
For local development, run the TypeScript source with `npm run wp-release -- <command>` (for example, `npm run wp-release -- changeset-status --since origin/main`). GitHub workflows use the same CLI for versioning and tagging. `SUBTREE_DEPLOY_TOKEN` lets them update the Version Packages PR, push tags, and create GitHub Releases.
|
|
133
133
|
|
|
@@ -9,6 +9,7 @@ export interface ChangesetVersionInput extends ChangesetRepository {
|
|
|
9
9
|
}
|
|
10
10
|
export interface ChangesetTagInput extends ChangesetRepository {
|
|
11
11
|
dryRun?: boolean;
|
|
12
|
+
untagged?: boolean;
|
|
12
13
|
push?: boolean;
|
|
13
14
|
githubRelease?: boolean;
|
|
14
15
|
since?: string;
|
|
@@ -18,6 +19,7 @@ export interface ChangesetTagResult {
|
|
|
18
19
|
package: string;
|
|
19
20
|
version: string;
|
|
20
21
|
tag: string;
|
|
22
|
+
exists: boolean;
|
|
21
23
|
created: boolean;
|
|
22
24
|
notes: string;
|
|
23
25
|
}>;
|
|
@@ -157,6 +157,9 @@ export async function tagChangesets(input) {
|
|
|
157
157
|
if (input.githubRelease && !input.push) {
|
|
158
158
|
throw new ValidationError('GitHub Releases require pushing the tags.');
|
|
159
159
|
}
|
|
160
|
+
if (input.untagged && input.push) {
|
|
161
|
+
throw new ValidationError('Listing untagged releases cannot be combined with pushing tags.');
|
|
162
|
+
}
|
|
160
163
|
const context = await getReleaseContext(input);
|
|
161
164
|
if (!context) {
|
|
162
165
|
throw new ValidationError('No wp-release config found. Add wp-release.config.js or pass --config <path>.');
|
|
@@ -165,6 +168,7 @@ export async function tagChangesets(input) {
|
|
|
165
168
|
? (await changedPackagesSince(input.cwd, context.packages, input.since)).packages
|
|
166
169
|
: context.packages;
|
|
167
170
|
const results = [];
|
|
171
|
+
const dryRun = input.dryRun || input.untagged;
|
|
168
172
|
const tagFormat = context.config.tagFormat ?? '{path}/{version}';
|
|
169
173
|
for (const pkg of packages) {
|
|
170
174
|
const version = 'git-tag' === pkg.versionConfig.from.kind
|
|
@@ -173,33 +177,35 @@ export async function tagChangesets(input) {
|
|
|
173
177
|
const tag = formatTag(tagFormat, pkg, version);
|
|
174
178
|
const exists = await gitTagExists(input.cwd, tag);
|
|
175
179
|
const notes = await readReleaseNotes(pkg.directory, version);
|
|
176
|
-
if (!exists && !
|
|
180
|
+
if (!exists && !dryRun) {
|
|
177
181
|
await git(input.cwd, ['tag', tag]);
|
|
178
182
|
}
|
|
179
183
|
results.push({
|
|
180
184
|
package: pkg.name,
|
|
181
185
|
version,
|
|
182
186
|
tag,
|
|
183
|
-
|
|
187
|
+
exists,
|
|
188
|
+
created: !exists && !dryRun,
|
|
184
189
|
notes,
|
|
185
190
|
});
|
|
186
191
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
'origin',
|
|
193
|
-
...created.map((item) => item.tag),
|
|
194
|
-
]);
|
|
192
|
+
// Push one tag at a time because GitHub doesn't create push events for
|
|
193
|
+
// tags when more than three are pushed at once.
|
|
194
|
+
if (input.push && !dryRun) {
|
|
195
|
+
for (const item of results.filter((result) => result.created)) {
|
|
196
|
+
await git(input.cwd, ['push', 'origin', item.tag]);
|
|
195
197
|
}
|
|
196
198
|
}
|
|
197
|
-
if (input.githubRelease && !
|
|
199
|
+
if (input.githubRelease && !dryRun) {
|
|
198
200
|
for (const release of results) {
|
|
199
201
|
await createGitHubRelease(input.cwd, release);
|
|
200
202
|
}
|
|
201
203
|
}
|
|
202
|
-
return {
|
|
204
|
+
return {
|
|
205
|
+
tags: input.untagged
|
|
206
|
+
? results.filter((result) => !result.exists)
|
|
207
|
+
: results,
|
|
208
|
+
};
|
|
203
209
|
}
|
|
204
210
|
async function createGitHubRelease(cwd, release) {
|
|
205
211
|
try {
|
package/dist/cli.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { appendFileSync } from 'node:fs';
|
|
1
2
|
import { parseArgs } from 'node:util';
|
|
2
3
|
import zip from "./commands/zip.js";
|
|
3
4
|
import checksums from "./commands/checksums.js";
|
|
@@ -36,6 +37,7 @@ const globalArgs = {
|
|
|
36
37
|
'log-format': { type: 'string' },
|
|
37
38
|
ci: { type: 'boolean' },
|
|
38
39
|
json: { type: 'boolean' },
|
|
40
|
+
'github-output': { type: 'boolean' },
|
|
39
41
|
config: { type: 'string' },
|
|
40
42
|
};
|
|
41
43
|
const globalOptions = `Global options:
|
|
@@ -47,6 +49,8 @@ const globalOptions = `Global options:
|
|
|
47
49
|
when GITHUB_ACTIONS=true, otherwise text)
|
|
48
50
|
--ci Same as --log-format github
|
|
49
51
|
--json Print the result as JSON
|
|
52
|
+
--github-output Set the result as JSON to the "result" output of
|
|
53
|
+
the GitHub Actions step
|
|
50
54
|
--config <path> Path to a JavaScript release config file`;
|
|
51
55
|
/**
|
|
52
56
|
* Get the top-level help text listing all commands.
|
|
@@ -143,6 +147,21 @@ function createLogWriter(values, streams) {
|
|
|
143
147
|
}
|
|
144
148
|
return create(streams);
|
|
145
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* Get the GitHub Actions step output file for --github-output, checked before
|
|
152
|
+
* the command runs.
|
|
153
|
+
*
|
|
154
|
+
* @param values Parsed option values.
|
|
155
|
+
* @return Output file path, or undefined without --github-output.
|
|
156
|
+
* @throws {ValidationError} For --github-output without GITHUB_OUTPUT.
|
|
157
|
+
*/
|
|
158
|
+
function getGitHubOutputFile(values) {
|
|
159
|
+
const file = process.env.GITHUB_OUTPUT;
|
|
160
|
+
if (getBoolean(values, 'github-output') && !file) {
|
|
161
|
+
throw new ValidationError('--github-output requires the GITHUB_OUTPUT environment variable of GitHub Actions.');
|
|
162
|
+
}
|
|
163
|
+
return getBoolean(values, 'github-output') ? file : undefined;
|
|
164
|
+
}
|
|
146
165
|
/**
|
|
147
166
|
* Parse the arguments of a command and run it.
|
|
148
167
|
*
|
|
@@ -169,6 +188,7 @@ async function runCommand(command, args, io) {
|
|
|
169
188
|
if ('' === configFile?.trim()) {
|
|
170
189
|
throw new ValidationError('--config <path> must not be empty.');
|
|
171
190
|
}
|
|
191
|
+
const githubOutputFile = getGitHubOutputFile(values);
|
|
172
192
|
logger = new Logger({
|
|
173
193
|
writer: createLogWriter(values, { stdout, stderr }),
|
|
174
194
|
quiet: getBoolean(values, 'quiet') || getBoolean(values, 'json'),
|
|
@@ -184,6 +204,10 @@ async function runCommand(command, args, io) {
|
|
|
184
204
|
if (getBoolean(values, 'json')) {
|
|
185
205
|
stdout.write(JSON.stringify(result, null, '\t') + '\n');
|
|
186
206
|
}
|
|
207
|
+
if (githubOutputFile) {
|
|
208
|
+
// Compact JSON has no line breaks, so it fits a single output line.
|
|
209
|
+
appendFileSync(githubOutputFile, `result=${JSON.stringify(result)}\n`);
|
|
210
|
+
}
|
|
187
211
|
return exitCode;
|
|
188
212
|
}
|
|
189
213
|
catch (error) {
|
|
@@ -91,6 +91,9 @@ export declare const changesetTagArgs: {
|
|
|
91
91
|
readonly 'dry-run': {
|
|
92
92
|
readonly type: "boolean";
|
|
93
93
|
};
|
|
94
|
+
readonly untagged: {
|
|
95
|
+
readonly type: "boolean";
|
|
96
|
+
};
|
|
94
97
|
readonly 'github-release': {
|
|
95
98
|
readonly type: "boolean";
|
|
96
99
|
};
|
|
@@ -102,6 +105,7 @@ export declare const changesetTagArgs: {
|
|
|
102
105
|
export interface ChangesetTagArgs {
|
|
103
106
|
push: boolean;
|
|
104
107
|
dryRun: boolean;
|
|
108
|
+
untagged: boolean;
|
|
105
109
|
githubRelease: boolean;
|
|
106
110
|
since?: string;
|
|
107
111
|
}
|
|
@@ -113,6 +113,7 @@ export function parseChangesetVersionArgs(values) {
|
|
|
113
113
|
export const changesetTagArgs = {
|
|
114
114
|
push: { type: 'boolean' },
|
|
115
115
|
'dry-run': { type: 'boolean' },
|
|
116
|
+
untagged: { type: 'boolean' },
|
|
116
117
|
'github-release': { type: 'boolean' },
|
|
117
118
|
since: { type: 'string' },
|
|
118
119
|
};
|
|
@@ -126,6 +127,7 @@ export function parseChangesetTagArgs(values) {
|
|
|
126
127
|
const args = {
|
|
127
128
|
push: getBoolean(values, 'push'),
|
|
128
129
|
dryRun: getBoolean(values, 'dry-run'),
|
|
130
|
+
untagged: getBoolean(values, 'untagged'),
|
|
129
131
|
githubRelease: getBoolean(values, 'github-release'),
|
|
130
132
|
since: getString(values, 'since'),
|
|
131
133
|
};
|
|
@@ -135,5 +137,8 @@ export function parseChangesetTagArgs(values) {
|
|
|
135
137
|
if (args.githubRelease && !args.push) {
|
|
136
138
|
throw new ValidationError('--github-release requires --push.');
|
|
137
139
|
}
|
|
140
|
+
if (args.untagged && args.push) {
|
|
141
|
+
throw new ValidationError('--untagged cannot be combined with --push.');
|
|
142
|
+
}
|
|
138
143
|
return args;
|
|
139
144
|
}
|
|
@@ -2,17 +2,20 @@ import { tagChangesets } from "../changeset-release.js";
|
|
|
2
2
|
import { parseChangesetTagArgs, changesetTagArgs } from "./changeset-args.js";
|
|
3
3
|
export default {
|
|
4
4
|
name: 'changeset-tag',
|
|
5
|
-
usage: 'changeset-tag [--dry-run] [--since <ref>] [--push] [--github-release]',
|
|
5
|
+
usage: 'changeset-tag [--dry-run] [--untagged] [--since <ref>] [--push] [--github-release]',
|
|
6
6
|
summary: 'Create missing release tags for configured package versions.',
|
|
7
7
|
help: `Options:
|
|
8
8
|
--dry-run List missing tags without creating them
|
|
9
|
+
--untagged List only releases without a tag, without creating tags
|
|
9
10
|
--since <ref> Tag packages changed since this git ref
|
|
10
11
|
--push Push newly created tags to origin
|
|
11
12
|
--github-release Create a GitHub Release for each tag
|
|
12
13
|
|
|
13
14
|
Tags are created only when absent, and GitHub Releases are created only when
|
|
14
15
|
missing, so rerunning after a partial failure is safe. --github-release also
|
|
15
|
-
requires --push
|
|
16
|
+
requires --push. With --json or --github-output, --untagged lists the releases
|
|
17
|
+
that still need a tag, for example to release each of them with a separate
|
|
18
|
+
workflow.`,
|
|
16
19
|
options: changesetTagArgs,
|
|
17
20
|
async run({ values, cwd, configFile, logger }) {
|
|
18
21
|
const args = parseChangesetTagArgs(values);
|
package/package.json
CHANGED