Skip to content

Commit cace01d

Browse files
committed
Added dev-dependencie "github" for easy github api access.
now Building a commit history and adding it to the release. Should be able to push releases to github.
1 parent a89cd5d commit cace01d

File tree

2 files changed

+189
-38
lines changed

2 files changed

+189
-38
lines changed

build/tasks/publish.js

Lines changed: 188 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
module.exports = function (grunt) {
22
var Git = require('nodegit');
33
var npmUtils = require('npm-utils');
4+
var Github = require('github');
45
var gitUser = process.env.GIT_USER;
56
var gitPassword = process.env.GIT_PASSWORD;
67
var gitEmail = process.env.GIT_EMAIL;
7-
var releaseNotes;
8+
var lastCommit;
89

910
function getMasterCommit (repo) {
1011
return repo.getMasterCommit();
@@ -66,9 +67,7 @@ module.exports = function (grunt) {
6667
newContent = JSON.parse(blobs[0].toString('utf-8'));
6768
oldContent = JSON.parse(blobs[1].toString('utf-8'));
6869
if (newContent.version != oldContent.version) {
69-
return buildReleaseNotes(repo, oldContent.version).then(function () {
70-
return true;
71-
});
70+
return true;
7271
}
7372
return false;
7473
}).then(function (versionChanged) {
@@ -101,6 +100,10 @@ module.exports = function (grunt) {
101100
return;
102101
}
103102
return getMasterCommit(repository)
103+
.then(function (masterCommit) {
104+
lastCommit = masterCommit.sha();
105+
return masterCommit;
106+
})
104107
.then(getPatches)
105108
.then(findPackageJsonPatch)
106109
.then(function (patch) {
@@ -164,7 +167,7 @@ module.exports = function (grunt) {
164167
return Git.Object.lookup(repository, id, Git.Object.TYPE.COMMIT);
165168
})
166169
.then(function (object) {
167-
return Git.Tag.annotationCreate(repository, version, object, author, 'Release v'+version); // 0 = don't force tag creation
170+
return Git.Tag.create(repository, version, object, author, 'Release v'+version, 0);
168171
}).then(function () {
169172
grunt.log.writeln('Created tag ' + version);
170173
return repository.getRemote('origin');
@@ -189,30 +192,59 @@ module.exports = function (grunt) {
189192
});
190193
}
191194

192-
function buildReleaseNotes (repository, version) {
193-
releaseNotes = '### Release ' + grunt.config.data.version + '\n Commits: \n';
194-
return repository.getReferenceCommit(version).then(function (targetCommit) {
195-
return getMasterCommit(repository).then(function (masterCommit) {
196-
return new Promise(function (resolve) {
197-
var history = masterCommit.history(Git.Revwalk.SORT.TIME);
198-
history.on('end', function (commits) {
199-
for (var i = 0; i < commits.length; i++) {
200-
var commit = commits[i];
201-
if (commit.id().toString() == targetCommit.id().toString()) {
202-
break;
203-
}
204-
205-
if (process.env.TRAVIS_REPO_SLUG) {
206-
releaseNotes += '* [[`' + commit.sha() + '`](https://github.com/' + process.env.TRAVIS_REPO_SLUG + 'commit/' + commit.sha() +')] - ' + commit.summary() + '\n';
207-
} else {
208-
releaseNotes += '* [`' + commit.sha() + '`] - ' + commit.summary() + '\n';
209-
}
210-
}
211-
resolve();
212-
});
213-
history.start();
195+
function publishReleaseNotes () {
196+
var github = new Github();
197+
if (!process.env.TRAVIS_REPO_SLUG) return;
198+
var owner = process.env.TRAVIS_REPO_SLUG.split('/')[0];
199+
var repo = process.env.TRAVIS_REPO_SLUG.split('/')[1];
200+
github.authenticate({
201+
type: 'basic',
202+
username: gitUser,
203+
password: gitPassword
204+
});
205+
var commitParser = new GithubCommitParser(github, owner, repo);
206+
return github.gitdata.getTags({
207+
owner: owner,
208+
repo: repo,
209+
per_page: 1
210+
}).then(function (latestTag) {
211+
var latestReleaseCommit = null;
212+
if (latestTag[0]) {
213+
latestReleaseCommit = latestTag[0].object.sha;
214+
}
215+
return commitParser.loadCommits(lastCommit, latestReleaseCommit)
216+
.then(commitParser.loadClosedIssuesForCommits.bind(commitParser))
217+
.then(commitParser.loadMergedPullRequestsForCommits.bind(commitParser));
218+
}).then(function () {
219+
var releaseNotes = '### Release ' + grunt.config.data.version + '\n';
220+
if (commitParser.closedIssues.length > 0) {
221+
releaseNotes += '## Issues closed in this release: \n';
222+
commitParser.closedIssues.forEach(function (issue) {
223+
releaseNotes += '* [[`#'+ issue.number + '`]](' + issue.html_url + ') - ' + issue.title + '\n';
224+
});
225+
}
226+
if (commitParser.mergedPullRequests.length > 0) {
227+
releaseNotes += '## Merged pull requests in this release: \n';
228+
commitParser.mergedPullRequests.forEach(function (pr) {
229+
releaseNotes += '* [[`#' + pr.number + '`]](' + pr.html_url + ') - ' + pr.title + '\n';
214230
});
231+
}
232+
releaseNotes += '## Commits in this release: \n';
233+
commitParser.commits.forEach(function (commit) {
234+
releaseNotes += '* [[`' + commit.sha.substr(0,7) + '`]](' + commit.html_url + ') - ' + commit.split('\n')[0] + '\n';
235+
});
236+
return releaseNotes;
237+
}).then(function (releaseNotes) {
238+
return github.repos.createRelease({
239+
owner: owner,
240+
repo: repo,
241+
tag_name: grunt.config.data.version,
242+
name: 'Release ' + grunt.config.data.version,
243+
body: releaseNotes
215244
});
245+
})
246+
.then(function () {
247+
grunt.log.writeln('created github release');
216248
});
217249
}
218250

@@ -231,16 +263,134 @@ module.exports = function (grunt) {
231263
}
232264

233265
grunt.registerTask('publish-post-build', function () {
234-
grunt.task.requires('build-only');
235-
var done = this.async();
236-
commitRelease()
237-
.then(function () {
238-
grunt.log.writeln('Done publishing.');
239-
done();
240-
}).catch(function (e) {
241-
grunt.log.error(e);
242-
grunt.log.error(e.stack());
243-
done(false);
266+
grunt.task.requires('build-only');
267+
var done = this.async();
268+
commitRelease()
269+
.then(publishReleaseNotes)
270+
.then(function () {
271+
grunt.log.writeln('Done publishing.');
272+
done();
273+
}).catch(function (e) {
274+
grunt.log.error(e);
275+
grunt.log.error(e.stack());
276+
done(false);
277+
});
278+
});
279+
280+
};
281+
282+
function GithubCommitParser (github, user, repository) {
283+
this.github = github;
284+
this.user = user;
285+
this.repository = repository;
286+
this.reset();
287+
}
288+
GithubCommitParser.prototype = {
289+
reset: function () {
290+
this.commits = [];
291+
this.closedIssuesEvents = [];
292+
this.closedIssues = [];
293+
this.commitPage = 1;
294+
this.issueEventsPage = 1;
295+
this.issueEvents = [];
296+
this.mergedPullRequests = [];
297+
this.mergedPullRequestEvents = [];
298+
},
299+
loadCommits: function (startCommitSha, endCommitSha) {
300+
var containsCommit = this._containsCommit.bind(this, endCommitSha);
301+
var self = this;
302+
return this.github.repos.getCommits({
303+
owner: this.user,
304+
repo: this.repository,
305+
sha: startCommitSha,
306+
page: self.commitPage++,
307+
per_page: 100
308+
}).then(function (commits) {
309+
self.commits = self.commits.concat(commits);
310+
return containsCommit();
311+
}).then(function (res) {
312+
if (res.contains && self.commits.length % 100 === 0) {
313+
self.commits.splice(res.index+1);
314+
return self;
315+
} else {
316+
return self.loadCommits(startCommitSha, endCommitSha);
317+
}
318+
});
319+
},
320+
loadClosedIssuesForCommits: function () {
321+
var self = this;
322+
return new Promise(function (resolve) {
323+
if (self.issueEvents.length === 0) {
324+
resolve(self._loadIssueEvents());
325+
} else {
326+
resolve();
327+
}
328+
}).then(function () {
329+
self._filterClosedIssueEvents();
330+
}).then(function () {
331+
self.closedIssues = self.closedIssuesEvents.map(function (event) {
332+
return event.issue;
244333
});
245-
});
334+
return self;
335+
});
336+
},
337+
loadMergedPullRequestsForCommits: function () {
338+
var self = this;
339+
return new Promise(function (resolve) {
340+
if (self.issueEvents.length === 0) {
341+
resolve(self._loadIssueEvents());
342+
} else {
343+
resolve();
344+
}
345+
}).then(function () {
346+
self._filterPullRequests();
347+
}).then(function () {
348+
self.mergedPullRequests = self.mergedPullRequestEvents.filter(function (event) {
349+
return event.issue;
350+
});
351+
return self;
352+
});
353+
},
354+
_loadIssueEvents: function () {
355+
var self = this;
356+
return this.github.issues.getEventsForRepo({
357+
owner: this.user,
358+
repo: this.repository,
359+
page: this.issueEventsPage++,
360+
per_page: 100
361+
}).then(function (issueEvents) {
362+
self.issueEvents = self.issueEvents.concat(issueEvents);
363+
if (issueEvents.length < 100) {
364+
return;
365+
} else {
366+
return self._loadIssueEvents();
367+
}
368+
});
369+
},
370+
_filterPullRequests: function () {
371+
var commitShas = this.commits.map(function (commit) {
372+
return commit.sha;
373+
});
374+
this.mergedPullRequestEvents = this.issueEvents.filter(function (event) {
375+
return commitShas.indexOf(event.commit_id) != -1 && event.event == 'merged';
376+
});
377+
},
378+
_filterClosedIssueEvents: function () {
379+
var commitShas = this.commits.map(function (commit) {
380+
return commit.sha;
381+
});
382+
this.closedIssuesEvents = this.issueEvents.filter(function (issueEvent) {
383+
return commitShas.indexOf(issueEvent.commit_id) != -1 && issueEvent.event == 'closed' && !issueEvent.issue.pullRequest;
384+
});
385+
},
386+
_containsCommit: function (commitSha) {
387+
var commits = this.commits.map(function (commit) {
388+
return commit.sha;
389+
});
390+
if (commits.indexOf(commitSha) == -1) {
391+
return {contains: false, index: null};
392+
} else {
393+
return {contains: true, index: commits.indexOf(commitSha)};
394+
}
395+
}
246396
};

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"escodegen": "^1.6.1",
1717
"esprima": "^3.0.0",
1818
"estraverse": "^4.1.0",
19+
"github": "^8.1.1",
1920
"grunt": "^1.0.1",
2021
"grunt-cli": "^1.2.0",
2122
"grunt-contrib-jshint": "^1.0.0",

0 commit comments

Comments
 (0)