Skip to content
This repository has been archived by the owner on Jul 31, 2019. It is now read-only.

Commit

Permalink
Merge pull request #207 from mtharrison/dynamic-changelog
Browse files Browse the repository at this point in the history
Dynamic changelog generation using the Github API. Closes #171, #144
  • Loading branch information
nlf committed Jul 28, 2015
2 parents 07bb617 + ba906dc commit 553fdc1
Show file tree
Hide file tree
Showing 9 changed files with 316 additions and 23 deletions.
237 changes: 237 additions & 0 deletions lib/changelog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
var Async = require('async');
var Config = require('getconfig');
var Utils = require('./utils');
var Querystring = require('querystring');

var internals = {};

internals.dependencyRegex = /(?:update|upgrade) (\w+)\/(\w+) to (.*) from (.*)/i;

internals.hapiOrg = 'hapijs';

internals.perPage = 100;

internals.requestOptions = {
headers: {
'user-agent': 'hapijs.com',
'authorization': 'token ' + Config.githubToken
},
json: true
};

exports.methods = [];

exports.methods.push({
name: 'changelog.milestones',
method: function (callback) {

var params = Querystring.encode({
state: 'closed',
per_page: internals.perPage
});

return Utils.downloadAllPages('https://api.github.com/repos/hapijs/hapi/milestones?' + params, internals.perPage, internals.requestOptions, function (err, milestones) {

if (err) {
return callback(err);
}

var compare = function (a, b) {

if (a.id < b.id) {
return 1;
}
if (a.id > b.id) {
return -1;
}
return 0;
};

callback(null, milestones.sort(compare));
});
},
options: {
cache: {
expiresIn: Utils.oneHour,
staleIn: Utils.fifteenMinutes,
staleTimeout: 1000
},
generateKey: function () {

return 'changelogMilestones';
}
}
});

exports.methods.push({
name: 'changelog.build',
method: function (request, callback) {

var methods = request.server.methods.changelog;
var changelog = { };

var getDependencyIssues = function (issue, cb) {

methods.getDependencyIssues(request, issue.title, function (result, err) {

if (err) {
return cb(err);
}

if (!result) {
return cb(null);
}

issue.pluginIssues = {
repo: internals.hapiOrg + '/' + result.repo,
issues: result.issues
};

cb(null);
});
};

var checkForDependencies = function (issues, cb) {

if (issues.length > 0) {

return Async.eachLimit(issues, 10, getDependencyIssues, function (err) {

if (err) {
return cb(err);
}

cb(null);
});
}

cb(null);
};

var getIssues = function (milestone, cb) {

methods.issuesForMilestone('hapi', milestone.number, function (err, issues) {

if (err) {
return cb(err);
}

changelog[milestone.title] = issues;
checkForDependencies(issues, cb);
});
};

Async.eachLimit(request.pre.milestones, 10, getIssues, function (err) {

if (err) {
return callback(err);
}

callback(null, changelog);
});
},
options: {
cache: {
expiresIn: Utils.oneHour,
staleIn: Utils.fifteenMinutes,
staleTimeout: 1000
},
generateKey: function () {

return 'changelog';
}
}
});

exports.methods.push({
name: 'changelog.getDependencyIssues',
method: function (request, issueTitle, callback) {

var methods = request.server.methods.changelog;
var matches = issueTitle.match(internals.dependencyRegex);

if (!matches) {
return callback(null);
}

if (matches[1] !== internals.hapiOrg) {
return callback(null);
}

var repo = matches[2];
var to = matches[3];

methods.getMilestoneNumberFromTitle(repo, to, function (err, number) {

if (!number) {
return callback(null);
}

if (err) {
return callback(err);
}

methods.issuesForMilestone(repo, number, function (err, issues) {

if (err) {
return callback(err);
}

callback({ repo: repo, issues: issues });
});
});
}
});

exports.methods.push({
name: 'changelog.issuesForMilestone',
method: function (repo, milestoneNumber, callback) {

var params = Querystring.encode({
state: 'closed',
milestone: milestoneNumber,
per_page: internals.perPage
});

Utils.downloadAllPages('https://api.github.com/repos/hapijs/' + repo + '/issues?' + params, internals.perPage, internals.requestOptions, function (err, issues) {

if (err) {
return callback(err);
}

callback(null, issues);
});
},
options: {
cache: {
expiresIn: Utils.oneYear
}
}
});

