-
Notifications
You must be signed in to change notification settings - Fork 3
/
.release-it.js
158 lines (138 loc) · 5.04 KB
/
.release-it.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
/*! Copyright (c) 2020 Siemens AG. Licensed under the MIT License. */
const { execSync } = require("child_process");
const fs = require("fs");
const os = require("os");
const path = require("path");
const readlineSync = require("readline-sync");
const releaseNotesFile = path.join(os.tmpdir(), "vda-5050-cli-relnotes.txt");
const changelogFile = "CHANGELOG.md";
/**
* Invoked by npm run scripts.
*
* Prompt the user to enter release notes which are embedded into the
* conventional changelog entry in the process of running release-it afterwards.
*/
function promptReleaseNotes() {
const lines = [];
let i = 1;
let line;
readlineSync.setDefaultOptions({ keepWhitespace: true });
console.log("Enter release notes (line by line, to finish press ENTER key only)");
while (line = readlineSync.question(`Line ${i++}: `)) {
lines.push(line);
}
console.log("...");
if (lines.length > 0) {
fs.writeFileSync(releaseNotesFile, lines.join("\n"), "utf-8");
}
}
/**
* A release-it "before:release" hook function.
*
* After generating the conventional changelog file for the current release,
* insert release notes between the release header and the commit messages.
* Additionally, ensure the Changelog title is moved/added to the beginning of
* the file and remove any duplicate version of the new release.
*/
function augmentChangelog() {
// Enforce uniform line endings.
const readLines = file => fs.readFileSync(file, "utf-8").replace(/\r\n/g, "\n").split("\n");
const findLineIndex = (regexp, allLines, startIndex) => {
const len = allLines.length;
for (let i = startIndex || 0; i < len; i++) {
if (regexp.test(allLines[i])) {
return i;
}
}
return undefined;
};
const escapeRegex = s => s.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&");
const releaseRegex = version => {
const versionRegex = escapeRegex(version);
const urlRegex = "\\S+";
return new RegExp(`^##? (${versionRegex})|(\\[${versionRegex}\\]\\(${urlRegex}\\)) \\(\\d\\d\\d\\d-\\d\\d-\\d\\d\\)$`);
};
const anyReleaseRegex = /^##? (\S+)|(\[\S+\]\(\S+\)) \(\d\d\d\d-\d\d-\d\d\)$/;
const [version, latestVersion, isCi] = process.argv.slice(1);
let relNotes;
// Use the prompted release notes in a non-CI environment. In a CI
// environment, the release notes file could have been generated by a tool.
try {
relNotes = readLines(releaseNotesFile);
fs.unlinkSync(releaseNotesFile);
} catch { }
const lines = readLines(changelogFile);
// Move/add changelog title to the top.
const titleLine = "# Changelog";
const titleRegex = new RegExp(`^${escapeRegex(titleLine)}$`);
const indexTitle = findLineIndex(titleRegex, lines);
if (indexTitle !== undefined) {
lines.unshift(...lines.splice(indexTitle, 2));
} else {
lines.unshift(titleLine, "");
}
const indexVersion = findLineIndex(releaseRegex(version), lines);
// Remove latest release version if it equals the new release.
if (version === latestVersion) {
const indexLatestVersion = findLineIndex(releaseRegex(latestVersion), lines, indexVersion + 1);
if (indexLatestVersion !== undefined) {
let indexNext = findLineIndex(anyReleaseRegex, lines, indexLatestVersion + 1);
if (indexNext === undefined) {
indexNext = lines.length;
}
lines.splice(indexLatestVersion, indexNext - indexLatestVersion);
}
}
// Insert release notes if given.
if (relNotes && relNotes.length > 0) {
lines.splice(indexVersion + 2, 0, ...relNotes);
}
fs.writeFileSync(changelogFile, lines.join("\n"), "utf-8");
// Stage the modified changelog file again.
execSync(`git add ${changelogFile}`);
}
module.exports = {
// Invoked by npm run scripts before running release-it to prompt the user
// for entering release notes.
promptReleaseNotes,
// Invoked by release-it in the "before:release" hook to augment the
// changelog that has been generated.
augmentChangelog,
// release-it options
"git": {
"requireCleanWorkingDir": true,
"push": true,
"requireCommits": true,
"addUntrackedFiles": true,
"commitMessage": "chore: release v${version}",
"commitArgs": [
"--no-verify"
],
"tagName": "v${version}",
"tagAnnotation": "chore: release v${version}",
"tagArgs": [
"--force"
],
"requireUpstream": false
},
"github": {
"release": false
},
"gitlab": {
"release": false
},
"npm": {
"publish": true,
"publishPath": "."
},
"hooks": {
"before:release": "node -e \"require('./.release-it.js').augmentChangelog()\" \"${version}\" \"${latestVersion}\" \"${ci}\""
},
"plugins": {
"@release-it/conventional-changelog": {
"preset": "angular",
"infile": changelogFile
}
},
"disable-metrics": true
};