Skip to content

Commit

Permalink
my hands are typing words
Browse files Browse the repository at this point in the history
  • Loading branch information
maccyber committed Oct 31, 2016
1 parent c4fe130 commit 27e5f3e
Show file tree
Hide file tree
Showing 12 changed files with 149 additions and 72 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

# dockerhub-webhook

Automatic [Docker](https://www.docker.com) deployment with [Webhooks](https://docs.docker.com/docker-hub/builds/#webhooks) written in [NodeJS](https://nodejs.org).
Automatic [docker](https://www.docker.com) deployment with [webhooks](https://docs.docker.com/docker-hub/builds/#webhooks).

dockerhub-webhook listens to incoming HTTP POST-requests from hub.docker.com and triggers your specified script(s).

Expand All @@ -16,6 +16,8 @@ dockerhub-webhook listens to incoming HTTP POST-requests from hub.docker.com and
* Can be runned in a docker container
* Supports updating multiple docker images
* Scripts can trigger docker or docker-compose
* Used in production
* Good logging

# Create a token
Create a secret token with ``openssl``, ``uuidgen`` or something else. Don't use any slashes since token is going to be used in the URL.
Expand Down
22 changes: 15 additions & 7 deletions handlers/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
'use strict'

const config = require('../config')
const runScript = require('../lib/run-script')
const Boom = require('boom')
const config = require('../config')
const hookAction = require('../lib/hook-action')

module.exports = (request, reply) => {
const hooks = require('../scripts')
Expand All @@ -25,15 +25,23 @@ module.exports = (request, reply) => {
request.log(['debug'], err)
reply(Boom.badRequest(err))
} else {
reply(payload.repository.name).code(204)

request.log(['debug'], 'Payload from docker hub:')
request.log(['debug'], payload)
request.log(['debug'], `Updating repo: ${payload.repository.name}`)
request.log(['debug'], `Running hook on repo: ${payload.repository.name}`)

const options = {
script: hooks[payload.repository.name],
callbackUrl: payload.callback_url,
request: request
callbackUrl: payload.callback_url
}
reply(payload.repository.name).code(204)
runScript(options)
hookAction(options, (err, data) => {
if (err) {
request.log(['err'], err)
} else {
request.log(['debug'], data.script)
request.log(['debug'], data.callback)
}
})
}
}
9 changes: 6 additions & 3 deletions lib/dockerhub-callback.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ const http = require('request')

module.exports = (options, callback) => {
if (!options) {
return callback(new Error('Missing required input: options'))
return callback('Missing required input: options')
}
if (!options.callbackUrl) {
return callback(new Error('Missing required input: options.callbackUrl'))
return callback('Missing required input: options.callbackUrl')
}
const httpOptions = {
json: true,
Expand All @@ -24,10 +24,13 @@ module.exports = (options, callback) => {
http(httpOptions, (err, response, body) => {
if (err) {
return callback(err)
} else if (response.statusCode !== 200) {
return callback(`Callback URL returned: ${body}`)
}
const message = {
code: response.statusCode,
response: body,
text: `Callback sent to ${options.callbackUrl}`
text: `Callback successfully sent to ${options.callbackUrl}`
}
return callback(null, message)
})
Expand Down
29 changes: 29 additions & 0 deletions lib/hook-action.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'use strict'

const runScript = require('../lib/run-script')
const dockerhubCallback = require('../lib/dockerhub-callback')

module.exports = (options, callback) => {
if (!options) {
return callback('Missing required input: options')
}
if (!options.callbackUrl) {
return callback('Missing required input: options.callbackUrl')
}
if (!options.script) {
return callback('Missing required input: options.script')
}
runScript(options, (err, data) => {
if (err) {
return callback(err)
} else {
dockerhubCallback(data.options, (err, result) => {
if (err) {
return callback(err)
} else {
return callback(null, { callback: result.text, script: data.result })
}
})
}
})
}
41 changes: 12 additions & 29 deletions lib/run-script.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,47 +2,30 @@

const path = require('path')
const fileExists = require('file-exists')
const dockerhubCallback = require('./dockerhub-callback')
const exec = require('child_process').exec

module.exports = (options) => {
module.exports = (options, callback) => {
if (!options) {
return new Error('Missing required input: options')
}
if (!options.request) {
return new Error('Missing required input: options.request')
return callback('Missing required input: options')
}
if (!options.script) {
return new Error('Missing required input: options.script')
return callback('Missing required input: options.script')
}
const request = options.request
const cmd = path.resolve('scripts/' + options.script)
if (!fileExists(cmd)) {
request.log(['debug'], `File: ${cmd} does not exist`)
return new Error(`File: ${cmd} does not exist`)
const scriptPath = path.resolve('scripts/' + options.script)
if (!fileExists(scriptPath)) {
return callback(`File: ${scriptPath} does not exist`)
}
request.log(['debug'], `Running script: ${cmd}`)
exec(cmd, (err, stdout, stderr) => {
if (err || stderr) {
exec(scriptPath, (err, stdout, stderr) => {
if (err) {
return callback(err)
} else if (stderr) {
options.state = 'error'
}
const result = err || stderr || stdout
if (result) {
options.description = result.substring(0, 200)
request.log(['debug'], result)
}
if (options.callbackUrl) {
dockerhubCallback(options, (err, data) => {
if (err) {
request.log(['error'], err)
}
request.log(['debug'], data.text)
request.log(['debug'], data.response)
return
})
} else {
return
return callback(null, { options: options, result: result })
}
return callback(null, true)
})
}

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "dockerhub-webhook",
"version": "2.0.3",
"version": "2.0.4",
"description": "Docker hub webhook",
"license": "MIT",
"author": {
Expand Down
18 changes: 11 additions & 7 deletions plugins/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,17 @@ const goodOptions = {
interval: 900000
},
reporters: {
console: [{
module: 'good-squeeze',
name: 'Squeeze',
args: [{ log: '*', ops: '*', error: '*', request: '*', response: '*' }]
}, {
module: 'good-console'
}, 'stdout']
console: [
{
module: 'good-squeeze',
name: 'Squeeze',
args: [{ log: '*', ops: '*', error: '*', request: '*', response: '*' }]
},
{
module: 'good-console'
},
'stdout'
]
}
}

Expand Down
2 changes: 2 additions & 0 deletions scripts/fail.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
echo "I fail"
exit 1
3 changes: 2 additions & 1 deletion scripts/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@

module.exports = {
'testhook': 'hello.sh', // Name of reponame : Script
'maccyber.io': 'maccyber.io.sh'
'maccyber.io': 'maccyber.io.sh',
'fail': 'fail.sh'
}
6 changes: 3 additions & 3 deletions test/test-dockerhub-callback.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ const dockerhubCallback = require('../lib/dockerhub-callback')
tap.test('dockerhubCallback missing options', (t) => {
const options = false
dockerhubCallback(options, (err) => {
t.equal(err.message, 'Missing required input: options', 'Missing options ok')
t.equal(err, 'Missing required input: options', 'Missing options ok')
t.end()
})
})

tap.test('dockerhubCallback missing options.callbackUrl', (t) => {
const options = {}
dockerhubCallback(options, (err) => {
t.equal(err.message, 'Missing required input: options.callbackUrl', 'Missing options.callbackUrl ok')
t.equal(err, 'Missing required input: options.callbackUrl', 'Missing options.callbackUrl ok')
t.end()
})
})
Expand All @@ -37,7 +37,7 @@ tap.test('dockerhubCallback', (t) => {
if (err) {
throw err
}
t.equal(data.text, `Callback sent to ${options.callbackUrl}`, 'dockerhubCallback ok')
t.equal(data.text, `Callback successfully sent to ${options.callbackUrl}`, 'dockerhubCallback ok')
t.equal(data.response.test, 'ok', 'dockerhubCallback response ok')
t.end()
})
Expand Down
31 changes: 31 additions & 0 deletions test/test-hook-action.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'use strict'

const tap = require('tap')
const hookAction = require('../lib/hook-action')

tap.test('hookAction missing options', (t) => {
const options = false
hookAction(options, (err) => {
t.equal(err, 'Missing required input: options', 'Missing options ok')
t.end()
})
})

tap.test('hookAction missing options.callbackUrl', (t) => {
const options = {}
hookAction(options, (err) => {
t.equal(err, 'Missing required input: options.callbackUrl', 'Missing options.callbackUrl ok')
t.end()
})
})

tap.test('hookAction missing options.script', (t) => {
const options = {
callbackUrl: true
}
hookAction(options, (err) => {
t.equal(err, 'Missing required input: options.script', 'Missing options.script ok')
t.end()
})
})

54 changes: 34 additions & 20 deletions test/test-run-script.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,53 @@
'use strict'

const tap = require('tap')
const Hapi = require('hapi')
const runScript = require('../lib/run-script')
const server = new Hapi.Server()

tap.test('runScript missing options', (t) => {
const options = false
const result = runScript(options)
t.equal(result.message, 'Missing required input: options', 'runScript missing options ok')
t.end()
runScript(options, (err) => {
t.equal(err, 'Missing required input: options', 'runScript missing options ok')
t.end()
})
})

tap.test('runScript missing options.request', (t) => {
tap.test('runScript missing options.script', (t) => {
const options = {}
const result = runScript(options)
t.equal(result.message, 'Missing required input: options.request', 'runScript missing options.request ok')
t.end()
runScript(options, (err) => {
t.equal(err, 'Missing required input: options.script', 'runScript missing options.script ok')
t.end()
})
})

tap.test('runScript missing options.script', (t) => {
tap.test('runScript script do not exist', (t) => {
const options = {
request: server
script: 'dengalevandrer'
}
const result = runScript(options)
t.equal(result.message, 'Missing required input: options.script', 'runScript missing options.script ok')
t.end()
runScript(options, (err) => {
t.match(err, 'does not exist', 'runScript script do not exist ok')
t.end()
})
})

tap.test('runScript script do not exist', (t) => {
tap.test('runScript run fail script', (t) => {
const options = {
request: server,
script: 'dengalevandrer'
script: 'fail.sh'
}
runScript(options, (err, data) => {
t.equal(err.code, 1, 'runScript fails ok')
t.end()
})
})

tap.test('runScript run through', (t) => {
const options = {
script: 'hello.sh'
}
const result = runScript(options)
t.match(result.message, 'does not exist', 'runScript script do not exist ok')
t.end()
runScript(options, (err, data) => {
if (err) {
throw err
}
t.equal(data.result, 'Running dummy script\n', 'runScript runs ok')
t.end()
})
})

0 comments on commit 27e5f3e

Please sign in to comment.