@wpelevator/wp-release 0.15.0 → 0.17.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 (98) hide show
  1. package/README.md +366 -39
  2. package/dist/changeset-config.d.ts +8 -0
  3. package/dist/changeset-config.js +3 -0
  4. package/dist/changeset-release.d.ts +9 -3
  5. package/dist/changeset-release.js +23 -14
  6. package/dist/cli.d.ts +6 -0
  7. package/dist/cli.js +12 -0
  8. package/dist/commands/artifact-signing.d.ts +20 -0
  9. package/dist/commands/artifact-signing.js +42 -0
  10. package/dist/commands/build.d.ts +32 -0
  11. package/dist/commands/build.js +91 -0
  12. package/dist/commands/changeset-add.d.ts +55 -6
  13. package/dist/commands/changeset-add.js +12 -3
  14. package/dist/commands/changeset-args.js +2 -2
  15. package/dist/commands/changeset-project-args.d.ts +63 -0
  16. package/dist/commands/changeset-project-args.js +114 -0
  17. package/dist/commands/changeset-status.d.ts +50 -1
  18. package/dist/commands/changeset-status.js +4 -2
  19. package/dist/commands/changeset-tag.d.ts +55 -6
  20. package/dist/commands/changeset-tag.js +7 -4
  21. package/dist/commands/changeset-version.d.ts +55 -6
  22. package/dist/commands/changeset-version.js +4 -2
  23. package/dist/commands/checksums.d.ts +4 -1
  24. package/dist/commands/checksums.js +27 -6
  25. package/dist/commands/i18n-audit.d.ts +2 -0
  26. package/dist/commands/i18n-audit.js +2 -0
  27. package/dist/commands/i18n-compile.d.ts +6 -0
  28. package/dist/commands/i18n-compile.js +76 -0
  29. package/dist/commands/i18n-json.d.ts +2 -0
  30. package/dist/commands/i18n-json.js +2 -0
  31. package/dist/commands/i18n-mo.d.ts +2 -0
  32. package/dist/commands/i18n-mo.js +2 -0
  33. package/dist/commands/i18n-php.d.ts +2 -0
  34. package/dist/commands/i18n-php.js +2 -0
  35. package/dist/commands/i18n-pot.d.ts +2 -0
  36. package/dist/commands/i18n-pot.js +2 -0
  37. package/dist/commands/i18n.d.ts +12 -0
  38. package/dist/commands/i18n.js +174 -0
  39. package/dist/commands/package-source.d.ts +43 -0
  40. package/dist/commands/package-source.js +101 -0
  41. package/dist/commands/verify.d.ts +7 -1
  42. package/dist/commands/verify.js +53 -17
  43. package/dist/commands/zip.d.ts +20 -8
  44. package/dist/commands/zip.js +109 -124
  45. package/dist/i18n/atomic-output.d.ts +23 -0
  46. package/dist/i18n/atomic-output.js +90 -0
  47. package/dist/i18n/audit.d.ts +7 -0
  48. package/dist/i18n/audit.js +69 -0
  49. package/dist/i18n/catalog.d.ts +54 -0
  50. package/dist/i18n/catalog.js +86 -0
  51. package/dist/i18n/compile.d.ts +27 -0
  52. package/dist/i18n/compile.js +71 -0
  53. package/dist/i18n/extraction.d.ts +45 -0
  54. package/dist/i18n/extraction.js +105 -0
  55. package/dist/i18n/files.d.ts +7 -0
  56. package/dist/i18n/files.js +45 -0
  57. package/dist/i18n/generate.d.ts +49 -0
  58. package/dist/i18n/generate.js +240 -0
  59. package/dist/i18n/javascript.d.ts +7 -0
  60. package/dist/i18n/javascript.js +143 -0
  61. package/dist/i18n/metadata.d.ts +16 -0
  62. package/dist/i18n/metadata.js +117 -0
  63. package/dist/i18n/options.d.ts +52 -0
  64. package/dist/i18n/options.js +156 -0
  65. package/dist/i18n/packages.d.ts +24 -0
  66. package/dist/i18n/packages.js +86 -0
  67. package/dist/i18n/php.d.ts +9 -0
  68. package/dist/i18n/php.js +238 -0
  69. package/dist/i18n/placeholders.d.ts +9 -0
  70. package/dist/i18n/placeholders.js +13 -0
  71. package/dist/i18n/po.d.ts +24 -0
  72. package/dist/i18n/po.js +180 -0
  73. package/dist/i18n/pot.d.ts +16 -0
  74. package/dist/i18n/pot.js +119 -0
  75. package/dist/i18n/translation-json.d.ts +14 -0
  76. package/dist/i18n/translation-json.js +96 -0
  77. package/dist/i18n/translation-php.d.ts +6 -0
  78. package/dist/i18n/translation-php.js +35 -0
  79. package/dist/index.d.ts +28 -0
  80. package/dist/index.js +16 -0
  81. package/dist/integrity.d.ts +33 -0
  82. package/dist/integrity.js +115 -0
  83. package/dist/output-files.d.ts +7 -0
  84. package/dist/output-files.js +25 -0
  85. package/dist/package-build.d.ts +33 -0
  86. package/dist/package-build.js +112 -0
  87. package/dist/package-files.d.ts +25 -0
  88. package/dist/package-files.js +24 -0
  89. package/dist/package-zip.d.ts +14 -2
  90. package/dist/package-zip.js +129 -38
  91. package/dist/release-tags.js +6 -0
  92. package/dist/single-project.d.ts +32 -0
  93. package/dist/single-project.js +144 -0
  94. package/dist/summary.d.ts +9 -0
  95. package/dist/summary.js +25 -0
  96. package/dist/zip.d.ts +3 -0
  97. package/dist/zip.js +16 -6
  98. package/package.json +20 -3
