@wpelevator/wp-release 0.12.0 → 0.13.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.
Files changed (49) hide show
  1. package/README.md +90 -6
  2. package/dist/changeset-config.d.ts +86 -2
  3. package/dist/changeset-config.js +101 -6
  4. package/dist/changeset-dependents.d.ts +19 -8
  5. package/dist/changeset-dependents.js +96 -34
  6. package/dist/changeset-files.d.ts +6 -5
  7. package/dist/changeset-files.js +7 -5
  8. package/dist/changeset-packages.d.ts +45 -8
  9. package/dist/changeset-packages.js +73 -14
  10. package/dist/changeset-prompt.d.ts +119 -0
  11. package/dist/changeset-prompt.js +203 -0
  12. package/dist/changeset-release.d.ts +38 -3
  13. package/dist/changeset-release.js +88 -11
  14. package/dist/changesets.d.ts +6 -2
  15. package/dist/changesets.js +18 -12
  16. package/dist/cli.d.ts +7 -1
  17. package/dist/cli.js +18 -5
  18. package/dist/commands/changeset-add.d.ts +5 -2
  19. package/dist/commands/changeset-add.js +108 -9
  20. package/dist/commands/changeset-args.d.ts +24 -5
  21. package/dist/commands/changeset-args.js +57 -14
  22. package/dist/commands/changeset-status.d.ts +2 -0
  23. package/dist/commands/changeset-tag.js +2 -1
  24. package/dist/commands/changeset-version.d.ts +6 -0
  25. package/dist/commands/changeset-version.js +15 -3
  26. package/dist/commands/command.d.ts +3 -0
  27. package/dist/commands/deploy-git.d.ts +24 -4
  28. package/dist/commands/deploy-git.js +56 -3
  29. package/dist/commands/deploy-svn.d.ts +24 -4
  30. package/dist/commands/deploy-svn.js +56 -2
  31. package/dist/commands/package-deploys.d.ts +78 -0
  32. package/dist/commands/package-deploys.js +108 -0
  33. package/dist/git-deploy.d.ts +32 -0
  34. package/dist/git-deploy.js +57 -1
  35. package/dist/index.d.ts +5 -2
  36. package/dist/index.js +2 -1
  37. package/dist/package-deploy.d.ts +105 -0
  38. package/dist/package-deploy.js +288 -0
  39. package/dist/release-repository.d.ts +14 -2
  40. package/dist/release-repository.js +46 -7
  41. package/dist/release-tags.d.ts +3 -1
  42. package/dist/release-tags.js +5 -2
  43. package/dist/tag-format.d.ts +3 -3
  44. package/dist/tag-format.js +1 -1
  45. package/dist/version-files.d.ts +2 -1
  46. package/dist/version-files.js +12 -7
  47. package/dist/versions.d.ts +28 -3
  48. package/dist/versions.js +84 -9
  49. package/package.json +1 -1
@@ -7,48 +7,76 @@ export const changesetAddArgs = {
7
7
  bump: { type: 'string', multiple: true },
8
8
  summary: { type: 'string' },
9
9
  empty: { type: 'boolean' },
10
+ since: { type: 'string' },
10
11
  name: { type: 'string' },
11
12
  };
12
13
  /**
13
- * Parse and validate the `changeset-add` options.
14
+ * Check that a bump is patch, minor or major.
15
+ *
16
+ * @param bump Bump option value.
17
+ * @param packageName Package of the bump, for the error.
18
+ * @return The bump.
19
+ * @throws {ValidationError} For another value.
20
+ */
21
+ function parseBump(bump, packageName) {
22
+ if (!CHANGESET_BUMPS.includes(bump)) {
23
+ const target = packageName ? ` for package "${packageName}"` : '';
24
+ throw new ValidationError(`Invalid bump "${bump}"${target}; expected patch, minor or major.`);
25
+ }
26
+ return bump;
27
+ }
28
+ /**
29
+ * Parse and validate the `changeset-add` options. Without --package, a
30
+ * single --bump applies to the changed packages without a changeset, and
31
+ * without --bump either the command asks for the changeset in a terminal.
14
32
  *
15
33
  * @param values Parsed CLI options.
16
34
  * @return Normalized changeset input.
17
- * @throws {ValidationError} If required options are missing or conflicting.
35
+ * @throws {ValidationError} If options are conflicting or incomplete.
18
36
  */
