@pnpm/releasing.commands 1100.7.0 → 1100.8.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 (97) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/lib/change/index.d.ts +42 -0
  3. package/lib/change/index.js +250 -0
  4. package/lib/deploy/createDeployFiles.d.ts +26 -0
  5. package/lib/deploy/createDeployFiles.js +255 -0
  6. package/lib/deploy/deploy.d.ts +12 -0
  7. package/lib/deploy/deploy.js +398 -0
  8. package/lib/deploy/deployHook.d.ts +2 -0
  9. package/lib/deploy/deployHook.js +15 -0
  10. package/lib/deploy/index.d.ts +2 -0
  11. package/lib/deploy/index.js +3 -0
  12. package/lib/index.d.ts +7 -0
  13. package/lib/lane/index.d.ts +24 -0
  14. package/lib/lane/index.js +157 -0
  15. package/lib/pack-app/index.d.ts +2 -0
  16. package/lib/pack-app/index.js +3 -0
  17. package/lib/pack-app/packApp.d.ts +22 -0
  18. package/lib/pack-app/packApp.js +558 -0
  19. package/lib/publish/FailedToPublishError.d.ts +22 -0
  20. package/lib/publish/FailedToPublishError.js +40 -0
  21. package/lib/publish/batchPublish.d.ts +20 -0
  22. package/lib/publish/batchPublish.js +201 -0
  23. package/lib/publish/displayError.d.ts +1 -0
  24. package/lib/publish/displayError.js +23 -0
  25. package/lib/publish/executeTokenHelper.d.ts +4 -0
  26. package/lib/publish/executeTokenHelper.js +17 -0
  27. package/lib/publish/extractManifestFromPacked.d.ts +19 -0
  28. package/lib/publish/extractManifestFromPacked.js +110 -0
  29. package/lib/publish/index.d.ts +3 -0
  30. package/lib/publish/index.js +4 -0
  31. package/lib/publish/oidc/authToken.d.ts +73 -0
  32. package/lib/publish/oidc/authToken.js +97 -0
  33. package/lib/publish/oidc/idToken.d.ts +76 -0
  34. package/lib/publish/oidc/idToken.js +90 -0
  35. package/lib/publish/oidc/provenance.d.ts +73 -0
  36. package/lib/publish/oidc/provenance.js +91 -0
  37. package/lib/publish/otp.d.ts +38 -0
  38. package/lib/publish/otp.js +41 -0
  39. package/lib/publish/otpEnv.d.ts +7 -0
  40. package/lib/publish/otpEnv.js +5 -0
  41. package/lib/publish/pack.d.ts +34 -0
  42. package/lib/publish/pack.js +425 -0
  43. package/lib/publish/previousChangelog.d.ts +25 -0
  44. package/lib/publish/previousChangelog.js +194 -0
  45. package/lib/publish/publish.d.ts +40 -0
  46. package/lib/publish/publish.js +256 -0
  47. package/lib/publish/publishPackedPkg.d.ts +79 -0
  48. package/lib/publish/publishPackedPkg.js +298 -0
  49. package/lib/publish/recursivePublish.d.ts +18 -0
  50. package/lib/publish/recursivePublish.js +135 -0
  51. package/lib/publish/registryConfigKeys.d.ts +30 -0
  52. package/lib/publish/registryConfigKeys.js +50 -0
  53. package/lib/publish/utils/shared-context.d.ts +7 -0
  54. package/lib/publish/utils/shared-context.js +20 -0
  55. package/lib/publishedNames.d.ts +18 -0
  56. package/lib/publishedNames.js +29 -0
  57. package/lib/resolveUnpublishedDirs.d.ts +18 -0
  58. package/lib/resolveUnpublishedDirs.js +20 -0
  59. package/lib/stage/approve.d.ts +2 -0
  60. package/lib/stage/approve.js +14 -0
  61. package/lib/stage/context.d.ts +14 -0
  62. package/lib/stage/context.js +25 -0
  63. package/lib/stage/download.d.ts +2 -0
  64. package/lib/stage/download.js +32 -0
  65. package/lib/stage/errors.d.ts +15 -0
  66. package/lib/stage/errors.js +17 -0
  67. package/lib/stage/help.d.ts +1 -0
  68. package/lib/stage/help.js +84 -0
  69. package/lib/stage/index.d.ts +13 -0
  70. package/lib/stage/index.js +57 -0
  71. package/lib/stage/list.d.ts +2 -0
  72. package/lib/stage/list.js +49 -0
  73. package/lib/stage/parsing.d.ts +6 -0
  74. package/lib/stage/parsing.js +27 -0
  75. package/lib/stage/publish.d.ts +7 -0
  76. package/lib/stage/publish.js +38 -0
  77. package/lib/stage/reject.d.ts +2 -0
  78. package/lib/stage/reject.js +16 -0
  79. package/lib/stage/rendering.d.ts +11 -0
  80. package/lib/stage/rendering.js +50 -0
  81. package/lib/stage/request.d.ts +29 -0
  82. package/lib/stage/request.js +110 -0
  83. package/lib/stage/types.d.ts +38 -0
  84. package/lib/stage/types.js +3 -0
  85. package/lib/stage/view.d.ts +2 -0
  86. package/lib/stage/view.js +14 -0
  87. package/lib/tarball/index.d.ts +2 -0
  88. package/lib/tarball/index.js +3 -0
  89. package/lib/tarball/publishSummary.d.ts +47 -0
  90. package/lib/tarball/publishSummary.js +36 -0
  91. package/lib/tarball/safeTarballFilename.d.ts +8 -0
  92. package/lib/tarball/safeTarballFilename.js +21 -0
  93. package/lib/tarball/summarizeTarball.d.ts +12 -0
  94. package/lib/tarball/summarizeTarball.js +84 -0
  95. package/lib/version/index.d.ts +35 -0
  96. package/lib/version/index.js +364 -0
  97. package/package.json +49 -49
