Skip to content

Commit

Permalink
Merge pull request #5 from deptofdefense/updates
Browse files Browse the repository at this point in the history
Slight refactor handler.js
  • Loading branch information
tomberek authored Mar 2, 2017
2 parents 7242848 + 5ec0199 commit 4c52273
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 92 deletions.
192 changes: 101 additions & 91 deletions handler.js
Original file line number Diff line number Diff line change
@@ -1,54 +1,63 @@
'use strict';

const https = require('https');
const crypto = require('crypto');
const url = require('url');

// Commentary and postComment func adopted from
// Commentary and postComment func adopted from
// https://github.com/christo4ferris/dco-check-bot/blob/master/bot.js (Apache 2.0)
const dco_not_found = '\n\nPlease submit commits with a Signed-off-by statement in order to allow us to process your pull request.';
const dnf_tail1 =' For example a comment on the last line of your request like this:\n`Signed-off-by: Bob Bobertown <[email protected]>`';
const dnf_tail2 ='\n\nEnsure you supply a valid e-mail with the comment. These commands may be useful:';
const dnf_tail3 ='\n```git commit --amend --signoff```\nor\n```git filter-branch -f --commit-filter \'git commit-tree -S "$@"\' HEAD```'
const dnf_tail =` For example a comment on the last line of your request like this:
\`Signed-off-by: Bob Boberton <[email protected]>\`
Ensure you supply a valid e-mail with the comment. These commands may be useful:
\`\`\`
git commit --amend --signoff
\`\`\`
or
\`\`\`
git filter-branch -f --commit-filter 'git commit-tree -S "$@"' HEAD
\`\`\`
`;
const dco_found = '\n\nI can confirm that a sign-off has been included. It is okay to process this pull request.';
const greeting = 'Hi ';
const thanks = ',\n\nThanks for submitting this pull request!';
const signature = '\n\ndco-bot';

const regex = /^Signed-off-by: .*<[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,63}>$/im;
const regex = /Signed-off-by: .*<[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,63}>$/im;
const regexPath = /[^/]*$/;

