Browse Source

Squashed 'applications/githook/' content from commit 853c905

git-subtree-dir: applications/githook
git-subtree-split: 853c905433
Paul Liverman III 6 years ago
commit
1968f5e88e
7 changed files with 268 additions and 0 deletions
  1. 1
    0
      .gitignore
  2. 21
    0
      LICENSE
  3. 55
    0
      ReadMe.md
  4. 152
    0
      githook.moon
  5. 25
    0
      migrations.moon
  6. 4
    0
      models/GithookLogs.moon
  7. 10
    0
      views/githook_get.moon

+ 1
- 0
.gitignore View File

@@ -0,0 +1 @@
1
+*.lua

+ 21
- 0
LICENSE View File

@@ -0,0 +1,21 @@
1
+The MIT License (MIT)
2
+
3
+Copyright (c) 2016-2018 Paul Liverman III
4
+
5
+Permission is hereby granted, free of charge, to any person obtaining a copy
6
+of this software and associated documentation files (the "Software"), to deal
7
+in the Software without restriction, including without limitation the rights
8
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+copies of the Software, and to permit persons to whom the Software is
10
+furnished to do so, subject to the following conditions:
11
+
12
+The above copyright notice and this permission notice shall be included in all
13
+copies or substantial portions of the Software.
14
+
15
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+SOFTWARE.

+ 55
- 0
ReadMe.md View File

@@ -0,0 +1,55 @@
1
+## Installation
2
+
3
+(Note: I'm going to rewrite this to explain how to use with locator, a simple
4
+server locator I designed for use with Lapis and these sub-applications.)
5
+
6
+Dependencies:
7
+
8
+- Lapis (duh)
9
+- MoonScript
10
+- OpenResty user needs a bash shell (ch -s /bin/bash user)
11
+
12
+From the shell:
13
+
14
+```bash
15
+git subtree add --prefix githook https://github.com/lazuscripts/githook.git master --squash
16
+```
17
+
18
+(`--prefix` specifies where it will be saved.)
19
+
20
+Alternately, you can add it as a remote for easier maintenance:
21
+
22
+```bash
23
+git remote add -f githook https://github.com/lazuscripts/githook.git
24
+git subtree add --prefix githook githook master --squash
25
+```
26
+
27
+From your main application class: `@include "githook.githook"` (or wherever you put it)
28
+
29
+### Updating
30
+
31
+From the shell:
32
+
33
+```bash
34
+git subtree pull --prefix githook https://github.com/lazuscripts/githook.git master --squash
35
+```
36
+
37
+Or, if it is set up as remote:
38
+
39
+```bash
40
+git subtree pull --prefix githook githook master --squash
41
+```
42
+
43
+## Config
44
+
45
+All configuration is optional. Without configuration, will attempt to update any
46
+time it is visited.
47
+
48
+- `githook_branch "branch"` which branch you want updating (as string)
49
+  (to prevent updates triggering when pushing unrelated branches)
50
+- `githook_secret "secret"` the secret string used on GitHub
51
+
52
+Will attempt to checkout, pull, update submodules if needed, compile all code,
53
+then run migrations, and finally update the running server without interruption.
54
+
55
+Returns a log along with exit codes on success or failure.

+ 152
- 0
githook.moon View File

