release-it 0.0.0-pl.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 (64) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +421 -0
  3. package/bin/release-it.js +42 -0
  4. package/config/release-it.json +70 -0
  5. package/lib/cli.js +44 -0
  6. package/lib/config.js +139 -0
  7. package/lib/index.js +152 -0
  8. package/lib/log.js +69 -0
  9. package/lib/plugin/GitBase.js +125 -0
  10. package/lib/plugin/GitRelease.js +58 -0
  11. package/lib/plugin/Plugin.js +73 -0
  12. package/lib/plugin/factory.js +89 -0
  13. package/lib/plugin/git/Git.js +220 -0
  14. package/lib/plugin/git/prompts.js +19 -0
  15. package/lib/plugin/github/GitHub.js +403 -0
  16. package/lib/plugin/github/prompts.js +16 -0
  17. package/lib/plugin/github/util.js +39 -0
  18. package/lib/plugin/gitlab/GitLab.js +277 -0
  19. package/lib/plugin/gitlab/prompts.js +9 -0
  20. package/lib/plugin/npm/npm.js +281 -0
  21. package/lib/plugin/npm/prompts.js +12 -0
  22. package/lib/plugin/version/Version.js +129 -0
  23. package/lib/prompt.js +33 -0
  24. package/lib/shell.js +91 -0
  25. package/lib/spinner.js +29 -0
  26. package/lib/util.js +109 -0
  27. package/package.json +122 -0
  28. package/test/cli.js +20 -0
  29. package/test/config.js +144 -0
  30. package/test/git.init.js +250 -0
  31. package/test/git.js +358 -0
  32. package/test/github.js +487 -0
  33. package/test/gitlab.js +252 -0
  34. package/test/log.js +143 -0
  35. package/test/npm.js +417 -0
  36. package/test/plugin-name.js +9 -0
  37. package/test/plugins.js +238 -0
  38. package/test/prompt.js +97 -0
  39. package/test/resources/file-v2.0.1.txt +1 -0
  40. package/test/resources/file-v2.0.2.txt +1 -0
  41. package/test/resources/file1 +1 -0
  42. package/test/shell.js +74 -0
  43. package/test/spinner.js +58 -0
  44. package/test/stub/config/default/.release-it.json +5 -0
  45. package/test/stub/config/invalid-config-rc +1 -0
  46. package/test/stub/config/invalid-config-txt +2 -0
  47. package/test/stub/config/merge/.release-it.json +5 -0
  48. package/test/stub/config/merge/package.json +7 -0
  49. package/test/stub/config/toml/.release-it.toml +2 -0
  50. package/test/stub/config/yaml/.release-it.yaml +2 -0
  51. package/test/stub/config/yml/.release-it.yml +2 -0
  52. package/test/stub/github.js +130 -0
  53. package/test/stub/gitlab.js +44 -0
  54. package/test/stub/plugin-context.js +36 -0
  55. package/test/stub/plugin-replace.js +9 -0
  56. package/test/stub/plugin.js +39 -0
  57. package/test/stub/shell.js +24 -0
  58. package/test/tasks.interactive.js +208 -0
  59. package/test/tasks.js +585 -0
  60. package/test/util/helpers.js +32 -0
  61. package/test/util/index.js +78 -0
  62. package/test/util/setup.js +5 -0
  63. package/test/utils.js +97 -0
  64. package/test/version.js +173 -0
