Skip to content
This repository was archived by the owner on Oct 20, 2022. It is now read-only.

Commit e47e8b8

Browse files
committed
release.js
2 parents 521d973 + 0d45ac0 commit e47e8b8

File tree

1 file changed

+219
-0
lines changed

1 file changed

+219
-0
lines changed

release.js

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
var PACKAGE_JSON_FILE = './package.json',
2+
RELEASES_NOTES_FILE = './RELEASES NOTES.txt';
3+
4+
var child = require('child_process'),
5+
fs = require('fs'),
6+
semver = require('semver'),
7+
yargs = require('yargs'),
8+
argv = yargs
9+
.usage("$0 --start [--type major|minor|patch] [--version <version>] \n$0 --finish")
10+
.default('type', 'minor')
11+
.argv;
12+
13+
function execSync(command) {
14+
console.info('Exec command: ' + command);
15+
var res = child.execSync(command);
16+
res = String(res).trim();
17+
return res;
18+
}
19+
20+
function gitGetCurrentBranch() {
21+
return execSync('git rev-parse --abbrev-ref HEAD');
22+
}
23+
24+
function gitIsRepoClean() {
25+
// '-uno' => do not hwo untracked files
26+
return execSync('git status -s -uno').length === 0;
27+
}
28+
29+
function gitGetLastTag() {
30+
return execSync('git describe --abbrev=0 --tags');
31+
}
32+
33+
function gitGetCommits(startTag, endTag) {
34+
return execSync('git log ' + startTag + '...' + endTag + ' --format=%f').split('\n');
35+
}
36+
37+
function gitCheckout(branch) {
38+
return execSync('git checkout ' + branch);
39+
}
40+
41+
function gitPull() {
42+
return execSync('git pull --all');
43+
}
44+
45+
function gitCommit(message) {
46+
if (!message || message.length === 0) {
47+
console.error('Please provide a commit message');
48+
return;
49+
}
50+
return execSync('git commit -am \"' + message + '\"');
51+
}
52+
53+
function gitPush() {
54+
execSync('git push --all');
55+
execSync('git push --tags');
56+
}
57+
58+
function gitFlowStart(type, version) {
59+
return execSync('git flow ' + type + ' start ' + version);
60+
}
61+
62+
function gitFlowFinish(type, version) {
63+
64+
try {
65+
execSync('git flow ' + type + ' finish -F ' + version + ' -m \"' + type + ' v' + version + '\"');
66+
} catch (err) {
67+
// In case of hotfix, there will be a conflict when merging hotfix branch into development with package.json file (version value)
68+
// Then resolve the merge and finish again the hotfix
69+
if (type === 'hotfix') {
70+
execSync('git checkout --ours package.json');
71+
execSync('git commit -am \"Merge tag v' + version + ' into development\"');
72+
execSync('git flow ' + type + ' finish -F ' + version + ' -m \"' + type + ' v' + version + '\"');
73+
}
74+
}
75+
}
76+
77+
function prependFile(path, data) {
78+
79+
var options = {
80+
encoding: 'utf8',
81+
mode: 438 /*=0666*/
82+
},
83+
appendOptions = {
84+
encoding: options.encoding,
85+
mode: options.mode,
86+
flags: 'w'
87+
},
88+
currentFileData = "";
89+
90+
// Open and read input file
91+
try {
92+
currentFileData = fs.readFileSync(path, options);
93+
} catch (err) {
94+
console.error('Failed to open file ' + path);
95+
return;
96+
}
97+
98+
// Prepend data and write file
99+
fs.writeFileSync(path, data + currentFileData, appendOptions);
100+
}
101+
102+
function generateReleaseNotes(version) {
103+
var notes= "";
104+
105+
// Get current date
106+
var date = new Date(),
107+
y = date.getFullYear().toString(),
108+
m = (date.getMonth() + 1).toString(),
109+
d = date.getDate().toString(),
110+
MM = m[1] ? m : "0" + m[0],
111+
DD = d[1] ? d : "0" + d[0];
112+
113+
notes = '### Release Notes v' + version + ' (' + y + '/' + MM + '/' + DD + ')\n';
114+
115+
// Get last/previous tag
116+
var lastTag = gitGetLastTag();
117+
118+
// Get commits since last tag
119+
var commits = gitGetCommits(lastTag, 'HEAD');
120+
for (var i =0; i < commits.length; i++) {
121+
notes += '* ' + commits[i] + '\n';
122+
}
123+
notes += '\n';
124+
125+
return notes;
126+
}
127+
128+
function startRelease() {
129+
130+
var releaseType = argv.type === 'patch' ? 'hotfix' : 'release';
131+
132+
// Check if repository is clean
133+
if (!gitIsRepoClean()) {
134+
console.error("Repository is not clean");
135+
return;
136+
}
137+
138+
if (releaseType === 'hotfix') {
139+
// Checkout master branch
140+
gitCheckout('master');
141+
} else {
142+
// Checkout development branch
143+
gitCheckout('development');
144+
}
145+
146+
// Read package.json file
147+
var pkg = require(PACKAGE_JSON_FILE);
148+
149+
// Get current version from package.json and increment it:
150+
// - if version ends with '-dev' suffix, then suffix is removed
151+
// - else version number is incremented
152+
console.info("Current version: " + pkg.version);
153+
console.info("Release type: " + argv.type);
154+
var version = argv.version ? argv.version : semver.inc(pkg.version, argv.type);
155+
pkg.version = version;
156+
console.info("=> Release version: " + pkg.version);
157+
158+
// Start git flow release
159+
console.info('Start git ' + releaseType + ' v' + pkg.version);
160+
gitFlowStart(releaseType, pkg.version);
161+
162+
// Write/update and commit package.jon file with the new version number
163+
fs.writeFileSync(PACKAGE_JSON_FILE, JSON.stringify(pkg, null, ' '), {encoding: 'utf8',mode: 438 /*=0666*/});
164+
gitCommit('v' + pkg.version);
165+
166+
// Generate release notes, write/update and commit 'RELEASE NOTES.txt' file
167+
var notes = generateReleaseNotes(version);
168+
prependFile(RELEASES_NOTES_FILE, notes);
169+
170+
console.info("Please complete and commit release notes...");
171+
}
172+
173+
function finishRelease() {
174+
175+
// Get flow type
176+
var branch = gitGetCurrentBranch(),
177+
releaseType = branch.startsWith('release/') ? 'release' : (branch.startsWith('hotfix/') ? 'hotfix' : null);
178+
179+
// Check if we are on release branch
180+
if (releaseType === null) {
181+
console.error('Current branch = ' + branch + '. Please checkout current release/hotfix branch');
182+
return;
183+
}
184+
185+
// Update local branches
186+
// gitPull();
187+
188+
// Read package.json file
189+
var pkg = require(PACKAGE_JSON_FILE);
190+
191+
// Finish git flow
192+
console.info('Finish git ' + releaseType + ' v' + pkg.version);
193+
gitFlowFinish(releaseType, pkg.version);
194+
195+
if (releaseType === 'release') {
196+
// Increment version number for next release version in development
197+
gitCheckout('development');
198+
var version = semver.inc(pkg.version, 'minor');
199+
version += '-dev';
200+
pkg.version = version;
201+
console.info("Next release version in development: " + pkg.version);
202+
fs.writeFileSync(PACKAGE_JSON_FILE, JSON.stringify(pkg, null, ' '), {encoding: 'utf8',mode: 438 /*=0666*/});
203+
gitCommit('v' + pkg.version);
204+
}
205+
206+
// Push all branches and tags to remote
207+
gitPush();
208+
}
209+
210+
///////////////////////////////////////////////////////////////////////////////////////////////////
211+
212+
if (argv.start) {
213+
startRelease();
214+
} else if (argv.finish) {
215+
finishRelease();
216+
} else {
217+
yargs.showHelp();
218+
}
219+

0 commit comments

Comments
 (0)