@@ -1,3 +1,5 @@
1
+ import type { I18nOptions } from './i18n/options.ts';
2
+ import type { IntegrityConfig } from './integrity.ts';
1
3
  import type { Changeset, ChangesetBump, ChangesetPackage } from './changesets.ts';
2
4
  export type PackageVersionSource = {
3
5
  kind: 'package-json';
@@ -58,6 +60,8 @@ export interface PackageVersionConfig {
58
60
  export type PackageIdSource = 'package.json#name' | 'composer.json#name' | 'path';
59
61
  /** One directory pattern that describes packages sharing release behavior. */
60
62
  export interface ChangesetPackageGroup {
63
+ /** Extraction settings, independent of release file rules. */
64
+ i18n?: I18nOptions;
61
65
  /** Package directories to discover, relative to the configured package root. */
62
66
  glob: string;
63
67
  /** Package paths excluded from this group, relative to root. */
@@ -217,6 +221,10 @@ export interface DependentsConfig {
217
221
  }
218
222
  /** JavaScript configuration for changeset-aware releases. */
219
223
  export interface ChangesetConfig {
224
+ /** Extraction defaults for configured WordPress packages. */
225
+ i18n?: I18nOptions;
226
+ /** Default checksum format, placement and manifest signing for ZIPs. */
227
+ integrity?: IntegrityConfig;
220
228
  /** Branch receiving ordinary changes. */
221
229
  baseBranch?: string;
222
230
  /** Git remote that tags are pushed to and the base branch is compared on, origin by default. */
@@ -6,6 +6,7 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
6
6
  }
7
7
  return path;
8
8
  };
9
+ import { validateI18nOptions } from "./i18n/options.js";
9
10
  import { access } from 'node:fs/promises';
10
11
  import path from 'node:path';
11
12
  import { pathToFileURL } from 'node:url';
@@ -171,6 +172,7 @@ function validateChangesetConfig(config, configFile) {
171
172
  throw new ValidationError(`wp-release config ${configFile} must default-export a configuration object.`);
172
173
  }
173
174
  const candidate = config;
175
+ validateI18nOptions(candidate.i18n, `${configFile}.i18n`);
174
176
  if (!Array.isArray(candidate.packages)) {
175
177
  throw new ValidationError(`wp-release config ${configFile} must define a packages array.`);
176
178
  }
@@ -267,6 +269,7 @@ function validateChangesetConfig(config, configFile) {
267
269
  !Array.isArray(group.version.to)))) {
268
270
  throw new ValidationError(`wp-release config ${configFile} has an invalid packages[${index}] entry.`);
269
271
  }
