Squashed 'applications/githook/' content from commit 853c905
git-subtree-dir: applications/githook git-subtree-split: 853c905433ef1ecd7d9ea4b1f6fd6f73f28d7b20
This commit is contained in:
commit
1968f5e88e
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
*.lua
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2016-2018 Paul Liverman III
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
55
ReadMe.md
Normal file
55
ReadMe.md
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
## Installation
|
||||||
|
|
||||||
|
(Note: I'm going to rewrite this to explain how to use with locator, a simple
|
||||||
|
server locator I designed for use with Lapis and these sub-applications.)
|
||||||
|
|
||||||
|
Dependencies:
|
||||||
|
|
||||||
|
- Lapis (duh)
|
||||||
|
- MoonScript
|
||||||
|
- OpenResty user needs a bash shell (ch -s /bin/bash user)
|
||||||
|
|
||||||
|
From the shell:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git subtree add --prefix githook https://github.com/lazuscripts/githook.git master --squash
|
||||||
|
```
|
||||||
|
|
||||||
|
(`--prefix` specifies where it will be saved.)
|
||||||
|
|
||||||
|
Alternately, you can add it as a remote for easier maintenance:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git remote add -f githook https://github.com/lazuscripts/githook.git
|
||||||
|
git subtree add --prefix githook githook master --squash
|
||||||
|
```
|
||||||
|
|
||||||
|
From your main application class: `@include "githook.githook"` (or wherever you put it)
|
||||||
|
|
||||||
|
### Updating
|
||||||
|
|
||||||
|
From the shell:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git subtree pull --prefix githook https://github.com/lazuscripts/githook.git master --squash
|
||||||
|
```
|
||||||
|
|
||||||
|
Or, if it is set up as remote:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git subtree pull --prefix githook githook master --squash
|
||||||
|
```
|
||||||
|
|
||||||
|
## Config
|
||||||
|
|
||||||
|
All configuration is optional. Without configuration, will attempt to update any
|
||||||
|
time it is visited.
|
||||||
|
|
||||||
|
- `githook_branch "branch"` which branch you want updating (as string)
|
||||||
|
(to prevent updates triggering when pushing unrelated branches)
|
||||||
|
- `githook_secret "secret"` the secret string used on GitHub
|
||||||
|
|
||||||
|
Will attempt to checkout, pull, update submodules if needed, compile all code,
|
||||||
|
then run migrations, and finally update the running server without interruption.
|
||||||
|
|
||||||
|
Returns a log along with exit codes on success or failure.
|
152
githook.moon
Normal file
152
githook.moon
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
lapis = require "lapis"
|
||||||
|
config = require("lapis.config").get!
|
||||||
|
|
||||||
|
import respond_to, json_params from require "lapis.application"
|
||||||
|
import hmac_sha1, hmac_sha256 from require "lapis.util.encoding"
|
||||||
|
import encode from require "cjson"
|
||||||
|
import GithookLogs from require "models"
|
||||||
|
import locate, autoload, registry from require "locator"
|
||||||
|
import settings from autoload "utility"
|
||||||
|
import execute from locate "utility.shell"
|
||||||
|
import insert, concat from table
|
||||||
|
|
||||||
|
const_compare = (string1, string2) ->
|
||||||
|
local fail, dummy
|
||||||
|
|
||||||
|
for i = 1, math.max #string1, #string2, 100
|
||||||
|
if string1\sub(i,i) ~= string2\sub(i,i)
|
||||||
|
fail = true
|
||||||
|
else
|
||||||
|
dummy = true -- attempting to make execution time equal
|
||||||
|
|
||||||
|
return not fail
|
||||||
|
|
||||||
|
hex_dump = (str) ->
|
||||||
|
len = string.len str
|
||||||
|
hex = ""
|
||||||
|
|
||||||
|
for i = 1, len
|
||||||
|
hex ..= string.format( "%02x", string.byte( str, i ) )
|
||||||
|
|
||||||
|
return hex
|
||||||
|
|
||||||
|
run_update = (branch) ->
|
||||||
|
exit_codes, logs = {}, {}
|
||||||
|
failure = false
|
||||||
|
|
||||||
|
commands = registry.githook_commands branch, config._name
|
||||||
|
unless commands
|
||||||
|
commands = {
|
||||||
|
{"git checkout #{branch} 2> /dev/stdout"}
|
||||||
|
{"git pull origin 2> /dev/stdout"}
|
||||||
|
{"git submodule init 2> /dev/stdout"}
|
||||||
|
{"git submodule update 2> /dev/stdout"}
|
||||||
|
{"code=0\nfor file in $(find . -type f -name \"*.moon\"); do moonc \"$file\" 2> /dev/stdout\ntmp=$?\nif [ ! $tmp -eq 0 ]; then code=$tmp\nfi; done\necho $code", false}
|
||||||
|
{"lapis migrate #{config._name} 2> /dev/stdout"}
|
||||||
|
{"lapis build #{config._name} 2> /dev/stdout"}
|
||||||
|
}
|
||||||
|
for cmd in *commands
|
||||||
|
code, output = execute unpack cmd
|
||||||
|
insert exit_codes, code
|
||||||
|
insert logs, cmd[1]
|
||||||
|
insert logs, " #{output\gsub "\n", "\n "}"
|
||||||
|
if code != 0
|
||||||
|
failure = true
|
||||||
|
break
|
||||||
|
|
||||||
|
log = concat logs, "\n"
|
||||||
|
|
||||||
|
if failure
|
||||||
|
if settings["githook.save_logs"]
|
||||||
|
GithookLogs\create {
|
||||||
|
success: false
|
||||||
|
exit_codes: encode exit_codes
|
||||||
|
:log
|
||||||
|
}
|
||||||
|
return status: 500, json: {
|
||||||
|
status: "failure"
|
||||||
|
message: "a subprocess returned a non-zero exit code"
|
||||||
|
:log
|
||||||
|
:exit_codes
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if settings["githook.save_logs"] and settings["githook.save_on_success"]
|
||||||
|
GithookLogs\create {
|
||||||
|
exit_codes: encode exit_codes
|
||||||
|
:log
|
||||||
|
}
|
||||||
|
elseif settings["githook.save_logs"]
|
||||||
|
GithookLogs\create! -- we still record WHEN there was a success
|
||||||
|
return status: 200, json: {
|
||||||
|
status: "success"
|
||||||
|
message: "server updated to latest version of '#{branch}'"
|
||||||
|
:log
|
||||||
|
:exit_codes
|
||||||
|
}
|
||||||
|
|
||||||
|
ignored = (branch) ->
|
||||||
|
return status: 200, json: {
|
||||||
|
status: "success"
|
||||||
|
message: "ignored push (looking for updates to '#{branch}')"
|
||||||
|
}
|
||||||
|
|
||||||
|
unauthorized = ->
|
||||||
|
return status: 401, json: {
|
||||||
|
status: "unauthorized",
|
||||||
|
message: "invalid credentials or no credentials were sent"
|
||||||
|
}
|
||||||
|
|
||||||
|
invalid = (reason) ->
|
||||||
|
return status: 400, json: {
|
||||||
|
status: "invalid request"
|
||||||
|
message: reason
|
||||||
|
}
|
||||||
|
|
||||||
|
class extends lapis.Application
|
||||||
|
[githook: "/githook"]: respond_to {
|
||||||
|
before: =>
|
||||||
|
@branch = config.githook_branch or settings["githook.branch"] or "master"
|
||||||
|
|
||||||
|
GET: =>
|
||||||
|
unless settings["githook.allow_get"]
|
||||||
|
return status: 405, json: {
|
||||||
|
status: "method not allowed",
|
||||||
|
message: "Githook is not accepting GET requests."
|
||||||
|
}
|
||||||
|
|
||||||
|
unless settings["githook.run_without_auth"]
|
||||||
|
return unauthorized!
|
||||||
|
|
||||||
|
@results = run_update(@branch)
|
||||||
|
return render: locate "views.githook_get"
|
||||||
|
|
||||||
|
POST: json_params =>
|
||||||
|
secret = config.githook_secret or settings["githook.secret"]
|
||||||
|
if secret
|
||||||
|
ngx.req.read_body!
|
||||||
|
if body = ngx.req.get_body_data!
|
||||||
|
local authorized
|
||||||
|
if github_hash = @req.headers["X-Hub-Signature"]
|
||||||
|
authorized = const_compare "sha1=#{hex_dump hmac_sha1 secret, body}", github_hash
|
||||||
|
elseif gogs_hash = @req.headers["X-Gogs-Signature"]
|
||||||
|
authorized = const_compare gogs_hash, hex_dump hmac_sha256 secret, body
|
||||||
|
elseif @params.secret
|
||||||
|
authorized = const_compare @params.secret, secret
|
||||||
|
unless authorized
|
||||||
|
return unauthorized!
|
||||||
|
if @params.ref == "refs/heads/#{@branch}"
|
||||||
|
return run_update(@branch)
|
||||||
|
elseif @params.ref == nil
|
||||||
|
return invalid "'ref' not defined in request body"
|
||||||
|
else
|
||||||
|
return ignored(@branch)
|
||||||
|
else
|
||||||
|
return invalid "no request body"
|
||||||
|
elseif settings["githook.run_without_auth"]
|
||||||
|
if @params.ref == "refs/heads/#{@branch}"
|
||||||
|
return run_update(@branch)
|
||||||
|
else
|
||||||
|
return ignored(@branch)
|
||||||
|
else
|
||||||
|
return unauthorized!
|
||||||
|
}
|
25
migrations.moon
Normal file
25
migrations.moon
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import create_table, types, create_index from require "lapis.db.schema"
|
||||||
|
|
||||||
|
import autoload from require "locator"
|
||||||
|
import settings from autoload "utility"
|
||||||
|
|
||||||
|
{
|
||||||
|
[1519992142]: =>
|
||||||
|
create_table "githook_logs", {
|
||||||
|
{"id", types.serial primary_key: true}
|
||||||
|
{"success", types.boolean default: true}
|
||||||
|
{"exit_codes", types.text null: true}
|
||||||
|
{"log", types.text null: true}
|
||||||
|
|
||||||
|
{"created_at", types.time}
|
||||||
|
{"updated_at", types.time}
|
||||||
|
}
|
||||||
|
create_index "githook_logs", "id", unique: true
|
||||||
|
create_index "githook_logs", "success"
|
||||||
|
settings["githook.save_logs"] = true
|
||||||
|
settings["githook.save_on_success"] = true
|
||||||
|
settings["githook.allow_get"] = true
|
||||||
|
settings["githook.run_without_auth"] = false
|
||||||
|
-- settings["githook.branch"] = "master"
|
||||||
|
settings.save!
|
||||||
|
}
|
4
models/GithookLogs.moon
Normal file
4
models/GithookLogs.moon
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import Model from require "lapis.db.model"
|
||||||
|
|
||||||
|
class GithookLogs extends Model
|
||||||
|
@timestamp: true
|
10
views/githook_get.moon
Normal file
10
views/githook_get.moon
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import Widget from require "lapis.html"
|
||||||
|
|
||||||
|
class extends Widget
|
||||||
|
content: =>
|
||||||
|
h2 "#{@results.json.status\sub(1, 1)\upper!}#{@results.json.status\sub 2}"
|
||||||
|
element "table", ->
|
||||||
|
tr ->
|
||||||
|
for code in *@results.json.exit_codes
|
||||||
|
th code
|
||||||
|
pre @results.json.log
|
Loading…
Reference in New Issue
Block a user