release-it 19.0.6 → 19.2.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.
package/README.md CHANGED
@@ -315,40 +315,41 @@ Since v11, release-it can be extended in many, many ways. Here are some plugins:
315
315
  | [release-it-pnpm][16] | Add basic support for pnpm workspaces, integrates with [bumpp][50] and [changelogithub][51] |
316
316
  | [changesets-release-it-plugin][52] | Combine [Changesets][53] changelog management with release-it |
317
317
  | [release-it-gitea][54] | Gitea plugin to create Gitea releases and upload attachments |
318
+ | [release-it-beautiful-changelog][55] | Generate beautiful changelogs using conventional commits by [@unjs/changelogen][45] |
318
319
 
319
320
  Internally, release-it uses its own plugin architecture (for Git, GitHub, GitLab, npm).
320
321
 
321
- → See all [release-it plugins on npm][55].
322
+ → See all [release-it plugins on npm][56].
322
323
 
323
- → See [plugins][56] for documentation to write plugins.
324
+ → See [plugins][57] for documentation to write plugins.
324
325
 
325
326
  ## Use release-it programmatically
326
327
 
327
328
  While mostly used as a CLI tool, release-it can be used as a dependency to integrate in your own scripts. See [use
328
- release-it programmatically][57] for example code.
329
+ release-it programmatically][58] for example code.
329
330
 
330
331
  ## Projects using release-it
331
332
 
332
- - [AdonisJs][58]
333
- - [Axios][59]
334
- - [Chakra UI][60]
335
- - [Halo][61]
336
- - [hosts][62]
337
- - [js-cookie][63]
338
- - [jQuery][64]
339
- - [Madge][65]
340
- - [Metalsmith][66]
341
- - [n8n][67]
342
- - [Node-Redis][68]
343
- - [React Native Paper][69]
344
- - [Readability.js][70]
345
- - [Redux][71]
346
- - [Saleor][72]
347
- - [Semantic UI React][73]
348
- - [tabler-icons][74]
349
- - Swagger ([swagger-ui][75] + [swagger-editor][76])
350
- - [Repositories that depend on release-it][77]
351
- - GitHub search for [path:\*\*/.release-it.json][78]
333
+ - [AdonisJs][59]
334
+ - [Axios][60]
335
+ - [Chakra UI][61]
336
+ - [Halo][62]
337
+ - [hosts][63]
338
+ - [js-cookie][64]
339
+ - [jQuery][65]
340
+ - [Madge][66]
341
+ - [Metalsmith][67]
342
+ - [n8n][68]
343
+ - [Node-Redis][69]
344
+ - [React Native Paper][70]
345
+ - [Readability.js][71]
346
+ - [Redux][72]
347
+ - [Saleor][73]
348
+ - [Semantic UI React][74]
349
+ - [tabler-icons][75]
350
+ - Swagger ([swagger-ui][76] + [swagger-editor][77])
351
+ - [Repositories that depend on release-it][78]
352
+ - GitHub search for [path:\*\*/.release-it.json][79]
352
353
 
353
354
  ## Node.js version support
354
355
 
@@ -362,17 +363,17 @@ The latest major version is v19, supporting Node.js 20 and up:
362
363
  | v16 | v16 |
363
364
  | v15 | v14 |
364
365
 
365
- Also see [CHANGELOG.md][79] for dates and details.
366
+ Also see [CHANGELOG.md][80] for dates and details.
366
367
 
367
368
  ## Links
368
369
 
369
- - See [CHANGELOG.md][79] for major/breaking updates, and [releases][80] for a detailed version history.
370
- - To **contribute**, please read [CONTRIBUTING.md][81] first.
371
- - Please [open an issue][82] if anything is missing or unclear in this documentation.
370
+ - See [CHANGELOG.md][80] for major/breaking updates, and [releases][81] for a detailed version history.
371
+ - To **contribute**, please read [CONTRIBUTING.md][82] first.
372
+ - Please [open an issue][83] if anything is missing or unclear in this documentation.
372
373
 
373
374
  ## License
374
375
 
375
- [MIT][83]
376
+ [MIT][84]
376
377
 
377
378
  Are you using release-it at work? Please consider [sponsoring me][14]!
378
379
 
@@ -430,32 +431,33 @@ Are you using release-it at work? Please consider [sponsoring me][14]!
430
431
  [52]: https://www.npmjs.com/package/changesets-release-it-plugin
431
432
  [53]: https://github.com/changesets/changesets
432
433
  [54]: https://github.com/lib-pack/release-it-gitea
