-
-
Save tbranyen/2481cfdb27424d60e528 to your computer and use it in GitHub Desktop.
// | |
// README: | |
// - Listens for PUSH events | |
// - Fetches the ref pushed via the given remote | |
// - Sets the repositories HEAD to latest ref | |
// - Checks out the new HEAD (--force) | |
// - Install dependencies from package.json | |
// - Calls `npm run reload` (My app uses this) | |
// - Calls `nginx -s reload` (My app also uses this) | |
// | |
// Usage: | |
// export SECRET=YOUR_GITHUB_WEBHOOK_SECRET | |
// export CWD=/path/to/your/project | |
// export REMOTE=origin | |
// export SOCKET_PRIV="your_user:your_group" | |
// export GIT_AUTHOR="Your Name" | |
// export GIT_EMAIL="Your Email" | |
// | |
// As root: | |
// node auto-deploy | |
// | |
['SECRET', 'CWD', 'REMOTE', 'SOCKET_PRIV', 'GIT_AUTHOR', 'GIT_EMAIL'] | |
.forEach(function(ENV) { | |
if (!(ENV in process.env)) { | |
console.error('Missing environment variable: ' + ENV); | |
process.exit(); | |
} | |
}); | |
var express = require('express'); | |
var Git = require('nodegit'); | |
var exec = require('child_process').execSync; | |
var createHandler = require('github-webhook-handler'); | |
var GHWebHook = createHandler({ path: '/', secret: process.env.SECRET }); | |
var me = Git.Signature.now(process.env.GIT_AUTHOR, process.env.GIT_EMAIL); | |
GHWebHook.on('push', function (event) { | |
var payload = event.payload; | |
if (payload.ref !== 'refs/heads/master') { | |
return; | |
} | |
function fetchRemote(repo) { | |
console.log('Fetching remote', process.env.REMOTE); | |
return repo.getRemote(process.env.REMOTE).then(function(remote) { | |
remote.setCallbacks({ | |
credentials: function(url, userName) { | |
return Git.Cred.sshKeyFromAgent(userName); | |
} | |
}); | |
return remote.fetch([payload.ref], me, 'Fetched latest deployment'); | |
}).then(function() { | |
return repo; | |
}); | |
} | |
function resetAndCheckout(repo) { | |
return repo.getReference(process.env.REMOTE).then(function(ref) { | |
console.log('Changing HEAD to', ref.target()); | |
return repo.setHead(ref.name(), me, 'Set head to ' + ref.target()); | |
}).then(function() { | |
console.log('Checking out HEAD'); | |
return Git.Checkout.head(repo, { | |
checkoutStrategy: Git.Checkout.STRATEGY.FORCE | |
}); | |
}); | |
} | |
function reloadAndComplete() { | |
console.log('Ensure Node modules are up-to-date'); | |
exec('npm install', { cwd: process.env.CWD }); | |
console.log('Reloading application'); | |
exec('npm run reload', { cwd: process.env.CWD }); | |
console.log('Resetting NGINX'); | |
exec('nginx -s reload'); | |
console.log('Completed deployment'); | |
} | |
// Async-flow. | |
Promise.resolve(process.env.CWD) | |
.then(function(path) { | |
console.log('Opened repository'); | |
return Git.Repository.open(path); | |
}) | |
.then(fetchRemote) | |
.then(resetAndCheckout) | |
.then(reloadAndComplete) | |
.catch(function(ex) { | |
console.log(ex.stack); | |
}); | |
}); | |
// Attempt to clean up previous socket and re-bind. | |
try { exec('rm ./socket'); } catch (ex) {} | |
express().use(GHWebHook).listen('./socket'); | |
exec('chown ' + process.env.SOCKET_PRIV + ' ./socket'); |
@thejmazz, it's super common to use env variables, but I wouldn't set these in the .bashrc
. Maybe in a Makefile or bash script. That way it's easier to run.
@tbranyen Oh yeah good idea, thanks!
Hi, I try to do something like this, and have copied line 69 - 80. Where you have "process.env.REMOTE" I have a name for a tag, and that works, "ref.isValid()" says it's true. But when I get to the next thing:
return repo.setHead(ref.name(), repo.defaultSignature, 'Set head to ' + ref.target());
Then I get this error:
Assertion failed: (handle->InternalFieldCount() > 0), function Unwrap, file /Users/johnh/.node-gyp/0.10.38/src/node_object_wrap.h, line 61.
Am I doing something wrong?
Edit: It worked when creating a signature.
@tbranyen Thanks for sharing this. A late question: I was wondering if there is any reason behind using execSync and not making asynchronous calls instead on line 76-87?
Cool! Was planning on figuring out how to do this myself after just playing with nodegit. Then I saw your tweet retweeted by @nodegit and came across this! Will save me some time haha. Is it normal practice to export environment variables for something like this in your
.bashrc
(or relevant) or to set them temporarily when starting up the script? Server should be always on so its not really temporary but still lol.