UNPKG

22.6 kBJavaScriptView Raw
1"use strict";
2var __assign = (this && this.__assign) || function () {
3 __assign = Object.assign || function(t) {
4 for (var s, i = 1, n = arguments.length; i < n; i++) {
5 s = arguments[i];
6 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7 t[p] = s[p];
8 }
9 return t;
10 };
11 return __assign.apply(this, arguments);
12};
13var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14 return new (P || (P = Promise))(function (resolve, reject) {
15 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
16 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
17 function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
18 step((generator = generator.apply(thisArg, _arguments || [])).next());
19 });
20};
21var __generator = (this && this.__generator) || function (thisArg, body) {
22 var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
23 return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
24 function verb(n) { return function (v) { return step([n, v]); }; }
25 function step(op) {
26 if (f) throw new TypeError("Generator is already executing.");
27 while (_) try {
28 if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
29 if (y = 0, t) op = [op[0] & 2, t.value];
30 switch (op[0]) {
31 case 0: case 1: t = op; break;
32 case 4: _.label++; return { value: op[1], done: false };
33 case 5: _.label++; y = op[1]; op = [0]; continue;
34 case 7: op = _.ops.pop(); _.trys.pop(); continue;
35 default:
36 if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
37 if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
38 if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
39 if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
40 if (t[2]) _.ops.pop();
41 _.trys.pop(); continue;
42 }
43 op = body.call(thisArg, _);
44 } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
45 if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
46 }
47};
48var __read = (this && this.__read) || function (o, n) {
49 var m = typeof Symbol === "function" && o[Symbol.iterator];
50 if (!m) return o;
51 var i = m.call(o), r, ar = [], e;
52 try {
53 while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
54 }
55 catch (error) { e = { error: error }; }
56 finally {
57 try {
58 if (r && !r.done && (m = i["return"])) m.call(i);
59 }
60 finally { if (e) throw e.error; }
61 }
62 return ar;
63};
64var __spread = (this && this.__spread) || function () {
65 for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
66 return ar;
67};
68var __importDefault = (this && this.__importDefault) || function (mod) {
69 return (mod && mod.__esModule) ? mod : { "default": mod };
70};
71Object.defineProperty(exports, "__esModule", { value: true });
72var arr_flatten_1 = __importDefault(require("arr-flatten"));
73var url_1 = require("url");
74var url_join_1 = __importDefault(require("url-join"));
75var make_hooks_1 = require("./utils/make-hooks");
76var getHeaderDepth = function (line) {
77 return line.split('').reduce(function (count, char) { return (char === '#' ? count + 1 : count); }, 0);
78};
79var filterLabel = function (commits, label) {
80 return commits.filter(function (commit) { return commit.labels.includes(label); });
81};
82var Changelog = /** @class */ (function () {
83 function Changelog(logger, options) {
84 this.logger = logger;
85 this.options = options;
86 this.hooks = make_hooks_1.makeChangelogHooks();
87 this.options.labels.pushToBaseBranch = __assign({ name: 'pushToBaseBranch', title: "\u26A0\uFE0F Pushed to " + options.baseBranch, description: 'N/A' }, (this.options.labels.pushToBaseBranch || {}));
88 }
89 Changelog.prototype.loadDefaultHooks = function () {
90 var _this = this;
91 this.hooks.renderChangelogAuthor.tap('Default', function (author, commit) {
92 return _this.createUserLink(author, commit);
93 });
94 this.hooks.renderChangelogAuthorLine.tap('Default', function (author, user) {
95 var authorString = author.name && user ? author.name + " (" + user + ")" : user;
96 return authorString ? "- " + authorString : undefined;
97 });
98 this.hooks.renderChangelogLine.tap('Default', function (_a) {
99 var _b = __read(_a, 2), commit = _b[0], line = _b[1];
100 return [
101 commit,
102 line
103 ];
104 });
105 this.hooks.renderChangelogTitle.tap('Default', function (label, changelogTitles) { return "#### " + changelogTitles[label] + "\n"; });
106 this.hooks.omitReleaseNotes.tap('Renovate', function (commit) {
107 var names = ['renovate-pro[bot]', 'renovate-bot'];
108 if (commit.authors.find(function (author) {
109 return Boolean((author.name && names.includes(author.name)) ||
110 (author.username && names.includes(author.username)));
111 })) {
112 return true;
113 }
114 });
115 };
116 Changelog.prototype.generateReleaseNotes = function (commits) {
117 return __awaiter(this, void 0, void 0, function () {
118 var split, sections, result;
119 return __generator(this, function (_a) {
120 switch (_a.label) {
121 case 0:
122 if (commits.length === 0) {
123 return [2 /*return*/, ''];
124 }
125 this.logger.verbose.info('Generating release notes for:\n', commits);
126 split = this.splitCommits(commits);
127 this.logger.verbose.info('Split commits into groups');
128 this.logger.veryVerbose.info('\n', split);
129 sections = [];
130 return [4 /*yield*/, this.createReleaseNotesSection(commits, sections)];
131 case 1:
132 _a.sent();
133 this.logger.verbose.info('Added release notes to changelog');
134 return [4 /*yield*/, this.createLabelSection(split, sections)];
135 case 2:
136 _a.sent();
137 this.logger.verbose.info('Added groups to changelog');
138 return [4 /*yield*/, this.createAuthorSection(split, sections)];
139 case 3:
140 _a.sent();
141 this.logger.verbose.info('Added authors to changelog');
142 result = sections.join('\n\n');
143 this.logger.verbose.info('Successfully generated release notes.');
144 return [2 /*return*/, result];
145 }
146 });
147 });
148 };
149 Changelog.prototype.createUserLink = function (author, commit) {
150 var githubUrl = new url_1.URL(this.options.baseUrl).origin;
151 if (author.username === 'invalid-email-address') {
152 return;
153 }
154 return author.username
155 ? "[@" + author.username + "](" + url_join_1.default(githubUrl, author.username) + ")"
156 : author.email || commit.authorEmail;
157 };
158 /**
159 * Split commits into changelogTitle sections.
160 */
161 Changelog.prototype.splitCommits = function (commits) {
162 var currentCommits = __spread(commits);
163 var order = ['major', 'minor', 'patch'];
164 var sections = Object.values(this.options.labels)
165 .filter(function (label) { return label.title; })
166 .sort(function (a, b) {
167 var bIndex = order.indexOf(b.name) + 1 || order.length + 1;
168 var aIndex = order.indexOf(a.name) + 1 || order.length + 1;
169 return aIndex - bIndex;
170 });
171 commits
172 .filter(function (_a) {
173 var labels = _a.labels;
174 return labels.length === 0;
175 })
176 .map(function (_a) {
177 var labels = _a.labels;
178 return labels.push('patch');
179 });
180 return Object.assign.apply(Object, __spread([{}], sections.map(function (label) {
181 var _a;
182 var matchedCommits = filterLabel(currentCommits, label.name);
183 currentCommits = currentCommits.filter(function (commit) { return !matchedCommits.includes(commit); });
184 return matchedCommits.length === 0
185 ? {}
186 : (_a = {}, _a[label.name] = matchedCommits, _a);
187 })));
188 };
189 Changelog.prototype.createUserLinkList = function (commit) {
190 return __awaiter(this, void 0, void 0, function () {
191 var result;
192 var _this = this;
193 return __generator(this, function (_a) {
194 switch (_a.label) {
195 case 0:
196 result = new Set();
197 return [4 /*yield*/, Promise.all(commit.authors.map(function (author) { return __awaiter(_this, void 0, void 0, function () {
198 var link;
199 return __generator(this, function (_a) {
200 switch (_a.label) {
201 case 0: return [4 /*yield*/, this.hooks.renderChangelogAuthor.promise(author, commit, this.options)];
202 case 1:
203 link = _a.sent();
204 if (link) {
205 result.add(link);
206 }
207 return [2 /*return*/];
208 }
209 });
210 }); }))];
211 case 1:
212 _a.sent();
213 return [2 /*return*/, __spread(result).join(' ')];
214 }
215 });
216 });
217 };
218 Changelog.prototype.generateCommitNote = function (commit) {
219 return __awaiter(this, void 0, void 0, function () {
220 var subject, pr, prLink, user;
221 return __generator(this, function (_a) {
222 switch (_a.label) {
223 case 0:
224 subject = commit.subject ? commit.subject.trim() : '';
225 pr = '';
226 if (commit.pullRequest && commit.pullRequest.number) {
227 prLink = url_join_1.default(this.options.baseUrl, 'pull', commit.pullRequest.number.toString());
228 pr = "[#" + commit.pullRequest.number + "](" + prLink + ")";
229 }
230 return [4 /*yield*/, this.createUserLinkList(commit)];
231 case 1:
232 user = _a.sent();
233 return [2 /*return*/, "- " + subject + " " + pr + (user ? " (" + user + ")" : '')];
234 }
235 });
236 });
237 };
238 Changelog.prototype.createAuthorSection = function (split, sections) {
239 return __awaiter(this, void 0, void 0, function () {
240 var seenUsers, authors, commits, authorSection;
241 var _this = this;
242 return __generator(this, function (_a) {
243 switch (_a.label) {
244 case 0:
245 seenUsers = new Set();
246 authors = new Set();
247 commits = Object.values(split).reduce(function (labeledCommits, sectionCommits) { return __spread(labeledCommits, sectionCommits); }, []);
248 return [4 /*yield*/, Promise.all(arr_flatten_1.default(commits.map(function (commit) {
249 return commit.authors.map(function (author) { return __awaiter(_this, void 0, void 0, function () {
250 var username, user, authorEntry;
251 return __generator(this, function (_a) {
252 switch (_a.label) {
253 case 0:
254 if (author.username === 'invalid-email-address') {
255 return [2 /*return*/];
256 }
257 username = (author.username || author.name);
258 return [4 /*yield*/, this.hooks.renderChangelogAuthor.promise(author, commit, this.options)];
259 case 1:
260 user = _a.sent();
261 if (user && seenUsers.has(username)) {
262 return [2 /*return*/];
263 }
264 seenUsers.add(username);
265 return [4 /*yield*/, this.hooks.renderChangelogAuthorLine.promise(author, user)];
266 case 2:
267 authorEntry = _a.sent();
268 if (authorEntry && !authors.has(authorEntry)) {
269 authors.add(authorEntry);
270 }
271 return [2 /*return*/];
272 }
273 });
274 }); });
275 })))];
276 case 1:
277 _a.sent();
278 if (authors.size === 0) {
279 return [2 /*return*/];
280 }
281 authorSection = "#### Authors: " + authors.size + "\n\n";
282 authorSection += __spread(authors).join('\n');
283 sections.push(authorSection);
284 return [2 /*return*/];
285 }
286 });
287 });
288 };
289 Changelog.prototype.createLabelSection = function (split, sections) {
290 return __awaiter(this, void 0, void 0, function () {
291 var changelogTitles, labelSections;
292 var _this = this;
293 return __generator(this, function (_a) {
294 switch (_a.label) {
295 case 0:
296 changelogTitles = Object.entries(this.options.labels).reduce(function (titles, _a) {
297 var _b = __read(_a, 2), labelDef = _b[1];
298 if (labelDef.title) {
299 titles[labelDef.name] = labelDef.title;
300 }
301 return titles;
302 }, {});
303 return [4 /*yield*/, Promise.all(Object.entries(split).map(function (_a) {
304 var _b = __read(_a, 2), label = _b[0], labelCommits = _b[1];
305 return __awaiter(_this, void 0, void 0, function () {
306 var title, lines;
307 var _this = this;
308 return __generator(this, function (_c) {
309 switch (_c.label) {
310 case 0: return [4 /*yield*/, this.hooks.renderChangelogTitle.promise(label, changelogTitles)];
311 case 1:
312 title = _c.sent();
313 lines = new Set();
314 return [4 /*yield*/, Promise.all(labelCommits.map(function (commit) { return __awaiter(_this, void 0, void 0, function () {
315 var _a, line, _b, _c, _d;
316 return __generator(this, function (_e) {
317 switch (_e.label) {
318 case 0:
319 _c = (_b = this.hooks.renderChangelogLine).promise;
320 _d = [commit];
321 return [4 /*yield*/, this.generateCommitNote(commit)];
322 case 1: return [4 /*yield*/, _c.apply(_b, [_d.concat([
323 _e.sent()
324 ])])];
325 case 2:
326 _a = __read.apply(void 0, [_e.sent(), 2]), line = _a[1];
327 lines.add(line);
328 return [2 /*return*/];
329 }
330 });
331 }); }))];
332 case 2:
333 _c.sent();
334 return [2 /*return*/, __spread([
335 title
336 ], __spread(lines).sort(function (a, b) { return a.split('\n').length - b.split('\n').length; })).join('\n')];
337 }
338 });
339 });
340 }))];
341 case 1:
342 labelSections = _a.sent();
343 labelSections.map(function (section) { return sections.push(section); });
344 return [2 /*return*/];
345 }
346 });
347 });
348 };
349 Changelog.prototype.createReleaseNotesSection = function (commits, sections) {
350 return __awaiter(this, void 0, void 0, function () {
351 var section, visited, included;
352 var _this = this;
353 return __generator(this, function (_a) {
354 switch (_a.label) {
355 case 0:
356 if (!commits.length) {
357 return [2 /*return*/];
358 }
359 section = '';
360 visited = new Set();
361 return [4 /*yield*/, Promise.all(commits.map(function (commit) { return __awaiter(_this, void 0, void 0, function () {
362 var omit;
363 return __generator(this, function (_a) {
364 switch (_a.label) {
365 case 0: return [4 /*yield*/, this.hooks.omitReleaseNotes.promise(commit)];
366 case 1:
367 omit = _a.sent();
368 if (!omit) {
369 return [2 /*return*/, commit];
370 }
371 return [2 /*return*/];
372 }
373 });
374 }); }))];
375 case 1:
376 included = _a.sent();
377 included.map(function (commit) {
378 if (!commit) {
379 return;
380 }
381 var pr = commit.pullRequest;
382 if (!pr || !pr.body) {
383 return;
384 }
385 var title = /^[#]{0,5}[ ]*[R|r]elease [N|n]otes$/;
386 var lines = pr.body.split('\n').map(function (line) { return line.replace(/\r$/, ''); });
387 var notesStart = lines.findIndex(function (line) { return Boolean(line.match(title)); });
388 if (notesStart === -1 || visited.has(pr.number)) {
389 return;
390 }
391 var depth = getHeaderDepth(lines[notesStart]);
392 visited.add(pr.number);
393 var notes = '';
394 for (var index = notesStart; index < lines.length; index++) {
395 var line = lines[index];
396 var isTitle = line.match(title);
397 if (line.startsWith('#') && getHeaderDepth(line) <= depth && !isTitle) {
398 break;
399 }
400 if (!isTitle) {
401 notes += line + "\n";
402 }
403 }
404 section += "_From #" + pr.number + "_\n\n" + notes.trim() + "\n\n";
405 });
406 if (!section) {
407 return [2 /*return*/];
408 }
409 sections.push("### Release Notes\n\n" + section + "---");
410 return [2 /*return*/];
411 }
412 });
413 });
414 };
415 return Changelog;
416}());
417exports.default = Changelog;
418//# sourceMappingURL=changelog.js.map
\No newline at end of file