Skip to content

Commit

Permalink
Merge pull request #1 from mauris/develop
Browse files Browse the repository at this point in the history
Development updates for 1.1.0
  • Loading branch information
mauris authored Aug 22, 2016
2 parents e33b79b + 3128dde commit 187e2be
Show file tree
Hide file tree
Showing 7 changed files with 285 additions and 64 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,5 @@ $RECYCLE.BIN/

# Linux trash folder which might appear on any partition or disk
.Trash-*

testAuth.json
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

Accuser is a lightweight framework that lets you write Github bots that monitor Pull Requests and assign a person to the PR.

The framework wraps around the [node-github](https://github.com/mikedeboer/node-github) library to make it easier to monitor pull requests, assign people and write comments.

## Future Implementation

- [ ] Adding / Removing Labels
- [ ] Renaming Title
- [ ] Support for issues also

## License

Code released under the MIT license.
Code released under the MIT license.
24 changes: 21 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,33 @@
{
"name": "accuser",
"version": "1.0.4",
"version": "1.1.0",
"description": "A Github Pull Request bot for assigning people to pull requests",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"test": "mocha"
},
"author": "Sam Yong <mauris@hotmail.sg>",
"contributors": [
{
"name": "Sam Yong",
"email": "mauris@hotmail.sg"
}
],
"homepage": "https://github.com/mauris/accuser",
"repository": {
"type": "git",
"url": "https://github.com/mauris/accuser.git"
},
"author": "Sam Yong",
"license": "MIT",
"engine": {
"node": ">=0.4.0"
},
"dependencies": {
"bluebird": "^3.4.1",
"github": "^2.5.1"
},
"devDependencies": {
"mocha": "^3.0.2",
"sinon": "^1.17.5"
}
}
119 changes: 59 additions & 60 deletions src/Accuser.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

var GitHubApi = require("github");
var Promise = require('bluebird');
var Repository = require("./Repository");