exports.methods.push({
name: 'changelog.getMilestoneNumberFromTitle',
method: function (repo, milestoneTitle, callback) {

var params = Querystring.encode({
state: 'closed',
per_page: internals.perPage
});

Utils.downloadAllPages('https://api.github.com/repos/hapijs/' + repo + '/milestones?' + params, internals.perPage, internals.requestOptions, function (err, milestones) {

for (var i = 0; i < milestones.length; ++i) {
if (milestones[i].title === milestoneTitle) {
return callback(null, milestones[i].number);
}
}

callback(null, null);
});
},
options: {
cache: {
expiresIn: Utils.oneYear
}
}
});
19 changes: 0 additions & 19 deletions lib/github.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,25 +143,6 @@ exports.methods.push({
}
});

exports.methods.push({
name: 'github.changelog',
method: function (callback) {

var options = Hoek.applyToDefaults(internals.requestOptions, {
headers: {
accept: 'application/vnd.github.3.html'
}
});

return Utils.download('https://api.github.com/repos/hapijs/hapi/contents/CHANGELOG.md', options, callback);
},
options: {
cache: {
expiresIn: Utils.oneDay
}
}
});

exports.methods.push({
name: 'github.latestUpdate',
method: function (request, callback) {
Expand Down
5 changes: 3 additions & 2 deletions lib/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@ exports.routes.push({
{ method: 'github.issues()', assign: 'issues' },
{ method: 'github.pullRequests()', assign: 'pullRequests' },
{ method: 'github.commits()', assign: 'commits' },
{ method: 'github.changelog()', assign: 'changelog' }
]
{ method: 'changelog.milestones()', assign: 'milestones' }
],
{ method: 'changelog.build', assign: 'changelog' }
],
handler: function (request, reply) {

Expand Down
45 changes: 45 additions & 0 deletions lib/utils.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
var Async = require('async');
var Wreck = require('wreck');

exports.download = function (url, options, callback) {
Expand All @@ -19,6 +20,50 @@ exports.download = function (url, options, callback) {
});
};

exports.downloadAllPages = function (url, perPage, options, callback) {

if (typeof options === 'function') {
callback = options;
options = {};
}

var page = 1;
var result = [];
var lastSize;

var fn = function (cb) {

Wreck.get(url + '&page=' + page, options, function (err, res, payload) {

if (err || res.statusCode !== 200) {
console.log(res.statusCode);
console.log(payload);
return cb(err || new Error('ERROR: Failed to download, got statusCode: ' + res.statusCode));
}

result = result.concat(payload);
lastSize = payload.length;
page++;
cb(null);
});
};

var test = function () {

return lastSize !== perPage;
};

Async.doUntil(fn, test, function (err) {

if (err) {
return callback(err);
}

callback(null, result);
});
};

exports.fifteenMinutes = 900000;
exports.oneHour = 3600000;
exports.oneDay = 86400000;
exports.oneYear = 31556900000;
2 changes: 1 addition & 1 deletion public/css/main.css

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions public/css/sections/github.styl
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@
color: $orange-dark

.changelog
text-align: left

ul
margin: 0

Expand All @@ -107,6 +109,10 @@
margin-top: 8px
font-size: $font-small
color: $gray-light
margin-left: 57px

li
margin: 10px 0px

@media $smartphone

Expand Down
1 change: 1 addition & 0 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ server.method(require('./lib/npm').methods);
server.method(require('./lib/github').methods);
server.method(require('./lib/markdown').methods);
server.method(require('./lib/community').methods);
server.method(require('./lib/changelog').methods);

server.route(require('./lib/routes').routes);

Expand Down
21 changes: 21 additions & 0 deletions templates/includes/changelog.jade
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
each milestone in milestones
h2
a(href=milestone.html_url, title=milestone.title)
strong= milestone.title

ul.milestone-issues
each issue in changelog[milestone.title]
li
a(href=issue.html_url, title=issue.title)
| ##{issue.number}
| &nbsp; #{issue.title}

if issue.pluginIssues
ul.plugin-issues
li
strong= issue.pluginIssues.repo
each pluginIssue in issue.pluginIssues.issues
li
a(href=pluginIssue.html_url, title=pluginIssue.title)
| ##{pluginIssue.number}
| &nbsp; #{pluginIssue.title}
3 changes: 2 additions & 1 deletion templates/updates.jade
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,5 @@ block content
section.changelog
.content
h3 Changelog
.changelog!= changelog
.changelog
include includes/changelog

0 comments on commit 553fdc1

Please sign in to comment.