@@ -0,0 +1,398 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { FILTERING } from '@pnpm/cli.common-cli-options-help';
4
+ import { docsUrl } from '@pnpm/cli.utils';
5
+ import { types as configTypes } from '@pnpm/config.reader';
6
+ import { WORKSPACE_MANIFEST_FILENAME } from '@pnpm/constants';
7
+ import { PnpmError } from '@pnpm/error';
8
+ import { fetchFromDir } from '@pnpm/fetching.directory-fetcher';
9
+ import { createIndexedPkgImporter } from '@pnpm/fs.indexed-pkg-importer';
10
+ import { isEmptyDirOrNothing } from '@pnpm/fs.is-empty-dir-or-nothing';
11
+ import { install } from '@pnpm/installing.commands';
12
+ import { getLockfileImporterId, readWantedLockfile, writeWantedLockfile } from '@pnpm/lockfile.fs';
13
+ import { globalWarn, logger } from '@pnpm/logger';
14
+ import { rimraf } from '@zkochan/rimraf';
15
+ import { isSubdir } from 'is-subdir';
16
+ import { pick } from 'ramda';
17
+ import { renderHelp } from 'render-help';
18
+ import { writeYamlFile } from 'write-yaml-file';
19
+ import { createDeployFiles } from './createDeployFiles.js';
20
+ import { deployHook } from './deployHook.js';
21
+ const FORCE_LEGACY_DEPLOY = 'force-legacy-deploy';
22
+ export const shorthands = {
23
+ ...install.shorthands,
24
+ legacy: [`--config.${FORCE_LEGACY_DEPLOY}=true`],
25
+ };
26
+ const DEPLOY_OWN_OPTIONS = pick([FORCE_LEGACY_DEPLOY], configTypes);
27
+ export function rcOptionsTypes() {
28
+ return {
29
+ ...install.rcOptionsTypes(),
30
+ ...DEPLOY_OWN_OPTIONS,
31
+ };
32
+ }
33
+ export function cliOptionsTypes() {
34
+ return {
35
+ ...install.cliOptionsTypes(),
36
+ ...DEPLOY_OWN_OPTIONS,
37
+ };
38
+ }
39
+ export const commandNames = ['deploy'];
40
+ export const overridableByScript = true;
41
+ export function help() {
42
+ return renderHelp({
43
+ description: 'Experimental! Deploy a package from a workspace',
44
+ url: docsUrl('deploy'),
45
+ usages: ['pnpm --filter=<deployed project name> deploy <target directory>'],
46
+ descriptionLists: [
47
+ {
48
+ title: 'Options',
49
+ list: [
50
+ {
51
+ description: "Packages in `devDependencies` won't be installed",
52
+ name: '--prod',
53
+ shortAlias: '-P',
54
+ },
55
+ {
56
+ description: 'Only `devDependencies` are installed',
57
+ name: '--dev',
58
+ shortAlias: '-D',
59
+ },
60
+ {
61
+ description: '`optionalDependencies` are not installed',
62
+ name: '--no-optional',
63
+ },
64
+ {
65
+ description: 'Force legacy deploy implementation',
66
+ name: '--legacy',
67
+ },
68
+ ],
69
+ },
70
+ FILTERING,
71
+ ],
72
+ });
73
+ }
74
+ export async function handler(opts, params) {
75
+ if (!opts.workspaceDir) {
76
+ let hint;
77
+ if (opts.rootProjectManifest?.scripts?.['deploy'] != null) {
78
+ hint = 'Maybe you wanted to invoke "pnpm run deploy"';
79
+ }
80
+ throw new PnpmError('CANNOT_DEPLOY', 'A deploy is only possible from inside a workspace', { hint });
81
+ }
82
+ const selectedProjects = Object.values(opts.selectedProjectsGraph ?? {});
83
+ if (selectedProjects.length === 0) {
84
+ throw new PnpmError('NOTHING_TO_DEPLOY', 'No project was selected for deployment');
85
+ }
86
+ if (selectedProjects.length > 1) {
87
+ throw new PnpmError('CANNOT_DEPLOY_MANY', 'Cannot deploy more than 1 project');
88
+ }
89
+ if (params.length !== 1) {
90
+ throw new PnpmError('INVALID_DEPLOY_TARGET', 'This command requires one parameter');
91
+ }
92
+ const selectedProject = selectedProjects[0].package;
93
+ const deployDirParam = params[0];
94
+ const deployDir = path.isAbsolute(deployDirParam) ? deployDirParam : path.join(opts.dir, deployDirParam);
95
+ validateDeployTarget(deployDir, {
96
+ dir: opts.dir,
97
+ force: opts.force,
98
+ projectDir: selectedProject.rootDir,
99
+ workspaceDir: opts.workspaceDir,
100
+ });
101
+ const normalizedDeployDir = path.resolve(deployDir);
102
+ const normalizedWorkspaceDir = path.resolve(opts.workspaceDir);
103
+ const workspaceChildTarget = isChildPath(normalizedDeployDir, normalizedWorkspaceDir);
104
+ if (workspaceChildTarget) {
105
+ createWorkspaceChildTargetParents(normalizedWorkspaceDir, normalizedDeployDir);
106
+ }
107
+ if (!isEmptyDirOrNothing(deployDir)) {
108
+ if (!opts.force) {
109
+ throw new PnpmError('DEPLOY_DIR_NOT_EMPTY', `Deploy path ${deployDir} is not empty`);
110
+ }
111
+ logger.warn({ message: 'using --force, deleting deploy path', prefix: deployDir });
112
+ }
113
+ if (workspaceChildTarget) {
114
+ validateWorkspaceChildTargetComponents(normalizedWorkspaceDir, normalizedDeployDir);
115
+ }
116
+ await rimraf(deployDir);
117
+ if (workspaceChildTarget) {
118
+ createWorkspaceChildTargetParents(normalizedWorkspaceDir, normalizedDeployDir);
119
+ createWorkspaceChildTargetDir(normalizedWorkspaceDir, normalizedDeployDir);
120
+ }
121
+ else {
122
+ await fs.promises.mkdir(deployDir, { recursive: true });
123
+ }
124
+ const includeOnlyPackageFiles = !opts.deployAllFiles;
125
+ await copyProject(selectedProject.rootDir, deployDir, { includeOnlyPackageFiles });
126
+ if (opts.sharedWorkspaceLockfile) {
127
+ const warning = opts.forceLegacyDeploy
128
+ ? 'Shared workspace lockfile detected but configuration forces legacy deploy implementation.'
129
+ : await deployFromSharedLockfile(opts, selectedProject, deployDir);
130
+ if (warning) {
131
+ globalWarn(warning);
132
+ }
133
+ else {
134
+ return;
135
+ }
136
+ }
137
+ const deployedProject = opts.allProjects?.find(({ rootDir }) => rootDir === selectedProject.rootDir);
138
+ if (deployedProject) {
139
+ deployedProject.modulesDir = path.relative(selectedProject.rootDir, path.join(deployDir, 'node_modules'));
140
+ }
141
+ await install.handler({
142
+ ...opts,
143
+ confirmModulesPurge: false,
144
+ // Deploy doesn't work with dedupePeerDependents=true currently as for deploy
145
+ // we need to select a single project for install, while dedupePeerDependents
146
+ // doesn't work with filters right now.
147
+ // Related issue: https://github.com/pnpm/pnpm/issues/6858
148
+ dedupePeerDependents: false,
149
+ // If enabled, dedupe-injected-deps will symlink workspace packages in the
150
+ // deployed dir to their original (non-deployed) directory in an attempt to
151
+ // dedupe workspace packages that don't need to be injected. The deployed
152
+ // dir shouldn't have symlinks to the original workspace. Disable
153
+ // dedupe-injected-deps to always inject workspace packages since copying is
154
+ // desirable.
155
+ dedupeInjectedDeps: false,
156
+ // Compute the wanted lockfile correctly by setting pruneLockfileImporters.
157
+ // Since pnpm deploy only installs dependencies for a single selected
158
+ // project, other projects in the "importers" lockfile section will be
159
+ // empty when node-linker=hoisted.
160
+ //
161
+ // For example, when deploying project-1, project-2 may not be populated,
162
+ // even if it has dependencies.
163
+ //
164
+ // importers:
165
+ // project-1:
166
+ // dependencies:
167
+ // foo:
168
+ // specifier: ^1.0.0
169
+ // version: ^1.0.0
170
+ // project-2: {}
171
+ //
172
+ // Avoid including these empty importers in the in-memory wanted lockfile.
173
+ // This is important when node-linker=hoisted to prevent project-2 from
174
+ // being included in the hoisted install. If project-2 is errantly hoisted
175
+ // to the root node_modules dir, downstream logic will fail to inject it to
176
+ // the deploy directory. It's also just weird to include empty importers
177
+ // that don't matter to the filtered lockfile generated for pnpm deploy.
178
+ pruneLockfileImporters: true,
179
+ // The node_modules for a pnpm deploy should be self-contained. The global
180
+ // virtual store would create symlinks outside of the deploy directory.
181
+ enableGlobalVirtualStore: false,
182
+ depth: Infinity,
183
+ hooks: {
184
+ ...opts.hooks,
185
+ readPackage: [
186
+ ...(opts.hooks?.readPackage ?? []),
187
+ deployHook,
188
+ ],
189
+ },
190
+ frozenLockfile: false,
191
+ preferFrozenLockfile: false,
192
+ // Deploy doesn't work currently with hoisted node_modules.
193
+ // TODO: make it work as we need to prefer packages from the lockfile during deployment.
194
+ useLockfile: opts.nodeLinker !== 'hoisted',
195
+ saveLockfile: false,
196
+ virtualStoreDir: path.join(deployDir, 'node_modules/.pnpm'),
197
+ modulesDir: path.relative(opts.workspaceDir, path.join(deployDir, 'node_modules')),
198
+ includeOnlyPackageFiles,
199
+ });
200
+ }
201
+ async function copyProject(src, dest, opts) {
202
+ const { filesMap } = await fetchFromDir(src, opts);
203
+ const importPkg = createIndexedPkgImporter('clone-or-copy');
204
+ importPkg(dest, { filesMap, force: true, resolvedFrom: 'local-dir' });
205
+ }
206
+ function validateDeployTarget(deployDir, opts) {
207
+ const normalizedDeployDir = path.resolve(deployDir);
208
+ const workspaceDir = path.resolve(opts.workspaceDir);
209
+ const projectDir = path.resolve(opts.projectDir);
210
+ const dir = path.resolve(opts.dir);
211
+ if (samePath(normalizedDeployDir, workspaceDir)) {
212
+ throw unsafeDeployTarget(normalizedDeployDir, 'target is the workspace root');
213
+ }
214
+ if (isAncestorPath(normalizedDeployDir, workspaceDir)) {
215
+ throw unsafeDeployTarget(normalizedDeployDir, 'target contains the workspace root');
216
+ }
217
+ if (samePath(normalizedDeployDir, projectDir)) {
218
+ throw unsafeDeployTarget(normalizedDeployDir, 'target is the selected project root');
219
+ }
220
+ if (isAncestorPath(normalizedDeployDir, projectDir)) {
221
+ throw unsafeDeployTarget(normalizedDeployDir, 'target contains the selected project');
222
+ }
223
+ if (samePath(normalizedDeployDir, dir)) {
224
+ throw unsafeDeployTarget(normalizedDeployDir, 'target is the current directory');
225
+ }
226
+ if (isAncestorPath(normalizedDeployDir, dir)) {
227
+ throw unsafeDeployTarget(normalizedDeployDir, 'target contains the current directory');
228
+ }
229
+ if (opts.force && !isChildPath(normalizedDeployDir, workspaceDir)) {
230
+ throw unsafeDeployTarget(normalizedDeployDir, 'target is outside the workspace');
231
+ }
232
+ if (isChildPath(normalizedDeployDir, workspaceDir)) {
233
+ validateWorkspaceChildTargetComponents(workspaceDir, normalizedDeployDir);
234
+ }
235
+ }
236
+ function validateWorkspaceChildTargetComponents(workspaceDir, deployDir) {
237
+ const relative = path.relative(workspaceDir, deployDir);
238
+ let current = workspaceDir;
239
+ for (const component of relative.split(path.sep)) {
240
+ if (!component)
241
+ continue;
242
+ current = path.join(current, component);
243
+ let stat;
244
+ try {
245
+ stat = fs.lstatSync(current);
246
+ }
247
+ catch (error) {
248
+ if (isENOENT(error))
249
+ return;
250
+ throw error;
251
+ }
252
+ if (stat.isSymbolicLink()) {
253
+ throw unsafeDeployTarget(current, 'target path contains a symlink');
254
+ }
255
+ }
256
+ }
257
+ function createWorkspaceChildTargetParents(workspaceDir, deployDir) {
258
+ const parent = path.dirname(deployDir);
259
+ const relative = path.relative(workspaceDir, parent);
260
+ let current = workspaceDir;
261
+ for (const component of relative.split(path.sep)) {
262
+ if (!component)
263
+ continue;
264
+ current = path.join(current, component);
265
+ createWorkspaceChildTargetComponent(current);
266
+ }
267
+ }
268
+ function createWorkspaceChildTargetDir(workspaceDir, deployDir) {
269
+ try {
270
+ fs.mkdirSync(deployDir);
271
+ }
272
+ catch (error) {
273
+ if (isEEXIST(error)) {
274
+ throw unsafeDeployTarget(deployDir, 'target changed during deploy preparation');
275
+ }
276
+ throw error;
277
+ }
278
+ validateWorkspaceChildTargetComponents(workspaceDir, deployDir);
279
+ }
280
+ function createWorkspaceChildTargetComponent(component) {
281
+ try {
282
+ fs.mkdirSync(component);
283
+ }
284
+ catch (error) {
285
+ if (!isEEXIST(error))
286
+ throw error;
287
+ }
288
+ const stat = fs.lstatSync(component);
289
+ if (stat.isSymbolicLink()) {
290
+ throw unsafeDeployTarget(component, 'target path contains a symlink');
291
+ }
292
+ if (!stat.isDirectory()) {
293
+ throw unsafeDeployTarget(component, 'target path contains a non-directory');
294
+ }
295
+ }
296
+ function unsafeDeployTarget(deployDir, reason) {
297
+ return new PnpmError('INVALID_DEPLOY_TARGET', `Refusing to deploy to unsafe target ${deployDir}: ${reason}`);
298
+ }
299
+ function samePath(left, right) {
300
+ return path.normalize(left) === path.normalize(right);
301
+ }
302
+ function isAncestorPath(parent, child) {
303
+ return isChildPath(child, parent);
304
+ }
305
+ function isChildPath(child, parent) {
306
+ return !samePath(child, parent) && isSubdir(parent, child);
307
+ }
308
+ function isENOENT(error) {
309
+ return typeof error === 'object' && error != null && 'code' in error && error.code === 'ENOENT';
310
+ }
311
+ function isEEXIST(error) {
312
+ return typeof error === 'object' && error != null && 'code' in error && error.code === 'EEXIST';
313
+ }
314
+ async function deployFromSharedLockfile(opts, selectedProject, deployDir) {
315
+ if (!opts.injectWorkspacePackages) {
316
+ throw new PnpmError('DEPLOY_NONINJECTED_WORKSPACE', 'By default, starting from pnpm v10, we only deploy from workspaces that have "inject-workspace-packages=true" set', {
317
+ hint: 'If you want to deploy without using injected dependencies, run "pnpm deploy" with the "--legacy" flag or set "force-legacy-deploy" to true',
318
+ });
319
+ }
320
+ const { allProjects, lockfileDir, rootProjectManifestDir, workspaceDir, } = opts;
321
+ // The following errors should not be possible. It is a programmer error if they are reached.
322
+ if (!allProjects)
323
+ throw new Error('opts.allProjects is undefined.');
324
+ if (!lockfileDir)
325
+ throw new Error('opts.lockfileDir is undefined.');
326
+ if (!workspaceDir)
327
+ throw new Error('opts.workspaceDir is undefined.');
328
+ const lockfile = await readWantedLockfile(lockfileDir, { ignoreIncompatible: false });
329
+ if (!lockfile) {
330
+ return 'Shared lockfile not found. Falling back to installing without a lockfile.';
331
+ }
332
+ const projectId = getLockfileImporterId(lockfileDir, selectedProject.rootDir);
333
+ const deployFiles = createDeployFiles({
334
+ allProjects,
335
+ deployDir,
336
+ include: {
337
+ dependencies: opts.production !== false,
338
+ devDependencies: opts.dev !== false,
339
+ optionalDependencies: opts.optional !== false,
340
+ },
341
+ lockfile,
342
+ lockfileDir,
343
+ patchedDependencies: opts.patchedDependencies,
344
+ selectedProjectManifest: selectedProject.manifest,
345
+ projectId,
346
+ rootProjectManifestDir,
347
+ allowBuilds: opts.allowBuilds,
348
+ });
349
+ const filesToWrite = [
350
+ fs.promises.writeFile(path.join(deployDir, 'package.json'), JSON.stringify(deployFiles.manifest, undefined, 2) + '\n'),
351
+ writeWantedLockfile(deployDir, deployFiles.lockfile),
352
+ ];
353
+ if (deployFiles.workspaceManifest) {
354
+ filesToWrite.push(writeYamlFile(path.join(deployDir, WORKSPACE_MANIFEST_FILENAME), deployFiles.workspaceManifest));
355
+ }
356
+ await Promise.all(filesToWrite);
357
+ try {
358
+ await install.handler({
359
+ ...opts,
360
+ allProjects: undefined,
361
+ allProjectsGraph: undefined,
362
+ selectedProjectsGraph: undefined,
363
+ rootProjectManifest: deployFiles.manifest,
364
+ // The node_modules for a pnpm deploy should be self-contained. The global
365
+ // virtual store would create symlinks outside of the deploy directory.
366
+ enableGlobalVirtualStore: false,
367
+ rootProjectManifestDir: deployDir,
368
+ dir: deployDir,
369
+ lockfileDir: deployDir,
370
+ workspaceDir: undefined,
371
+ virtualStoreDir: undefined,
372
+ modulesDir: undefined,
373
+ confirmModulesPurge: false,
374
+ frozenLockfile: true,
375
+ injectWorkspacePackages: undefined, // the effects of injecting workspace packages should already be part of the package snapshots
376
+ overrides: undefined, // the effects of the overrides should already be part of the package snapshots
377
+ packageExtensions: undefined, // the effects of the package extensions should already be part of the package snapshots
378
+ configDependencies: undefined, // configDependencies (e.g. pacquet) are not installed into the deploy dir, so the install engine they designate isn't on disk to invoke
379
+ hooks: {
380
+ ...opts.hooks,
381
+ readPackage: [
382
+ ...(opts.hooks?.readPackage ?? []),
383
+ deployHook,
384
+ ],
385
+ calculatePnpmfileChecksum: undefined, // the effects of the pnpmfile should already be part of the package snapshots
386
+ },
387
+ });
388
+ }
389
+ catch (error) {
390
+ globalWarn(`Deployment with a shared lockfile has failed. If this is a bug, please report it at <https://github.com/pnpm/pnpm/issues>.
391
+ As a workaround, add the following to pnpm-workspace.yaml:
392
+
393
+ forceLegacyDeploy: true`);
394
+ throw error;
395
+ }
396
+ return undefined;
397
+ }
398
+ //# sourceMappingURL=deploy.js.map
@@ -0,0 +1,2 @@
1
+ import { type BaseManifest } from '@pnpm/types';
2
+ export declare function deployHook<Pkg extends BaseManifest>(pkg: Pkg): Pkg;
@@ -0,0 +1,15 @@
1
+ import { DEPENDENCIES_FIELDS } from '@pnpm/types';
2
+ export function deployHook(pkg) {
3
+ pkg.dependenciesMeta = pkg.dependenciesMeta ?? {};
4
+ for (const depField of DEPENDENCIES_FIELDS) {
5
+ for (const [depName, depVersion] of Object.entries(pkg[depField] ?? {})) {
6
+ if (depVersion.startsWith('workspace:')) {
7
+ pkg.dependenciesMeta[depName] = {
8
+ injected: true,
9
+ };
10
+ }
11
+ }
12
+ }
13
+ return pkg;
14
+ }
15
+ //# sourceMappingURL=deployHook.js.map
@@ -0,0 +1,2 @@
1
+ import * as deploy from './deploy.js';
2
+ export { deploy };
@@ -0,0 +1,3 @@
1
+ import * as deploy from './deploy.js';
2
+ export { deploy };
3
+ //# sourceMappingURL=index.js.map
package/lib/index.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ export { change } from './change/index.js';
2
+ export { deploy } from './deploy/index.js';
3
+ export { lane } from './lane/index.js';
4
+ export { packApp } from './pack-app/index.js';
5
+ export { pack, publish } from './publish/index.js';
6
+ export * as stage from './stage/index.js';
7
+ export { version } from './version/index.js';
@@ -0,0 +1,24 @@
1
+ import type { Config } from '@pnpm/config.reader';
2
+ import type { Project, ProjectsGraph } from '@pnpm/types';
3
+ export declare function rcOptionsTypes(): Record<string, unknown>;
4
+ export declare function cliOptionsTypes(): Record<string, unknown>;
5
+ export declare const commandNames: string[];
6
+ /**
7
+ * The reserved name of the default lane: every package is on it unless
8
+ * assigned elsewhere, packages on it release stable versions, and no
9
+ * prerelease lane can take the name.
10
+ */
11
+ export declare const MAIN_LANE = "main";
12
+ export declare function help(): string;
13
+ export type LaneCommandOptions = Pick<Config, 'dir' | 'filter' | 'versioning' | 'workspaceDir'> & {
14
+ allProjects?: Project[];
15
+ selectedProjectsGraph?: ProjectsGraph;
16
+ };
17
+ export declare function handler(opts: LaneCommandOptions, params: string[]): Promise<string>;
18
+ export declare const lane: {
19
+ handler: typeof handler;
20
+ help: typeof help;
21
+ commandNames: string[];
22
+ cliOptionsTypes: typeof cliOptionsTypes;
23
+ rcOptionsTypes: typeof rcOptionsTypes;
24
+ };
@@ -0,0 +1,157 @@
1
+ import { PnpmError } from '@pnpm/error';
2
+ import { indexProjectRefs, toProjectDir } from '@pnpm/releasing.versioning';
3
+ import { updateWorkspaceManifest } from '@pnpm/workspace.workspace-manifest-writer';
4
+ import { renderHelp } from 'render-help';
5
+ import { getReleasableProjects } from '../change/index.js';
6
+ export function rcOptionsTypes() {
7
+ return {};
8
+ }
9
+ export function cliOptionsTypes() {
10
+ return {
11
+ recursive: Boolean,
12
+ };
13
+ }
14
+ export const commandNames = ['lane'];
15
+ /**
16
+ * The reserved name of the default lane: every package is on it unless
17
+ * assigned elsewhere, packages on it release stable versions, and no
18
+ * prerelease lane can take the name.
19
+ */
20
+ export const MAIN_LANE = 'main';
21
+ export function help() {
22
+ return renderHelp({
23
+ description: 'Manages per-package release lanes. A lane is a parallel release track: while a package is on one, the bare "pnpm version -r" releases it as X.Y.Z-<lane>.N prereleases while the rest of the workspace keeps releasing stable versions. Moving a package back to the main lane releases its accumulated stable version on the next run. Membership lives under the versioning.lanes key of pnpm-workspace.yaml; this command is a convenience editor for that key.',
24
+ usages: [
25
+ 'pnpm lane',
26
+ 'pnpm lane <name> --filter <pattern>',
27
+ 'pnpm lane main --filter <pattern>',
28
+ ],
29
+ descriptionLists: [
30
+ {
31
+ title: 'Options',
32
+ list: [
33
+ {
34
+ description: 'Select the packages to move between lanes',
35
+ name: '--filter <pattern>',
36
+ },
37
+ ],
38
+ },
39
+ ],
40
+ });
41
+ }
42
+ export async function handler(opts, params) {
43
+ const workspaceDir = opts.workspaceDir;
44
+ if (!workspaceDir) {
45
+ throw new PnpmError('WORKSPACE_ONLY', 'pnpm lane is only supported in a workspace');
46
+ }
47
+ if (params.length === 0) {
48
+ return renderLanes(opts.versioning?.lanes ?? {});
49
+ }
50
+ const laneName = params[0];
51
+ if ((opts.filter ?? []).length === 0) {
52
+ throw new PnpmError('VERSIONING_LANE_FILTER_REQUIRED', 'Select the packages to move with --filter, e.g. "pnpm lane alpha --filter <pkg>..."');
53
+ }
54
+ const refs = indexProjectRefs(opts.allProjects ?? [], workspaceDir);
55
+ const releasableDirs = new Set(getReleasableProjects(opts.allProjects ?? [], workspaceDir, opts.versioning).map((project) => project.dir));
56
+ const selected = Object.values(opts.selectedProjectsGraph ?? {})
57
+ .map((node) => ({
58
+ name: node.package.manifest.name,
59
+ dir: toProjectDir(workspaceDir, node.package.rootDir),
60
+ }))
61
+ .filter((project) => project.name != null && releasableDirs.has(project.dir));
62
+ if (selected.length === 0) {
63
+ throw new PnpmError('VERSIONING_NO_PACKAGES', 'The filter selected no releasable packages');
64
+ }
65
+ // Existing entries may reference projects by name or by directory; resolve
66
+ // them so assignments and removals key on the project, not the spelling.
67
+ const lanes = { ...opts.versioning?.lanes };
68
+ const laneByDir = new Map();
69
+ for (const [key, lane] of Object.entries(lanes)) {
70
+ for (const dir of refs.refToDirs(key)) {
71
+ laneByDir.set(dir, { key, lane });
72
+ }
73
+ }
74
+ let output;
75
+ if (laneName === MAIN_LANE) {
76
+ for (const project of selected) {
77
+ const existing = laneByDir.get(project.dir);
78
+ if (existing != null) {
79
+ delete lanes[existing.key];
80
+ }
81
+ }
82
+ output = `Moved to the main lane:\n${selected.map((project) => ` ${refFor(project, refs)}\n`).join('')}` +
83
+ 'The accumulated stable versions release on the next "pnpm version -r" run.';
84
+ }
85
+ else {
86
+ if (laneName.toLowerCase() === MAIN_LANE) {
87
+ throw new PnpmError('VERSIONING_INVALID_LANE_NAME', `Invalid lane name: ${laneName}. "main" is the reserved default lane; spell it in lowercase to move packages back onto it.`);
88
+ }
89
+ // A purely numeric lane name is rejected because semver parses an
90
+ // all-digit prerelease identifier as a number, which changes sorting
91
+ // semantics.
92
+ if (!/^[0-9A-Z-]+$/i.test(laneName) || /^\d+$/.test(laneName)) {
93
+ throw new PnpmError('VERSIONING_INVALID_LANE_NAME', `Invalid lane name: ${laneName}. Lane names may contain only alphanumerics and hyphens, and cannot be purely numeric.`);
94
+ }
95
+ for (const project of selected) {
96
+ const existing = laneByDir.get(project.dir);
97
+ if (existing != null && existing.lane !== laneName) {
98
+ throw new PnpmError('VERSIONING_ALREADY_ON_LANE', `${refFor(project, refs)} is already on the "${existing.lane}" lane. Move it back with "pnpm lane main" first.`);
99
+ }
100
+ if (existing == null) {
101
+ lanes[refFor(project, refs)] = laneName;
102
+ }
103
+ }
104
+ output = `Moved to the "${laneName}" lane:\n${selected.map((project) => ` ${refFor(project, refs)}\n`).join('')}`;
105
+ }
106
+ const versioning = { ...opts.versioning };
107
+ if (Object.keys(lanes).length > 0) {
108
+ versioning.lanes = lanes;
109
+ }
110
+ else {
111
+ delete versioning.lanes;
112
+ }
113
+ await updateWorkspaceManifest(workspaceDir, {
114
+ updatedFields: {
115
+ versioning: Object.keys(versioning).length > 0 ? versioning : undefined,
116
+ },
117
+ });
118
+ return output;
119
+ }
120
+ /**
121
+ * How the project is referenced in versioning.lanes and in output: the bare
122
+ * name, or the directory path when the name is shared by several projects.
123
+ */
124
+ function refFor(project, refs) {
125
+ return refs.nameToDirs(project.name).length > 1 ? `./${project.dir}` : project.name;
126
+ }
127
+ function renderLanes(lanes) {
128
+ const laneEntries = Object.entries(lanes);
129
+ if (laneEntries.length === 0) {
130
+ return 'All packages are on the main lane.';
131
+ }
132
+ const byLane = new Map();
133
+ for (const [ref, laneName] of laneEntries) {
134
+ let members = byLane.get(laneName);
135
+ if (members == null) {
136
+ members = [];
137
+ byLane.set(laneName, members);
138
+ }
139
+ members.push(ref);
140
+ }
141
+ let output = 'Lanes:\n';
142
+ for (const [laneName, members] of Array.from(byLane.entries()).sort(([left], [right]) => left.localeCompare(right))) {
143
+ output += ` ${laneName}:\n`;
144
+ for (const ref of members.sort()) {
145
+ output += ` ${ref}\n`;
146
+ }
147
+ }
148
+ return output;
149
+ }
150
+ export const lane = {
151
+ handler,
152
+ help,
153
+ commandNames,
154
+ cliOptionsTypes,
155
+ rcOptionsTypes,
156
+ };
157
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,2 @@
1
+ import * as packApp from './packApp.js';
2
+ export { packApp };
@@ -0,0 +1,3 @@
1
+ import * as packApp from './packApp.js';
2
+ export { packApp };
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,22 @@
1
+ import type { Config } from '@pnpm/config.reader';
2
+ export declare const commandNames: string[];
3
+ export declare function rcOptionsTypes(): Record<string, unknown>;
4
+ export declare function cliOptionsTypes(): Record<string, unknown>;
5
+ export declare const shorthands: Record<string, string>;
6
+ export declare function help(): string;
7
+ export type PackAppOptions = Pick<Config, 'dir' | 'pnpmHomeDir'> & Partial<Pick<Config, 'ca' | 'cert' | 'configByUri' | 'httpProxy' | 'httpsProxy' | 'key' | 'localAddress' | 'nodeDownloadMirrors' | 'noProxy' | 'strictSsl' | 'userAgent'>> & {
8
+ entry?: string;
9
+ target?: string | string[];
10
+ runtime?: string;
11
+ outputDir?: string;
12
+ outputName?: string;
13
+ };
14
+ export declare function handler(opts: PackAppOptions, params: string[]): Promise<string>;
15
+ /** Fields pack-app reads from `pnpm.app` in package.json. */
16
+ export interface ProjectAppConfig {
17
+ entry?: string;
18
+ targets?: string[];
19
+ runtime?: string;
20
+ outputDir?: string;
21
+ outputName?: string;
22
+ }