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