@pnpm/releasing.commands 1100.5.4 → 1100.6.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.
@@ -4,10 +4,13 @@ import { types as allTypes } from '@pnpm/config.reader';
4
4
  import { PnpmError } from '@pnpm/error';
5
5
  import { runLifecycleHook } from '@pnpm/exec.lifecycle';
6
6
  import { isGitRepo, isWorkingTreeClean } from '@pnpm/network.git-utils';
7
+ import { applyReleasePlan, assembleReleasePlan, changelogStorage, readChangeIntents, readLedger, toProjectDir, } from '@pnpm/releasing.versioning';
7
8
  import { safeExeca as execa } from 'execa';
8
9
  import { pick } from 'ramda';
9
10
  import { renderHelp } from 'render-help';
10
11
  import { inc, valid } from 'semver';
12
+ import { renderReleasePlan, toWorkspaceProjects } from '../change/index.js';
13
+ import { changelogHasSection, fetchPublishedChangelog } from '../publish/previousChangelog.js';
11
14
  export function rcOptionsTypes() {
12
15
  return pick([
13
16
  'allow-same-version',
@@ -22,6 +25,7 @@ export function rcOptionsTypes() {
22
25
  export function cliOptionsTypes() {
23
26
  return {
24
27
  ...rcOptionsTypes(),
28
+ 'dry-run': Boolean,
25
29
  json: Boolean,
26
30
  preid: String,
27
31
  recursive: Boolean,
@@ -38,6 +42,7 @@ export function help() {
38
42
  usages: [
39
43
  'pnpm version <newversion>',
40
44
  'pnpm version <major|minor|patch|premajor|preminor|prepatch|prerelease>',
45
+ 'pnpm version -r [--dry-run]',
41
46
  ],
42
47
  descriptionLists: [
43
48
  {
@@ -84,9 +89,13 @@ export function help() {
84
89
  name: '--json',
85
90
  },
86
91
  {
87
- description: 'Apply command to all packages in workspace',
92
+ description: 'Apply command to all packages in workspace. Without a version argument, consumes the pending change intents from .changeset/ and applies the resulting release plan',
88
93
  name: '--recursive',
89
94
  },
95
+ {
96
+ description: 'Print the release plan the pending change intents produce without applying it',
97
+ name: '--dry-run',
98
+ },
90
99
  ],
91
100
  },
92
101
  ],
@@ -95,6 +104,9 @@ export function help() {
95
104
  export async function handler(opts, params) {
96
105
  const rawBump = params[0];
97
106
  if (!rawBump) {
107
+ if (opts.recursive) {
108
+ return releaseFromIntents(opts);
109
+ }
98
110
  throw new PnpmError('INVALID_VERSION_BUMP', 'A version argument is required. Must be a valid semver version (e.g. 1.2.3) or one of: major, minor, patch, premajor, preminor, prepatch, prerelease');
99
111
  }
100
112
  const explicitVersion = valid(rawBump);
@@ -142,6 +154,83 @@ export async function handler(opts, params) {
142
154
  }
143
155
  return output;
144
156
  }
157
+ async function releaseFromIntents(opts) {
158
+ const workspaceDir = opts.workspaceDir;
159
+ if (!workspaceDir) {
160
+ throw new PnpmError('WORKSPACE_ONLY', 'The bare "pnpm version -r" form consumes change intents and is only supported in a workspace');
161
+ }
162
+ if (!opts.dryRun && opts.gitChecks !== false && await isGitRepo({ cwd: workspaceDir })) {
163
+ if (!await isWorkingTreeClean({ cwd: workspaceDir })) {
164
+ throw new PnpmError('UNCLEAN_WORKING_TREE', 'Working tree is not clean. Commit or stash your changes.');
165
+ }
166
+ }
167
+ const intents = await readChangeIntents(workspaceDir);
168
+ const ledger = await readLedger(workspaceDir);
169
+ const projects = toWorkspaceProjects(opts.allProjects ?? []);
170
+ const filter = (opts.filter ?? []).length > 0
171
+ ? new Set(Object.keys(opts.selectedProjectsGraph ?? {}).map((rootDir) => toProjectDir(workspaceDir, rootDir)))
172
+ : undefined;
173
+ const plan = assembleReleasePlan({
174
+ workspaceDir,
175
+ projects,
176
+ intents,
177
+ ledger,
178
+ versioning: opts.versioning,
179
+ filter,
180
+ enforceWorkspaceProtocol: true,
181
+ });
182
+ const applyOpts = {
183
+ workspaceDir,
184
+ projects,
185
+ allIntents: intents,
186
+ versioning: opts.versioning,
187
+ verifyPublished: buildVerifyPublished(opts),
188
+ };
189
+ if (plan.releases.length === 0) {
190
+ // A full (unfiltered) run garbage-collects the intent files an empty plan
191
+ // leaves behind: declined ("none"-only) intents and files a merge
192
+ // resurrected after every named package had already consumed them. A
193
+ // filtered run must not — "nothing pending in this scope" is no reason to
194
+ // delete prose belonging to packages outside the filter.
195
+ if (!opts.dryRun && filter == null) {
196
+ await applyReleasePlan(plan, applyOpts);
197
+ }
198
+ return 'No pending changes. Record one with "pnpm change".';
199
+ }
200
+ if (opts.dryRun) {
201
+ return renderReleasePlan(plan);
202
+ }
203
+ const applied = await applyReleasePlan(plan, applyOpts);
204
+ if (opts.json) {
205
+ return JSON.stringify(applied, null, 2);
206
+ }
207
+ let output = 'Versions applied:\n';
208
+ for (const release of applied) {
209
+ output += `${release.name}: ${release.currentVersion} → ${release.newVersion}\n`;
210
+ }
211
+ return output;
212
+ }
213
+ /**
214
+ * In `registry` storage, the gate that lets consumed intents be collected:
215
+ * the release must be published and its tarball's CHANGELOG.md must already
216
+ * carry the composed section. Any error resolving that (offline, transient
217
+ * failure) counts as "not confirmed" so the intent — still the only prose —
218
+ * is kept. `undefined` in `repository` storage, where the committed changelog
219
+ * makes the ledger alone sufficient.
220
+ */
221
+ function buildVerifyPublished(opts) {
222
+ if (changelogStorage(opts.versioning) !== 'registry')
223
+ return undefined;
224
+ return async (name, version, section) => {
225
+ try {
226
+ const changelog = await fetchPublishedChangelog(opts, name, version);
227
+ return changelog != null && changelogHasSection(changelog, section);
228
+ }
229
+ catch {
230
+ return false;
231
+ }
232
+ };
233
+ }
145
234
  async function bumpPackageVersion(pkgDir, rawBump, explicitVersion, opts) {
146
235
  const { manifest, writeProjectManifest, fileName } = await readProjectManifest(pkgDir);
147
236
  if (!manifest.name || !manifest.version) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pnpm/releasing.commands",
3
- "version": "1100.5.4",
3
+ "version": "1100.6.0",
4
4
  "description": "Commands for deploy, pack, and publish",
5
5
  "keywords": [
6
6
  "pnpm",
@@ -28,7 +28,42 @@
28
28
  ],
29
29
  "dependencies": {
30
30
  "@inquirer/prompts": "^8.4.3",
31
+ "@pnpm/bins.resolver": "1100.0.9",
32
+ "@pnpm/catalogs.types": "1100.0.0",
33
+ "@pnpm/cli.common-cli-options-help": "1100.0.2",
34
+ "@pnpm/cli.utils": "1101.0.14",
35
+ "@pnpm/config.pick-registry-for-package": "1100.0.10",
36
+ "@pnpm/config.reader": "1101.12.0",
37
+ "@pnpm/constants": "1100.0.0",
38
+ "@pnpm/deps.path": "1100.0.9",
39
+ "@pnpm/engine.runtime.commands": "1100.1.11",
40
+ "@pnpm/engine.runtime.node-resolver": "1101.1.13",
41
+ "@pnpm/error": "1100.0.1",
42
+ "@pnpm/exec.lifecycle": "1100.1.3",
43
+ "@pnpm/exec.pnpm-cli-runner": "1100.0.1",
44
+ "@pnpm/fetching.directory-fetcher": "1100.0.20",
45
+ "@pnpm/fetching.types": "1100.0.2",
46
+ "@pnpm/fs.indexed-pkg-importer": "1100.0.18",
47
+ "@pnpm/fs.is-empty-dir-or-nothing": "1100.0.0",
48
+ "@pnpm/fs.packlist": "1100.0.2",
49
+ "@pnpm/installing.client": "1100.2.14",
50
+ "@pnpm/installing.commands": "1100.10.5",
51
+ "@pnpm/lockfile.fs": "1100.1.11",
52
+ "@pnpm/lockfile.types": "1100.0.14",
53
+ "@pnpm/network.auth-header": "1101.1.4",
54
+ "@pnpm/network.fetch": "1100.1.5",
55
+ "@pnpm/network.git-utils": "1100.0.2",
56
+ "@pnpm/network.web-auth": "1101.2.0",
31
57
  "@pnpm/npm-package-arg": "^2.0.0",
58
+ "@pnpm/releasing.exportable-manifest": "1100.1.10",
59
+ "@pnpm/releasing.versioning": "1100.1.0",
60
+ "@pnpm/resolving.npm-resolver": "1102.1.3",
61
+ "@pnpm/resolving.registry.types": "1100.1.4",
62
+ "@pnpm/resolving.resolver-base": "1100.5.2",
63
+ "@pnpm/types": "1101.4.0",
64
+ "@pnpm/workspace.projects-filter": "1100.0.27",
65
+ "@pnpm/workspace.projects-sorter": "1100.0.9",
66
+ "@pnpm/workspace.workspace-manifest-writer": "1100.0.16",
32
67
  "@types/normalize-path": "^3.0.2",
33
68
  "@zkochan/rimraf": "^4.0.0",
34
69
  "chalk": "^5.6.2",
@@ -51,42 +86,23 @@
51
86
  "tinyglobby": "^0.2.16",
52
87
  "validate-npm-package-name": "7.0.2",
53
88
  "write-json-file": "^7.0.0",
54
- "write-yaml-file": "^6.0.0",
55
- "@pnpm/bins.resolver": "1100.0.8",
56
- "@pnpm/cli.common-cli-options-help": "1100.0.2",
57
- "@pnpm/config.pick-registry-for-package": "1100.0.9",
58
- "@pnpm/cli.utils": "1101.0.13",
59
- "@pnpm/config.reader": "1101.11.1",
60
- "@pnpm/constants": "1100.0.0",
61
- "@pnpm/deps.path": "1100.0.8",
62
- "@pnpm/engine.runtime.commands": "1100.1.9",
63
- "@pnpm/engine.runtime.node-resolver": "1101.1.11",
64
- "@pnpm/error": "1100.0.1",
65
- "@pnpm/exec.lifecycle": "1100.1.2",
66
- "@pnpm/exec.pnpm-cli-runner": "1100.0.1",
67
- "@pnpm/fetching.directory-fetcher": "1100.0.19",
68
- "@pnpm/catalogs.types": "1100.0.0",
69
- "@pnpm/fs.indexed-pkg-importer": "1100.0.17",
70
- "@pnpm/fs.packlist": "1100.0.1",
71
- "@pnpm/fs.is-empty-dir-or-nothing": "1100.0.0",
72
- "@pnpm/installing.client": "1100.2.12",
73
- "@pnpm/installing.commands": "1100.10.3",
74
- "@pnpm/lockfile.types": "1100.0.13",
75
- "@pnpm/lockfile.fs": "1100.1.9",
76
- "@pnpm/network.auth-header": "1101.1.3",
77
- "@pnpm/network.fetch": "1100.1.4",
78
- "@pnpm/network.git-utils": "1100.0.2",
79
- "@pnpm/network.web-auth": "1101.2.0",
80
- "@pnpm/resolving.resolver-base": "1100.5.1",
81
- "@pnpm/releasing.exportable-manifest": "1100.1.9",
82
- "@pnpm/types": "1101.3.2",
83
- "@pnpm/workspace.projects-sorter": "1100.0.8"
89
+ "write-yaml-file": "^6.0.0"
84
90
  },
85
91
  "peerDependencies": {
86
92
  "@pnpm/logger": "^1100.0.0"
87
93
  },
88
94
  "devDependencies": {
89
95
  "@jest/globals": "30.4.1",
96
+ "@pnpm/assert-project": "1100.0.19",
97
+ "@pnpm/catalogs.config": "1100.0.2",
98
+ "@pnpm/hooks.pnpmfile": "1100.0.19",
99
+ "@pnpm/logger": "1100.0.0",
100
+ "@pnpm/prepare": "1100.0.19",
101
+ "@pnpm/releasing.commands": "1100.6.0",
102
+ "@pnpm/test-fixtures": "1100.0.0",
103
+ "@pnpm/test-ipc-server": "1100.0.0",
104
+ "@pnpm/testing.command-defaults": "1100.0.9",
105
+ "@pnpm/testing.registry-mock": "1100.0.9",
90
106
  "@types/cross-spawn": "^6.0.6",
91
107
  "@types/is-windows": "^1.0.2",
92
108
  "@types/libnpmpublish": "^11.2.0",
@@ -102,18 +118,7 @@
102
118
  "load-json-file": "^7.0.1",
103
119
  "tar": "^7.5.15",
104
120
  "undici": "^7.27.2",
105
- "write-yaml-file": "^6.0.0",
106
- "@pnpm/assert-project": "1100.0.18",
107
- "@pnpm/catalogs.config": "1100.0.2",
108
- "@pnpm/hooks.pnpmfile": "1100.0.17",
109
- "@pnpm/logger": "1100.0.0",
110
- "@pnpm/releasing.commands": "1100.5.4",
111
- "@pnpm/prepare": "1100.0.18",
112
- "@pnpm/test-ipc-server": "1100.0.0",
113
- "@pnpm/test-fixtures": "1100.0.0",
114
- "@pnpm/testing.registry-mock": "1100.0.8",
115
- "@pnpm/testing.command-defaults": "1100.0.8",
116
- "@pnpm/workspace.projects-filter": "1100.0.25"
121
+ "write-yaml-file": "^6.0.0"
117
122
  },
118
123
  "engines": {
119
124
  "node": ">=22.13"