release-it 15.6.1 → 15.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.
package/bin/release-it.js CHANGED
@@ -38,5 +38,5 @@ const options = parseCliArguments([].slice.call(process.argv, 2));
38
38
  updater({ pkg: pkg }).notify();
39
39
  release(options).then(
40
40
  () => process.exit(0),
41
- () => process.exit(1)
41
+ ({ code }) => process.exit(Number.isInteger(code) ? code : 1)
42
42
  );
@@ -6,6 +6,8 @@
6
6
  "requireBranch": false,
7
7
  "requireUpstream": true,
8
8
  "requireCommits": false,
9
+ "requireCommitsFail": true,
10
+ "commitsPath": "",
9
11
  "addUntrackedFiles": false,
10
12
  "commit": true,
11
13
  "commitMessage": "Release ${version}",
@@ -46,8 +46,8 @@ class Git extends GitBase {
46
46
  if (this.options.requireUpstream && !(await this.hasUpstreamBranch())) {
47
47
  throw e(`No upstream configured for current branch.${EOL}Please set an upstream branch.`, docs);
48
48
  }
49
- if (this.options.requireCommits && (await this.getCommitsSinceLatestTag()) === 0) {
50
- throw e(`There are no commits since the latest tag.`, docs);
49
+ if (this.options.requireCommits && (await this.getCommitsSinceLatestTag(this.options.commitsPath)) === 0) {
50
+ throw e(`There are no commits since the latest tag.`, docs, this.options.requireCommitsFail);
51
51
  }
52
52
  }
53
53
 
@@ -120,10 +120,10 @@ class Git extends GitBase {
120
120
  );
121
121
  }
122
122
 
