release-it 18.1.1 → 19.0.0-next.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.
@@ -1,6 +1,7 @@
1
1
  import path from 'node:path';
2
+ import { renameSync } from 'node:fs';
3
+ import childProcess from 'node:child_process';
2
4
  import test from 'ava';
3
- import sh from 'shelljs';
4
5
  import _ from 'lodash';
5
6
  import sinon from 'sinon';
6
7
  import Log from '../lib/log.js';
@@ -9,6 +10,7 @@ import Prompt from '../lib/prompt.js';
9
10
  import Config from '../lib/config.js';
10
11
  import runTasks from '../lib/index.js';
11
12
  import Git from '../lib/plugin/git/Git.js';
13
+ import { execOpts } from '../lib/util.js';
12
14
  import { mkTmpDir, gitAdd } from './util/helpers.js';
13
15
  import ShellStub from './stub/shell.js';
14
16
  import { interceptPublish as interceptGitLabPublish } from './stub/gitlab.js';
@@ -68,10 +70,10 @@ test.before(t => {
68
70
  test.serial.beforeEach(t => {
69
71
  const bare = mkTmpDir();
70
72
  const target = mkTmpDir();
71
- sh.pushd('-q', bare);
72
- sh.exec(`git init --bare .`);
73
- sh.exec(`git clone ${bare} ${target}`);
74
- sh.pushd('-q', target);
73
+ process.chdir(bare);
74
+ childProcess.execSync(`git init --bare .`, execOpts);
75
+ childProcess.execSync(`git clone ${bare} ${target}`, execOpts);
76
+ process.chdir(target);
75
77
  gitAdd('line', 'file', 'Add file');
76
78
  t.context = { bare, target };
77
79
  });
@@ -81,7 +83,7 @@ test.serial.afterEach(() => {
81
83
  });
82
84
 
83
85
  test.serial('should run tasks without throwing errors', async t => {
84
- sh.mv('.git', 'foo');
86
+ renameSync('.git', 'foo');
85
87
  const { name, latestVersion, version } = await runTasks({}, getContainer());
86
88
  t.is(version, '0.0.1');
87
89
  t.true(log.obtrusive.firstCall.args[0].includes(`release ${name} (currently at ${latestVersion})`));
@@ -118,7 +120,7 @@ test.serial('should not run hooks for cancelled release-cycle methods', async t
118
120
  const { target } = t.context;
119
121
  const pkgName = path.basename(target);
120
122
  gitAdd(`{"name":"${pkgName}","version":"1.0.0"}`, 'package.json', 'Add package.json');
121
- sh.exec('git tag 1.0.0');
123
+ childProcess.execSync('git tag 1.0.0', execOpts);
122
124
 
123
125
  const hooks = getHooks(['version', 'git', 'github', 'gitlab', 'npm']);
124
126
  const inquirer = { prompt: sandbox.stub().callsFake(([options]) => ({ [options.name]: false })) };
@@ -159,7 +161,7 @@ test.serial('should run "after:*:release" plugin hooks', async t => {
159
161
  const pkgName = path.basename(target);
160
162
  const owner = path.basename(path.dirname(bare));
161
163
  gitAdd(`{"name":"${pkgName}","version":"1.0.0"}`, 'package.json', 'Add package.json');
162
- sh.exec('git tag 1.0.0');
164
+ childProcess.execSync('git tag 1.0.0', execOpts);
163
165
  const sha = gitAdd('line', 'file', 'More file');
164
166
 
165
167
  const git = factory(Git);
package/test/tasks.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import path from 'node:path';
2
+ import childProcess from 'node:child_process';
3
+ import { appendFileSync, mkdirSync, renameSync } from 'node:fs';
2
4
  import test from 'ava';
3
5
  import semver from 'semver';
4
- import sh from 'shelljs';
5
6
  import _ from 'lodash';
6
7
  import sinon from 'sinon';
7
8
  import Log from '../lib/log.js';
@@ -9,6 +10,7 @@ import Spinner from '../lib/spinner.js';
9
10
  import Config from '../lib/config.js';
10
11
  import runTasks from '../lib/index.js';
11
12
  import Git from '../lib/plugin/git/Git.js';
13
+ import { execOpts } from '../lib/util.js';
12
14
  import { mkTmpDir, gitAdd, getArgs } from './util/helpers.js';
13
15
  import ShellStub from './stub/shell.js';
14
16
  import {
@@ -60,10 +62,10 @@ test.before(t => {
60
62
  test.serial.beforeEach(t => {
61
63
  const bare = mkTmpDir();
62
64
  const target = mkTmpDir();
63
- sh.pushd('-q', bare);
64
- sh.exec(`git init --bare .`);
65
- sh.exec(`git clone ${bare} ${target}`);
66
- sh.pushd('-q', target);
65
+ process.chdir(bare);
66
+ childProcess.execSync(`git init --bare .`, execOpts);
67
+ childProcess.execSync(`git clone ${bare} ${target}`, execOpts);
68
+ process.chdir(target);
67
69
  gitAdd('line', 'file', 'Add file');
68
70
  t.context = { bare, target };
69
71
  });
@@ -73,28 +75,30 @@ test.serial.afterEach(() => {
73
75
  });
74
76
 
75
77
  test.serial('should run tasks without throwing errors', async t => {
76
- sh.mv('.git', 'foo');
78
+ renameSync('.git', 'foo');
77
79
  const { name, latestVersion, version } = await runTasks({}, getContainer());
78
80
  t.true(log.obtrusive.firstCall.args[0].includes(`release ${name} (${latestVersion}...${version})`));
79
81
  t.regex(log.log.lastCall.args[0], /Done \(in [0-9]+s\.\)/);
80
82
  });
81
83
 
82
84
  test.serial('should run tasks without package.json', async t => {
83
- sh.exec('git tag 1.0.0');
85
+ childProcess.execSync('git tag 1.0.0', execOpts);
84
86
  gitAdd('line', 'file', 'Add file');
85
87
  const { name } = await runTasks({}, getContainer({ increment: 'major', git: { commit: false } }));
86
88
  t.true(log.obtrusive.firstCall.args[0].includes(`release ${name} (1.0.0...2.0.0)`));
87
89
  t.regex(log.log.lastCall.args[0], /Done \(in [0-9]+s\.\)/);
88
90
  t.is(log.warn.callCount, 0);
89
91
  {
90
- const { stdout } = sh.exec('git describe --tags --match=* --abbrev=0');
92
+ const stdout = childProcess.execSync('git describe --tags --match=* --abbrev=0', {
93
+ encoding: 'utf-8'
94
+ });
91
95
  t.is(stdout.trim(), '2.0.0');
92
96
  }
93
97
  });
94
98
 
95
99
  test.serial('should disable plugins', async t => {
96
100
  gitAdd('{"name":"my-package","version":"1.2.3"}', 'package.json', 'Add package.json');
97
- sh.exec('git tag 1.2.3');
101
+ childProcess.execSync('git tag 1.2.3', execOpts);
98
102
  gitAdd('line', 'file', 'Add file');
99
103
  const container = getContainer({ increment: 'minor', git: false, npm: false });
100
104
  const { latestVersion, version } = await runTasks({}, container);
@@ -105,12 +109,12 @@ test.serial('should disable plugins', async t => {
105
109
 
106
110
  test.serial('should run tasks with minimal config and without any warnings/errors', async t => {
107
111
  gitAdd('{"name":"my-package","version":"1.2.3"}', 'package.json', 'Add package.json');
108
- sh.exec('git tag 1.2.3');
112
+ childProcess.execSync('git tag 1.2.3', execOpts);
109
113
  gitAdd('line', 'file', 'More file');
110
114
  await runTasks({}, getContainer({ increment: 'patch' }));
111
115
  t.true(log.obtrusive.firstCall.args[0].includes('release my-package (1.2.3...1.2.4)'));
112
116
  t.regex(log.log.lastCall.args[0], /Done \(in [0-9]+s\.\)/);
113
- const { stdout } = sh.exec('git describe --tags --match=* --abbrev=0');
117
+ const stdout = childProcess.execSync('git describe --tags --match=* --abbrev=0', { encoding: 'utf-8' });
114
118
  t.is(stdout.trim(), '1.2.4');
115
119
  });
116
120
 
@@ -119,22 +123,22 @@ test.serial('should use pkg.version', async t => {
119
123
  await runTasks({}, getContainer({ increment: 'minor' }));
120
124
  t.true(log.obtrusive.firstCall.args[0].includes('release my-package (1.2.3...1.3.0)'));
121
125
  t.regex(log.log.lastCall.args[0], /Done \(in [0-9]+s\.\)/);
122
- const { stdout } = sh.exec('git describe --tags --match=* --abbrev=0');
126
+ const stdout = childProcess.execSync('git describe --tags --match=* --abbrev=0', { encoding: 'utf-8' });
123
127
  t.is(stdout.trim(), '1.3.0');
124
128
  });
125
129
 
126
130
  test.serial('should use pkg.version (in sub dir) w/o tagging repo', async t => {
127
131
  gitAdd('{"name":"root-package","version":"1.0.0"}', 'package.json', 'Add package.json');
128
- sh.exec('git tag 1.0.0');
129
- sh.mkdir('my-package');
130
- sh.pushd('-q', 'my-package');
132
+ childProcess.execSync('git tag 1.0.0', execOpts);
133
+ mkdirSync('my-package');
134
+ process.chdir('my-package');
131
135
  gitAdd('{"name":"my-package","version":"1.2.3"}', 'package.json', 'Add package.json');
132
136
  const container = getContainer({ increment: 'minor', git: { tag: false } });
133
137
  const exec = sinon.spy(container.shell, 'exec');
134
138
  await runTasks({}, container);
135
139
  t.true(log.obtrusive.firstCall.args[0].endsWith('release my-package (1.2.3...1.3.0)'));
136
140
  t.regex(log.log.lastCall.args[0], /Done \(in [0-9]+s\.\)/);
137
- const { stdout } = sh.exec('git describe --tags --match=* --abbrev=0');
141
+ const stdout = childProcess.execSync('git describe --tags --match=* --abbrev=0', { encoding: 'utf-8' });
138
142
  t.is(stdout.trim(), '1.0.0');
139
143
  const npmArgs = getArgs(exec.args, 'npm');
140
144
  t.is(npmArgs[5], 'npm version 1.3.0 --no-git-tag-version');
@@ -143,12 +147,12 @@ test.serial('should use pkg.version (in sub dir) w/o tagging repo', async t => {
143
147
 
144
148
  test.serial('should ignore version in pkg.version and use git tag instead', async t => {
145
149
  gitAdd('{"name":"my-package","version":"0.0.0"}', 'package.json', 'Add package.json');
146
- sh.exec('git tag 1.1.1');
150
+ childProcess.execSync('git tag 1.1.1', execOpts);
147
151
  gitAdd('line', 'file', 'More file');
148
152
  await runTasks({}, getContainer({ increment: 'minor', npm: { ignoreVersion: true } }));
149
153
  t.true(log.obtrusive.firstCall.args[0].includes('release my-package (1.1.1...1.2.0)'));
150
154
  t.regex(log.log.lastCall.args[0], /Done \(in [0-9]+s\.\)/);
151
- const { stdout } = sh.exec('git describe --tags --match=* --abbrev=0');
155
+ const stdout = childProcess.execSync('git describe --tags --match=* --abbrev=0', { encoding: 'utf-8' });
152
156
  t.is(stdout.trim(), '1.2.0');
153
157
  });
154
158
 
@@ -158,7 +162,7 @@ test.serial('should release all the things (basic)', async t => {
158
162
  const pkgName = path.basename(target);
159
163
  const owner = path.basename(path.dirname(bare));
160
164
  gitAdd(`{"name":"${pkgName}","version":"1.0.0"}`, 'package.json', 'Add package.json');
161
- sh.exec('git tag 1.0.0');
165
+ childProcess.execSync('git tag 1.0.0', execOpts);
162
166
  const sha = gitAdd('line', 'file', 'More file');
163
167
 
164
168
  interceptGitHubAuthentication();
@@ -201,10 +205,10 @@ test.serial('should release with correct tag name', async t => {
201
205
  const project = path.basename(bare);
202
206
  const pkgName = path.basename(target);
203
207
  const owner = path.basename(path.dirname(bare));
204
- const { stdout } = sh.exec('git rev-parse --abbrev-ref HEAD');
208
+ const stdout = childProcess.execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf-8' });
205
209
  const branchName = stdout.trim();
206
210
  gitAdd(`{"name":"${pkgName}","version":"1.0.0"}`, 'package.json', 'Add package.json');
207
- sh.exec(`git tag ${pkgName}-${branchName}-1.0.0`);
211
+ childProcess.execSync(`git tag ${pkgName}-${branchName}-1.0.0`, execOpts);
208
212
  const sha = gitAdd('line', 'file', 'More file');
209
213
 
210
214
  interceptGitHubCreate({
@@ -246,9 +250,9 @@ test.serial('should release all the things (pre-release, github, gitlab)', async
246
250
  const owner = path.basename(path.dirname(bare));
247
251
  const url = `https://gitlab.com/${owner}/${project}`;
248
252
  gitAdd(`{"name":"${pkgName}","version":"1.0.0"}`, 'package.json', 'Add package.json');
249
- sh.exec('git tag v1.0.0');
253
+ childProcess.execSync('git tag v1.0.0', execOpts);
250
254
  const sha = gitAdd('line', 'file', 'More file');
251
- sh.exec('git push --follow-tags');
255
+ childProcess.execSync('git push --follow-tags', execOpts);
252
256
  const git = factory(Git);
253
257
  const ref = (await git.getBranchName()) ?? 'HEAD';
254
258
 
@@ -327,13 +331,17 @@ test.serial('should release all the things (pre-release, github, gitlab)', async
327
331
  'npm publish . --tag alpha'
328
332
  ]);
329
333
 
330
- const { stdout: commitMessage } = sh.exec('git log --oneline --format=%B -n 1 HEAD');
334
+ const commitMessage = childProcess.execSync('git log --oneline --format=%B -n 1 HEAD', {
335
+ encoding: 'utf-8'
336
+ });
331
337
  t.is(commitMessage.trim(), `Release 1.1.0-alpha.0 for ${pkgName} (from 1.0.0)`);
332
338
 
333
- const { stdout: tagName } = sh.exec('git describe --tags --match=* --abbrev=0');
339
+ const tagName = childProcess.execSync('git describe --tags --match=* --abbrev=0', { encoding: 'utf-8' });
334
340
  t.is(tagName.trim(), 'v1.1.0-alpha.0');
335
341
 
336
- const { stdout: tagAnnotation } = sh.exec('git for-each-ref refs/tags/v1.1.0-alpha.0 --format="%(contents)"');
342
+ const tagAnnotation = childProcess.execSync('git for-each-ref refs/tags/v1.1.0-alpha.0 --format="%(contents)"', {
343
+ encoding: 'utf-8'
344
+ });
337
345
  t.is(tagAnnotation.trim(), `${owner} ${owner}/${project} ${project}`);
338
346
 
339
347
  t.true(log.obtrusive.firstCall.args[0].endsWith(`release ${pkgName} (1.0.0...1.1.0-alpha.0)`));
@@ -349,7 +357,7 @@ test.serial('should publish pre-release without pre-id with different npm.tag',
349
357
  const { target } = t.context;
350
358
  const pkgName = path.basename(target);
351
359
  gitAdd(`{"name":"${pkgName}","version":"1.0.0"}`, 'package.json', 'Add package.json');
352
- sh.exec('git tag v1.0.0');
360
+ childProcess.execSync('git tag v1.0.0', execOpts);
353
361
 
354
362
  const container = getContainer({ increment: 'major', preRelease: true, npm: { name: pkgName, tag: 'next' } });
355
363
  const exec = sinon.spy(container.shell, 'exec');
@@ -367,7 +375,7 @@ test.serial('should publish pre-release without pre-id with different npm.tag',
367
375
  'npm publish . --tag next'
368
376
  ]);
369
377
 
370
- const { stdout } = sh.exec('git describe --tags --match=* --abbrev=0');
378
+ const stdout = childProcess.execSync('git describe --tags --match=* --abbrev=0', { encoding: 'utf-8' });
371
379
  t.is(stdout.trim(), 'v2.0.0-0');
372
380
  t.true(log.obtrusive.firstCall.args[0].endsWith(`release ${pkgName} (1.0.0...2.0.0-0)`));
373
381
  t.true(log.log.firstCall.args[0].endsWith(`https://www.npmjs.com/package/${pkgName}`));
@@ -459,7 +467,7 @@ test.serial('should use custom changelog command with context', async t => {
459
467
  const { bare } = t.context;
460
468
  const project = path.basename(bare);
461
469
  const owner = path.basename(path.dirname(bare));
462
- sh.exec('git tag v1.0.0');
470
+ childProcess.execSync('git tag v1.0.0', execOpts);
463
471
  gitAdd('line', 'file', 'More file');
464
472
 
465
473
  interceptGitHubAuthentication();
@@ -499,10 +507,10 @@ test.serial('should use custom changelog command with context', async t => {
499
507
  {
500
508
  test.serial('should run all hooks', async t => {
501
509
  gitAdd(`{"name":"hooked","version":"1.0.0","type":"module"}`, 'package.json', 'Add package.json');
502
- sh.exec(`npm install ${rootDir}`);
510
+ childProcess.execSync(`npm install ${rootDir}`, execOpts);
503
511
  const plugin = "import { Plugin } from 'release-it'; class MyPlugin extends Plugin {}; export default MyPlugin;";
504
- sh.ShellString(plugin).toEnd('my-plugin.js');
505
512
 
513
+ appendFileSync('my-plugin.js', plugin);
506
514
  const hooks = {};
507
515
  ['before', 'after'].forEach(prefix => {
508
516
  ['version', 'git', 'npm', 'my-plugin'].forEach(ns => {
@@ -1,24 +1,26 @@
1
- import fs from 'node:fs';
1
+ import { appendFileSync, mkdirSync, mkdtempSync, promises } from 'node:fs';
2
2
  import os from 'node:os';
3
3
  import path from 'node:path';
4
- import sh from 'shelljs';
4
+ import childProcess from 'node:child_process';
5
+ import { execOpts } from '../../lib/util.js';
5
6
 
6
7
  const mkTmpDir = () => {
7
- const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'release-it-'));
8
+ const dir = mkdtempSync(path.join(os.tmpdir(), 'release-it-'));
8
9
  return dir;
9
10
  };
10
11
 
11
- const readFile = file => fs.promises.readFile(path.resolve(file), 'utf8');
12
+ const readFile = file => promises.readFile(path.resolve(file), 'utf8');
12
13
 
13
14
  const gitAdd = (content, filePath, message) => {
14
15
  const pathSegments = filePath.split('/').filter(Boolean);
15
16
  pathSegments.pop();
16
17
  if (pathSegments.length) {
17
- sh.mkdir('-p', pathSegments.join('/'));
18
+ mkdirSync(path.resolve(pathSegments.join('/')), { mode: parseInt('0777', 8), recursive: true });
18
19
  }
19
- sh.ShellString(content).toEnd(filePath);
20
- sh.exec(`git add ${filePath}`);
21
- const { stdout } = sh.exec(`git commit -m "${message}"`);
20
+
21
+ appendFileSync(filePath, content);
22
+ childProcess.execSync(`git add ${filePath}`, execOpts);
23
+ const stdout = childProcess.execSync(`git commit -m "${message}"`, { encoding: 'utf-8' });
22
24
  const match = stdout.match(/\[.+([a-z0-9]{7})\]/);
23
25
  return match ? match[1] : null;
24
26
  };
@@ -20,6 +20,7 @@ export let factory = (Definition, { namespace, options = {}, container = {} } =
20
20
  spinner.show.callsFake(({ enabled = true, task }) => (enabled ? task() : () => {}));
21
21
  container.spinner = spinner;
22
22
  container.shell = container.shell || new ShellStub({ container });
23
+
23
24
  container.prompt = container.prompt || new Prompt({ container });
24
25
  container.shell.cache = { set: () => {}, has: () => false };
25
26
 
@@ -1,5 +1,3 @@
1
- import shelljs from 'shelljs';
2
1
  import nock from 'nock';
3
2
 
4
- shelljs.config.silent = true;
5
3
  nock.disableNetConnect();
@@ -0,0 +1,18 @@
1
+ import { spawnSync } from 'node:child_process';
2
+
3
+ const getCommandAndArgs = input => {
4
+ if (typeof input !== 'string' || !input.trim()) {
5
+ throw new Error('Invalid input: expected a non-empty string.');
6
+ }
7
+
8
+ const [command, ...args] = input.trim().split(/\s+/);
9
+
10
+ return [command, args];
11
+ };
12
+
13
+ const exec = (command, opts = { stdio: 'inherit' }) => {
14
+ const [cmd, args] = getCommandAndArgs(command);
15
+ return spawnSync(cmd, args, opts);
16
+ };
17
+
18
+ export default { getCommandAndArgs, exec };