Skip to content

Commit 0f4a089

Browse files
committed
chore(packaging): switch to conventional changelog
1 parent 3c77855 commit 0f4a089

File tree

2 files changed

+12
-211
lines changed

2 files changed

+12
-211
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"broccoli-stew": "^0.2.1",
5353
"broccoli-writer": "^0.1.1",
5454
"canonical-path": "0.0.2",
55+
"conventional-changelog": "^0.0.17",
5556
"css": "mlaval/css#issue65",
5657
"del": "~1",
5758
"dgeni": "^0.4.1",
@@ -96,7 +97,6 @@
9697
"parse5": "1.3.2",
9798
"protractor": "2.0.0",
9899
"q": "^1.0.1",
99-
"qq": "^0.3.5",
100100
"react": "^0.13.2",
101101
"run-sequence": "^0.3.6",
102102
"sorted-object": "^1.0.0",

scripts/publish/changelog.js

Lines changed: 11 additions & 210 deletions
Original file line numberDiff line numberDiff line change
@@ -1,222 +1,23 @@
11
#!/usr/bin/env node
22

3-
// TODO(vojta): pre-commit hook for validating messages
4-
// TODO(vojta): report errors, currently Q silence everything which really sucks
5-
63
'use strict';
74

8-
var child = require('child_process');
95
var fs = require('fs');
10-
var util = require('util');
11-
var q = require('qq');
12-
13-
var GIT_LOG_CMD = 'git log --grep="%s" -E --format=%s %s..HEAD';
14-
var GIT_TAG_CMD = 'git describe --tags --abbrev=0';
15-
16-
var HEADER_TPL = '<a name="%s"></a>\n# %s (%s)\n\n';
17-
var LINK_ISSUE = '[#%s](https://github.com/angular/angular.js/issues/%s)';
18-
var LINK_COMMIT = '[%s](https://github.com/angular/angular.js/commit/%s)';
19-
20-
var EMPTY_COMPONENT = '$$';
21-
22-
23-
var warn = function() {
24-
console.log('WARNING:', util.format.apply(null, arguments));
25-
};
26-
27-
28-
var parseRawCommit = function(raw) {
29-
if (!raw) return null;
30-
31-
var lines = raw.split('\n');
32-
var msg = {}, match;
33-
34-
msg.hash = lines.shift();
35-
msg.subject = lines.shift();
36-
msg.closes = [];
37-
msg.breaks = [];
38-
39-
lines.forEach(function(line) {
40-
match = line.match(/(?:Closes|Fixes)\s#(\d+)/);
41-
if (match) msg.closes.push(parseInt(match[1]));
42-
});
43-
44-
match = raw.match(/BREAKING CHANGE:([\s\S]*)/);
45-
if (match) {
46-
msg.breaking = match[1];
47-
}
48-
6+
var cl = require('conventional-changelog');
497

50-
msg.body = lines.join('\n');
51-
match = msg.subject.match(/^(.*)\((.*)\)\:\s(.*)$/);
8+
var changelogFile = 'CHANGELOG.md';
529

53-
if (!match || !match[1] || !match[3]) {
54-
warn('Incorrect message: %s %s', msg.hash, msg.subject);
55-
msg.type = 'other';
56-
msg.component = 'other';
57-
} else {
58-
msg.type = match[1];
59-
msg.component = match[2];
60-
msg.subject = match[3];
61-
}
62-
63-
return msg;
64-
};
65-
66-
67-
var linkToIssue = function(issue) {
68-
return util.format(LINK_ISSUE, issue, issue);
69-
};
70-
71-
72-
var linkToCommit = function(hash) {
73-
return util.format(LINK_COMMIT, hash.substr(0, 8), hash);
10+
var config = {
11+
file: changelogFile,
12+
repository: 'https://github.com/angular/angular',
13+
version: require('../../package.json').version
7414
};
7515

76-
77-
var currentDate = function() {
78-
var now = new Date();
79-
var pad = function(i) {
80-
return ('0' + i).substr(-2);
81-
};
82-
83-
return util.format('%d-%s-%s', now.getFullYear(), pad(now.getMonth() + 1), pad(now.getDate()));
84-
};
85-
86-
87-
var printSection = function(stream, title, section, printCommitLinks) {
88-
printCommitLinks = printCommitLinks === undefined ? true : printCommitLinks;
89-
var components = Object.getOwnPropertyNames(section).sort();
90-
var buffer = '';
91-
var sectionIsEmpty = true;
92-
93-
var write = function(str) {
94-
buffer += str;
95-
sectionIsEmpty = false;
96-
}
97-
98-
components.forEach(function(name) {
99-
var prefix = '-';
100-
var nested = section[name].length > 1;
101-
102-
if (name !== EMPTY_COMPONENT) {
103-
if (nested) {
104-
write(util.format('- **%s:**\n', name));
105-
prefix = ' -';
106-
} else {
107-
prefix = util.format('- **%s:**', name);
108-
}
109-
}
110-
111-
section[name].forEach(function(commit) {
112-
if (printCommitLinks) {
113-
write(util.format('%s %s\n (%s', prefix, commit.subject, linkToCommit(commit.hash)));
114-
if (commit.closes.length) {
115-
write(',\n ' + commit.closes.map(linkToIssue).join(', '));
116-
}
117-
write(')\n');
118-
} else {
119-
write(util.format('%s %s\n', prefix, commit.subject));
120-
}
121-
});
122-
});
123-
124-
if (sectionIsEmpty) {
125-
// Nothing in this section. Skip.
16+
cl(config, function(err, log) {
17+
if (err) {
18+
console.error('Failed to generate changelog: ' + err);
12619
return;
12720
}
12821

129-
stream.write(util.format('\n## %s\n\n', title));
130-
stream.write(buffer);
131-
stream.write('\n');
132-
};
133-
134-
135-
var readGitLog = function(grep, from) {
136-
var deferred = q.defer();
137-
138-
// TODO(vojta): if it's slow, use spawn and stream it instead
139-
child.exec(util.format(GIT_LOG_CMD, grep, '%H%n%s%n%b%n==END==', from), function(code, stdout, stderr) {
140-
var commits = [];
141-
142-
stdout.split('\n==END==\n').forEach(function(rawCommit) {
143-
var commit = parseRawCommit(rawCommit);
144-
if (commit) commits.push(commit);
145-
});
146-
147-
deferred.resolve(commits);
148-
});
149-
150-
return deferred.promise;
151-
};
152-
153-
154-
var writeChangelog = function(stream, commits, version) {
155-
var sections = {
156-
fix: {},
157-
feat: {},
158-
perf: {},
159-
breaks: {},
160-
other: {}
161-
};
162-
163-
sections.breaks[EMPTY_COMPONENT] = [];
164-
165-
commits.forEach(function(commit) {
166-
var section = sections[commit.type];
167-
var component = commit.component || EMPTY_COMPONENT;
168-
169-
if (section) {
170-
section[component] = section[component] || [];
171-
section[component].push(commit);
172-
}
173-
174-
if (commit.breaking) {
175-
sections.breaks[component] = sections.breaks[component] || [];
176-
sections.breaks[component].push({
177-
subject: util.format("due to %s,\n %s", linkToCommit(commit.hash), commit.breaking),
178-
hash: commit.hash,
179-
closes: []
180-
});
181-
}
182-
});
183-
184-
stream.write(util.format(HEADER_TPL, version, version, currentDate()));
185-
printSection(stream, 'Features', sections.feat);
186-
printSection(stream, 'Performance Improvements', sections.perf);
187-
printSection(stream, 'Breaking Changes', sections.breaks, false);
188-
printSection(stream, 'Other (malformed commit messages)', sections.other);
189-
};
190-
191-
192-
var getPreviousTag = function() {
193-
var deferred = q.defer();
194-
child.exec(GIT_TAG_CMD, function(code, stdout, stderr) {
195-
if (code) deferred.reject('Cannot get the previous tag.');
196-
else deferred.resolve(stdout.replace('\n', ''));
197-
});
198-
return deferred.promise;
199-
};
200-
201-
202-
var generate = function(version, file) {
203-
204-
getPreviousTag().then(function(tag) {
205-
console.log('Reading git log since', tag);
206-
readGitLog('^fix|^feat|^perf|BREAKING', tag).then(function(commits) {
207-
console.log('Parsed', commits.length, 'commits');
208-
console.log('Generating changelog to', file || 'stdout', '(', version, ')');
209-
writeChangelog(file ? fs.createWriteStream(file) : process.stdout, commits, version);
210-
});
211-
});
212-
};
213-
214-
215-
// publish for testing
216-
exports.parseRawCommit = parseRawCommit;
217-
exports.printSection = printSection;
218-
219-
// hacky start if not run by jasmine :-D
220-
if (process.argv.join('').indexOf('jasmine-node') === -1) {
221-
generate(process.argv[2], process.argv[3]);
222-
}
22+
fs.writeFileSync(changelogFile, log);
23+
});

0 commit comments

Comments
 (0)