var Accuser = function (options) {
options = options || {};
Expand All @@ -20,12 +21,6 @@ Accuser.prototype.authenticate = function(config) {
return this.github.authenticate(config);
};

Accuser.prototype.watch = function(user, repository) {
var self = this;
this.repos.push([user, repository]);
return self;
}

Accuser.prototype.accuse = function(pr, usernames) {
var self = this;
self.github.issues.addAssigneesToIssue({
Expand All @@ -46,73 +41,77 @@ Accuser.prototype.comment = function(pr, comment) {
});
};

Accuser.prototype.addWorker = function() {
Accuser.prototype.addRepository = function(user, repo) {
var self = this;
var worker = {
'filters': [],
'do': []
};
this.workers.push(worker);
var workerChainer = {
"filter": function(filterCallback) {
worker.filters.push(filterCallback);
return workerChainer;
},
"do": function(doCallback) {
worker.do.push(doCallback);
return workerChainer;
}
};
return workerChainer;
var repository = new Repository(user, repo);
self.repos.push(repository);
return repository;
};

Accuser.prototype.run = function() {
var self = this;
var github = self.github;
var prList = [];

var runWorkers = function() {
// the list is now done, run all workers
self.workers.forEach(function(worker){
prList.forEach(function(pr){
var activateWorker = true;
worker.filters.forEach(function(filter){
activateWorker = activateWorker && filter(pr);
});
if (activateWorker) {
worker.do.forEach(function(doCallback){
doCallback(pr);
});
}
var runWorkers = function(repository, prList) {
// the list is now done, run all workers
repository.workers.forEach(function(worker){
prList.forEach(function(pr){
var activateWorker = true;
worker.filters.forEach(function(filter){
activateWorker = activateWorker && filter(repository, pr);
});
if (activateWorker) {
worker.do.forEach(function(doCallback){
doCallback(repository, pr);
});
}
});
};
});
};

var tick = function() {
self.repos.forEach(function(val) {
var user = val[0];
var repo = val[1];
var createResponseCallback = function(github, resolve, repository) {
return function(result) {
runWorkers(repository, result);
if (github.hasNextPage(result)) {
github.getNextPage(result, processResponse);
} else {
// done with all paginations
resolve();
}
};
};

var processResponse = function(res) {
prList = prList.concat(res);
if (github.hasNextPage(res)) {
github.getNextPage(res, processResponse);
} else {
runWorkers();
setTimeout(tick, self.interval);
}
}
Accuser.prototype.tick = function() {
var self = this;
var promises = [];
self.repos.forEach(function(repository) {
var repoPromise = new Promise(function(resolve, reject){
self.github.pullRequests
.getAll({
'user': user,
'repo': repo,
'user': repository.user,
'repo': repository.repo,
'state': 'open'
})
.then(processResponse);
.then(createResponseCallback(self.github, resolve, repository));
});
promises.push(repoPromise);
});

return Promise
.all(promises);
};

Accuser.prototype.run = function() {
var self = this;
var github = self.github;

var tickInterval = function() {
self.tick()
.then(function() {
setTimeout(tickInterval, self.interval);
});
};

tick();
}
self.tick()
.then(function() {
setTimeout(tickInterval, self.interval);
});
};

module.exports = Accuser;
28 changes: 28 additions & 0 deletions src/Repository.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

var Repository = function (user, repo) {
this.user = user;
this.repo = repo;
this.workers = [];
};

Repository.prototype.newWorker = function() {
var self = this;
var worker = {
'filters': [],
'do': []
};
self.workers.push(worker);
var workerChainer = {
"filter": function(filterCallback) {
worker.filters.push(filterCallback);
return workerChainer;
},
"do": function(doCallback) {
worker.do.push(doCallback);
return workerChainer;
}
};
return workerChainer;
};

module.exports = Repository;
131 changes: 131 additions & 0 deletions test/testAccuser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
var assert = require('assert');
var sinon = require('sinon');
var Promise = require('bluebird');
var Accuser = require('../');

describe("Accuser", function() {
var accuser;
var samplePR = {
number: 20,
base: {
repo: {
name: "accuser",
owner: {
login: "mauris"
}
}
}
};

beforeEach(function() {
accuser = new Accuser();
});

it("should authenticate with Github", function(next) {
var repository = accuser.addRepository("mauris", "accuser");
assert(repository);
assert(accuser.repos[0] === repository);
next();
});

it("should be able to add a new repository", function(next) {
accuser.github = {
authenticate: function(config){
assert(config.type === "oauth");
assert(config.token === "some token");
}
};
var mock = sinon.mock(accuser.github);
mock.expects("authenticate").once();
accuser.authenticate({
"type": "oauth",
"token": "some token"
});
mock.verify();
next();
});

it("should accuse someone based on a pull request object and username", function(next) {
accuser.github = {
issues: {
addAssigneesToIssue: function(obj) {
assert(obj.repo === samplePR.base.repo.name);
assert(obj.user === samplePR.base.repo.owner.login);
assert(obj.number === samplePR.number);
assert(obj.assignees[0] === "mauris");
}
}
};
var mock = sinon.mock(accuser.github.issues);
mock.expects("addAssigneesToIssue").once();
accuser.accuse(samplePR, ["mauris"]);
mock.verify();
next();
});

it("should add a comment to a pull request", function(next) {
accuser.github = {
issues: {
createComment: function(obj) {
assert(obj.repo === samplePR.base.repo.name);
assert(obj.user === samplePR.base.repo.owner.login);
assert(obj.number === samplePR.number);
assert(obj.body === "some comment");
}
}
};
var mock = sinon.mock(accuser.github.issues);
mock.expects("createComment").once();
accuser.comment(samplePR, "some comment");
mock.verify();
next();
});

it("should fetch pull requests from an added repository", function(next) {
var repository = accuser.addRepository("mauris", "accuser");

var filterSpy = sinon.spy();
var workerFilter = function(repo, pr) {
assert(repository === repo);
assert(pr == samplePR);
filterSpy();
return true;
};

var doSpy = sinon.spy();
var workerDo = function(repo, pr) {
assert(repository === repo);
assert(pr == samplePR);
doSpy();
};

repository.newWorker()
.filter(workerFilter)
.do(workerDo);

accuser.github = {
pullRequests: {
getAll: function(obj) {
return new Promise(function(resolve, reject){
resolve([samplePR]);
})
}
},
hasNextPage: function() {
return false
}
};
var mock = sinon.mock(accuser.github.pullRequests);
mock.expects("getAll").once().returns(new Promise(function(resolve, reject){
resolve([samplePR]);
}));

accuser.tick()
.then(function(){
assert(filterSpy.calledOnce);
assert(doSpy.calledOnce);
mock.verify();
next();
});
});
});
Loading

0 comments on commit 187e2be

Please sign in to comment.