var goodChain = true;
var optionsTemplate = {
hostname: 'api.github.com',
method: 'POST',
headers: {
'User-Agent': 'dco-bot',
'Authorization': "token " + process.env.GITHUB_SECRET
}
const optionsTemplate = {
hostname: 'api.github.com',
method: 'POST',
headers: {
'User-Agent': 'dco-bot',
Authorization: `token ${process.env.GITHUB_SECRET}`,
},
};
function deleteComments(payload,callback){
var options = Object.assign({},optionsTemplate,{
function deleteComments(payload, callback) {
const options = Object.assign({}, optionsTemplate, {
path: url.parse(payload.pull_request.comments_url).pathname,
method: 'GET'
method: 'GET',
});
var req = https.request(options, function(res) {
var comments = '';
res.on('data', function (chunk) {
const req = https.request(options, (res) => {
let comments = '';
res.on('data', (chunk) => {
comments += chunk;
});
res.on('end',function(){
var commentsObj = JSON.parse(comments);
commentsObj = commentsObj.filter(function(a){
var body = a.body.split('\n');
return body[body.length-1] == 'dco-bot';
res.on('end', () => {
let commentsObj = JSON.parse(comments);
commentsObj = commentsObj.filter((a) => {
const body = a.body.split('\n');
return body[body.length - 1] === 'dco-bot';
});

for(var i = 0 ; i < commentsObj.length ; i++ ){
var options = Object.assign({},optionsTemplate,{
path: url.parse(commentsObj[i].url).pathname,
method: 'DELETE'
});
var req2 = https.request(options);
req2.end();
for (const comment of commentsObj) {
const options2 = Object.assign({}, optionsTemplate, {
path: url.parse(comment.url).pathname,
method: 'DELETE',
});
const req2 = https.request(options2);
req2.end();
}
callback();
});
Expand All @@ -57,28 +66,28 @@ function deleteComments(payload,callback){
}

function postComment(payload, msg, callback) {
var tmp = {};
const tmp = {};
tmp.body = greeting + payload.pull_request.user.login + thanks + msg + signature;
var postData = JSON.stringify(tmp);
var options = Object.assign({},optionsTemplate,{
const postData = JSON.stringify(tmp);
const options = Object.assign({}, optionsTemplate, {
path: url.parse(payload.pull_request.comments_url).pathname,
});
console.log('posting to: ' + payload.pull_request.comments_url + ' data: ' + postData);
var req = https.request(options, function(res) {
console.log('STATUS: ' + res.statusCode);
if (res.statusCode != 201) {
console.log('HEADERS: ' + JSON.stringify(res.headers));
console.log(`posting to: ${payload.pull_request.comments_url} data: ${postData}`);
const req = https.request(options, (res) => {
console.log(`STATUS: ${res.statusCode}`);
if (res.statusCode !== 201) {
console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
}
res.on('end',function(){
console.log("Returning callback");
callback(null,
{statusCode: 200,
body:"Comment complete: " + payload.pull_request.comments_url });
res.on('end', () => {
console.log('Returning callback');
callback(null,
{ statusCode: 200,
body: `Comment complete: ${payload.pull_request.comments_url}` });
});
});
req.on('error', function(e) {
console.log('unable to post comment: ' + e.message);
errMsg = '[502] Unable to post comment: ' + e.message;
req.on('error', (e) => {
console.log(`unable to post comment: ${e.message}`);
const errMsg = `[502] Unable to post comment: ${e.message}`;
callback(new Error(errMsg));
});
req.end(postData);
Expand All @@ -87,74 +96,75 @@ function postComment(payload, msg, callback) {
// Used as inspiration (CC)
// http://www.slideshare.net/jsquyres/fun-with-github-webhooks-verifying-signedoffby
function getCommits(payload, msg, callback) {
var options = Object.assign({},optionsTemplate,{
let goodChain = true;
const options = Object.assign({}, optionsTemplate, {
path: url.parse(payload.pull_request.commits_url).pathname,
method: 'GET'
method: 'GET',
});
console.log('COMMITS: ' + payload.pull_request.commits_url);
var req = https.get(options, function (res) {
var commitBody = '';
console.log('STATUS: ' + res.statusCode);
if (res.statusCode != 200) {
console.log('HEADERS: ' + JSON.stringify(res.headers));
console.log(`COMMITS: ${payload.pull_request.commits_url}`);
const req = https.get(options, (res) => {
let commitBody = '';
console.log(`STATUS: ${res.statusCode}`);
if (res.statusCode !== 200) {
console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
}
res.setEncoding('utf8');
res.on('data', function (chunk) {
res.on('data', (chunk) => {
commitBody += chunk;
});
res.on('end', function(){
var commits = JSON.parse(commitBody);
var body = {
"target_url": "https://github.com/deptofdefense/code.mil",
"description": "All commits up to this point been signed off.",
"context": "DCO"
res.on('end', () => {
const commits = JSON.parse(commitBody);
const body = {
target_url: 'https://github.com/deptofdefense/code.mil',
description: 'All commits up to this point been signed off.',
context: 'DCO',
};
var badSha;
const path = url.parse(payload.pull_request.statuses_url).pathname.replace(regexPath,'');
for(var i = 0 ; i < commits.length ; i++){
var sha = commits[i].sha;
var options = Object.assign({},optionsTemplate,{path:path + sha});
var bodyLines = commits[i].commit.message.split('\n');
var sigLine = bodyLines[bodyLines.length-1]; // Perhaps it can occur anywhere?
var req2 = https.request(options,function(res2){
req2.on('error',function(e){console.log("error: ",e)});
let badSha;
const path = url.parse(payload.pull_request.statuses_url).pathname.replace(regexPath, '');
for (const commit of commits) {
const options2 = Object.assign({}, optionsTemplate, { path: path + commit.sha });
const bodyLines = commit.commit.message.split('\n');
const sigLine = bodyLines[bodyLines.length - 1]; // Perhaps it can occur anywhere?
const req2 = https.request(options2, () => {
req2.on('error', (e) => { console.log('error: ', e); });
});
if (regex.test(sigLine) && (goodChain || (i != (commits.length - 1)))){
console.log("Setting ",sha," to success.");
body.state = "success";
if (regex.test(sigLine) && (goodChain || (commit !== commits[commits.length - 1]))){
console.log('Setting ', commit.sha, ' to success.');
body.state = 'success';
} else {
goodChain = false;
badSha = badSha || sha;
console.log("Setting ",sha," to error.");
body.state = "error";
body.description = "A commit (" + badSha + ") is not signed off."
goodChain = false;
badSha = badSha || commit.sha;
console.log('Setting ', commit.sha, ' to error.');
body.state = 'error';
body.description = `A commit (${badSha}) is not signed off.`;
}
req2.end(JSON.stringify(body));
}
if (goodChain){

if (goodChain) {
postComment(
payload,
dco_found, callback);
} else {
postComment(
payload,
dco_not_found+dnf_tail1+dnf_tail2+dnf_tail3, callback);
dco_not_found + dnf_tail, callback);
}
});
});
req.on('error', function(e) {
console.log('[502]: Unable to retrieve commits: ' + e.message);
req.on('error', (e) => {
console.log(`[502]: Unable to retrieve commits: ${e.message}`);
});
}

function signRequestBody(key, body) {
return `sha1=${crypto.createHmac("sha1", key).update(JSON.stringify(body)).digest("hex")}`;
return `sha1=${crypto.createHmac('sha1', key).update(JSON.stringify(body)).digest('hex')}`;
}

module.exports.dcobot = (event, context, callback) => {
// Mangled and adopted (unknown license) from
// Mangled and adopted (unknown license) from
// https://raw.githubusercontent.com/serverless/examples/master/aws-node-github-webhook-listener/handler.js
var errMsg;
let errMsg;
const token = process.env.GITHUB_WEBHOOK_SECRET;
const headers = event.headers;
const sig = headers['X-Hub-Signature'];
Expand Down Expand Up @@ -184,13 +194,13 @@ module.exports.dcobot = (event, context, callback) => {
// event.body = JSON.parse(event.body); Not needed with serverless libraries.
console.log(`Github-Event: "${githubEvent}" with action: "${event.body.action}"`);

if (event.body.action != 'opened' && event.body.action != 'reopened' && event.body.action != 'synchronize'){
errMsg = '[202] No action required for ' + event.body.action;
if (event.body.action !== 'opened' && event.body.action !== 'reopened' && event.body.action !== 'synchronize') {
errMsg = `[202] No action required for ${event.body.action}`;
return callback(new Error(errMsg));
}
deleteComments(event.body,function(){
getCommits(event.body,'',callback);
deleteComments(event.body, () => {
getCommits(event.body, '', callback);
});
return callback(null, {statusCode:200,body:'Success: ' + JSON.stringify(event.body)});
return callback(null, { statusCode: 200, body: `Success: ${JSON.stringify(event.body)}` });
};

7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,15 @@
"logs": "serverless logs -f dcobot -t"
},
"author": "Tom Bereknyei",
"license": "MIT",
"license": "BSD-2",
"dependencies": {
"crypto": "^0.0.3",
"https": "^1.0.0",
"url": "^0.11.0"
},
"devDependencies": {
"eslint": "^3.16.1",
"eslint-config-airbnb-base": "^11.1.0",
"eslint-plugin-import": "^2.2.0"
}
}

0 comments on commit 4c52273

Please sign in to comment.