-
Notifications
You must be signed in to change notification settings - Fork 67
/
generate-changelog.js
86 lines (72 loc) · 3.01 KB
/
generate-changelog.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
const { program } = require('commander');
const { execSync } = require('child_process');
const fs = require('fs');
program
.requiredOption('--repoUrl <name>', 'Provide a git repo url', 'https://github.com/openedx/paragon')
.action((options) => {
if (fs.existsSync('CHANGELOG.md')) {
throw new Error('CHANGELOG file already exists.');
}
const { repoUrl } = options;
const cmd = 'git log --pretty=format:"%h|%H|%ad|%s|%d|%b||" --date=short';
const commitLog = execSync(cmd, { encoding: 'utf8' }).split('||\n');
// store information of the current release while we go over all
// commits between this release and previous one
let bugFixes = '';
let features = '';
let header = '';
let breakingChanges = '';
let currentTag;
commitLog.forEach(entry => {
const [shaShort, shaFull, date, commitSubject, refNames, body] = entry.split('|');
if (!header) {
header = `## %RELEASE_LINK% (${date})\n\n`;
}
// check if commit has a tag attached which would indicate a new release
let prevTag = refNames && refNames.match(/tag: (.*?)(,|\))/g);
if (prevTag) {
prevTag = prevTag[0].split(':')[1].trim().slice(0, -1);
}
// we found a previous release! time to add an entry to CHANGELOG.md
// with all the collected changes between releases
if (prevTag && currentTag) {
fs.appendFileSync('./CHANGELOG.md', header.replace('%RELEASE_LINK%', `[${currentTag}](${repoUrl}/compare/${prevTag}...${currentTag})`));
if (features) {
fs.appendFileSync('./CHANGELOG.md', `### Features\n${features}\n\n`);
features = '';
}
if (bugFixes) {
fs.appendFileSync('./CHANGELOG.md', `### Bug Fixes\n${bugFixes}\n\n`);
bugFixes = '';
}
if (breakingChanges) {
fs.appendFileSync('./CHANGELOG.md', `### BREAKING CHANGES\n${breakingChanges}\n\n`);
breakingChanges = '';
}
fs.appendFileSync('./CHANGELOG.md', '\n\n');
header = `## %RELEASE_LINK% (${date})\n\n`;
}
if (commitSubject) {
let commitMsgToAdd = commitSubject.trim();
const issue = commitSubject && commitSubject.match(/\(#\d+\)$/g);
if (issue && issue.length > 0) {
const issueId = issue[0].trim().slice(1, -1);
commitMsgToAdd = commitMsgToAdd.replace(issue[0], `([${issueId}](${repoUrl}/issues/${issueId.slice(1)}))`);
}
// add link to the commit
commitMsgToAdd = `${commitMsgToAdd} ([${shaShort}](${repoUrl}/commit/${shaFull}))`;
if (commitMsgToAdd.startsWith('feat:')) {
features += `\n* ${commitMsgToAdd.slice(5)}`;
} else if (commitMsgToAdd.startsWith('fix:')) {
bugFixes += `\n* ${commitMsgToAdd.slice(4)} `;
}
}
if (body) {
breakingChanges = body.includes('BREAKING CHANGE') && body.split('BREAKING CHANGE').pop().slice(2);
}
if (prevTag) {
currentTag = prevTag;
}
});
});
program.parse(process.argv);