19
37
  export function parseChangesetAddArgs(values) {
20
38
  const names = getStrings(values, 'package');
21
39
  const bumps = getStrings(values, 'bump');
22
40
  const summary = getString(values, 'summary')?.trim();
23
41
  const empty = getBoolean(values, 'empty');
42
+ const since = getString(values, 'since');
24
43
  const name = getString(values, 'name');
25
- if (empty && (names.length || bumps.length || summary)) {
26
- throw new ValidationError('--empty cannot be combined with --package, --bump or --summary.');
44
+ if (empty && (names.length || bumps.length || summary || since)) {
45
+ throw new ValidationError('--empty cannot be combined with --package, --bump, --summary or --since.');
27
46
  }
28
- if (!empty && (!names.length || names.length !== bumps.length)) {
47
+ if (names.length && names.length !== bumps.length) {
29
48
  throw new ValidationError('Pass matching repeated --package <name> and --bump <patch|minor|major> options, or use --empty.');
30
49
  }
31
- if (!empty && !summary) {
32
- throw new ValidationError('--summary <text> is required unless --empty is set.');
50
+ if (!names.length && bumps.length > 1) {
51
+ throw new ValidationError('Pass a single --bump without --package to release the changed packages, or pair each --bump with a --package.');
52
+ }
53
+ if (names.length && undefined !== since) {
54
+ throw new ValidationError('--since selects the changed packages, so it cannot be combined with --package.');
55
+ }
56
+ if ('' === since?.trim()) {
57
+ throw new ValidationError('--since <ref> must not be empty.');
58
+ }
59
+ if (bumps.length && !summary) {
60
+ throw new ValidationError('--summary <text> is required with --bump.');
33
61
  }
34
62
  if (name && !/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(name)) {
35
63
  throw new ValidationError('--name must contain only letters, numbers, dots, underscores or hyphens.');
36
64
  }
37
65
  const packages = {};
38
66
  names.forEach((packageName, index) => {
39
- const bump = bumps[index];
40
67
  if (Object.hasOwn(packages, packageName)) {
41
68
  throw new ValidationError(`Package "${packageName}" was passed more than once.`);
42
69
  }
43
- if (!CHANGESET_BUMPS.includes(bump)) {
44
- throw new ValidationError(`Invalid bump "${bump}" for package "${packageName}"; expected patch, minor or major.`);
45
- }
46
- packages[packageName] = bump;
70
+ packages[packageName] = parseBump(bumps[index] ?? '', packageName);
47
71
  });
48
72
  return {
49
73
  packages,
50
- summary: summary ?? '',
51
74
  empty,
75
+ ...(!names.length && bumps.length
76
+ ? { bump: parseBump(bumps[0] ?? '') }
77
+ : {}),
78
+ ...(summary ? { summary } : {}),
79
+ ...(since ? { since } : {}),
52
80
  ...(name ? { name } : {}),
53
81
  };
54
82
  }
@@ -76,6 +104,8 @@ export const changesetVersionArgs = {
76
104
  date: { type: 'string' },
77
105
  package: { type: 'string', multiple: true },
78
106
  'no-dependents': { type: 'boolean' },
107
+ prerelease: { type: 'string' },
108
+ snapshot: { type: 'string' },
79
109
  };
80
110
  /**
81
111
  * Validate and normalize a release date option.
@@ -102,19 +132,32 @@ export function parseChangesetDate(value) {
102
132
  *
103
133
  * @param values Parsed CLI options.
104
134
  * @return Normalized versioning input.
105
- * @throws {ValidationError} If --date is invalid.
135
+ * @throws {ValidationError} If --date is invalid, or an option is empty or conflicting.
106
136
  */
107
137
  export function parseChangesetVersionArgs(values) {
108
138
  const date = parseChangesetDate(getString(values, 'date'));
109
139
  const packages = getStrings(values, 'package');
140
+ const prerelease = getString(values, 'prerelease')?.trim();
110
141
  if (packages.some((name) => !name.trim())) {
111
142
  throw new ValidationError('--package <name> must not be empty.');
112
143
  }
144
+ const snapshot = getString(values, 'snapshot')?.trim();
145
+ if ('' === prerelease) {
146
+ throw new ValidationError('--prerelease <id> must not be empty.');
147
+ }
148
+ if ('' === snapshot) {
149
+ throw new ValidationError('--snapshot <id> must not be empty.');
150
+ }
151
+ if (prerelease && snapshot) {
152
+ throw new ValidationError('--prerelease cannot be combined with --snapshot.');
153
+ }
113
154
  return {
114
155
  dryRun: getBoolean(values, 'dry-run'),
115
156
  dependents: !getBoolean(values, 'no-dependents'),
116
157
  ...(date ? { date } : {}),
117
158
  ...(packages.length ? { packages } : {}),
159
+ ...(prerelease ? { prerelease } : {}),
160
+ ...(snapshot ? { snapshot } : {}),
118
161
  };
119
162
  }
120
163
  /** Parse-args options for `changeset-tag`. */
@@ -1,4 +1,5 @@
1
1
  export interface ChangesetStatusResult {
2
+ since?: string;
2
3
  changesets: Array<{
3
4
  fileName: string;
4
5
  packages: Record<string, string>;
@@ -34,6 +35,7 @@ declare const _default: {
34
35
  currentVersion: string;
35
36
  nextVersion: string;
36
37
  }[];
38
+ since?: string;
37
39
  changesets: import("../changesets.ts").Changeset[];
38
40
  changedPackages: string[];
39
41
  changedPackageFiles: Record<string, string[]>;
@@ -10,7 +10,8 @@ export default {
10
10
  creating them
11
11
  --untagged List only releases without a tag, without creating tags
12
12
  --since <ref> Tag packages changed since this git ref
13
- --package <name> Tag only this package (repeatable)
13
+ --package <name> Tag only this package, by identifier or path under
14
+ the configured root (repeatable)
14
15
  --version <version> Fail unless the single --package is at this version;
15
16
  the version to tag for packages versioned by git tags
16
17
  --push Push newly created tags to origin, one at a time
@@ -29,6 +29,12 @@ declare const _default: {
29
29
  readonly 'no-dependents': {
30
30
  readonly type: "boolean";
31
31
  };
32
+ readonly prerelease: {
33
+ readonly type: "string";
34
+ };
35
+ readonly snapshot: {
36
+ readonly type: "string";
37
+ };
32
38
  };
33
39
  run({ values, cwd, configFile, logger }: import("./command.ts").CommandContext): Promise<{
34
40
  exitCode: number;
@@ -3,18 +3,30 @@ import { getChangesetVersionSummary } from "../summary.js";
3
3
  import { parseChangesetVersionArgs, changesetVersionArgs, } from "./changeset-args.js";
4
4
  export default {
5
5
  name: 'changeset-version',
6
- usage: 'changeset-version [--dry-run] [--date <YYYY-MM-DD>] [--package <name>] [--no-dependents]',
6
+ usage: 'changeset-version [--dry-run] [--date <YYYY-MM-DD>] [--package <name>] [--no-dependents] [--prerelease <id> | --snapshot <id>]',
7
7
  summary: 'Apply pending version bumps and changelog entries.',
8
8
  help: `Options:
9
9
  --dry-run Print the release plan without writing files
10
10
  --date <YYYY-MM-DD> Changelog date (default: today)
11
- --package <name> Version only this package (repeatable)
11
+ --package <name> Version only this package, by identifier or path
12
+ under the configured root (repeatable)
12
13
  --no-dependents Leave the configured dependents of the selected sources out
14
+ --prerelease <id> Release pre-releases like 1.3.0-rc.1, with an identifier
15
+ like rc (numbered from the tags) or rc.1
16
+ --snapshot <id> Release snapshots like 1.3.0-pr-251.20261012183000,
17
+ with an identifier like pr-251 and the UTC time
13
18
 
14
19
  Updates configured version files, prepends changelog entries and removes the
15
20
  applied changeset files. With --package, a changeset that also names other
16
21
  packages keeps only their entries, so it still applies to their releases, and
17
- changesets without packages are left for a run without --package.`,
22
+ changesets without packages are left for a run without --package.
23
+
24
+ With --prerelease, run it on a branch that isn't merged and tag that branch,
25
+ since the pre-release consumes the changesets that the stable release needs.
26
+ The readme Stable tag keeps the last stable version.
27
+
28
+ With --snapshot, build and publish the versioned files without committing
29
+ them, for example to test a pull request.`,
18
30
  options: changesetVersionArgs,
19
31
  async run({ values, cwd, configFile, logger }) {
20
32
  const args = parseChangesetVersionArgs(values);
@@ -1,4 +1,5 @@
1
1
  import type { ParseArgsOptionsConfig } from 'node:util';
2
+ import type { PromptTerminal } from '../changeset-prompt.ts';
2
3
  import type { Logger } from '../logger.ts';
3
4
  /**
4
5
  * Parsed option values from node:util parseArgs().
@@ -15,6 +16,8 @@ export interface CommandContext {
15
16
  configFile?: string;
16
17
  /** Logger for the command output. */
17
18
  logger: Logger;
19
+ /** Terminal for interactive prompts, only when the CLI runs in one and prints no JSON. */
20
+ terminal?: PromptTerminal;
18
21
  }
19
22
  export interface CommandOutcome<Result = unknown> {
20
23
  /** Process exit code. */
@@ -15,12 +15,22 @@ declare const _default: {
15
15
  summary: string;
16
16
  help: string;
17
17
  options: {
18
- message: {
19
- type: "string";
20
- };
21
18
  'dry-run': {
22
19
  type: "boolean";
23
20
  };
21
+ 'release-ref': {
22
+ readonly type: "string";
23
+ };
24
+ package: {
25
+ readonly type: "string";
26
+ readonly multiple: true;
27
+ };
28
+ list: {
29
+ readonly type: "boolean";
30
+ };
31
+ message: {
32
+ type: "string";
33
+ };
24
34
  'git-url': {
25
35
  type: "string";
26
36
  };
@@ -37,7 +47,17 @@ declare const _default: {
37
47
  type: "string";
38
48
  };
39
49
  };
40
- run({ values, positionals, cwd, logger }: import("./command.ts").CommandContext): Promise<{
50
+ run({ values, positionals, cwd, configFile, logger }: import("./command.ts").CommandContext): Promise<{
51
+ exitCode: number;
52
+ result: {
53
+ packages: import("../package-deploy.ts").PackageDeployPlanItem[];
54
+ };
55
+ } | {
56
+ exitCode: number;
57
+ result: {
58
+ deploys: import("./package-deploys.ts").PackageDeployOutcome<import("../git-deploy.ts").GitDeployResult>[];
59
+ };
60
+ } | {
41
61
  exitCode: number;
42
62
  result: import("../git-deploy.ts").GitDeployResult;
43
63
  }>;
@@ -1,6 +1,22 @@
1
1
  import { GitDeploy, resolveGitDeployOptions } from "../git-deploy.js";
2
+ import { getGitDeploys } from "../package-deploy.js";
2
3
  import { fileSelectionArgs, getFileSelectionInput, getSourceDirArg, sourceDirArgs, } from "./args.js";
3
4
  import { getBoolean, getString } from "./command.js";
5
+ import { getPackageDeployArgs, listPackageDeploys, packageDeployArgs, runPackageDeploys, } from "./package-deploys.js";
6
+ /** Options of a single deploy target, which --release-ref takes from the config. */
7
+ const TARGET_FLAGS = [
8
+ 'source-dir',
9
+ 'git-url',
10
+ 'branch',
11
+ 'tag',
12
+ 'split-prefix',
13
+ 'source-ref',
14
+ 'distignore',
15
+ 'no-distignore',
16
+ 'exclude',
17
+ 'exclude-gitattributes',
18
+ 'message',
19
+ ];
4
20
  /**
5
21
  * Map the parsed "deploy-git" arguments to resolveGitDeployOptions() input.
6
22
  *
@@ -25,7 +41,7 @@ export function getGitDeployInputFromArgs(values, positionals, cwd) {
25
41
  }
26
42
  export default {
27
43
  name: 'deploy-git',
28
- usage: 'deploy-git [<source-dir>] --git-url <url> [options]',
44
+ usage: 'deploy-git [<source-dir>] --git-url <url> [options] | deploy-git --release-ref <ref> [--package <name>] [--list] [--dry-run]',
29
45
  summary: 'Deploy the files of a plugin, theme or package to a Git repository as a release commit.',
30
46
  help: `Arguments:
31
47
  <source-dir> Directory with the files to release (default: .),
@@ -37,6 +53,17 @@ Writes (none by default):
37
53
  --tag <name> Create this tag for the release, on top of --branch
38
54
  or the default branch of the repository
39
55
 
56
+ Configured packages (instead of the options above):
57
+ --release-ref <ref> Deploy the packages that this ref releases to the Git
58
+ targets in the config: the package of a release tag,
59
+ like refs/tags/plugins/alpha/1.2.0, or every package
60
+ for a branch, like refs/heads/main
61
+ --package <name> Deploy only this package (repeatable), for example
62
+ in a CI job for each package or to retry one
63
+ --list List the deploys without running them, with the
64
+ deploys of each package as the result for --json
65
+ and --github-output, for a CI matrix
66
+
40
67
  Options:
41
68
  --git-url <url> Repository to deploy to
42
69
  --split-prefix <dir> Use the history of this directory of the source
@@ -56,9 +83,21 @@ branch only moves forward, a release without changes isn't pushed again, an
56
83
  older build doesn't move a branch that has newer source history, a tag that
57
84
  already has the same files is reused, and a tag with other files
58
85
  fails with exit code 2 (delete it in the repository to release it again). The source directory must be inside a Git repository.
59
- Credentials come from git, like a token in the URL or an SSH key.
86
+ Credentials come from git, like a credential helper or an SSH key. For an
87
+ HTTPS repository on github.com, or on the host of GITHUB_SERVER_URL, the
88
+ GITHUB_TOKEN environment variable is sent as an authorization header, so the
89
+ token stays out of the URL.
90
+
91
+ With --release-ref, each package deploys to every Git target of its
92
+ deploy.git config, with the history of its directory, in one log group for
93
+ each package, and a failed deploy doesn't stop the others but exits with 1. A release tag creates the tag of each target on top
94
+ of its default branch, and a branch releases to the same branch.
60
95
 
61
96
  Examples:
97
+ wp-release deploy-git --release-ref "$GITHUB_REF"
98
+ Deploy the configured packages of a tag or branch push
99
+ wp-release deploy-git --release-ref refs/heads/main --list
100
+ Preview what a push to main deploys
62
101
  wp-release deploy-git build --git-url git@github.com:me/my-plugin-dist.git --branch main --tag 1.2.0
63
102
  Release a build to a distribution repository and tag it
64
103
  wp-release deploy-git packages/my-plugin --split-prefix packages/my-plugin --git-url … --branch main
@@ -72,9 +111,23 @@ Examples:
72
111
  'source-ref': { type: 'string' },
73
112
  ...fileSelectionArgs,
74
113
  message: { type: 'string' },
114
+ ...packageDeployArgs,
75
115
  'dry-run': { type: 'boolean' },
76
116
  },
77
- async run({ values, positionals, cwd, logger }) {
117
+ async run({ values, positionals, cwd, configFile, logger }) {
118
+ const { ref, packages, list } = getPackageDeployArgs(values, positionals, TARGET_FLAGS);
119
+ if (ref) {
120
+ const deploys = await getGitDeploys({
121
+ cwd,
122
+ ref,
123
+ packages,
124
+ dryRun: getBoolean(values, 'dry-run'),
125
+ ...(configFile ? { configFile } : {}),
126
+ });
127
+ return list
128
+ ? listPackageDeploys(deploys, logger, ref)
129
+ : runPackageDeploys(deploys, (input) => new GitDeploy(resolveGitDeployOptions(input), logger).run(), logger, ref);
130
+ }
78
131
  const options = resolveGitDeployOptions(getGitDeployInputFromArgs(values, positionals, cwd));
79
132
  const result = await new GitDeploy(options, logger).run();
80
133
  return { exitCode: 0, result };
@@ -23,6 +23,19 @@ declare const _default: {
23
23
  summary: string;
24
24
  help: string;
25
25
  options: {
26
+ 'dry-run': {
27
+ type: "boolean";
28
+ };
29
+ 'release-ref': {
30
+ readonly type: "string";
31
+ };
32
+ package: {
33
+ readonly type: "string";
34
+ readonly multiple: true;
35
+ };
36
+ list: {
37
+ readonly type: "boolean";
38
+ };
26
39
  'svn-url': {
27
40
  type: "string";
28
41
  };
@@ -35,9 +48,6 @@ declare const _default: {
35
48
  force: {
36
49
  type: "boolean";
37
50
  };
38
- 'dry-run': {
39
- type: "boolean";
40
- };
41
51
  trunk: {
42
52
  type: "boolean";
43
53
  };
@@ -66,7 +76,17 @@ declare const _default: {
66
76
  type: "string";
67
77
  };
68
78
  };
69
- run({ values, positionals, cwd, logger }: import("./command.ts").CommandContext): Promise<{
79
+ run({ values, positionals, cwd, configFile, logger }: import("./command.ts").CommandContext): Promise<{
80
+ exitCode: number;
81
+ result: {
82
+ packages: import("../package-deploy.ts").PackageDeployPlanItem[];
83
+ };
84
+ } | {
85
+ exitCode: number;
86
+ result: {
87
+ deploys: import("./package-deploys.ts").PackageDeployOutcome<import("../svn-deploy.ts").DeployResult>[];
88
+ };
89
+ } | {
70
90
  exitCode: number;
71
91
  result: import("../svn-deploy.ts").DeployResult;
72
92
  }>;
@@ -1,7 +1,28 @@
1
1
  import { resolveDeployOptions } from "../deploy-options.js";
2
+ import { getSvnDeploys } from "../package-deploy.js";
2
3
  import { SvnDeploy } from "../svn-deploy.js";
3
4
  import { fileSelectionArgs, getFileSelectionInput, getSourceDirArg, sourceDirArgs, } from "./args.js";
4
5
  import { getBoolean, getString } from "./command.js";
6
+ import { getPackageDeployArgs, listPackageDeploys, packageDeployArgs, runPackageDeploys, } from "./package-deploys.js";
7
+ /** Options of a single deploy, which --release-ref takes from the config. */
8
+ const TARGET_FLAGS = [
9
+ 'source-dir',
10
+ 'trunk',
11
+ 'readme-only',
12
+ 'svn-tag',
13
+ 'assets-dir',
14
+ 'no-assets',
15
+ 'slug',
16
+ 'version',
17
+ 'readme',
18
+ 'from-zip',
19
+ 'distignore',
20
+ 'no-distignore',
21
+ 'exclude',
22
+ 'exclude-gitattributes',
23
+ 'svn-url',
24
+ 'message',
25
+ ];
5
26
  /**
6
27
  * Map the parsed "deploy-svn" arguments to resolveDeployOptions() input.
7
28
  * Flags that aren't passed stay undefined, so that the same defaults apply
@@ -35,7 +56,7 @@ export function getDeployInputFromArgs(input) {
35
56
  }
36
57
  export default {
37
58
  name: 'deploy-svn',
38
- usage: 'deploy-svn [<source-dir>] [options]',
59
+ usage: 'deploy-svn [<source-dir>] [options] | deploy-svn --release-ref <ref> [--package <name>] [--list] [--dry-run]',
39
60
  summary: 'Deploy a plugin to the WordPress.org plugin SVN repository.',
40
61
  help: `Arguments:
41
62
  <source-dir> Directory with the plugin files (default: .), also
@@ -51,6 +72,15 @@ Writes (none by default, assets only with --assets-dir):
51
72
  screenshots to assets/
52
73
  --no-assets Don't sync --assets-dir for this run
53
74
 
75
+ Configured packages (instead of the writes and the source options):
76
+ --release-ref <ref> Deploy the package that this release tag releases,
77
+ like refs/tags/plugins/alpha/1.2.0, to the SVN
78
+ targets in the config. Branches aren't deployed.
79
+ --package <name> Deploy only this package (repeatable)
80
+ --list List the deploys without running them, with the
81
+ deploys of each package as the result for --json
82
+ and --github-output, for a CI matrix
83
+
54
84
  Options:
55
85
  --slug <slug> Plugin slug (default: project directory name)
56
86
  --version <version> Version to check (default: --svn-tag, then the Version header)
@@ -71,7 +101,13 @@ Options:
71
101
  Credentials are only needed to commit. Exits with 3 when they're missing
72
102
  or rejected.
73
103
 
104
+ With --release-ref, a stable release syncs trunk/, creates its tag and syncs
105
+ the assetsDir of each deploy.svn target, while a pre-release only creates its
106
+ tag. A failed deploy doesn't stop the others and exits with 1.
107
+
74
108
  Examples:
109
+ wp-release deploy-svn --release-ref "$GITHUB_REF"
110
+ Deploy the configured plugin of a release tag push
75
111
  wp-release deploy-svn dist --trunk --svn-tag 1.2.0 --assets-dir .wordpress-org
76
112
  Deploy 1.2.0 to trunk and the tag, and update the assets
77
113
  wp-release deploy-svn dist --svn-tag 1.2.0-rc.1
@@ -96,9 +132,27 @@ Examples:
96
132
  'svn-username': { type: 'string' },
97
133
  message: { type: 'string' },
98
134
  force: { type: 'boolean' },
135
+ ...packageDeployArgs,
99
136
  'dry-run': { type: 'boolean' },
100
137
  },
101
- async run({ values, positionals, cwd, logger }) {
138
+ async run({ values, positionals, cwd, configFile, logger }) {
139
+ const { ref, packages, list } = getPackageDeployArgs(values, positionals, TARGET_FLAGS);
140
+ if (ref) {
141
+ const deploys = await getSvnDeploys({
142
+ cwd,
143
+ ref,
144
+ packages,
145
+ dryRun: getBoolean(values, 'dry-run'),
146
+ ...(configFile ? { configFile } : {}),
147
+ });
148
+ return list
149
+ ? listPackageDeploys(deploys, logger, ref)
150
+ : runPackageDeploys(deploys, (input) => new SvnDeploy(resolveDeployOptions({
151
+ ...input,
152
+ svnUsername: getString(values, 'svn-username'),
153
+ force: getBoolean(values, 'force'),
154
+ }), logger).run(), logger, ref);
155
+ }
102
156
  const options = resolveDeployOptions(getDeployInputFromArgs({ values, positionals, cwd }));
103
157
  const result = await new SvnDeploy(options, logger).run();
104
158
  return { exitCode: 0, result };
@@ -0,0 +1,78 @@
1
+ import type { Logger } from '../logger.ts';
2
+ import type { PackageDeploy, PackageDeployPlanItem } from '../package-deploy.ts';
3
+ import type { ParsedValues } from './command.ts';
4
+ /**
5
+ * Options of the deploy commands that deploy the configured packages of a
6
+ * ref, in node:util parseArgs() format.
7
+ */
8
+ export declare const packageDeployArgs: {
9
+ readonly 'release-ref': {
10
+ readonly type: "string";
11
+ };
12
+ readonly package: {
13
+ readonly type: "string";
14
+ readonly multiple: true;
15
+ };
16
+ readonly list: {
17
+ readonly type: "boolean";
18
+ };
19
+ };
20
+ /** Result of one deploy of a configured package. */
21
+ export interface PackageDeployOutcome<Result> {
22
+ package: string;
23
+ /** Package, target and ref, with credentials redacted. */
24
+ label: string;
25
+ version?: string;
26
+ branch?: string;
27
+ /** Deploy result, unless it failed. */
28
+ result?: Result;
29
+ /** Error message of a failed deploy. */
30
+ error?: string;
31
+ }
32
+ /**
33
+ * Get the ref and the packages to deploy from the config, failing for the
34
+ * options that set a single deploy target instead.
35
+ *
36
+ * @param values Parsed CLI values.
37
+ * @param positionals Positional arguments.
38
+ * @param targetFlags Options of a single deploy target.
39
+ * @return The ref and the selected packages.
40
+ * @throws {ValidationError} For --package without --release-ref, or a single target option with it.
41
+ */
42
+ export declare function getPackageDeployArgs(values: ParsedValues, positionals: string[], targetFlags: string[]): {
43
+ ref?: string;
44
+ packages: string[];
45
+ list: boolean;
46
+ };
47
+ /**
48
+ * Run the deploys of the configured packages one at a time, in one log group
49
+ * for each package, continuing after a failed deploy so that one package or
50
+ * target doesn't block the others.
51
+ *
52
+ * @param deploys Deploys from getGitDeploys() or getSvnDeploys().
53
+ * @param deploy Runs one deploy.
54
+ * @param logger Logger.
55
+ * @param ref Deployed ref, for the log.
56
+ * @return Exit code 1 when a deploy failed, and the result of each deploy.
57
+ */
58
+ export declare function runPackageDeploys<Input, Result>(deploys: PackageDeploy<Input>[], deploy: (input: Input) => Promise<Result>, logger: Logger, ref: string): Promise<{
59
+ exitCode: number;
60
+ result: {
61
+ deploys: PackageDeployOutcome<Result>[];
62
+ };
63
+ }>;
64
+ /**
65
+ * List the deploys of the configured packages without running them, one line
66
+ * for each deploy, with the plan as the result for --json and --github-output.
67
+ *
68
+ * @param deploys Deploys from getGitDeploys() or getSvnDeploys().
69
+ * @param logger Logger.
70
+ * @param ref Deployed ref, for the log.
71
+ * @return Exit code 0 and the deploys of each package.
72
+ */
73
+ export declare function listPackageDeploys(deploys: PackageDeploy<unknown>[], logger: Logger, ref: string): {
74
+ exitCode: number;
75
+ result: {
76
+ packages: PackageDeployPlanItem[];
77
+ };
78
+ };