package/test/prompt.js ADDED
@@ -0,0 +1,97 @@
1
+ import test from 'ava';
2
+ import sinon from 'sinon';
3
+ import Prompt from '../lib/prompt.js';
4
+ import Config from '../lib/config.js';
5
+ import git from '../lib/plugin/git/prompts.js';
6
+ import github from '../lib/plugin/github/prompts.js';
7
+ import gitlab from '../lib/plugin/gitlab/prompts.js';
8
+ import npm from '../lib/plugin/npm/prompts.js';
9
+ import { factory } from './util/index.js';
10
+
11
+ const prompts = { git, github, gitlab, npm };
12
+
13
+ const yes = ([options]) => Promise.resolve({ [options.name]: true });
14
+ const no = ([options]) => Promise.resolve({ [options.name]: false });
15
+
16
+ test.beforeEach(t => {
17
+ t.context.getInquirer = stub => ({
18
+ prompt: stub
19
+ });
20
+ });
21
+
22
+ test('should not create prompt if disabled', async t => {
23
+ const task = sinon.spy();
24
+ const stub = sinon.stub().callsFake(yes);
25
+ const inquirer = t.context.getInquirer(stub);
26
+ const prompt = factory(Prompt, { container: { inquirer } });
27
+ prompt.register(prompts.git);
28
+ await prompt.show({ enabled: false, prompt: 'push', task });
29
+ t.is(stub.callCount, 0);
30
+ t.is(task.callCount, 0);
31
+ });
32
+
33
+ test('should create prompt', async t => {
34
+ const stub = sinon.stub().callsFake(yes);
35
+ const inquirer = t.context.getInquirer(stub);
36
+ const prompt = factory(Prompt, { container: { inquirer } });
37
+ prompt.register(prompts.git);
38
+ await prompt.show({ prompt: 'push' });
39
+ t.is(stub.callCount, 1);
40
+ t.deepEqual(stub.firstCall.args[0][0], {
41
+ type: 'confirm',
42
+ message: 'Push?',
43
+ name: 'push',
44
+ choices: false,
45
+ transformer: false,
46
+ default: true
47
+ });
48
+ });
49
+
50
+ [
51
+ ['git', 'commit', 'Commit (Release 1.0.0)?'],
52
+ ['git', 'tag', 'Tag (1.0.0)?'],
53
+ ['git', 'push', 'Push?'],
54
+ ['github', 'release', 'Create a pre-release on GitHub (Release 1.0.0)?'],
55
+ ['gitlab', 'release', 'Create a release on GitLab (Release 1.0.0)?'],
56
+ ['npm', 'publish', 'Publish my-pkg@next to npm?'],
57
+ ['npm', 'otp', 'Please enter OTP for npm:']
58
+ ].map(async ([namespace, prompt, message]) => {
59
+ test(`should create prompt and render template message (${namespace}.${prompt})`, async t => {
60
+ const stub = sinon.stub().callsFake(yes);
61
+ const config = new Config({
62
+ isPreRelease: true,
63
+ git: { tagName: 'v${version}' },
64
+ npm: { name: 'my-pkg', tag: 'next' }
65
+ });
66
+ config.setContext({ version: '1.0.0', tagName: '1.0.0' });
67
+ const inquirer = t.context.getInquirer(stub);
68
+ const p = factory(Prompt, { container: { inquirer } });
69
+ p.register(prompts[namespace], namespace);
70
+ await p.show({ namespace, prompt, context: config.getContext() });
71
+ t.is(stub.callCount, 1);
72
+ t.is(stub.firstCall.args[0][0].message, message);
73
+ });
74
+ });
75
+
76
+ test('should execute task after positive answer', async t => {
77
+ const task = sinon.spy();
78
+ const stub = sinon.stub().callsFake(yes);
79
+ const inquirer = t.context.getInquirer(stub);
80
+ const prompt = factory(Prompt, { container: { inquirer } });
81
+ prompt.register(prompts.git);
82
+ await prompt.show({ prompt: 'push', task });
83
+ t.is(stub.callCount, 1);
84
+ t.is(task.callCount, 1);
85
+ t.is(task.firstCall.args[0], true);
86
+ });
87
+
88
+ test('should not execute task after negative answer', async t => {
89
+ const task = sinon.spy();
90
+ const stub = sinon.stub().callsFake(no);
91
+ const inquirer = t.context.getInquirer(stub);
92
+ const prompt = factory(Prompt, { container: { inquirer } });
93
+ prompt.register(prompts.git);
94
+ await prompt.show({ prompt: 'push', task });
95
+ t.is(stub.callCount, 1);
96
+ t.is(task.callCount, 0);
97
+ });
@@ -0,0 +1 @@
1
+ *
@@ -0,0 +1 @@
1
+ *
@@ -0,0 +1 @@
1
+ file1
package/test/shell.js ADDED
@@ -0,0 +1,74 @@
1
+ import test from 'ava';
2
+ import sh from 'shelljs';
3
+ import sinon from 'sinon';
4
+ import Shell from '../lib/shell.js';
5
+ import Log from '../lib/log.js';
6
+ import { factory } from './util/index.js';
7
+
8
+ const { stdout } = sh.exec('pwd');
9
+ const cwd = stdout.trim();
10
+
11
+ const shell = factory(Shell);
12
+
13
+ test('exec', async t => {
14
+ t.is(await shell.exec('echo bar'), 'bar');
15
+ });
16
+
17
+ test('exec (with context)', async t => {
18
+ const exec = cmd => shell.exec(cmd, { verbose: false }, shell.config.getContext());
19
+ t.is(await exec(''), undefined);
20
+ t.is(await exec('pwd'), cwd);
21
+ t.is(await exec('echo ${git.pushArgs}'), '--follow-tags');
22
+ t.is(await exec('echo -*- ${github.tokenRef} -*-'), '-*- GITHUB_TOKEN -*-');
23
+ });
24
+
25
+ test('exec (with args)', async t => {
26
+ t.is(await shell.exec([]), undefined);
27
+ t.is(await shell.exec(['pwd']), cwd);
28
+ t.is(await shell.exec(['echo', 'a', 'b']), 'a b');
29
+ t.is(await shell.exec(['echo', '"a"']), '"a"');
30
+ });
31
+
32
+ test('exec (dry-run/read-only)', async t => {
33
+ const shell = factory(Shell, { options: { 'dry-run': true } });
34
+ {
35
+ const actual = await shell.exec('pwd', { write: false });
36
+ t.is(actual, cwd);
37
+ t.is(shell.log.exec.callCount, 1);
38
+ t.is(shell.log.exec.firstCall.args[0], 'pwd');
39
+ }
40
+ {
41
+ const actual = await shell.exec('pwd');
42
+ t.is(actual, undefined);
43
+ t.is(shell.log.exec.callCount, 2);
44
+ t.is(shell.log.exec.secondCall.args[0], 'pwd');
45
+ t.deepEqual(shell.log.exec.secondCall.lastArg, { isDryRun: true });
46
+ }
47
+ });
48
+
49
+ test('exec (verbose)', async t => {
50
+ const shell = factory(Shell, { options: { verbose: true } });
51
+ const actual = await shell.exec('echo foo');
52
+ t.is(shell.log.exec.firstCall.args[0], 'echo foo');
53
+ t.is(shell.log.exec.callCount, 1);
54
+ t.is(shell.log.verbose.firstCall.args[0], 'foo');
55
+ t.is(shell.log.verbose.callCount, 1);
56
+ t.is(actual, 'foo');
57
+ });
58
+
59
+ test('should cache results of command execution', async t => {
60
+ const log = sinon.createStubInstance(Log);
61
+ const shell = factory(Shell, { container: { log } });
62
+ const result1 = await shell.exec('echo foo');
63
+ const result2 = await shell.exec('echo foo');
64
+ t.is(result1, result2);
65
+ t.deepEqual(log.exec.args, [
66
+ ['echo foo', { isExternal: false, isCached: false }],
67
+ ['echo foo', { isExternal: false, isCached: true }]
68
+ ]);
69
+ });
70
+
71
+ test('should bail out on failed command execution', async t => {
72
+ const shell = new Shell({ container: { log: sinon.createStubInstance(Log) } });
73
+ await t.throwsAsync(shell.exec('foo'));
74
+ });
@@ -0,0 +1,58 @@
1
+ import test from 'ava';
2
+ import sinon from 'sinon';
3
+ import Spinner from '../lib/spinner.js';
4
+ import Config from '../lib/config.js';
5
+
6
+ test.beforeEach(t => {
7
+ t.context.ora = sinon.spy();
8
+ });
9
+
10
+ const getConfig = options => {
11
+ const testConfig = {
12
+ ci: false,
13
+ config: false
14
+ };
15
+ return new Config(Object.assign({}, testConfig, options));
16
+ };
17
+
18
+ test('should not show spinner and not execute task if disabled', async t => {
19
+ const { ora } = t.context;
20
+ const task = sinon.spy();
21
+ const spinner = new Spinner({ container: { ora } });
22
+ await spinner.show({ enabled: false, task });
23
+ t.is(task.callCount, 0);
24
+ t.is(ora.callCount, 0);
25
+ });
26
+
27
+ test('should show spinner and run task by default', async t => {
28
+ const { ora } = t.context;
29
+ const task = sinon.stub().resolves();
30
+ const label = 'foo';
31
+ const config = getConfig({ ci: true });
32
+ const spinner = new Spinner({ container: { ora, config } });
33
+ await spinner.show({ task, label });
34
+ t.is(task.callCount, 1);
35
+ t.is(ora.callCount, 1);
36
+ t.is(ora.firstCall.args[0], task.firstCall.returnValue);
37
+ t.is(ora.firstCall.args[1], label);
38
+ });
39
+
40
+ test('should run task, but not show spinner if interactive', async t => {
41
+ const { ora } = t.context;
42
+ const task = sinon.stub().resolves();
43
+ const config = getConfig({ ci: false });
44
+ const spinner = new Spinner({ container: { ora, config } });
45
+ await spinner.show({ task });
46
+ t.is(task.callCount, 1);
47
+ t.is(ora.callCount, 0);
48
+ });
49
+
50
+ test('should run task and show spinner if interactive, but external', async t => {
51
+ const { ora } = t.context;
52
+ const task = sinon.stub().resolves();
53
+ const config = getConfig({ ci: false });
54
+ const spinner = new Spinner({ container: { ora, config } });
55
+ await spinner.show({ task, external: true });
56
+ t.is(task.callCount, 1);
57
+ t.is(ora.callCount, 1);
58
+ });
@@ -0,0 +1,5 @@
1
+ {
2
+ "github": {
3
+ "release": true
4
+ }
5
+ }
@@ -0,0 +1 @@
1
+ foo=bar
@@ -0,0 +1,2 @@
1
+ foo
2
+ bar\baz
@@ -0,0 +1,5 @@
1
+ {
2
+ "github": {
3
+ "release": true
4
+ }
5
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "release-it": {
3
+ "git": {
4
+ "push": false
5
+ }
6
+ }
7
+ }
@@ -0,0 +1,2 @@
1
+ [foo]
2
+ bar=1
@@ -0,0 +1,2 @@
1
+ foo:
2
+ bar: 1
@@ -0,0 +1,2 @@
1
+ foo:
2
+ bar: 1
@@ -0,0 +1,130 @@
1
+ import nock from 'nock';
2
+
3
+ const interceptAuthentication = ({ api = 'https://api.github.com', username = 'john' } = {}) => {
4
+ nock(api).get('/user').reply(200, {
5
+ login: username
6
+ });
7
+ };
8
+
9
+ const interceptCollaborator = ({
10
+ api = 'https://api.github.com',
11
+ owner = 'user',
12
+ project = 'repo',
13
+ username = 'john'
14
+ } = {}) => {
15
+ nock(api).get(`/repos/${owner}/${project}/collaborators/${username}`).reply(204);
16
+ };
17
+
18
+ const interceptListReleases = ({
19
+ host = 'github.com',
20
+ api = 'https://api.github.com',
21
+ owner = 'user',
22
+ project = 'repo',
23
+ tag_name
24
+ } = {}) => {
25
+ nock(api)
26
+ .get(`/repos/${owner}/${project}/releases?per_page=1&page=1`)
27
+ .reply(200, [
28
+ {
29
+ id: 1,
30
+ upload_url: `https://uploads.${host}/repos/${owner}/${project}/releases/1/assets{?name,label}`,
31
+ html_url: `https://${host}/${owner}/${project}/releases/tag/${tag_name}`,
32
+ tag_name,
33
+ target_commitish: 'main',
34
+ name: `Release ${tag_name}`,
35
+ body: 'Description of the release',
36
+ draft: false,
37
+ prerelease: false
38
+ }
39
+ ]);
40
+ };
41
+
42
+ const interceptCreate = ({
43
+ api = 'https://api.github.com',
44
+ host = 'github.com',
45
+ owner = 'user',
46
+ project = 'repo',
47
+ body: { tag_name, name = '', generate_release_notes = false, body = null, prerelease = false, draft = false }
48
+ } = {}) => {
49
+ nock(api)
50
+ .post(`/repos/${owner}/${project}/releases`, {
51
+ tag_name,
52
+ name,
53
+ body,
54
+ prerelease,
55
+ draft,
56
+ generate_release_notes
57
+ })
58
+ .reply(() => {
59
+ const id = 1;
60
+ const responseBody = {
61
+ id,
62
+ tag_name,
63
+ name,
64
+ body,
65
+ prerelease,
66
+ draft,
67
+ generate_release_notes,
68
+ upload_url: `https://uploads.${host}/repos/${owner}/${project}/releases/${id}/assets{?name,label}`,
69
+ html_url: `https://${host}/${owner}/${project}/releases/tag/${tag_name}`
70
+ };
71
+ return [200, responseBody, { location: `${api}/repos/${owner}/${project}/releases/${id}` }];
72
+ });
73
+ };
74
+
75
+ const interceptUpdate = ({
76
+ host = 'github.com',
77
+ api = 'https://api.github.com',
78
+ owner = 'user',
79
+ project = 'repo',
80
+ body: { tag_name, name = '', body = null, prerelease = false, draft = false, generate_release_notes = false }
81
+ } = {}) => {
82
+ nock(api)
83
+ .patch(`/repos/${owner}/${project}/releases/1`, { tag_name, name, body, draft, prerelease, generate_release_notes })
84
+ .reply(200, {
85
+ id: 1,
86
+ tag_name,
87
+ name,
88
+ body,
89
+ prerelease,
90
+ draft,
91
+ generate_release_notes,
92
+ upload_url: `https://uploads.${host}/repos/${owner}/${project}/releases/1/assets{?name,label}`,
93
+ html_url: `https://${host}/${owner}/${project}/releases/tag/${tag_name}`
94
+ });
95
+ };
96
+
97
+ const interceptAsset = ({
98
+ api = 'https://api.github.com',
99
+ host = 'github.com',
100
+ owner = 'user',
101
+ project = 'repo',
102
+ tagName,
103
+ body = {}
104
+ } = {}) => {
105
+ nock(`https://uploads.${host}`)
106
+ .post(`/repos/${owner}/${project}/releases/1/assets`, body)
107
+ .query(true)
108
+ .reply(200, function () {
109
+ const id = 1;
110
+ const [, name] = this.req.path.match(/\?name=([^&]+)/);
111
+ return {
112
+ id,
113
+ url: `${api}/repos/${owner}/${project}/releases/assets/${id}`,
114
+ name,
115
+ label: '',
116
+ state: 'uploaded',
117
+ size: this.req.headers['content-length'],
118
+ browser_download_url: `https://${host}/${owner}/${project}/releases/download/${tagName}/${name}`
119
+ };
120
+ });
121
+ };
122
+
123
+ export {
124
+ interceptAuthentication,
125
+ interceptCollaborator,
126
+ interceptListReleases,
127
+ interceptCreate,
128
+ interceptUpdate,
129
+ interceptAsset
130
+ };
@@ -0,0 +1,44 @@
1
+ import nock from 'nock';
2
+
3
+ export let interceptUser = ({ host = 'https://gitlab.com', owner = 'user' } = {}, options) =>
4
+ nock(host, options).get('/api/v4/user').reply(200, { id: 1, username: owner });
5
+
6
+ export let interceptCollaborator = (
7
+ { host = 'https://gitlab.com', owner = 'user', project = 'repo', group, userId = 1 } = {},
8
+ options
9
+ ) =>
10
+ nock(host, options)
11
+ .get(`/api/v4/projects/${group ? `${group}%2F` : ''}${owner}%2F${project}/members/all/${userId}`)
12
+ .reply(200, { id: userId, username: owner, access_level: 30 });
13
+
14
+ export let interceptPublish = ({ host = 'https://gitlab.com', owner = 'user', project = 'repo', body } = {}, options) =>
15
+ nock(host, options).post(`/api/v4/projects/${owner}%2F${project}/releases`, body).reply(200, {});
16
+
17
+ export let interceptMilestones = (
18
+ { host = 'https://gitlab.com', owner = 'user', project = 'repo', query = {}, milestones = [] } = {},
19
+ options
20
+ ) =>
21
+ nock(host, options)
22
+ .get(`/api/v4/projects/${owner}%2F${project}/milestones`)
23
+ .query(
24
+ Object.assign(
25
+ {
26
+ include_parent_milestones: true
27
+ },
28
+ query
29
+ )
30
+ )
31
+ .reply(200, JSON.stringify(milestones));
32
+
33
+ export let interceptAsset = ({ host = 'https://gitlab.com', owner = 'user', project = 'repo' } = {}) =>
34
+ nock(host)
35
+ .post(`/api/v4/projects/${owner}%2F${project}/uploads`)
36
+ .query(true)
37
+ .reply(200, function (_, requestBody) {
38
+ const [, name] = requestBody.match(/filename="([^"]+)/);
39
+ return {
40
+ alt: name,
41
+ url: `/uploads/7e8bec1fe27cc46a4bc6a91b9e82a07c/${name}`,
42
+ markdown: `[${name}](/uploads/7e8bec1fe27cc46a4bc6a91b9e82a07c/${name})`
43
+ };
44
+ });
@@ -0,0 +1,36 @@
1
+ import Plugin from '../../lib/plugin/Plugin.js';
2
+
3
+ class ContextPlugin extends Plugin {
4
+ init() {
5
+ const context = this.config.getContext();
6
+ this.exec(`echo ${context.version.isPreRelease}`);
7
+ this.exec('echo ${version.isPreRelease}');
8
+ }
9
+ beforeBump() {
10
+ const context = this.config.getContext();
11
+ this.exec(`echo ${context.name} ${context.repo.owner} ${context.latestVersion} ${context.version}`);
12
+ this.exec('echo ${name} ${repo.owner} ${latestVersion} ${version}');
13
+ }
14
+ bump(version) {
15
+ const repo = this.config.getContext('repo');
16
+ this.exec(`echo ${repo.owner} ${repo.project} ${repo.repository} ${version}`);
17
+ this.exec('echo ${repo.owner} ${repo.project} ${repo.repository} ${version}');
18
+ }
19
+ beforeRelease() {
20
+ const { repo, tagName } = this.config.getContext();
21
+ this.exec(`echo ${repo.owner} ${repo.project} ${repo.repository} ${tagName}`);
22
+ this.exec('echo ${repo.owner} ${repo.project} ${repo.repository} ${tagName}');
23
+ }
24
+ release() {
25
+ const { repo, latestVersion, version, tagName } = this.config.getContext();
26
+ this.exec(`echo ${repo.project} ${latestVersion} ${version} ${tagName}`);
27
+ this.exec('echo ${repo.project} ${latestVersion} ${version} ${tagName}');
28
+ }
29
+ afterRelease() {
30
+ const { repo, latestVersion, version, tagName } = this.config.getContext();
31
+ this.exec(`echo ${repo.project} ${latestVersion} ${version} ${tagName}`);
32
+ this.exec('echo ${repo.project} ${latestVersion} ${version} ${tagName}');
33
+ }
34
+ }
35
+
36
+ export default ContextPlugin;
@@ -0,0 +1,9 @@
1
+ import Plugin from '../../lib/plugin/Plugin.js';
2
+
3
+ class ReplacePlugin extends Plugin {
4
+ static disablePlugin() {
5
+ return ['version', 'git', 'npm'];
6
+ }
7
+ }
8
+
9
+ export default ReplacePlugin;
@@ -0,0 +1,39 @@
1
+ import Plugin from '../../lib/plugin/Plugin.js';
2
+
3
+ class MyPlugin extends Plugin {
4
+ init() {
5
+ this.log.info(`${this.namespace}:${this.getContext('name')}:init`);
6
+ }
7
+ getName() {
8
+ this.log.info(`${this.namespace}:${this.getContext('name')}:getName`);
9
+ return 'new-project-name';
10
+ }
11
+ getLatestVersion() {
12
+ this.log.info(`${this.namespace}:${this.getContext('name')}:getLatestVersion`);
13
+ return '1.2.3';
14
+ }
15
+ getIncrement() {
16
+ this.log.info(`${this.namespace}:${this.getContext('name')}:getIncrement`);
17
+ return 'minor';
18
+ }
19
+ getIncrementedVersionCI() {
20
+ this.log.info(`${this.namespace}:${this.getContext('name')}:getIncrementedVersionCI`);
21
+ }
22
+ beforeBump() {
23
+ this.log.info(`${this.namespace}:${this.getContext('name')}:beforeBump`);
24
+ }
25
+ bump(version) {
26
+ this.log.info(`${this.namespace}:${this.getContext('name')}:bump:${version}`);
27
+ }
28
+ beforeRelease() {
29
+ this.log.info(`${this.namespace}:${this.getContext('name')}:beforeRelease`);
30
+ }
31
+ release() {
32
+ this.log.info(`${this.namespace}:${this.getContext('name')}:release`);
33
+ }
34
+ afterRelease() {
35
+ this.log.info(`${this.namespace}:${this.getContext('name')}:afterRelease`);
36
+ }
37
+ }
38
+
39
+ export default MyPlugin;
@@ -0,0 +1,24 @@
1
+ import util from 'node:util';
2
+ import Shell from '../../lib/shell.js';
3
+
4
+ const debug = util.debug('release-it:shell-stub');
5
+
6
+ class ShellStub extends Shell {
7
+ exec(command) {
8
+ if (/^(npm (ping|publish|show)|git fetch)/.test(command)) {
9
+ debug(command);
10
+ return Promise.resolve();
11
+ }
12
+ if (/^npm whoami/.test(command)) {
13
+ debug(command);
14
+ return Promise.resolve('john');
15
+ }
16
+ if (/^npm access/.test(command)) {
17
+ debug(command);
18
+ return Promise.resolve(JSON.stringify({ john: ['write'] }));
19
+ }
20
+ return super.exec(...arguments);
21
+ }
22
+ }
23
+
24
+ export default ShellStub;