272
+ validateI18nOptions(group.i18n, `${configFile}.packages[${index}].i18n`);
270
273
  if (undefined !== group.idFrom &&
271
274
  !['path', 'package.json#name', 'composer.json#name'].includes(group.idFrom)) {
272
275
  throw new ValidationError(`wp-release config ${configFile} packages[${index}].idFrom is not supported.`);
@@ -1,9 +1,12 @@
1
+ import type { SingleProjectOptions } from './single-project.ts';
1
2
  import type { Changeset, ChangesetBump, ChangesetPackage, ChangesetReleasePlan, PackageRelease, VersionedRelease } from './changesets.ts';
2
3
  import type { GitRunner } from './git.ts';
3
4
  import { ReleaseRepository } from './release-repository.ts';
4
5
  export interface ChangesetRepository {
5
6
  cwd: string;
6
7
  configFile?: string;
8
+ /** Single-project fallback settings, used only without a release config. */
9
+ singleProject?: SingleProjectOptions;
7
10
  /** Tag format that replaces the tagFormat of the config. */
8
11
  tagFormat?: string;
9
12
  }
@@ -99,6 +102,7 @@ export interface ChangesetStatusResult {
99
102
  export declare class ChangesetRelease {
100
103
  readonly cwd: string;
101
104
  readonly configFile: string | undefined;
105
+ readonly singleProject: SingleProjectOptions | undefined;
102
106
  readonly tagFormat: string | undefined;
103
107
  readonly repository: ReleaseRepository;
104
108
  /**
@@ -109,7 +113,7 @@ export declare class ChangesetRelease {
109
113
  * Discover configured packages, pending changesets, and their proposed
110
114
  * versions.
111
115
  *
112
- * @return A release plan; `undefined` when no config is present.
116
+ * @return A release plan; `undefined` without a config or a recognized root project.
113
117
  */
114
118
  getPlan(): Promise<ChangesetReleasePlan | undefined>;
115
119
  /**
@@ -200,7 +204,7 @@ export declare class ChangesetRelease {
200
204
  * Load the configuration, discover the packages and plan the releases of
201
205
  * the pending changesets, including the releases of their dependents.
202
206
  *
203
- * @return Release context, undefined without a config.
207
+ * @return Release context, undefined without a config or a recognized root project.
204
208
  * @throws {ValidationError} For an invalid config, plan or changeset.
205
209
  */
206
210
  private loadContext;
@@ -218,6 +222,8 @@ export declare class ChangesetRelease {
218
222
  * @throws {ValidationError} Without a config.
219
223
  */
220
224
  private requireConfig;
225
+ /** Load an explicit/discovered config, otherwise resolve one root project. */
226
+ private loadConfig;
221
227
  /**
222
228
  * Get the directory of the changeset files.
223
229
  *
@@ -230,7 +236,7 @@ export declare class ChangesetRelease {
230
236
  * Discover configured packages, pending changesets, and their proposed versions.
231
237
  *
232
238
  * @param input Repository root and optional explicit config file.
233
- * @return A release plan; `undefined` when no config is present.
239
+ * @return A release plan; `undefined` without a config or a recognized root project.
234
240
  */
235
241
  export declare function getChangesetReleasePlan(input: ChangesetRepository): Promise<ChangesetReleasePlan | undefined>;
236
242
  /**
@@ -1,3 +1,4 @@
1
+ import { resolveSingleProjectConfig } from "./single-project.js";
1
2
  import path from 'node:path';
2
3
  import { getVersionedReleases, prependChangelog } from "./changelog.js";
3
4
  import { loadChangesetConfig } from "./changeset-config.js";
@@ -12,7 +13,7 @@ import { ReleaseRepository } from "./release-repository.js";
12
13
  import { DEFAULT_TAG_FORMAT, formatTag } from "./tag-format.js";
13
14
  import { verifyVersionTargets, writeVersion } from "./version-files.js";
14
15
  import { getPrereleaseVersion, getSnapshotVersion, isPrerelease, } from "./versions.js";
15
- const MISSING_CONFIG = 'No wp-release config found. Add wp-release.config.js or pass --config <path>.';
16
+ const MISSING_CONFIG = 'No wp-release config or root project found. Pass --version-* descriptors, add wp-release.config.js or pass --config <path>.';
16
17
  /**
17
18
  * Changeset releases of a repository: recording changesets, versioning the
18
19
  * packages they name and tagging the releases.
@@ -24,6 +25,7 @@ const MISSING_CONFIG = 'No wp-release config found. Add wp-release.config.js or
24
25
  export class ChangesetRelease {
25
26
  cwd;
26
27
  configFile;
28
+ singleProject;
27
29
  tagFormat;
28
30
  repository;
29
31
  /**
@@ -32,6 +34,7 @@ export class ChangesetRelease {
32
34
  constructor(options) {
33
35
  this.cwd = options.cwd;
34
36
  this.configFile = options.configFile;
37
+ this.singleProject = options.singleProject;
35
38
  this.tagFormat = options.tagFormat;
36
39
  this.repository = new ReleaseRepository({
37
40
  cwd: options.cwd,
@@ -42,7 +45,7 @@ export class ChangesetRelease {
42
45
  * Discover configured packages, pending changesets, and their proposed
43
46
  * versions.
44
47
  *
45
- * @return A release plan; `undefined` when no config is present.
48
+ * @return A release plan; `undefined` without a config or a recognized root project.
46
49
  */
47
50
  async getPlan() {
48
51
  const context = await this.loadContext();
@@ -361,19 +364,14 @@ export class ChangesetRelease {
361
364
  * Load the configuration, discover the packages and plan the releases of
362
365
  * the pending changesets, including the releases of their dependents.
363
366
  *
364
- * @return Release context, undefined without a config.
367
+ * @return Release context, undefined without a config or a recognized root project.
365
368
  * @throws {ValidationError} For an invalid config, plan or changeset.
366
369
  */
367
370
  async loadContext() {
368
- const loaded = await loadChangesetConfig({
369
- cwd: this.cwd,
370
- ...(this.configFile ? { configFile: this.configFile } : {}),
371
- ...(this.tagFormat ? { tagFormat: this.tagFormat } : {}),
372
- });
373
- if (!loaded) {
371
+ const config = await this.loadConfig();
372
+ if (!config) {
374
373
  return undefined;
375
374
  }
376
- const config = loaded.config;
377
375
  const packages = await discoverPackages(this.repository, config);
378
376
  const changesets = await readChangesets(this.getChangesetDirectory(config));
379
377
  const releases = [];
@@ -431,15 +429,26 @@ export class ChangesetRelease {
431
429
  * @throws {ValidationError} Without a config.
432
430
  */
433
431
  async requireConfig() {
432
+ const config = await this.loadConfig();
433
+ if (!config) {
434
+ throw new ValidationError(MISSING_CONFIG);
435
+ }
436
+ return config;
437
+ }
438
+ /** Load an explicit/discovered config, otherwise resolve one root project. */
439
+ async loadConfig() {
434
440
  const loaded = await loadChangesetConfig({
435
441
  cwd: this.cwd,
436
442
  ...(this.configFile ? { configFile: this.configFile } : {}),
437
443
  ...(this.tagFormat ? { tagFormat: this.tagFormat } : {}),
438
444
  });
439
- if (!loaded) {
440
- throw new ValidationError(MISSING_CONFIG);
445
+ if (loaded) {
446
+ if (this.singleProject) {
447
+ throw new ValidationError('Single-project options cannot be combined with a wp-release config. Set these options in the config instead.');
448
+ }
449
+ return loaded.config;
441
450
  }
442
- return loaded.config;
451
+ return resolveSingleProjectConfig(this.cwd, this.singleProject, this.tagFormat);
443
452
  }
444
453
  /**
445
454
  * Get the directory of the changeset files.
@@ -455,7 +464,7 @@ export class ChangesetRelease {
455
464
  * Discover configured packages, pending changesets, and their proposed versions.
456
465
  *
457
466
  * @param input Repository root and optional explicit config file.
458
- * @return A release plan; `undefined` when no config is present.
467
+ * @return A release plan; `undefined` without a config or a recognized root project.
459
468
  */
460
469
  export async function getChangesetReleasePlan(input) {
461
470
  return new ChangesetRelease(input).getPlan();
package/dist/cli.d.ts CHANGED
@@ -59,6 +59,12 @@ export declare function formatGitHubOutputs(result: unknown): string;
59
59
  * Results of the commands that can be run with execute(), by command name.
60
60
  */
61
61
  export interface CommandResults {
62
+ 'i18n-mo': import('./i18n/compile.ts').CompileTranslationsResult;
63
+ 'i18n-json': import('./i18n/compile.ts').CompileTranslationsResult;
64
+ 'i18n-php': import('./i18n/compile.ts').CompileTranslationsResult;
65
+ 'i18n-pot': import('./commands/i18n.ts').I18nCommandResult;
66
+ 'i18n-audit': import('./commands/i18n.ts').I18nCommandResult;
67
+ build: import('./commands/build.ts').BuildResult;
62
68
  'deploy-svn': import('./commands/deploy-svn.ts').DeploySvnResult;
63
69
  zip: ZipResult;
64
70
  checksums: ChecksumsResult;
package/dist/cli.js CHANGED
@@ -1,7 +1,13 @@
1
1
  import { randomUUID } from 'node:crypto';
2
2
  import { appendFileSync } from 'node:fs';
3
3
  import { parseArgs } from 'node:util';
4
+ import i18nMo from "./commands/i18n-mo.js";
5
+ import i18nJson from "./commands/i18n-json.js";
6
+ import i18nPhp from "./commands/i18n-php.js";
7
+ import i18nPot from "./commands/i18n-pot.js";
8
+ import i18nAudit from "./commands/i18n-audit.js";
4
9
  import zip from "./commands/zip.js";
10
+ import build from "./commands/build.js";
5
11
  import checksums from "./commands/checksums.js";
6
12
  import sign from "./commands/sign.js";
7
13
  import keygen from "./commands/keygen.js";
@@ -22,6 +28,12 @@ export const EXIT_SUCCESS = 0;
22
28
  export const EXIT_FAILURE = 1;
23
29
  export const EXIT_INVALID = 2;
24
30
  export const commands = [
31
+ i18nMo,
32
+ i18nJson,
33
+ i18nPhp,
34
+ i18nPot,
35
+ i18nAudit,
36
+ build,
25
37
  zip,
26
38
  checksums,
27
39
  sign,
@@ -0,0 +1,20 @@
1
+ import type { ParseArgsOptionsConfig } from 'node:util';
2
+ import type { SignFilesInput, SignatureFormat } from '../signing.ts';
3
+ import type { ParsedValues } from './command.ts';
4
+ export declare const checksumSigningArgs: ParseArgsOptionsConfig;
5
+ interface SigningPaths {
6
+ artifact?: string;
7
+ checksums: string;
8
+ }
9
+ /**
10
+ * Resolve explicit signing targets and validate them before creating artifacts.
11
+ *
12
+ * @param values Parsed CLI flags.
13
+ * @param paths Artifact and manifest paths that can be signed.
14
+ * @return Signing input, or undefined when no signing is requested.
15
+ * @throws {ValidationError} For formats without a signing target or invalid signing input.
16
+ */
17
+ export declare function getArtifactSigning(values: ParsedValues, paths: SigningPaths): (SignFilesInput & {
18
+ formats: SignatureFormat[];
19
+ }) | undefined;
20
+ export {};
@@ -0,0 +1,42 @@
1
+ import { ValidationError } from "../errors.js";
2
+ import { checkSigningInput } from "../signing.js";
3
+ import { parseSignatureFormats } from "./args.js";
4
+ import { getBoolean, getStrings } from "./command.js";
5
+ export const checksumSigningArgs = {
6
+ checksums: { type: 'boolean' },
7
+ 'sign-checksums': { type: 'boolean' },
8
+ 'sign-format': { type: 'string', multiple: true },
9
+ };
10
+ /**
11
+ * Resolve explicit signing targets and validate them before creating artifacts.
12
+ *
13
+ * @param values Parsed CLI flags.
14
+ * @param paths Artifact and manifest paths that can be signed.
15
+ * @return Signing input, or undefined when no signing is requested.
16
+ * @throws {ValidationError} For formats without a signing target or invalid signing input.
17
+ */
18
+ export function getArtifactSigning(values, paths) {
19
+ const names = getStrings(values, 'sign-format');
20
+ const targets = [
21
+ ...(getBoolean(values, 'sign') && paths.artifact
22
+ ? [paths.artifact]
23
+ : []),
24
+ ...(getBoolean(values, 'sign-checksums')
25
+ ? [paths.checksums]
26
+ : []),
27
+ ];
28
+ if (names.length && !targets.length) {
29
+ throw new ValidationError('--sign-format requires --sign or --sign-checksums; it does not enable signing.');
30
+ }
31
+ const signing = targets.length
32
+ ? {
33
+ paths: targets,
34
+ formats: parseSignatureFormats(names),
35
+ force: getBoolean(values, 'force'),
36
+ }
37
+ : undefined;
38
+ if (signing) {
39
+ checkSigningInput(signing);
40
+ }
41
+ return signing;
42
+ }
@@ -0,0 +1,32 @@
1
+ import type { BuildPackageResult } from '../package-build.ts';
2
+ import type { CommandOutcome } from './command.ts';
3
+ export interface BuildResult extends BuildPackageResult {
4
+ package?: string;
5
+ signatures?: string[];
6
+ publicKey?: string;
7
+ }
8
+ declare const _default: {
9
+ name: string;
10
+ usage: string;
11
+ summary: string;
12
+ help: string;
13
+ options: {
14
+ package: {
15
+ type: "string";
16
+ };
17
+ force: {
18
+ type: "boolean";
19
+ };
20
+ output: {
21
+ type: "string";
22
+ };
23
+ slug: {
24
+ type: "string";
25
+ };
26
+ version: {
27
+ type: "string";
28
+ };
29
+ };
30
+ run({ values, positionals, cwd, configFile, logger, }: import("./command.ts").CommandContext): Promise<CommandOutcome<BuildResult>>;
31
+ };
32
+ export default _default;
@@ -0,0 +1,91 @@
1
+ import { checksumSigningArgs, getArtifactSigning } from "./artifact-signing.js";
2
+ import { signFiles } from "../signing.js";
3
+ import { resolve } from 'node:path';
4
+ import { getBuildSummary, getSignSummary } from "../summary.js";
5
+ import { ValidationError } from "../errors.js";
6
+ import { buildPackage, getBuildChecksumsPath } from "../package-build.js";
7
+ import { fileSelectionArgs, sourceDirArgs } from "./args.js";
8
+ import { getBoolean, getString } from "./command.js";
9
+ import { getDirectorySource, getPackageArg, getPackageSource, } from "./package-source.js";
10
+ export default {
11
+ name: 'build',
12
+ usage: 'build [<source-dir>] --output <dir> [options] | build --package <name> --output <dir>',
13
+ summary: 'Copy the selected release files into an output directory.',
14
+ help: `Options:
15
+ --output <dir> Required destination; files go directly inside it
16
+ --source-dir <dir> Source directory (default: .), or a positional argument
17
+ --package <name> Use the configured package directory and file rules
18
+ --distignore <file> Ignore file (default: <source-dir>/.distignore)
19
+ --no-distignore Don't read an ignore file
20
+ --exclude <patterns> Extra patterns, comma-separated or repeated
21
+ --exclude-gitattributes Exclude Git export-ignore paths
22
+ --slug <slug> Slug in the manifest (default: project directory name)
23
+ --version <version> Manifest version (default: Version header)
24
+ --checksums Write <output-dir>.checksums.json beside the directory
25
+ --sign-checksums Generate and sign the manifest; implies --checksums
26
+ --sign-format <names> Formats: wordpress,minisign,ssh; requires --sign-checksums
27
+ --force Replace an existing output directory, removing stale files
28
+
29
+ The output directory is excluded from the source selection. It cannot be the
30
+ source directory or an ancestor. --sign is unsupported for directories.
31
+
32
+ Examples:
33
+ wp-release build --output dist/my-plugin
34
+ wp-release build --package plugins/alpha --output dist/alpha`,
35
+ options: {
36
+ output: { type: 'string' },
37
+ slug: { type: 'string' },
38
+ version: { type: 'string' },
39
+ ...checksumSigningArgs,
40
+ ...sourceDirArgs,
41
+ ...fileSelectionArgs,
42
+ package: { type: 'string' },
43
+ force: { type: 'boolean' },
44
+ },
45
+ async run({ values, positionals, cwd, configFile, logger, }) {
46
+ const output = getString(values, 'output');
47
+ if (!output?.trim()) {
48
+ throw new ValidationError('build requires --output <dir>.');
49
+ }
50
+ const name = getPackageArg(values, positionals);
51
+ const source = name
52
+ ? await getPackageSource(values, cwd, name, configFile)
53
+ : await getDirectorySource(values, positionals, cwd);
54
+ const outputDir = resolve(cwd, output);
55
+ const signing = getArtifactSigning(values, {
56
+ checksums: getBuildChecksumsPath(outputDir),
57
+ });
58
+ const built = await buildPackage({
59
+ sourceDir: source.sourceDir,
60
+ selection: source.selection,
61
+ outputDir,
62
+ checksums: getBoolean(values, 'checksums') ||
63
+ getBoolean(values, 'sign-checksums'),
64
+ slug: source.slug,
65
+ version: source.version,
66
+ ...(source.type ? { type: source.type } : {}),
67
+ force: getBoolean(values, 'force'),
68
+ });
69
+ const signed = signing
70
+ ? { ...(await signFiles(signing)), formats: signing.formats }
71
+ : undefined;
72
+ const result = {
73
+ ...built,
74
+ ...(signed
75
+ ? { signatures: signed.signatures, publicKey: signed.publicKey }
76
+ : {}),
77
+ ...(source.package ? { package: source.package } : {}),
78
+ };
79
+ logger.debug(`Built ${built.files} files from ${source.sourceDir}.`);
80
+ logger.info(built.outputDir);
81
+ if (built.checksumsPath) {
82
+ logger.info(built.checksumsPath);
83
+ }
84
+ signed?.signatures.forEach((path) => logger.info(path));
85
+ logger.summary((context) => getBuildSummary(context, result));
86
+ if (signed) {
87
+ logger.summary((context) => getSignSummary(context, signed));
88
+ }
89
+ return { exitCode: 0, result };
90
+ },
91
+ };
@@ -8,24 +8,73 @@ declare const _default: {
8
8
  summary: string;
9
9
  help: string;
10
10
  options: {
11
- readonly package: {
11
+ 'version-package-json': {
12
12
  readonly type: "string";
13
13
  readonly multiple: true;
14
14
  };
15
- readonly bump: {
15
+ 'version-composer-json': {
16
16
  readonly type: "string";
17
17
  readonly multiple: true;
18
18
  };
19
- readonly summary: {
19
+ 'version-wordpress-plugin': {
20
+ readonly type: "string";
21
+ readonly multiple: true;
22
+ };
23
+ 'version-wordpress-theme': {
24
+ readonly type: "string";
25
+ readonly multiple: true;
26
+ };
27
+ 'version-wordpress-stable-tag': {
28
+ readonly type: "string";
29
+ readonly multiple: true;
30
+ };
31
+ 'version-php-constant': {
32
+ readonly type: "string";
33
+ readonly multiple: true;
34
+ };
35
+ 'version-git-tag': {
36
+ readonly type: "string";
37
+ readonly multiple: true;
38
+ };
39
+ 'version-from': {
40
+ readonly type: "string";
41
+ };
42
+ 'base-branch': {
43
+ readonly type: "string";
44
+ };
45
+ remote: {
46
+ readonly type: "string";
47
+ };
48
+ 'changesets-dir': {
49
+ readonly type: "string";
50
+ };
51
+ 'readme-changelog': {
52
+ readonly type: "boolean";
53
+ };
54
+ 'no-readme-changelog': {
55
+ readonly type: "boolean";
56
+ };
57
+ 'changelog-insert-after': {
58
+ readonly type: "string";
59
+ };
60
+ package: {
61
+ readonly type: "string";
62
+ readonly multiple: true;
63
+ };
64
+ bump: {
65
+ readonly type: "string";
66
+ readonly multiple: true;
67
+ };
68
+ summary: {
20
69
  readonly type: "string";
21
70
  };
22
- readonly empty: {
71
+ empty: {
23
72
  readonly type: "boolean";
24
73
  };
25
- readonly since: {
74
+ since: {
26
75
  readonly type: "string";
27
76
  };
28
- readonly name: {
77
+ name: {
29
78
  readonly type: "string";
30
79
  };
31
80
  };
@@ -1,3 +1,4 @@
1
+ import { changesetProjectArgs, changesetProjectHelp, parseChangesetProjectArgs, } from "./changeset-project-args.js";
1
2
  import { resolvePackageNames } from "../changeset-packages.js";
2
3
  import { ChangesetPrompt } from "../changeset-prompt.js";
3
4
  import { ChangesetRelease } from "../changeset-release.js";
@@ -13,6 +14,12 @@ import { parseChangesetAddArgs, changesetAddArgs } from "./changeset-args.js";
13
14
  * @throws {ValidationError} If no changed package needs a changeset.
14
15
  */
15
16
  async function getChangedPackageBumps(release, input, bump) {
17
+ const packages = await release.getPackages();
18
+ if (!input.since &&
19
+ 1 === packages.length &&
20
+ '.' === packages[0]?.path) {
21
+ return { [packages[0].name]: bump };
22
+ }
16
23
  const status = await release.getStatus({
17
24
  ...(input.since ? { since: input.since } : {}),
18
25
  uncommitted: true,
@@ -99,15 +106,17 @@ export default {
99
106
 
100
107
  Use --package and --bump pairs for package releases, or --empty for changes
101
108
  that should pass the status check without producing a release. A single
102
- --bump without --package releases the packages that changed since the base
109
+ --bump without --package selects the sole root package, or releases packages
110
+ that changed since the base
103
111
  ref, including uncommitted files, and have no changeset yet. Without
104
112
  --package and --bump in a terminal, the command asks for the packages, with
105
- the changed ones preselected, their bumps and the release note.`,
106
- options: changesetAddArgs,
113
+ the changed ones preselected, their bumps and the release note.${changesetProjectHelp}`,
114
+ options: { ...changesetAddArgs, ...changesetProjectArgs },
107
115
  async run({ values, cwd, configFile, tagFormat, logger, terminal }) {
108
116
  const input = parseChangesetAddArgs(values);
109
117
  const release = new ChangesetRelease({
110
118
  cwd,
119
+ ...parseChangesetProjectArgs(values),
111
120
  ...(configFile ? { configFile } : {}),
112
121
  ...(tagFormat ? { tagFormat } : {}),
113
122
  });
@@ -193,8 +193,8 @@ export function parseChangesetTagArgs(values) {
193
193
  if ('' === args.version) {
194
194
  throw new ValidationError('--version <version> must not be empty.');
195
195
  }
196
- if (undefined !== args.version && 1 !== args.packages.length) {
197
- throw new ValidationError('--version <version> requires exactly one --package <name>.');
196
+ if (undefined !== args.version && args.packages.length > 1) {
197
+ throw new ValidationError('--version <version> accepts at most one --package <name>.');
198
198
  }
199
199
  if (args.untagged && args.push) {
200
200
  throw new ValidationError('--untagged cannot be combined with --push.');
@@ -0,0 +1,63 @@
1
+ import type { SingleProjectOptions } from '../single-project.ts';
2
+ import type { ParsedValues } from './command.ts';
3
+ export declare const changesetProjectArgs: {
4
+ readonly 'version-package-json': {
5
+ readonly type: "string";
6
+ readonly multiple: true;
7
+ };
8
+ readonly 'version-composer-json': {
9
+ readonly type: "string";
10
+ readonly multiple: true;
11
+ };
12
+ readonly 'version-wordpress-plugin': {
13
+ readonly type: "string";
14
+ readonly multiple: true;
15
+ };
16
+ readonly 'version-wordpress-theme': {
17
+ readonly type: "string";
18
+ readonly multiple: true;
19
+ };
20
+ readonly 'version-wordpress-stable-tag': {
21
+ readonly type: "string";
22
+ readonly multiple: true;
23
+ };
24
+ readonly 'version-php-constant': {
25
+ readonly type: "string";
26
+ readonly multiple: true;
27
+ };
28
+ readonly 'version-git-tag': {
29
+ readonly type: "string";
30
+ readonly multiple: true;
31
+ };
32
+ readonly 'version-from': {
33
+ readonly type: "string";
34
+ };
35
+ readonly 'base-branch': {
36
+ readonly type: "string";
37
+ };
38
+ readonly remote: {
39
+ readonly type: "string";
40
+ };
41
+ readonly 'changesets-dir': {
42
+ readonly type: "string";
43
+ };
44
+ readonly 'readme-changelog': {
45
+ readonly type: "boolean";
46
+ };
47
+ readonly 'no-readme-changelog': {
48
+ readonly type: "boolean";
49
+ };
50
+ readonly 'changelog-insert-after': {
51
+ readonly type: "string";
52
+ };
53
+ };
54
+ export declare const changesetProjectHelp = "\nSingle-project options (without a release config file):\n --version-package-json <file> npm version source/target (repeatable)\n --version-composer-json <file> Composer source/target (repeatable)\n --version-wordpress-plugin <file> Plugin header source/target (repeatable)\n --version-wordpress-theme <file> Theme header source/target (repeatable)\n --version-wordpress-stable-tag <file> Readme Stable tag source/target (repeatable)\n --version-php-constant <file>#<constant> PHP constant source/target (repeatable)\n --version-git-tag <pattern> Git tag source only; use {version}\n --version-from <kind>[:<file>] Choose the source; constants use file#constant\n --base-branch <branch> Default comparison branch on the remote\n --remote <name> Git remote (default: origin)\n --changesets-dir <dir> Changeset directory (default: .changeset)\n --readme-changelog / --no-readme-changelog\n Enable/disable readme changelog updates\n --changelog-insert-after <marker> Insert changelog entries after this marker\n\nExplicit descriptors define all version targets. Without them, detect one root\nproject. A unique non-Stable-tag descriptor is the inferred source; otherwise\npass --version-from, qualifying it with :file when its kind is repeated.\nUse the same project options for every changeset command.";
55
+ /**
56
+ * Parse shared single-project settings; operation flags stay command-specific.
57
+ *
58
+ * @param values Parsed command arguments.
59
+ * @return Fallback settings when explicitly supplied.
60
+ */
61
+ export declare function parseChangesetProjectArgs(values: ParsedValues): {
62
+ singleProject?: SingleProjectOptions;
63
+ };