Skip to content

Commit 8fbfe73

Browse files
authored
Chore: Add release script (#25)
1 parent 56873bf commit 8fbfe73

File tree

4 files changed

+115
-2
lines changed

4 files changed

+115
-2
lines changed

CONTRIBUTING.md

+10
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,13 @@ npm test
1919
This is an [ESLint](http://eslint.org) plugin. Documentation for the APIs that it uses can be found on ESLint's [Working with Plugins](http://eslint.org/docs/developer-guide/working-with-plugins) page.
2020

2121
This plugin is used to lint itself. The style is checked when `npm test` is run, and the build will fail if there are any linting errors. You can use `npm run lint -- --fix` to fix some linting errors. To run the tests without running the linter, you can use `node_modules/.bin/mocha`.
22+
23+
## Publishing
24+
25+
```bash
26+
node build/release.js
27+
git push --follow-tags
28+
npm publish
29+
```
30+
31+
`build/release.js` will generate a commit and tag like https://github.com/prettier/eslint-plugin-prettier/commit/56873bf2.

build/release.js

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
'use strict';
2+
3+
const fs = require('fs');
4+
const childProcess = require('child_process');
5+
const path = require('path');
6+
const semver = require('semver');
7+
const moment = require('moment');
8+
const PACKAGE_JSON_PATH = path.join(process.cwd(), 'package.json');
9+
const CHANGELOG_PATH = path.join(process.cwd(), 'CHANGELOG.md');
10+
const packageFile = require(PACKAGE_JSON_PATH);
11+
12+
function exec(command) {
13+
return childProcess.execSync(command).toString().slice(0, -1);
14+
}
15+
16+
const githubRepoUrl = exec('git config --get remote.origin.url').replace(
17+
/\.git$/,
18+
''
19+
);
20+
21+
function updatePackageJson(version) {
22+
fs.writeFileSync(
23+
PACKAGE_JSON_PATH,
24+
JSON.stringify(Object.assign({}, packageFile, { version }), null, 2) + '\n'
25+
);
26+
}
27+
28+
function updateChangelog(newText) {
29+
fs.writeFileSync(CHANGELOG_PATH, newText);
30+
}
31+
32+
function createGitCommit(version) {
33+
exec(
34+
`git commit -am 'Build: update package.json and changelog for v${version}'`
35+
);
36+
}
37+
38+
function createGitTag(version) {
39+
exec(`git tag v${version}`);
40+
}
41+
42+
function getCommitSubject(commitHash) {
43+
return exec(`git --no-pager show -s --oneline --format=%s ${commitHash}`);
44+
}
45+
46+
function getAbbreviatedCommitHash(commitHash) {
47+
return exec(`git --no-pager show -s --oneline --format=%h ${commitHash}`);
48+
}
49+
50+
function getCommitLink(commitHash) {
51+
return `[${getAbbreviatedCommitHash(commitHash)}](${githubRepoUrl}/commit/${commitHash})`;
52+
}
53+
54+
function replaceIssueLinks(message) {
55+
return message.replace(/#(\d+)/g, `[#$1](${githubRepoUrl}/issues/$1)`);
56+
}
57+
58+
const commitHashes = exec(`git log --format=%H v${packageFile.version}...HEAD`)
59+
.split('\n')
60+
.filter(hash => hash);
61+
62+
if (!commitHashes.length) {
63+
throw new RangeError('No commits since last release');
64+
}
65+
66+
const commitSubjects = commitHashes.map(getCommitSubject);
67+
let newVersion;
68+
69+
if (commitSubjects.some(subject => subject.startsWith('Breaking'))) {
70+
newVersion = semver.inc(packageFile.version, 'major');
71+
} else if (
72+
commitSubjects.some(
73+
subject => subject.startsWith('Update') || subject.startsWith('New')
74+
)
75+
) {
76+
newVersion = semver.inc(packageFile.version, 'minor');
77+
} else {
78+
newVersion = semver.inc(packageFile.version, 'patch');
79+
}
80+
81+
const newChangelogHeader = `## v${newVersion} (${moment
82+
.utc()
83+
.format('YYYY[-]MM[-]DD')})`;
84+
const commitLines = commitHashes.map(
85+
hash =>
86+
`* ${replaceIssueLinks(getCommitSubject(hash))} (${getCommitLink(hash)})`
87+
);
88+
const oldChangelog = fs.readFileSync(CHANGELOG_PATH).toString();
89+
const newChangelog = oldChangelog.replace(
90+
/^(# Changelog\n\n)/,
91+
`$1${newChangelogHeader}\n\n${commitLines.join('\n')}\n\n`
92+
);
93+
94+
updatePackageJson(newVersion);
95+
updateChangelog(newChangelog);
96+
createGitCommit(newVersion);
97+
createGitTag(newVersion);

package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@
4040
"eslint-plugin-eslint-plugin": "^0.7.1",
4141
"eslint-plugin-node": "^4.2.2",
4242
"mocha": "^3.1.2",
43-
"prettier": "^1.3.1"
43+
"moment": "^2.18.1",
44+
"prettier": "^1.3.1",
45+
"semver": "^5.3.0"
4446
},
4547
"engines": {
4648
"node": ">=4.0.0"

yarn.lock

+5-1
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,10 @@ mocha@^3.1.2:
727727
mkdirp "0.5.1"
728728
supports-color "3.1.2"
729729

730+
moment@^2.18.1:
731+
version "2.18.1"
732+
resolved "https://registry.yarnpkg.com/moment/-/moment-2.18.1.tgz#c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f"
733+
730734
731735
version "0.7.2"
732736
resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765"
@@ -901,7 +905,7 @@ rx-lite@^3.1.2:
901905
version "3.1.2"
902906
resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102"
903907

904-
908+
[email protected], semver@^5.3.0:
905909
version "5.3.0"
906910
resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
907911

0 commit comments

Comments
 (0)