forked from phips28/gh-action-bump-version
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
251 lines (224 loc) · 9.14 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
// test
const { execSync, spawn, execFile } = require('child_process');
const { existsSync } = require('fs');
const { EOL } = require('os');
const path = require('path');
// Change working directory if user defined PACKAGEJSON_DIR
if (process.env.PACKAGEJSON_DIR) {
process.env.GITHUB_WORKSPACE = `${process.env.GITHUB_WORKSPACE}/${process.env.PACKAGEJSON_DIR}`;
process.chdir(process.env.GITHUB_WORKSPACE);
}
const workspace = process.env.GITHUB_WORKSPACE;
(async () => {
// const pkg = getPackageJson();
const event = process.env.GITHUB_EVENT_PATH ? require(process.env.GITHUB_EVENT_PATH) : {};
if (!event.commits) {
console.log("Couldn't find any commits in this event, incrementing patch version...");
}
const tagPrefix = process.env['INPUT_TAG-PREFIX'] || '';
const messages = event.commits ? event.commits.map((commit) => commit.message + '\n' + commit.body) : [];
const commitMessage = process.env['INPUT_COMMIT-MESSAGE'] || 'ci: version bump to {{version}}';
console.log('commit messages:', messages);
const commitMessageRegex = new RegExp(commitMessage.replace(/{{version}}/g, `${tagPrefix}\\d+\\.\\d+\\.\\d+`), 'ig');
const isVersionBump = messages.find((message) => commitMessageRegex.test(message)) !== undefined;
if (isVersionBump) {
exitSuccess('No action necessary because we found a previous bump!');
return;
}
// input wordings for MAJOR, MINOR, PATCH, PRE-RELEASE
const majorWords = process.env['INPUT_MAJOR-WORDING'].split(',');
const minorWords = process.env['INPUT_MINOR-WORDING'].split(',');
// patch is by default empty, and '' would always be true in the includes(''), thats why we handle it separately
const patchWords = process.env['INPUT_PATCH-WORDING'] ? process.env['INPUT_PATCH-WORDING'].split(',') : null;
const preReleaseWords = process.env['INPUT_RC-WORDING'] ? process.env['INPUT_RC-WORDING'].split(',') : null;
console.log('config words:', { majorWords, minorWords, patchWords, preReleaseWords });
// get default version bump
let version = process.env.INPUT_DEFAULT;
let foundWord = null;
// get the pre-release prefix specified in action
let preid = process.env.INPUT_PREID;
// case: if wording for MAJOR found
if (
messages.some(
(message) => /^([a-zA-Z]+)(\(.+\))?(\!)\:/.test(message) || majorWords.some((word) => message.includes(word)),
)
) {
version = 'major';
}
// case: if wording for MINOR found
else if (messages.some((message) => minorWords.some((word) => message.includes(word)))) {
version = 'minor';
}
// case: if wording for PATCH found
else if (patchWords && messages.some((message) => patchWords.some((word) => message.includes(word)))) {
version = 'patch';
}
// case: if wording for PRE-RELEASE found
else if (
preReleaseWords &&
messages.some((message) =>
preReleaseWords.some((word) => {
if (message.includes(word)) {
foundWord = word;
return true;
} else {
return false;
}
}),
)
) {
preid = foundWord.split('-')[1];
version = 'prerelease';
}
console.log('version action after first waterfall:', version);
// case: if default=prerelease,
// rc-wording is also set
// and does not include any of rc-wording
// then unset it and do not run
if (
version === 'prerelease' &&
preReleaseWords &&
!messages.some((message) => preReleaseWords.some((word) => message.includes(word)))
) {
version = null;
}
// case: if default=prerelease, but rc-wording is NOT set
if (version === 'prerelease' && preid) {
version = 'prerelease';
version = `${version} --preid=${preid}`;
}
console.log('version action after final decision:', version);
// case: if nothing of the above matches
if (version === null) {
exitSuccess('No version keywords found, skipping bump.');
return;
}
// case: if user sets push to false, to skip pushing new tag/package.json
const push = process.env['INPUT_PUSH'];
if (push === 'false' || push === false) {
exitSuccess('User requested to skip pushing new tag and package.json. Finished.');
return;
}
// GIT logic
try {
// const current = pkg.version.toString();
// get version from latest git tag instead of package.json file
const current = runInWorkspace('git', ['describe', '--tags', '--abbrev=0']);
// set git user
await runInWorkspace('git', ['config', 'user.name', `"${process.env.GITHUB_USER || 'Automated Version Bump'}"`]);
await runInWorkspace('git', [
'config',
'user.email',
`"${process.env.GITHUB_EMAIL || '[email protected]'}"`,
]);
let currentBranch = /refs\/[a-zA-Z]+\/(.*)/.exec(process.env.GITHUB_REF)[1];
let isPullRequest = false;
if (process.env.GITHUB_HEAD_REF) {
// Comes from a pull request
currentBranch = process.env.GITHUB_HEAD_REF;
isPullRequest = true;
}
if (process.env['INPUT_TARGET-BRANCH']) {
// We want to override the branch that we are pulling / pushing to
currentBranch = process.env['INPUT_TARGET-BRANCH'];
}
console.log('currentBranch:', currentBranch);
console.log('currentVersion:', version);
// do it in the current checked out github branch (DETACHED HEAD)
// important for further usage of the package.json version
// await runInWorkspace('npm', ['version', '--allow-same-version=true', '--git-tag-version=false', current]);
console.log('current:', current, '/', 'version:', version);
// let newVersion = execSync(`npm version --git-tag-version=false ${version}`).toString().trim().replace(/^v/, '');
let newVersion = execFile('./generate-semver.sh').toString();
let output = JSON.stringify(newVersion);
console.log('newVersion:', output);
newVersion = execFile('./generate-semver.sh');
output = JSON.stringify(newVersion);
console.log('newVersion:', output);
newVersion = `${tagPrefix}${newVersion}`;
if (process.env['INPUT_SKIP-COMMIT'] !== 'true') {
await runInWorkspace('git', ['commit', '-a', '-m', commitMessage.replace(/{{version}}/g, newVersion)]);
}
// now go to the actual branch to perform the same versioning
if (isPullRequest) {
// First fetch to get updated local version of branch
await runInWorkspace('git', ['fetch']);
}
await runInWorkspace('git', ['checkout', currentBranch]);
// await runInWorkspace('npm', ['version', '--allow-same-version=true', '--git-tag-version=false', current]);
console.log('current:', current, '/', 'version:', version);
// newVersion = execSync(`npm version --git-tag-version=false ${version}`).toString().trim().replace(/^v/, '');
newVersion = execFile('./generate-semver.sh', ['-l text -f ./artifacts/version.txt -o none']);
console.log('newVersion:', newVersion);
newVersion = `${tagPrefix}${newVersion}`;
console.log(`::set-output name=newTag::${newVersion}`);
try {
// to support "actions/checkout@v1"
if (process.env['INPUT_SKIP-COMMIT'] !== 'true') {
await runInWorkspace('git', ['commit', '-a', '-m', commitMessage.replace(/{{version}}/g, newVersion)]);
}
} catch (e) {
console.warn(
'git commit failed because you are using "actions/checkout@v2"; ' +
'but that doesnt matter because you dont need that git commit, thats only for "actions/checkout@v1"',
);
}
const remoteRepo = `https://${process.env.GITHUB_ACTOR}:${process.env.GITHUB_TOKEN}@github.com/${process.env.GITHUB_REPOSITORY}.git`;
if (process.env['INPUT_SKIP-TAG'] !== 'true') {
await runInWorkspace('git', ['tag', newVersion]);
if (process.env['INPUT_SKIP-PUSH'] !== 'true') {
await runInWorkspace('git', ['push', remoteRepo, '--follow-tags']);
await runInWorkspace('git', ['push', remoteRepo, '--tags']);
}
} else {
if (process.env['INPUT_SKIP-PUSH'] !== 'true') {
await runInWorkspace('git', ['push', remoteRepo]);
}
}
} catch (e) {
logError(e);
exitFailure('Failed to bump version');
return;
}
exitSuccess('Version bumped!');
})();
function getPackageJson() {
const pathToPackage = path.join(workspace, 'package.json');
if (!existsSync(pathToPackage)) throw new Error("package.json could not be found in your project's root.");
return require(pathToPackage);
}
function exitSuccess(message) {
console.info(`✔ success ${message}`);
process.exit(0);
}
function exitFailure(message) {
logError(message);
process.exit(1);
}
function logError(error) {
console.error(`✖ fatal ${error.stack || error}`);
}
function runInWorkspace(command, args) {
return new Promise((resolve, reject) => {
const child = spawn(command, args, { cwd: workspace });
let isDone = false;
const errorMessages = [];
child.on('error', (error) => {
if (!isDone) {
isDone = true;
reject(error);
}
});
child.stderr.on('data', (chunk) => errorMessages.push(chunk));
child.on('exit', (code) => {
if (!isDone) {
if (code === 0) {
resolve();
} else {
reject(`${errorMessages.join('')}${EOL}${command} exited with code ${code}`);
}
}
});
});
//return execa(command, args, { cwd: workspace });
}