@@ -0,0 +1,152 @@
1
+lapis = require "lapis"
2
+config = require("lapis.config").get!
3
+
4
+import respond_to, json_params from require "lapis.application"
5
+import hmac_sha1, hmac_sha256 from require "lapis.util.encoding"
6
+import encode from require "cjson"
7
+import GithookLogs from require "models"
8
+import locate, autoload, registry from require "locator"
9
+import settings from autoload "utility"
10
+import execute from locate "utility.shell"
11
+import insert, concat from table
12
+
13
+const_compare = (string1, string2) ->
14
+  local fail, dummy
15
+
16
+  for i = 1, math.max #string1, #string2, 100
17
+    if string1\sub(i,i) ~= string2\sub(i,i)
18
+      fail = true
19
+    else
20
+      dummy = true -- attempting to make execution time equal
21
+
22
+  return not fail
23
+
24
+hex_dump = (str) ->
25
+  len = string.len str
26
+  hex = ""
27
+
28
+  for i = 1, len
29
+    hex ..= string.format( "%02x", string.byte( str, i ) )
30
+
31
+  return hex
32
+
33
+run_update = (branch) ->
34
+  exit_codes, logs = {}, {}
35
+  failure = false
36
+
37
+  commands = registry.githook_commands branch, config._name
38
+  unless commands
39
+    commands = {
40
+      {"git checkout #{branch} 2> /dev/stdout"}
41
+      {"git pull origin 2> /dev/stdout"}
42
+      {"git submodule init 2> /dev/stdout"}
43
+      {"git submodule update 2> /dev/stdout"}
44
+      {"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}
45
+      {"lapis migrate #{config._name} 2> /dev/stdout"}
46
+      {"lapis build #{config._name} 2> /dev/stdout"}
47
+    }
48
+  for cmd in *commands
49
+    code, output = execute unpack cmd
50
+    insert exit_codes, code
51
+    insert logs, cmd[1]
52
+    insert logs, "    #{output\gsub "\n", "\n    "}"
53
+    if code != 0
54
+      failure = true
55
+      break
56
+
57
+  log = concat logs, "\n"
58
+
59
+  if failure
60
+    if settings["githook.save_logs"]
61
+      GithookLogs\create {
62
+        success: false
63
+        exit_codes: encode exit_codes
64
+        :log
65
+      }
66
+    return status: 500, json: {
67
+      status: "failure"
68
+      message: "a subprocess returned a non-zero exit code"
69
+      :log
70
+      :exit_codes
71
+    }
72
+  else
73
+    if settings["githook.save_logs"] and settings["githook.save_on_success"]
74
+      GithookLogs\create {
75
+        exit_codes: encode exit_codes
76
+        :log
77
+      }
78
+    elseif settings["githook.save_logs"]
79
+      GithookLogs\create! -- we still record WHEN there was a success
80
+    return status: 200, json: {
81
+      status: "success"
82
+      message: "server updated to latest version of '#{branch}'"
83
+      :log
84
+      :exit_codes
85
+    }
86
+
87
+ignored = (branch) ->
88
+  return status: 200, json: {
89
+    status: "success"
90
+    message: "ignored push (looking for updates to '#{branch}')"
91
+  }
92
+
93
+unauthorized = ->
94
+  return status: 401, json: {
95
+    status: "unauthorized",
96
+    message: "invalid credentials or no credentials were sent"
97
+  }
98
+
99
+invalid = (reason) ->
100
+  return status: 400, json: {
101
+    status: "invalid request"
102
+    message: reason
103
+  }
104
+
105
+class extends lapis.Application
106
+  [githook: "/githook"]: respond_to {
107
+    before: =>
108
+      @branch = config.githook_branch or settings["githook.branch"] or "master"
109
+
110
+    GET: =>
111
+      unless settings["githook.allow_get"]
112
+        return status: 405, json: {
113
+          status: "method not allowed",
114
+          message: "Githook is not accepting GET requests."
115
+        }
116
+
117
+      unless settings["githook.run_without_auth"]
118
+        return unauthorized!
119
+
120
+      @results = run_update(@branch)
121
+      return render: locate "views.githook_get"
122
+
123
+    POST: json_params =>
124
+      secret = config.githook_secret or settings["githook.secret"]
125
+      if secret
126
+        ngx.req.read_body!
127
+        if body = ngx.req.get_body_data!
128
+          local authorized
129
+          if github_hash = @req.headers["X-Hub-Signature"]
130
+            authorized = const_compare "sha1=#{hex_dump hmac_sha1 secret, body}", github_hash
131
+          elseif gogs_hash = @req.headers["X-Gogs-Signature"]
132
+            authorized = const_compare gogs_hash, hex_dump hmac_sha256 secret, body
133
+          elseif @params.secret
134
+            authorized = const_compare @params.secret, secret
135
+          unless authorized
136
+            return unauthorized!
137
+          if @params.ref == "refs/heads/#{@branch}"
138
+            return run_update(@branch)
139
+          elseif @params.ref == nil
140
+            return invalid "'ref' not defined in request body"
141
+          else
142
+            return ignored(@branch)
143
+        else
144
+          return invalid "no request body"
145
+      elseif settings["githook.run_without_auth"]
146
+        if @params.ref == "refs/heads/#{@branch}"
147
+          return run_update(@branch)
148
+        else
149
+          return ignored(@branch)
150
+      else
151
+        return unauthorized!
152
+    }

+ 25
- 0
migrations.moon View File

@@ -0,0 +1,25 @@
1
+import create_table, types, create_index from require "lapis.db.schema"
2
+
3
+import autoload from require "locator"
4
+import settings from autoload "utility"
5
+
6
+{
7
+  [1519992142]: =>
8
+    create_table "githook_logs", {
9
+      {"id", types.serial primary_key: true}
10
+      {"success", types.boolean default: true}
11
+      {"exit_codes", types.text null: true}
12
+      {"log", types.text null: true}
13
+
14
+      {"created_at", types.time}
15
+      {"updated_at", types.time}
16
+    }
17
+    create_index "githook_logs", "id", unique: true
18
+    create_index "githook_logs", "success"
19
+    settings["githook.save_logs"] = true
20
+    settings["githook.save_on_success"] = true
21
+    settings["githook.allow_get"] = true
22
+    settings["githook.run_without_auth"] = false
23
+    -- settings["githook.branch"] = "master"
24
+    settings.save!
25
+}

+ 4
- 0
models/GithookLogs.moon View File

@@ -0,0 +1,4 @@
1
+import Model from require "lapis.db.model"
2
+
3
+class GithookLogs extends Model
4
+  @timestamp: true

+ 10
- 0
views/githook_get.moon View File

@@ -0,0 +1,10 @@
1
+import Widget from require "lapis.html"
2
+
3
+class extends Widget
4
+  content: =>
5
+    h2 "#{@results.json.status\sub(1, 1)\upper!}#{@results.json.status\sub 2}"
6
+    element "table", ->
7
+      tr ->
8
+        for code in *@results.json.exit_codes
9
+          th code
10
+    pre @results.json.log