433
- [55]: https://www.npmjs.com/search?q=keywords:release-it-plugin
434
- [56]: ./docs/plugins.md
435
- [57]: ./docs/recipes/programmatic.md
436
- [58]: https://github.com/adonisjs/core
437
- [59]: https://github.com/axios/axios
438
- [60]: https://github.com/chakra-ui/chakra-ui
439
- [61]: https://github.com/halo-dev/halo
440
- [62]: https://github.com/StevenBlack/hosts
441
- [63]: https://github.com/js-cookie/js-cookie
442
- [64]: https://github.com/jquery/jquery
443
- [65]: https://github.com/pahen/madge
444
- [66]: https://github.com/metalsmith/metalsmith
445
- [67]: https://github.com/n8n-io/n8n
446
- [68]: https://github.com/redis/node-redis
447
- [69]: https://github.com/callstack/react-native-paper
448
- [70]: https://github.com/mozilla/readability
449
- [71]: https://github.com/reduxjs/redux
450
- [72]: https://github.com/saleor/saleor
451
- [73]: https://github.com/Semantic-Org/Semantic-UI-React
452
- [74]: https://github.com/tabler/tabler-icons
453
- [75]: https://github.com/swagger-api/swagger-ui
454
- [76]: https://github.com/swagger-api/swagger-editor
455
- [77]: https://github.com/release-it/release-it/network/dependents
456
- [78]: https://github.com/search?q=path%3A**%2F.release-it.json&type=code
457
- [79]: ./CHANGELOG.md
458
- [80]: https://github.com/release-it/release-it/releases
459
- [81]: ./.github/CONTRIBUTING.md
460
- [82]: https://github.com/release-it/release-it/issues/new
461
- [83]: ./LICENSE
434
+ [55]: https://github.com/mohammadGh/release-it-beautiful-changelog
435
+ [56]: https://www.npmjs.com/search?q=keywords:release-it-plugin
436
+ [57]: ./docs/plugins.md
437
+ [58]: ./docs/recipes/programmatic.md
438
+ [59]: https://github.com/adonisjs/core
439
+ [60]: https://github.com/axios/axios
440
+ [61]: https://github.com/chakra-ui/chakra-ui
441
+ [62]: https://github.com/halo-dev/halo
442
+ [63]: https://github.com/StevenBlack/hosts
443
+ [64]: https://github.com/js-cookie/js-cookie
444
+ [65]: https://github.com/jquery/jquery
445
+ [66]: https://github.com/pahen/madge
446
+ [67]: https://github.com/metalsmith/metalsmith
447
+ [68]: https://github.com/n8n-io/n8n
448
+ [69]: https://github.com/redis/node-redis
449
+ [70]: https://github.com/callstack/react-native-paper
450
+ [71]: https://github.com/mozilla/readability
451
+ [72]: https://github.com/reduxjs/redux
452
+ [73]: https://github.com/saleor/saleor
453
+ [74]: https://github.com/Semantic-Org/Semantic-UI-React
454
+ [75]: https://github.com/tabler/tabler-icons
455
+ [76]: https://github.com/swagger-api/swagger-ui
456
+ [77]: https://github.com/swagger-api/swagger-editor
457
+ [78]: https://github.com/release-it/release-it/network/dependents
458
+ [79]: https://github.com/search?q=path%3A**%2F.release-it.json&type=code
459
+ [80]: ./CHANGELOG.md
460
+ [81]: https://github.com/release-it/release-it/releases
461
+ [82]: ./.github/CONTRIBUTING.md
462
+ [83]: https://github.com/release-it/release-it/issues/new
463
+ [84]: ./LICENSE
@@ -27,6 +27,7 @@
27
27
  "publish": true,
28
28
  "publishPath": ".",
29
29
  "publishArgs": [],
30
+ "publishPackageManager": "npm",
30
31
  "tag": null,
31
32
  "otp": null,
32
33
  "ignoreVersion": false,
@@ -2,12 +2,12 @@ import path from 'node:path';
2
2
  import semver from 'semver';
3
3
  import urlJoin from 'url-join';
4
4
  import Plugin from '../Plugin.js';
5
- import { hasAccess, rejectAfter, parseVersion, readJSON, e, fixArgs } from '../../util.js';
5
+ import { hasAccess, rejectAfter, parseVersion, readJSON, e, fixArgs, getNpmEnv } from '../../util.js';
6
6
  import prompts from './prompts.js';
7
7
 
8
8
  const docs = 'https://git.io/release-it-npm';
9
9
 
