UNPKG

19.4 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 commits
160 .filter(function (commit) { return commit.labels.length === 0; })
161 .map(function (commit) { return commit.labels.push('patch'); });
162 var sections = Object.values(this.options.labels).filter(function (label) { return label.title; });
163 return Object.assign.apply(Object, __spread([{}], sections.map(function (label) {
164 var _a;
165 var matchedCommits = filterLabel(currentCommits, label.name);
166 if (matchedCommits.length === 0) {
167 return {};
168 }
169 currentCommits = currentCommits.filter(function (commit) { return !matchedCommits.includes(commit); });
170 return _a = {},
171 _a[label.name] = matchedCommits,
172 _a;
173 })));
174 };
175 Changelog.prototype.createUserLinkList = function (commit) {
176 return __awaiter(this, void 0, void 0, function () {
177 var result;
178 var _this = this;
179 return __generator(this, function (_a) {
180 switch (_a.label) {
181 case 0:
182 result = new Set();
183 return [4 /*yield*/, Promise.all(commit.authors.map(function (author) { return __awaiter(_this, void 0, void 0, function () {
184 var link;
185 return __generator(this, function (_a) {
186 switch (_a.label) {
187 case 0: return [4 /*yield*/, this.hooks.renderChangelogAuthor.promise(author, commit, this.options)];
188 case 1:
189 link = _a.sent();
190 if (link) {
191 result.add(link);
192 }
193 return [2 /*return*/];
194 }
195 });
196 }); }))];
197 case 1:
198 _a.sent();
199 return [2 /*return*/, __spread(result).join(' ')];
200 }
201 });
202 });
203 };
204 Changelog.prototype.generateCommitNote = function (commit) {
205 return __awaiter(this, void 0, void 0, function () {
206 var jira, pr, link, prLink, user;
207 return __generator(this, function (_a) {
208 switch (_a.label) {
209 case 0:
210 jira = '';
211 pr = '';
212 if (commit.jira && this.options.jira) {
213 link = url_join_1.default.apply(void 0, __spread([this.options.jira], commit.jira.number));
214 jira = "[" + commit.jira.number + "](" + link + "): ";
215 }
216 if (commit.pullRequest && commit.pullRequest.number) {
217 prLink = url_join_1.default(this.options.baseUrl, 'pull', commit.pullRequest.number.toString());
218 pr = "[#" + commit.pullRequest.number + "](" + prLink + ")";
219 }
220 return [4 /*yield*/, this.createUserLinkList(commit)];
221 case 1:
222 user = _a.sent();
223 return [2 /*return*/, "- " + jira + commit.subject.trim() + " " + pr + (user ? " (" + user + ")" : '')];
224 }
225 });
226 });
227 };
228 Changelog.prototype.createAuthorSection = function (split, sections) {
229 return __awaiter(this, void 0, void 0, function () {
230 var seenUsers, authors, commits, authorSection;
231 var _this = this;
232 return __generator(this, function (_a) {
233 switch (_a.label) {
234 case 0:
235 seenUsers = new Set();
236 authors = new Set();
237 commits = Object.values(split).reduce(function (labeledCommits, sectionCommits) { return __spread(labeledCommits, sectionCommits); }, []);
238 return [4 /*yield*/, Promise.all(arr_flatten_1.default(commits.map(function (commit) {
239 return commit.authors.map(function (author) { return __awaiter(_this, void 0, void 0, function () {
240 var user, authorEntry;
241 return __generator(this, function (_a) {
242 switch (_a.label) {
243 case 0:
244 if (author.username === 'invalid-email-address') {
245 return [2 /*return*/];
246 }
247 return [4 /*yield*/, this.hooks.renderChangelogAuthor.promise(author, commit, this.options)];
248 case 1:
249 user = _a.sent();
250 if (user && seenUsers.has(user)) {
251 return [2 /*return*/];
252 }
253 seenUsers.add(user);
254 return [4 /*yield*/, this.hooks.renderChangelogAuthorLine.promise(author, user)];
255 case 2:
256 authorEntry = _a.sent();
257 if (authorEntry && !authors.has(authorEntry)) {
258 authors.add(authorEntry);
259 }
260 return [2 /*return*/];
261 }
262 });
263 }); });
264 })))];
265 case 1:
266 _a.sent();
267 if (authors.size === 0) {
268 return [2 /*return*/];
269 }
270 authorSection = "#### Authors: " + authors.size + "\n\n";
271 authorSection += __spread(authors).join('\n');
272 sections.push(authorSection);
273 return [2 /*return*/];
274 }
275 });
276 });
277 };
278 Changelog.prototype.createLabelSection = function (split, sections) {
279 return __awaiter(this, void 0, void 0, function () {
280 var changelogTitles;
281 var _this = this;
282 return __generator(this, function (_a) {
283 switch (_a.label) {
284 case 0:
285 changelogTitles = Object.entries(this.options.labels).reduce(function (titles, _a) {
286 var _b = __read(_a, 2), labelDef = _b[1];
287 if (labelDef.title) {
288 titles[labelDef.name] = labelDef.title;
289 }
290 return titles;
291 }, {});
292 return [4 /*yield*/, Promise.all(Object.entries(split).map(function (_a) {
293 var _b = __read(_a, 2), label = _b[0], labelCommits = _b[1];
294 return __awaiter(_this, void 0, void 0, function () {
295 var title, lines;
296 var _this = this;
297 return __generator(this, function (_c) {
298 switch (_c.label) {
299 case 0: return [4 /*yield*/, this.hooks.renderChangelogTitle.promise(label, changelogTitles)];
300 case 1:
301 title = _c.sent();
302 return [4 /*yield*/, this.hooks.renderChangelogLine.promise(labelCommits, function (commit) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
303 return [2 /*return*/, this.generateCommitNote(commit)];
304 }); }); })];
305 case 2:
306 lines = _c.sent();
307 sections.push(__spread([title], lines).join('\n'));
308 return [2 /*return*/];
309 }
310 });
311 });
312 }))];
313 case 1:
314 _a.sent();
315 return [2 /*return*/];
316 }
317 });
318 });
319 };
320 Changelog.prototype.createReleaseNotesSection = function (commits, sections) {
321 if (!commits.length) {
322 return;
323 }
324 var visited = new Set();
325 var section = '';
326 commits.map(function (commit) {
327 var pr = commit.pullRequest;
328 if (!pr || !pr.body) {
329 return;
330 }
331 var title = /^[#]{0,5}[ ]*[R|r]elease [N|n]otes$/;
332 var lines = pr.body.split('\n').map(function (line) { return line.replace(/\r$/, ''); });
333 var notesStart = lines.findIndex(function (line) { return Boolean(line.match(title)); });
334 if (notesStart === -1 || visited.has(pr.number)) {
335 return;
336 }
337 var depth = getHeaderDepth(lines[notesStart]);
338 visited.add(pr.number);
339 var notes = '';
340 for (var index = notesStart; index < lines.length; index++) {
341 var line = lines[index];
342 var isTitle = line.match(title);
343 if (line.startsWith('#') && getHeaderDepth(line) <= depth && !isTitle) {
344 break;
345 }
346 if (!isTitle) {
347 notes += line + "\n";
348 }
349 }
350 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());
351 });
352 if (!section) {
353 return;
354 }
355 sections.push(dedent_1.default(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n ### Release Notes\n\n ", "---\n "], ["\n ### Release Notes\n\n ", "---\n "])), section));
356 };
357 return Changelog;
358}());
359exports.default = Changelog;
360var templateObject_1, templateObject_2;
361//# sourceMappingURL=changelog.js.map
\No newline at end of file