Skip to content

Commit

Permalink
Saving major refactor.
Browse files Browse the repository at this point in the history
  • Loading branch information
Josh Mervine committed Feb 4, 2014
1 parent 8fd759d commit 687476f
Show file tree
Hide file tree
Showing 10 changed files with 345 additions and 72 deletions.
5 changes: 5 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
language: node_js
node_js:
- "0.8"
- "0.10"
- "0.11"
104 changes: 104 additions & 0 deletions bin/gitfish
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#!/usr/bin/env node
var fs = require('fs');
var which = require('which').sync;
var path = require('path');
var action = process.argv[2];
var confile = process.argv[3];

// Ensure forever.
var forever;
try {
forever = which('forever');
} catch (e) {
forever = path.resolve(__dirname, '..', 'node_modules', '.bin', 'forever');
}
if (!fs.existsSync(forever)) {
usage(new Error('Forever not found.'));
}

// Default config file, if not specified.
if (typeof confile === 'undefined') {
confile = path.resolve(process.cwd(), 'config.json');
}

// Config file must exist.
if (!fs.existsSync(confile)) {
usage(new Error('Config file ('+confile+') wasn\'t found.'));
}

var script = 'gitfish.js';
var args = [process.argv[0], forever, action];
var config = require(confile);
var log = config.log || path.resolve(__dirname, '..', 'gitfish.log');
switch(action) {
case 'run':
require('../')({ config: confile || 'config.json' });
break;
case 'start':
case 'restart':
args = startArgs(args);
args.push(script);
execForever(args);
break;
case 'stop':
case 'logs':
args.push(script);
execForever(args);
break;
case 'list':
execForever(args);
break;
default:
usage();
}

function startArgs(args) {
return args.concat([
"--max", "1",
"--minUptime", "2000",
"--spinSleepTime", "2000",
"--plain", "--append",
"--sourceDir", path.resolve(__dirname),
"--pidFile", path.resolve(__dirname, '..', 'gitfish.pid'),
"--outFile", log,
"--errFile", log,
"--logFile", log
]);
}

function execForever(args) {
//console.dir(args);
//console.log(args.join(' '));
var childProcess = require('child_process');
childProcess.exec(args.join(' '), function (err, stdout, stderr) {
if (err) {
usage(err);
} else if (stderr) {
usage(new Error(stderr));
} else {
console.log(stdout);
process.exit(0);
}
});
}

// Print usage.
function usage(err) {
if (err) {
console.log(err.message);
//console.log(' ');
}
console.log('USAGE: gitfish ACTION [CONFIG_FILE]');
console.log(' ');
console.log(' Default CONFIG_FILE is <cwd>/config.json');
console.log(' ');
console.log(' Actions:');
console.log(' - run :: start gitfish in current session');
console.log(' - start :: starts gitfish daemonized w/ forever');
console.log(' - restart :: restarts gitfish daemon');
console.log(' - stop :: stops gitfish daemon');
console.log(' - list :: gitfish daemon information');
console.log(' ');
process.exit(1);
}

1 change: 1 addition & 0 deletions bin/gitfish.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require('../')({ config: process.argv[2] || 'config.json' });
6 changes: 1 addition & 5 deletions example.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
{
"port": 8000,
"token": "go-fish",
"command": {
"command" : "console.log('woot! command!')"
},
"script": {
"script": "example.script.js"
},
"gofish" : {
"command" : "console.log('you posted to /gofish')",
"script": "./test/script.js",
"branch" : "master"
}
}

154 changes: 89 additions & 65 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,79 +1,103 @@
#!/usr/bin/env node
var path = require('path');
var express = require('express');
var app = express();

var config;
try {
config = require(path.resolve(process.cwd(), (process.argv[2] || './config.json')));
} catch (e) {
console.error('RTFM yo! You need a config file!');
console.trace(e);
process.exit(1);
}

config.port = config.port || 8000;

app.use(express.bodyParser());

app.get('/:endpoint', function (req, res) {
console.log('Ack! Someone\'s trying to GET me!');
res.send(403);
return;
});