123
- async getCommitsSinceLatestTag() {
123
+ async getCommitsSinceLatestTag(commitsPath = '') {
124
124
  const latestTagName = await this.getLatestTagName();
125
125
  const ref = latestTagName ? `${latestTagName}..HEAD` : 'HEAD';
126
- return this.exec(`git rev-list ${ref} --count`, { options }).then(Number);
126
+ return this.exec(`git rev-list ${ref} --count ${commitsPath}`, { options }).then(Number);
127
127
  }
128
128
 
129
129
  async getUpstreamArgs(pushRepo) {
@@ -31,6 +31,12 @@ const parseErrormsg = err => {
31
31
  return msg;
32
32
  };
33
33
 
34
+ const truncateBody = body => {
35
+ // https://github.com/release-it/release-it/issues/965
36
+ if (body && body.length >= 124000) return body.substring(0, 124000) + '...';
37
+ return body;
38
+ };
39
+
34
40
  class GitHub extends Release {
35
41
  constructor(...args) {
36
42
  super(...args);
@@ -200,7 +206,7 @@ class GitHub extends Release {
200
206
  const { version, releaseNotes, isUpdate } = this.getContext();
201
207
  const { isPreRelease } = parseVersion(version);
202
208
  const name = format(releaseName, this.config.getContext());
203
- const body = autoGenerate ? (isUpdate ? null : '') : releaseNotes;
209
+ const body = autoGenerate ? (isUpdate ? null : '') : truncateBody(releaseNotes);
204
210
 
205
211
  return Object.assign(options, {
206
212
  owner,
@@ -91,6 +91,7 @@ class npm extends Plugin {
91
91
 
92
92
  release() {
93
93
  if (this.options.publish === false) return false;
94
+ if (this.getContext('private')) return false;
94
95
  const publish = () => this.publish({ otpCallback });
95
96
  const otpCallback =
96
97
  this.config.isCI && !this.config.isPromptOnlyVersion ? null : task => this.step({ prompt: 'otp', task });
package/lib/util.js CHANGED
@@ -89,7 +89,11 @@ const parseVersion = raw => {
89
89
  };
90
90
  };
91
91
 
92
- const e = (message, docs) => new Error(docs ? `${message}${EOL}Documentation: ${docs}${EOL}` : message);
92
+ const e = (message, docs, fail = true) => {
93
+ const error = new Error(docs ? `${message}${EOL}Documentation: ${docs}${EOL}` : message);
94
+ error.code = fail ? 1 : 0;
95
+ return error;
96
+ };
93
97
 
94
98
  export {
95
99
  getSystemInfo,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "release-it",
3
- "version": "15.6.1",
3
+ "version": "15.8.0",
4
4
  "description": "Generic CLI tool to automate versioning and package publishing related tasks.",
5
5
  "keywords": [
6
6
  "build",
@@ -67,7 +67,7 @@
67
67
  "execa": "7.0.0",
68
68
  "git-url-parse": "13.1.0",
69
69
  "globby": "13.1.3",
70
- "got": "12.5.3",
70
+ "got": "12.6.0",
71
71
  "inquirer": "9.1.4",
72
72
  "is-ci": "3.0.1",
73
73
  "lodash": "4.17.21",
@@ -90,7 +90,7 @@
90
90
  "@octokit/request-error": "3.0.3",
91
91
  "ava": "5.2.0",
92
92
  "eslint": "8.35.0",
93
- "eslint-config-prettier": "8.6.0",
93
+ "eslint-config-prettier": "8.7.0",
94
94
  "eslint-plugin-ava": "14.0.0",
95
95
  "eslint-plugin-import": "2.27.5",
96
96
  "eslint-plugin-prettier": "4.2.1",
package/test/git.init.js CHANGED
@@ -72,6 +72,36 @@ test.serial('should not throw if there are commits', async t => {
72
72
  await t.notThrowsAsync(gitClient.init());
73
73
  });
74
74
 
75
+ test.serial('should fail (exit code 1) if there are no commits', async t => {
76
+ const options = { git: { requireCommits: true } };
77
+ const gitClient = factory(Git, { options });
78
+ sh.exec('git tag 1.0.0');
79
+ await t.throwsAsync(gitClient.init(), { code: 1 });
80
+ });
81
+
82
+ test.serial('should not fail (exit code 0) if there are no commits', async t => {
83
+ const options = { git: { requireCommits: true, requireCommitsFail: false } };
84
+ const gitClient = factory(Git, { options });
85
+ sh.exec('git tag 1.0.0');
86
+ await t.throwsAsync(gitClient.init(), { code: 0 });
87
+ });
88
+
89
+ test.serial('should throw if there are no commits in specified path', async t => {
90
+ const options = { git: { requireCommits: true, commitsPath: 'dir' } };
91
+ const gitClient = factory(Git, { options });
92
+ sh.mkdir('dir');
93
+ sh.exec('git tag 1.0.0');
94
+ await t.throwsAsync(gitClient.init(), { message: /^There are no commits since the latest tag/ });
95
+ });
96
+
97
+ test.serial('should not throw if there are commits in specified path', async t => {
98
+ const options = { git: { requireCommits: true, commitsPath: 'dir' } };
99
+ const gitClient = factory(Git, { options });
100
+ sh.exec('git tag 1.0.0');
101
+ gitAdd('line', 'dir/file', 'Add file');
102
+ await t.notThrowsAsync(gitClient.init());
103
+ });
104
+
75
105
  test.serial('should not throw if there are no tags', async t => {
76
106
  const options = { git: { requireCommits: true } };
77
107
  const gitClient = factory(Git, { options });
package/test/github.js CHANGED
@@ -425,3 +425,34 @@ test('should generate GitHub web release url for enterprise host', async t => {
425
425
  );
426
426
  exec.restore();
427
427
  });
428
+
429
+ // eslint-disable-next-line ava/no-skip-test
430
+ test.skip('should truncate long body', async t => {
431
+ const releaseNotes = 'a'.repeat(125001);
432
+ const body = 'a'.repeat(124000) + '...';
433
+ const options = {
434
+ git,
435
+ github: {
436
+ pushRepo,
437
+ tokenRef,
438
+ release: true,
439
+ releaseName: 'Release ${tagName}',
440
+ releaseNotes: 'echo ' + releaseNotes
441
+ }
442
+ };
443
+ const github = factory(GitHub, { options });
444
+ const exec = sinon.stub(github.shell, 'exec').callThrough();
445
+ exec.withArgs('git log --pretty=format:"* %s (%h)" ${from}...${to}').resolves('');
446
+ exec.withArgs('git describe --tags --match=* --abbrev=0').resolves('2.0.1');
447
+
448
+ interceptAuthentication();
449
+ interceptCollaborator();
450
+ interceptCreate({ body: { tag_name: '2.0.2', name: 'Release 2.0.2', body } });
451
+
452
+ await runTasks(github);
453
+
454
+ const { isReleased, releaseUrl } = github.getContext();
455
+ t.true(isReleased);
456
+ t.is(releaseUrl, 'https://github.com/user/repo/releases/tag/2.0.2');
457
+ exec.restore();
458
+ });
@@ -30,7 +30,7 @@ const interceptListReleases = ({
30
30
  upload_url: `https://uploads.${host}/repos/${owner}/${project}/releases/1/assets{?name,label}`,
31
31
  html_url: `https://${host}/${owner}/${project}/releases/tag/${tag_name}`,
32
32
  tag_name,
33
- target_commitish: 'master',
33
+ target_commitish: 'main',
34
34
  name: `Release ${tag_name}`,
35
35
  body: 'Description of the release',
36
36
  draft: false,
package/test/tasks.js CHANGED
@@ -51,6 +51,10 @@ const getContainer = options => {
51
51
  };
52
52
  };
53
53
 
54
+ test.before(t => {
55
+ t.timeout(90 * 1000);
56
+ });
57
+
54
58
  test.serial.beforeEach(t => {
55
59
  const bare = mkTmpDir();
56
60
  const target = mkTmpDir();
@@ -380,7 +384,7 @@ test.serial('should handle private package correctly, bump lockfile', async t =>
380
384
  const npmArgs = getArgs(container.shell.exec.args, 'npm');
381
385
  t.deepEqual(npmArgs, ['npm version 1.0.1 --no-git-tag-version']);
382
386
  t.true(log.obtrusive.firstCall.args[0].endsWith(`release ${pkgName} (1.0.0...1.0.1)`));
383
- t.is(log.warn.lastCall.args[0], 'Skip publish: package is private.');
387
+ t.is(log.warn.length, 0);
384
388
  t.regex(log.log.firstCall.args[0], /Done \(in [0-9]+s\.\)/);
385
389
 
386
390
  exec.restore();
@@ -10,9 +10,14 @@ const mkTmpDir = () => {
10
10
 
11
11
  const readFile = file => fs.promises.readFile(path.resolve(file), 'utf8');
12
12
 
13
- const gitAdd = (content, file, message) => {
14
- sh.ShellString(content).toEnd(file);
15
- sh.exec(`git add ${file}`);
13
+ const gitAdd = (content, filePath, message) => {
14
+ const pathSegments = filePath.split('/').filter(Boolean);
15
+ pathSegments.pop();
16
+ if (pathSegments.length) {
17
+ sh.mkdir('-p', pathSegments.join('/'));
18
+ }
19
+ sh.ShellString(content).toEnd(filePath);
20
+ sh.exec(`git add ${filePath}`);
16
21
  const { stdout } = sh.exec(`git commit -m "${message}"`);
17
22
  const match = stdout.match(/\[.+([a-z0-9]{7})\]/);
18
23
  return match ? match[1] : null;