-
Notifications
You must be signed in to change notification settings - Fork 1
/
webhook_deploy_gogs.js
159 lines (136 loc) · 5.31 KB
/
webhook_deploy_gogs.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/**
* A server that listens on a port for Gogs's webhooks.
* It will check for a push event on the master branch, then deploy the project on the machine.
* The webhook's secret is check to ensure no malicious request from unknown sources.
*
* Usage :
* Set the "WEBHOOK_SECRET" environment variable with the webhook's secret.
*
* @see https://gogs.io/docs/features/webhook
*
*
* @author Antoine Sauvage <[email protected]>
* @license MIT 2019 - https://opensource.org/licenses/MIT
* @see https://gist.github.com/rigwild/4238a13cb3501c6e85065b403a71b475
*/
'use strict'
const fs = require('fs')
const http = require('http')
const path = require('path')
const { promisify } = require('util')
const exec = promisify(require('child_process').exec)
// The port which this script will listen on
const port = parseInt(process.env.WEBHOOK_PORT, 10)
// Check the "WEBHOOK_PORT" environment variable is set to a valid integer
if (!process.env.WEBHOOK_PORT || !parseInt(process.env.WEBHOOK_PORT, 10)) {
console.error(`${new Date().toLocaleString()} - The "WEBHOOK_PORT" environment variable is not set or is not an integer.`)
process.exit(1)
}
// The path to the project directory
const projectPath = path.resolve('.')
// The webhook secret to check the origin of the webhook event
// Check the "WEBHOOK_SECRET" environment variable is set
if (!process.env.WEBHOOK_SECRET && process.env.WEBHOOK_SECRET !== '') {
console.error(`${new Date().toLocaleString()} - The "WEBHOOK_SECRET" environment variable is not set.`)
process.exit(1)
}
const webhookSecret = process.env.WEBHOOK_SECRET
// Check whether the project path exists and script has read access
console.log(`${new Date().toLocaleString()} - Configured project path : ${projectPath}\n`)
try {
fs.accessSync(projectPath, fs.constants.W_OK)
console.log(`${new Date().toLocaleString()} - The project's directory exists and script has write permission.`)
}
catch (err) {
console.error(`${new Date().toLocaleString()} - The project's directory does not exist or script has not write permission.`, err)
process.exit(1)
}
// Check the "PORT" environment variable is set to a valid integer
if (!process.env.PORT || !parseInt(process.env.PORT, 10)) {
console.error(`${new Date().toLocaleString()} - The "PORT" environment variable is not set or is not an integer.`)
process.exit(1)
}
// Check the "SERVE_CLIENT" environment variable is set to 'true' or 'false'
if (!process.env.SERVE_CLIENT || !['true', 'false'].some(x => x === process.env.SERVE_CLIENT)) {
console.error(`${new Date().toLocaleString()} - The "SERVE_CLIENT" environment variable is not set or is not 'true' or 'false'`)
process.exit(1)
}
let env = {
PORT: parseInt(process.env.PORT, 10),
SERVE_CLIENT: process.env.SERVE_CLIENT,
IMAGES_PATH: process.env.IMAGES_PATH
}
env = Object.assign(process.env, env)
if (!env.IMAGES_PATH) env.IMAGES_PATH = ''
// Recap used environment variables
Object.keys(env).forEach(x => console.log(`${x}=${env[x]}`))
// The script that will be executed by the machine
const deployScript = `cd ${projectPath}` +
// ' && git reset --hard HEAD' +
' && git pull origin master' +
' && docker-compose down' +
' && docker-compose build' +
' && docker-compose up -d'
console.log('\nConfiguration is valid. Starting the webhook-listener server ...')
const deploy = async () => {
try {
console.log(`${new Date().toLocaleString()} - Deploying project ...`)
const startTime = process.hrtime()
const { stdout, stderr } = await exec(
deployScript,
{
cwd: projectPath,
env
}
)
const endTime = process.hrtime(startTime)
// Logs received from the deploy script are sent in stdout :
// git fetch and docker-compose build/up are writing their success logs in stderr...
// A deploy fail will be printed in stderr (in the catch)
console.log('stdout :\n', stdout)
console.log('stderr :\n', stderr)
console.log(`\n${new Date().toLocaleString()} - Project successfully deployed with Docker.`)
console.log(`Total deploy time : ${endTime[0]}s and ${endTime[1] / 1000000}ms.`)
}
catch (err) {
console.error(`\n${new Date().toLocaleString()} - Error deploying project.\n`, err)
}
}
// Configuration is fine, start the server
http.createServer((req, res) => {
// Check the method is POST
if (req.method !== 'POST') {
res.statusCode = 400
res.write('Wrong HTTP method.')
res.end()
return
}
// Check the event is a push
if (req.headers['x-gogs-event'] !== 'push') {
res.statusCode = 200
res.write('OK. Not a push event.')
res.end()
return
}
// Answer OK and close the connection
res.statusCode = 200
res.write('OK')
res.end()
let body = []
req.on('data', chunk => body.push(chunk))
req.on('end', () => {
try {
body = JSON.parse(Buffer.concat(body).toString())
// Check if the event was on master
if (!body.ref || body.ref !== 'refs/heads/master') return
// Check if secret matches
if (!body.secret || body.secret !== webhookSecret) return
console.log(`${new Date()} - Valid webhook event. Push on master was sent. Deployement process starts.`)
deploy()
}
catch (err) {
console.error(`${new Date()} - Invalid JSON was received`)
}
})
}).listen(port)
console.log(`${new Date().toLocaleString()} - Server is listening on http://localhost:${port}/`)