app.post('/:endpoint', function (req, res) {
var endpoint = req.param('endpoint');
console.log('Processing request: /%s', endpoint);
if (req.query.token !== config.token) {
res.send(403);
return;
var http = require('http');
var path = require('path');
var logger = require('./lib/logger');
var spawn = require('child_process').spawn;
var qs = require('querystring');

module.exports = function(c) {

if (c.logger) {
logger = c.logger;
}

var ref;
var config;
try {
ref = JSON.parse(req.body.payload).ref;
config = require(path.resolve(process.cwd(), c.config));
} catch (e) {
console.log('Invalid request...');
console.trace(e);
res.send(500);
return;
logger.error('RTFM yo! You need a config file!');
logger.error(e.stack);
process.exit(1);
}

if (config[endpoint].branch && !ref.match(config[endpoint].branch)) {
// Everything worked, but there's nothing to do here because
// we didn't see the right branch.
console.log('Skipping request: \n -> %s doesn\'t match %s', ref, config[endpoint].branch);
res.send(200);
return;
}
config.port = c.port || config.port || 8000;

if (config[endpoint].command) {
eval(config[endpoint].command);
res.send(200);
return;
}
http.createServer(function (request, response) {

var parts = request.url.split('?');

request.pathname = parts[0];
request.query = qs.parse(parts[1]);

if (request.method !== 'POST' ||
request.query.token !== config.token) {
logger.warn('Forbidden request: %s', request.url);
response.writeHead(403, {'Content-Type': 'text/plain'});
response.end('Forbidden 403\n');
return;
}

var endpoint = request.pathname;
if (endpoint.indexOf('/') === 0) {
endpoint = endpoint.replace('/', '');
}

if (typeof config[endpoint] === 'undefined') {
logger.error(new Error('404: Missing action: ' + endpoint).stack);
response.writeHead(404, {'Content-Type': 'text/plain'});
response.end('File Not Found 404\n');
return;
}

if (config[endpoint].script) {
console.log(' Running: \n -> %s', config[endpoint].script);
require('child_process').spawn(path.resolve(process.cwd(),config[endpoint].script), [], {
detached: true,
stdio: 'inherit'
var body = '';
request.on('data', function (data) {
body += data;
});
res.send(200);
return;
}
console.trace(new Error('Missing action.'));
res.send(500);
});

console.log('Starting on port: %s', config.port);
request.on('end', function () {
body = JSON.parse(body);

Object.keys(config).forEach(function (key) {
if (key !== "token" && key !== "port") {
console.log(' -> /%s', key);
}
});
var ref;
try {
ref = body.payload.ref;
} catch (e) {
logger.error('Invalid post:');
logger.error(e.stack);
response.writeHead(500, {'Content-Type': 'text/plain'});
response.end('Application Error 500\n');
return;
}

if (config[endpoint].branch &&
!ref.match(config[endpoint].branch)) {
logger.warn('Skipping request:\n -> %s doesn\'t match %s',
ref, config[endpoint].branch);
response.writeHead(200, {'Content-Type': 'text/plain'});
response.end();
return;
}

if (config[endpoint].script) {
logger.info(' Running:\n -> %s', config[endpoint].script);
spawn(path.resolve(process.cwd(), config[endpoint].script), [], {
detached: true,
stdio: 'inherit'
});
response.writeHead(200, {'Content-Type': 'text/plain'});
response.end();
return;
}
});

}).listen(config.port);

logger.info('Server running on port ', config.port);

Object.keys(config).forEach(function (key) {
if (key !== "token" && key !== "port") {
logger.info(' -> /%s', key);
}
});

};

app.listen(config.port);
12 changes: 12 additions & 0 deletions lib/logger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
var winston = require('winston');
var transport = new (winston.transports.Console)({ json: false, timestamp: true });
var logger = new (winston.Logger)({
level: 'info',
json: false,
timestamp: true,
exitOnError: false,
transports: [ transport ]
});

module.exports = logger;

29 changes: 27 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,35 @@
{
"name": "git-fish",
"version": "0.0.1",
"description": "Wrapper for phantomjs yslow.js",
"main": "./index.js",
"bin": {
"git-fish": "./index.js"
"git-fish": "./bin/gitfish"
},
"scripts": {
"test": "./test/test.js"
},
"repository": {
"type": "git",
"url": "https://github.com/jmervine/node-git-fish.git"
},
"keywords": [
"git",
"github",
"post recieve hook",
"hook",
"autodeploy",
"deployment"
],
"author": "Joshua Mervine <joshua@mervine.net> (http://mervine.net)",
"license": "MIT",
"dependencies": {
"express": "~3.3.5"
"forever": "~0.10.11",
"which": "~1.0.5",
"winston": "~0.7.2"
},
"devDependencies": {
"request": "~2.33.0",
"tape": "~2.4.2"
}
}
8 changes: 8 additions & 0 deletions test/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env node
var fs = require('fs');
fs.writeFile('/tmp/.git.fish.test.out', 'test', { encoding: 'utf-8' }, function (err) {
if (err) {
console.trace(err);
}
});

Loading

0 comments on commit 687476f

Please sign in to comment.