release-it 18.1.2 → 19.0.0-next.1

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