10
- const options = { write: false };
10
+ const getOptions = () => ({ write: false, env: getNpmEnv() });
11
11
 
12
12
  const MANIFEST_PATH = './package.json';
13
13
  const DEFAULT_TAG = 'latest';
@@ -84,8 +84,14 @@ class npm extends Plugin {
84
84
  if (!this.config.isIncrement) return false;
85
85
 
86
86
  const { versionArgs, allowSameVersion } = this.options;
87
- const args = [version, '--no-git-tag-version', allowSameVersion && '--allow-same-version', ...fixArgs(versionArgs)];
88
- const task = () => this.exec(`npm version ${args.filter(Boolean).join(' ')}`);
87
+ const args = [
88
+ version,
89
+ '--no-git-tag-version',
90
+ '--workspaces=false',
91
+ allowSameVersion && '--allow-same-version',
92
+ ...fixArgs(versionArgs)
93
+ ];
94
+ const task = () => this.exec(`npm version ${args.filter(Boolean).join(' ')}`, { options: getOptions() });
89
95
  return this.spinner.show({ task, label: 'npm version' });
90
96
  }
91
97
 
@@ -101,7 +107,7 @@ class npm extends Plugin {
101
107
  isRegistryUp() {
102
108
  const registry = this.getRegistry();
103
109
  const registryArg = registry ? ` --registry ${registry}` : '';
104
- return this.exec(`npm ping${registryArg}`, { options }).then(
110
+ return this.exec(`npm ping${registryArg}`, { options: getOptions() }).then(
105
111
  () => true,
106
112
  err => {
107
113
  if (/code E40[04]|404.*(ping not found|No content for path)/.test(err)) {
@@ -116,7 +122,7 @@ class npm extends Plugin {
116
122
  isAuthenticated() {
117
123
  const registry = this.getRegistry();
118
124
  const registryArg = registry ? ` --registry ${registry}` : '';
119
- return this.exec(`npm whoami${registryArg}`, { options }).then(
125
+ return this.exec(`npm whoami${registryArg}`, { options: getOptions() }).then(
120
126
  output => {
121
127
  const username = output ? output.trim() : null;
122
128
  this.setContext({ username });
@@ -142,7 +148,7 @@ class npm extends Plugin {
142
148
  if (username === null) return false;
143
149
 
144
150
  try {
145
- let npmVersion = await this.exec('npm --version', { options });
151
+ let npmVersion = await this.exec('npm --version', { options: getOptions() });
146
152
 
147
153
  let accessCommand;
148
154
  if (semver.gt(npmVersion, '9.0.0')) {
@@ -151,7 +157,7 @@ class npm extends Plugin {
151
157
  accessCommand = 'npm access ls-collaborators';
152
158
  }
153
159
 
154
- const output = await this.exec(`${accessCommand} ${name}${registryArg}`, { options });
160
+ const output = await this.exec(`${accessCommand} ${name}${registryArg}`, { options: getOptions() });
155
161
 
156
162
  try {
157
163
  const collaborators = JSON.parse(output);
@@ -178,11 +184,11 @@ class npm extends Plugin {
178
184
  const name = this.getName();
179
185
  const latestVersion = this.getLatestVersion();
180
186
  const tag = await this.resolveTag(latestVersion);
181
- return this.exec(`npm show ${name}@${tag} version${registryArg}`, { options }).catch(() => null);
187
+ return this.exec(`npm show ${name}@${tag} version${registryArg}`, { options: getOptions() }).catch(() => null);
182
188
  }
183
189
 
184
190
  getRegistryPreReleaseTags() {
185
- return this.exec(`npm view ${this.getName()} dist-tags --json`, { options }).then(
191
+ return this.exec(`npm view ${this.getName()} dist-tags --json`, { options: getOptions() }).then(
186
192
  output => {
187
193
  try {
188
194
  const tags = JSON.parse(output);
@@ -240,9 +246,10 @@ class npm extends Plugin {
240
246
  }
241
247
 
242
248
  async publish({ otp = this.options.otp, otpCallback } = {}) {
249
+ const publishPackageManager = this.options.publishPackageManager || 'npm';
243
250
  const { publishPath = '.', publishArgs } = this.options;
244
251
  const { private: isPrivate, tag = DEFAULT_TAG } = this.getContext();
245
- const otpArg = otp ? `--otp ${otp}` : '';
252
+ const otpArgs = otp ? ['--otp', otp] : [];
246
253
  const dryRunArg = this.config.isDryRun ? '--dry-run' : '';
247
254
  const registry = this.getRegistry();
248
255
  const registryArg = registry ? `--registry ${registry}` : '';
@@ -250,8 +257,20 @@ class npm extends Plugin {
250
257
  this.log.warn('Skip publish: package is private.');
251
258
  return false;
252
259
  }
253
- const args = [publishPath, `--tag ${tag}`, otpArg, dryRunArg, registryArg, ...fixArgs(publishArgs)].filter(Boolean);
254
- return this.exec(`npm publish ${args.join(' ')}`, { options })
260
+ const args = [
261
+ publishPath,
262
+ '--tag',
263
+ tag,
264
+ publishPackageManager === 'npm' && '--workspaces=false',
265
+ ...otpArgs,
266
+ dryRunArg,
267
+ registryArg,
268
+ ...fixArgs(publishArgs)
269
+ ].filter(Boolean);
270
+ const isInteractive = !this.config.isCI;
271
+ return this.exec([publishPackageManager, 'publish', ...args], {
272
+ options: { ...getOptions(), interactive: isInteractive }
273
+ })
255
274
  .then(() => {
256
275
  this.setContext({ isReleased: true });
257
276
  })
@@ -13,6 +13,8 @@ const CHOICES = {
13
13
  default: [...RELEASE_TYPES, ...PRERELEASE_TYPES]
14
14
  };
15
15
 
16
+ const EXIT = Symbol('exit');
17
+
16
18
  const getIncrementChoices = context => {
17
19
  const { latestIsPreRelease, isPreRelease, preReleaseId, preReleaseBase } = context.version;
18
20
  const types = latestIsPreRelease ? CHOICES.latestIsPreRelease : isPreRelease ? CHOICES.preRelease : CHOICES.default;
@@ -24,7 +26,11 @@ const getIncrementChoices = context => {
24
26
  name: 'Other, please specify...',
25
27
  value: null
26
28
  };
27
- return [...choices, otherChoice];
29
+ const exitChoice = {
30
+ name: 'Exit',
31
+ value: EXIT
32
+ };
33
+ return [...choices, otherChoice, exitChoice];
28
34
  };
29
35
 
30
36
  const versionTransformer = context => input =>
@@ -73,10 +79,12 @@ class Version extends Plugin {
73
79
  return new Promise(resolve => {
74
80
  this.step({
75
81
  prompt: 'incrementList',
76
- task: increment =>
77
- increment
82
+ task: increment => {
83
+ if (increment === EXIT) process.exit(0);
84
+ return increment
78
85
  ? resolve(this.incrementVersion(Object.assign({}, options, { increment })))
79
- : this.step({ prompt: 'version', task: resolve })
86
+ : this.step({ prompt: 'version', task: resolve });
87
+ }
80
88
  });
81
89
  });
82
90
  }
package/lib/shell.js CHANGED
@@ -52,7 +52,8 @@ class Shell {
52
52
 
53
53
  execStringCommand(command, options, { isExternal }) {
54
54
  return new Promise((resolve, reject) => {
55
- const proc = exec(command, (err, stdout, stderr) => {
55
+ const execOptions = options.env ? { env: options.env } : {};
56
+ const proc = exec(command, execOptions, (err, stdout, stderr) => {
56
57
  stdout = stdout.toString().trimEnd();
57
58
  const code = !err ? 0 : err === 'undefined' ? 1 : err.code;
58
59
  debug({ command, options, code, stdout, stderr });
@@ -69,35 +70,44 @@ class Shell {
69
70
 
70
71
  async execWithArguments(command, options = {}, { isExternal } = {}) {
71
72
  const [program, ...programArgs] = command;
73
+ const isInteractive = options.interactive === true;
72
74
 
73
75
  try {
74
76
  return await new Promise((resolve, reject) => {
75
- const proc = spawn(program, programArgs, {
76
- // we want to capture all output from the process so the extra 2 pipe
77
- stdio: ['inherit', 'pipe', 'pipe'],
77
+ const spawnOptions = {
78
+ stdio: isInteractive ? 'inherit' : ['inherit', 'pipe', 'pipe'],
79
+ env: options.env,
78
80
  ...options
79
- });
81
+ };
82
+ delete spawnOptions.interactive;
83
+
84
+ const proc =
85
+ process.platform === 'win32' && /^(npm|yarn|pnpm)$/.test(program)
86
+ ? spawn(command.join(' '), [], { ...spawnOptions, shell: true })
87
+ : spawn(program, programArgs, spawnOptions);
80
88
 
81
89
  let stdout = '';
82
90
  let stderr = '';
83
91
 
84
- proc.stdout.on('data', data => {
85
- stdout += data.toString();
86
- });
92
+ if (!isInteractive) {
93
+ proc.stdout.on('data', data => {
94
+ stdout += data.toString();
95
+ });
87
96
 
88
- proc.stderr.on('data', data => {
89
- stderr += data.toString();
90
- });
97
+ proc.stderr.on('data', data => {
98
+ stderr += data.toString();
99
+ });
100
+ }
91
101
 
92
102
  proc.on('close', code => {
93
103
  stdout = stdout === '""' ? '' : stdout;
94
- this.log.verbose(stdout, { isExternal });
104
+ if (!isInteractive) this.log.verbose(stdout, { isExternal });
95
105
  debug({ command, options, stdout, stderr });
96
106
 
97
107
  if (code === 0) {
98
108
  resolve((stdout || stderr).trim());
99
109
  } else {
100
- if (stdout) {
110
+ if (stdout && !isInteractive) {
101
111
  this.log.log(`\n${stdout}`);
102
112
  }
103
113
  debug({ code, command, options, stdout, stderr });
package/lib/util.js CHANGED
@@ -159,6 +159,19 @@ export const touch = (path, callback) => {
159
159
 
160
160
  export const fixArgs = args => (args ? (typeof args === 'string' ? args.split(' ') : args) : []);
161
161
 
162
+ // Remove npm_config_* variables set by others (e.g. pnpm) that npm warns about
163
+ export const getNpmEnv = () => {
164
+ const env = { ...process.env };
165
+ const removeVars = new Set([
166
+ 'npm_config_npm_globalconfig',
167
+ 'npm_config_verify_deps_before_run',
168
+ 'npm_config_overrides',
169
+ 'npm_config__jsr_registry'
170
+ ]);
171
+ for (const key of Object.keys(env)) if (removeVars.has(key.toLowerCase())) delete env[key];
172
+ return env;
173
+ };
174
+
162
175
  export const upperFirst = string => {
163
176
  return string ? string.charAt(0).toUpperCase() + string.slice(1) : '';
164
177
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "release-it",
3
- "version": "19.0.6",
3
+ "version": "19.2.0",
4
4
  "description": "Generic CLI tool to automate versioning and package publishing-related tasks.",
5
5
  "keywords": [
6
6
  "build",
@@ -79,47 +79,47 @@
79
79
  "license": "MIT",
80
80
  "dependencies": {
81
81
  "@nodeutils/defaults-deep": "1.1.0",
82
- "@octokit/rest": "22.0.0",
82
+ "@octokit/rest": "22.0.1",
83
83
  "@phun-ky/typeof": "2.0.3",
84
84
  "async-retry": "1.3.3",
85
- "c12": "3.3.1",
86
- "ci-info": "^4.3.0",
87
- "eta": "4.0.1",
85
+ "c12": "3.3.3",
86
+ "ci-info": "^4.3.1",
87
+ "eta": "4.5.0",
88
88
  "git-url-parse": "16.1.0",
89
- "inquirer": "12.9.6",
89
+ "inquirer": "12.11.1",
90
90
  "issue-parser": "7.0.1",
91
91
  "lodash.merge": "4.6.2",
92
- "mime-types": "3.0.1",
92
+ "mime-types": "3.0.2",
93
93
  "new-github-release-url": "2.0.0",
94
94
  "open": "10.2.0",
95
95
  "ora": "9.0.0",
96
96
  "os-name": "6.1.0",
97
97
  "proxy-agent": "6.5.0",
98
- "semver": "7.7.2",
98
+ "semver": "7.7.3",
99
99
  "tinyglobby": "0.2.15",
100
- "undici": "6.21.3",
100
+ "undici": "6.22.0",
101
101
  "url-join": "5.0.0",
102
102
  "wildcard-match": "5.1.4",
103
103
  "yargs-parser": "21.1.1"
104
104
  },
105
105
  "devDependencies": {
106
- "@eslint/compat": "1.3.2",
107
- "@eslint/eslintrc": "3.3.1",
108
- "@eslint/js": "9.35.0",
109
- "@octokit/request-error": "7.0.0",
110
- "@types/node": "24.5.2",
111
- "eslint": "9.35.0",
106
+ "@eslint/compat": "1.4.1",
107
+ "@eslint/eslintrc": "3.3.3",
108
+ "@eslint/js": "9.39.2",
109
+ "@octokit/request-error": "7.1.0",
110
+ "@types/node": "25.0.3",
111
+ "eslint": "9.39.2",
112
112
  "eslint-plugin-import-x": "4.16.1",
113
- "globals": "16.4.0",
113
+ "globals": "16.5.0",
114
114
  "installed-check": "9.3.0",
115
- "knip": "5.63.1",
116
- "mentoss": "0.11.0",
115
+ "knip": "5.76.3",
116
+ "mentoss": "0.12.0",
117
117
  "mock-stdio": "1.0.3",
118
- "prettier": "3.6.2",
118
+ "prettier": "3.7.4",
119
119
  "remark-cli": "12.0.1",
120
- "remark-preset-webpro": "1.1.1",
121
- "tar": "7.4.3",
122
- "typescript": "5.9.2"
120
+ "remark-preset-webpro": "2.0.1",
121
+ "tar": "7.5.2",
122
+ "typescript": "5.9.3"
123
123
  },
124
124
  "overrides": {
125
125
  "pac-resolver": "7.0.1",
package/schema/npm.json CHANGED
@@ -21,6 +21,10 @@
21
21
  },
22
22
  "default": []
23
23
  },
24
+ "publishPackageManager": {
25
+ "type": "string",
26
+ "default": "npm"
27
+ },
24
28
  "tag": {
25
29
  "type": "string",
26
30
  "default": null
package/test/npm.js CHANGED
@@ -155,7 +155,14 @@ describe('npm', async () => {
155
155
  exec.mock.mockImplementationOnce(() => Promise.reject(new Error(whoamiError)), 1);
156
156
  exec.mock.mockImplementationOnce(() => Promise.reject(new Error(accessError)), 2);
157
157
  await runTasks(npmClient);
158
- assert.equal(exec.mock.calls.at(-1).arguments[0].trim(), 'npm publish . --tag latest');
158
+ assert.deepEqual(exec.mock.calls.at(-1).arguments[0], [
159
+ 'npm',
160
+ 'publish',
161
+ '.',
162
+ '--tag',
163
+ 'latest',
164
+ '--workspaces=false'
165
+ ]);
159
166
  });
160
167
 
161
168
  test('should not throw if npm returns 400 for unsupported ping/whoami/access', async t => {
@@ -168,7 +175,14 @@ describe('npm', async () => {
168
175
  exec.mock.mockImplementationOnce(() => Promise.reject(new Error(whoamiError)), 1);
169
176
  exec.mock.mockImplementationOnce(() => Promise.reject(new Error(accessError)), 2);
170
177
  await runTasks(npmClient);
171
- assert.equal(exec.mock.calls.at(-1).arguments[0].trim(), 'npm publish . --tag latest');
178
+ assert.deepEqual(exec.mock.calls.at(-1).arguments[0], [
179
+ 'npm',
180
+ 'publish',
181
+ '.',
182
+ '--tag',
183
+ 'latest',
184
+ '--workspaces=false'
185
+ ]);
172
186
  });
173
187
 
174
188
  test('should throw if user is not authenticated', async t => {
@@ -238,9 +252,27 @@ describe('npm', async () => {
238
252
  });
239
253
 
240
254
  assert.equal(exec.mock.callCount(), 3);
241
- assert.equal(exec.mock.calls[0].arguments[0].trim(), 'npm publish . --tag latest');
242
- assert.equal(exec.mock.calls[1].arguments[0].trim(), 'npm publish . --tag latest --otp 123');
243
- assert.equal(exec.mock.calls[2].arguments[0].trim(), 'npm publish . --tag latest --otp 123456');
255
+ assert.deepEqual(exec.mock.calls[0].arguments[0], ['npm', 'publish', '.', '--tag', 'latest', '--workspaces=false']);
256
+ assert.deepEqual(exec.mock.calls[1].arguments[0], [
257
+ 'npm',
258
+ 'publish',
259
+ '.',
260
+ '--tag',
261
+ 'latest',
262
+ '--workspaces=false',
263
+ '--otp',
264
+ '123'
265
+ ]);
266
+ assert.deepEqual(exec.mock.calls[2].arguments[0], [
267
+ 'npm',
268
+ 'publish',
269
+ '.',
270
+ '--tag',
271
+ 'latest',
272
+ '--workspaces=false',
273
+ '--otp',
274
+ '123456'
275
+ ]);
244
276
 
245
277
  assert.equal(npmClient.log.warn.mock.callCount(), 1);
246
278
  assert.equal(npmClient.log.warn.mock.calls[0].arguments[0], 'The provided OTP is incorrect or has expired.');
@@ -255,7 +287,14 @@ describe('npm', async () => {
255
287
  return Promise.resolve();
256
288
  });
257
289
  await runTasks(npmClient);
258
- assert.equal(exec.mock.calls.at(-1).arguments[0].trim(), 'npm publish . --tag latest');
290
+ assert.deepEqual(exec.mock.calls.at(-1).arguments[0], [
291
+ 'npm',
292
+ 'publish',
293
+ '.',
294
+ '--tag',
295
+ 'latest',
296
+ '--workspaces=false'
297
+ ]);
259
298
  });
260
299
 
261
300
  test('should use extra publish arguments', async t => {
@@ -263,10 +302,15 @@ describe('npm', async () => {
263
302
  const npmClient = await factory(npm, { options });
264
303
  const exec = t.mock.method(npmClient.shell, 'exec', () => Promise.resolve());
265
304
  await runTasks(npmClient);
266
- assert.equal(
267
- exec.mock.calls.at(-1).arguments[0].trim(),
268
- 'npm publish . --tag latest --registry=http://my-internal-registry.local'
269
- );
305
+ assert.deepEqual(exec.mock.calls.at(-1).arguments[0], [
306
+ 'npm',
307
+ 'publish',
308
+ '.',
309
+ '--tag',
310
+ 'latest',
311
+ '--workspaces=false',
312
+ '--registry=http://my-internal-registry.local'
313
+ ]);
270
314
  });
271
315
 
272
316
  test('should skip checks', async () => {
@@ -306,8 +350,8 @@ describe('npm', async () => {
306
350
  'npm whoami --registry https://gitlab.com/api/v4/projects/my-scope%2Fmy-pkg/packages/npm/',
307
351
  'npm show @my-scope/my-pkg@latest version --registry https://gitlab.com/api/v4/projects/my-scope%2Fmy-pkg/packages/npm/',
308
352
  'npm --version',
309
- 'npm version 1.0.1 --no-git-tag-version',
310
- 'npm publish . --tag latest --registry https://gitlab.com/api/v4/projects/my-scope%2Fmy-pkg/packages/npm/'
353
+ 'npm version 1.0.1 --no-git-tag-version --workspaces=false',
354
+ 'npm publish . --tag latest --workspaces=false --registry https://gitlab.com/api/v4/projects/my-scope%2Fmy-pkg/packages/npm/'
311
355
  ]);
312
356
  });
313
357
 
@@ -322,7 +366,7 @@ describe('npm', async () => {
322
366
  if (command === 'npm whoami') return Promise.resolve('john');
323
367
  const re = /npm access (list collaborators --json|ls-collaborators) @my-scope\/my-pkg/;
324
368
  if (re.test(command)) return Promise.resolve(JSON.stringify({ john: ['write'] }));
325
- if (command === 'npm version 1.0.1 --no-git-tag-version')
369
+ if (command === 'npm version 1.0.1 --no-git-tag-version --workspaces=false')
326
370
  return Promise.reject('npm ERR! Version not changed, might want --allow-same-version');
327
371
  return Promise.resolve();
328
372
  });
@@ -334,7 +378,7 @@ describe('npm', async () => {
334
378
  'npm whoami',
335
379
  'npm show @my-scope/my-pkg@latest version',
336
380
  'npm --version',
337
- 'npm version 1.0.1 --no-git-tag-version'
381
+ 'npm version 1.0.1 --no-git-tag-version --workspaces=false'
338
382
  ]);
339
383
  });
340
384
 
@@ -5,16 +5,17 @@ const debug = util.debug('release-it:shell-stub');
5
5
 
6
6
  class ShellStub extends Shell {
7
7
  exec(command) {
8
- if (/^(npm (ping|publish|show)|git fetch)/.test(command)) {
9
- debug(command);
8
+ const cmd = Array.isArray(command) ? command.join(' ') : command;
9
+ if (/^(npm (ping|publish|show)|git fetch)/.test(cmd)) {
10
+ debug(cmd);
10
11
  return Promise.resolve();
11
12
  }
12
- if (/^npm whoami/.test(command)) {
13
- debug(command);
13
+ if (/^npm whoami/.test(cmd)) {
14
+ debug(cmd);
14
15
  return Promise.resolve('john');
15
16
  }
16
- if (/^npm access/.test(command)) {
17
- debug(command);
17
+ if (/^npm access/.test(cmd)) {
18
+ debug(cmd);
18
19
  return Promise.resolve(JSON.stringify({ john: ['write'] }));
19
20
  }
20
21
  return super.exec(...arguments);
package/test/tasks.js CHANGED
@@ -140,7 +140,7 @@ describe('tasks', () => {
140
140
  const stdout = childProcess.execSync('git describe --tags --match=* --abbrev=0', { encoding: 'utf-8' });
141
141
  assert.equal(stdout.trim(), '1.0.0');
142
142
  const npmArgs = getArgs(exec, 'npm');
143
- assert.equal(npmArgs[5], 'npm version 1.3.0 --no-git-tag-version');
143
+ assert.equal(npmArgs[5], 'npm version 1.3.0 --no-git-tag-version --workspaces=false');
144
144
  });
145
145
 
146
146
  test('should ignore version in pkg.version and use git tag instead', async () => {
@@ -187,8 +187,8 @@ describe('tasks', () => {
187
187
  `npm show ${pkgName}@latest version`,
188
188
  'npm --version',
189
189
  `npm access ${npmMajorVersion >= 9 ? 'list collaborators --json' : 'ls-collaborators'} ${pkgName}`,
190
- 'npm version 1.0.1 --no-git-tag-version',
191
- 'npm publish . --tag latest'
190
+ 'npm version 1.0.1 --no-git-tag-version --workspaces=false',
191
+ 'npm publish . --tag latest --workspaces=false'
192
192
  ]);
193
193
 
194
194
  assert(log.obtrusive.mock.calls[0].arguments[0].endsWith(`release ${pkgName} (1.0.0...1.0.1)`));
@@ -320,8 +320,8 @@ describe('tasks', () => {
320
320
  `npm show ${pkgName}@latest version`,
321
321
  'npm --version',
322
322
  `npm access ${npmMajorVersion >= 9 ? 'list collaborators --json' : 'ls-collaborators'} ${pkgName}`,
323
- 'npm version 1.1.0-alpha.0 --no-git-tag-version',
324
- 'npm publish . --tag alpha'
323
+ 'npm version 1.1.0-alpha.0 --no-git-tag-version --workspaces=false',
324
+ 'npm publish . --tag alpha --workspaces=false'
325
325
  ]);
326
326
 
327
327
  const commitMessage = childProcess.execSync('git log --oneline --format=%B -n 1 HEAD', {
@@ -361,8 +361,8 @@ describe('tasks', () => {
361
361
  `npm show ${pkgName}@latest version`,
362
362
  'npm --version',
363
363
  `npm access ${npmMajorVersion >= 9 ? 'list collaborators --json' : 'ls-collaborators'} ${pkgName}`,
364
- 'npm version 2.0.0-0 --no-git-tag-version',
365
- 'npm publish . --tag next'
364
+ 'npm version 2.0.0-0 --no-git-tag-version --workspaces=false',
365
+ 'npm publish . --tag next --workspaces=false'
366
366
  ]);
367
367
 
368
368
  const stdout = childProcess.execSync('git describe --tags --match=* --abbrev=0', { encoding: 'utf-8' });
@@ -383,7 +383,7 @@ describe('tasks', () => {
383
383
  await runTasks({}, container);
384
384
 
385
385
  const npmArgs = getArgs(exec, 'npm');
386
- assert.deepEqual(npmArgs, ['npm version 1.0.1 --no-git-tag-version']);
386
+ assert.deepEqual(npmArgs, ['npm version 1.0.1 --no-git-tag-version --workspaces=false']);
387
387
  assert(log.obtrusive.mock.calls[0].arguments[0].endsWith(`release ${pkgName} (1.0.0...1.0.1)`));
388
388
  assert.equal(log.warn.length, 0);
389
389
  assert.match(log.log.mock.calls[0].arguments[0], /Done \(in [0-9]+s\.\)/);
@@ -404,7 +404,7 @@ describe('tasks', () => {
404
404
  await runTasks({}, container);
405
405
 
406
406
  const npmArgs = getArgs(exec, 'npm');
407
- assert.equal(npmArgs[6], 'npm publish . --tag latest');
407
+ assert.equal(npmArgs[6], 'npm publish . --tag latest --workspaces=false');
408
408
  });
409
409
 
410
410
  test('should use pkg.publishConfig.registry', async t => {
package/types/config.d.ts CHANGED
@@ -77,6 +77,9 @@ export interface Config {
77
77
 
78
78
  publishArgs?: Array<any>;
79
79
 
80
+ /** @default "npm" */
81
+ publishPackageManager?: 'npm' | 'pnpm' | 'bun';
82
+
80
83
  /** @default null */
81
84
  tag?: any;
82
85