UNPKG

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