Skip to content

Instantly share code, notes, and snippets.

@thgh
Created May 1, 2017 11:10
Show Gist options
  • Save thgh/dda4164285d333a72a7d65022d097c31 to your computer and use it in GitHub Desktop.
Save thgh/dda4164285d333a72a7d65022d097c31 to your computer and use it in GitHub Desktop.
deployer.js
#!/usr/bin/env node
const exec = require('child_process').exec
// Default options
const options = {
host: '0.0.0.0',
port: 50005,
path: '/webhook',
delay: 10
}
// Initial state
const state = {
busy: false,
cmdOutput: '',
cmdStart: 0,
cmdEnd: 0
}
// Process command line arguments
process.argv.slice(2).forEach(v => {
if (v > 0 && v < 65536) {
options.port = v
} else {
const url = require('url').parse(v.includes('://') ? v : 'http://' + (v.includes('.') || v.startsWith('/') ? v : '/' + v))
options.host = url.hostname || options.host
options.port = url.port || options.port
options.path = url.path || options.path
}
})
require('http').createServer((request, response) => {
if (!request.url.endsWith(options.path)) {
return request.connection.destroy()
}
// Don't bother if busy
if (state.busy) {
response.writeHead(429)
return response.end(`Still working..\n\nStarted ${startedAgo()} seconds ago`)
}
const output = state.cmdEnd ? `Last deploy took ${lastDuration()} seconds and ended ${endedAgo()} seconds ago.\n\n${state.cmdOutput}` : 'First deploy'
// Rate limiting
if (state.cmdStart && endedAgo() < options.delay) {
response.writeHead(429)
return response.end('Too soon\n\n' + output)
}
toJson(request).then(data => {
if (options.secret && (!data || !data.hook || !data.hook.config || data.hook.config.secret === options.secret)) {
response.writeHead(404)
return response.end(output)
}
deploy()
response.end('Deploying now!\n\n' + output)
})
}).listen(options.port, options.host, 2, () => {
console.log('Listening on', green('http://' + options.host + ':' + options.port + options.path))
})
// Time helper functions
function startedAgo() {
return state.cmdStart && Math.floor((Date.now() - state.cmdStart) / 1000)
}
function endedAgo() {
return state.cmdEnd && Math.floor((Date.now() - state.cmdEnd) / 1000)
}
function lastDuration() {
return (state.cmdEnd - state.cmdStart) / 1000
}
// Request helper
function toJson(request) {
return new Promise((resolve, reject) => {
let body = ''
request.on('data', function(data) {
body += data
if (body.length > 1e5) {
request.connection.destroy()
}
})
request.on('end', function() {
resolve(JSON.parse(body || '{}'))
})
})
}
// Run npm deploy
function deploy() {
state.busy = true
state.cmdStart = Date.now()
exec('npm run deploy', (error, stdout, stderr) => {
state.busy = false
state.cmdError = error
state.cmdOutput = stderr || stdout
state.cmdEnd = Date.now()
})
}
function green(text) {
return '\u001b[1m\u001b[32m' + text + '\u001b[39m\u001b[22m'
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment