diff options
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/state/state.go | 8 | ||||
| -rw-r--r-- | internal/templates/templates.go | 168 |
2 files changed, 173 insertions, 3 deletions
diff --git a/internal/state/state.go b/internal/state/state.go index 38657cb..324fd34 100644 --- a/internal/state/state.go +++ b/internal/state/state.go | |||
| @@ -17,15 +17,17 @@ type State struct { | |||
| 17 | type Host struct { | 17 | type Host struct { |
| 18 | NextPort int `json:"next_port"` | 18 | NextPort int `json:"next_port"` |
| 19 | BaseDomain string `json:"base_domain,omitempty"` | 19 | BaseDomain string `json:"base_domain,omitempty"` |
| 20 | GitSetup bool `json:"git_setup,omitempty"` | ||
| 20 | Apps map[string]*App `json:"apps"` | 21 | Apps map[string]*App `json:"apps"` |
| 21 | } | 22 | } |
| 22 | 23 | ||
| 23 | // App represents a deployed application or static site | 24 | // App represents a deployed application or static site |
| 24 | type App struct { | 25 | type App struct { |
| 25 | Type string `json:"type"` // "app" or "static" | 26 | Type string `json:"type"` // "app", "static", "git-app", or "git-static" |
| 26 | Domain string `json:"domain"` | 27 | Domain string `json:"domain"` |
| 27 | Port int `json:"port,omitempty"` // only for type="app" | 28 | Port int `json:"port,omitempty"` // only for type="app" or "git-app" |
| 28 | Env map[string]string `json:"env,omitempty"` // only for type="app" | 29 | Repo string `json:"repo,omitempty"` // only for git types, e.g. "/srv/git/foo.git" |
| 30 | Env map[string]string `json:"env,omitempty"` // only for type="app" or "git-app" | ||
| 29 | Args string `json:"args,omitempty"` // only for type="app" | 31 | Args string `json:"args,omitempty"` // only for type="app" |
| 30 | Files []string `json:"files,omitempty"` // only for type="app" | 32 | Files []string `json:"files,omitempty"` // only for type="app" |
| 31 | Memory string `json:"memory,omitempty"` // only for type="app" | 33 | Memory string `json:"memory,omitempty"` // only for type="app" |
diff --git a/internal/templates/templates.go b/internal/templates/templates.go index ce1cbe5..8615117 100644 --- a/internal/templates/templates.go +++ b/internal/templates/templates.go | |||
| @@ -86,3 +86,171 @@ func StaticCaddy(data map[string]string) (string, error) { | |||
| 86 | 86 | ||
| 87 | return buf.String(), nil | 87 | return buf.String(), nil |
| 88 | } | 88 | } |
| 89 | |||
| 90 | var postReceiveHookTemplate = `#!/bin/bash | ||
| 91 | set -euo pipefail | ||
| 92 | |||
| 93 | REPO=/srv/git/{{.Name}}.git | ||
| 94 | SRC=/var/lib/{{.Name}}/src | ||
| 95 | NAME={{.Name}} | ||
| 96 | |||
| 97 | while read oldrev newrev refname; do | ||
| 98 | branch=$(git rev-parse --symbolic --abbrev-ref "$refname") | ||
| 99 | [ "$branch" = "main" ] || { echo "Pushed to $branch, skipping deploy."; exit 0; } | ||
| 100 | done | ||
| 101 | |||
| 102 | echo "==> Checking out code..." | ||
| 103 | git --work-tree="$SRC" --git-dir="$REPO" checkout -f main | ||
| 104 | |||
| 105 | cd "$SRC" | ||
| 106 | |||
| 107 | # Install deployment config from repo | ||
| 108 | if [ -f .ship/service ]; then | ||
| 109 | echo "==> Installing systemd unit..." | ||
| 110 | sudo cp .ship/service /etc/systemd/system/${NAME}.service | ||
| 111 | sudo systemctl daemon-reload | ||
| 112 | fi | ||
| 113 | if [ -f .ship/Caddyfile ]; then | ||
| 114 | echo "==> Installing Caddy config..." | ||
| 115 | sudo cp .ship/Caddyfile /etc/caddy/sites-enabled/${NAME}.caddy | ||
| 116 | sudo systemctl reload caddy | ||
| 117 | fi | ||
| 118 | |||
| 119 | echo "==> Building Docker image..." | ||
| 120 | docker build -t ${NAME}:latest . | ||
| 121 | |||
| 122 | echo "==> Restarting service..." | ||
| 123 | sudo systemctl restart ${NAME} | ||
| 124 | |||
| 125 | echo "==> Deploy complete!" | ||
| 126 | ` | ||
| 127 | |||
| 128 | var postReceiveHookStaticTemplate = `#!/bin/bash | ||
| 129 | set -euo pipefail | ||
| 130 | |||
| 131 | REPO=/srv/git/{{.Name}}.git | ||
| 132 | WEBROOT=/var/www/{{.Name}} | ||
| 133 | NAME={{.Name}} | ||
| 134 | |||
| 135 | while read oldrev newrev refname; do | ||
| 136 | branch=$(git rev-parse --symbolic --abbrev-ref "$refname") | ||
| 137 | [ "$branch" = "main" ] || { echo "Pushed to $branch, skipping deploy."; exit 0; } | ||
| 138 | done | ||
| 139 | |||
| 140 | echo "==> Deploying static site..." | ||
| 141 | git --work-tree="$WEBROOT" --git-dir="$REPO" checkout -f main | ||
| 142 | |||
| 143 | if [ -f "$WEBROOT/.ship/Caddyfile" ]; then | ||
| 144 | echo "==> Installing Caddy config..." | ||
| 145 | sudo cp "$WEBROOT/.ship/Caddyfile" /etc/caddy/sites-enabled/${NAME}.caddy | ||
| 146 | sudo systemctl reload caddy | ||
| 147 | fi | ||
| 148 | |||
| 149 | echo "==> Deploy complete!" | ||
| 150 | ` | ||
| 151 | |||
| 152 | var codeCaddyTemplate = `{{.BaseDomain}} { | ||
| 153 | @goget query go-get=1 | ||
| 154 | handle @goget { | ||
| 155 | root * /opt/ship/vanity | ||
| 156 | templates | ||
| 157 | rewrite * /index.html | ||
| 158 | file_server | ||
| 159 | } | ||
| 160 | |||
| 161 | @git path_regexp "^.*/(HEAD|info/refs|objects/info/[^/]+|git-upload-pack|git-receive-pack)$" | ||
| 162 | handle @git { | ||
| 163 | reverse_proxy unix//run/fcgiwrap.socket { | ||
| 164 | transport fastcgi { | ||
| 165 | env SCRIPT_FILENAME /usr/lib/git-core/git-http-backend | ||
| 166 | env GIT_PROJECT_ROOT /srv/git | ||
| 167 | env GIT_HTTP_EXPORT_ALL 1 | ||
| 168 | env REQUEST_METHOD {method} | ||
| 169 | env QUERY_STRING {query} | ||
| 170 | env PATH_INFO {path} | ||
| 171 | } | ||
| 172 | } | ||
| 173 | } | ||
| 174 | |||
| 175 | handle { | ||
| 176 | respond "not found" 404 | ||
| 177 | } | ||
| 178 | } | ||
| 179 | ` | ||
| 180 | |||
| 181 | var dockerServiceTemplate = `[Unit] | ||
| 182 | Description={{.Name}} | ||
| 183 | After=network.target docker.service | ||
| 184 | Requires=docker.service | ||
| 185 | |||
| 186 | [Service] | ||
| 187 | Type=simple | ||
| 188 | ExecStartPre=-/usr/bin/docker rm -f {{.Name}} | ||
| 189 | ExecStart=/usr/bin/docker run --rm --name {{.Name}} \ | ||
| 190 | -p 127.0.0.1:{{.Port}}:{{.Port}} \ | ||
| 191 | --env-file /etc/ship/env/{{.Name}}.env \ | ||
| 192 | -v /var/lib/{{.Name}}/data:/data \ | ||
| 193 | {{.Name}}:latest | ||
| 194 | ExecStop=/usr/bin/docker stop -t 10 {{.Name}} | ||
| 195 | Restart=always | ||
| 196 | RestartSec=5s | ||
| 197 | |||
| 198 | [Install] | ||
| 199 | WantedBy=multi-user.target | ||
| 200 | ` | ||
| 201 | |||
| 202 | var defaultAppCaddyTemplate = `{{.Domain}} { | ||
| 203 | reverse_proxy 127.0.0.1:{{.Port}} | ||
| 204 | } | ||
| 205 | ` | ||
| 206 | |||
| 207 | var defaultStaticCaddyTemplate = `{{.Domain}} { | ||
| 208 | root * /var/www/{{.Name}} | ||
| 209 | file_server | ||
| 210 | encode gzip | ||
| 211 | } | ||
| 212 | ` | ||
| 213 | |||
| 214 | // PostReceiveHook generates a post-receive hook for git-app repos | ||
| 215 | func PostReceiveHook(data map[string]string) (string, error) { | ||
| 216 | return renderTemplate("post-receive", postReceiveHookTemplate, data) | ||
| 217 | } | ||
| 218 | |||
| 219 | // PostReceiveHookStatic generates a post-receive hook for git-static repos | ||
| 220 | func PostReceiveHookStatic(data map[string]string) (string, error) { | ||
| 221 | return renderTemplate("post-receive-static", postReceiveHookStaticTemplate, data) | ||
| 222 | } | ||
| 223 | |||
| 224 | // CodeCaddy generates the base domain Caddy config for vanity imports + git HTTP | ||
| 225 | func CodeCaddy(data map[string]string) (string, error) { | ||
| 226 | return renderTemplate("code-caddy", codeCaddyTemplate, data) | ||
| 227 | } | ||
| 228 | |||
| 229 | // DockerService generates a systemd unit for a Docker-based app | ||
| 230 | func DockerService(data map[string]string) (string, error) { | ||
| 231 | return renderTemplate("docker-service", dockerServiceTemplate, data) | ||
| 232 | } | ||
| 233 | |||
| 234 | // DefaultAppCaddy generates a default Caddyfile for a git-app | ||
| 235 | func DefaultAppCaddy(data map[string]string) (string, error) { | ||
| 236 | return renderTemplate("default-app-caddy", defaultAppCaddyTemplate, data) | ||
| 237 | } | ||
| 238 | |||
| 239 | // DefaultStaticCaddy generates a default Caddyfile for a git-static site | ||
| 240 | func DefaultStaticCaddy(data map[string]string) (string, error) { | ||
| 241 | return renderTemplate("default-static-caddy", defaultStaticCaddyTemplate, data) | ||
| 242 | } | ||
| 243 | |||
| 244 | func renderTemplate(name, tmplStr string, data map[string]string) (string, error) { | ||
| 245 | tmpl, err := template.New(name).Parse(tmplStr) | ||
| 246 | if err != nil { | ||
| 247 | return "", err | ||
| 248 | } | ||
| 249 | |||
| 250 | var buf bytes.Buffer | ||
| 251 | if err := tmpl.Execute(&buf, data); err != nil { | ||
| 252 | return "", err | ||
| 253 | } | ||
| 254 | |||
| 255 | return buf.String(), nil | ||
| 256 | } | ||
