Last active 1729621834

This is a script I use on my host for deploying a website; it includes the ability to rollback if anything fails. I have my github action call this file with the repo name and sha in order to deploy a given site.

deploy.sh Raw
1#!/bin/bash
2
3set -e
4
5deploy() {
6 local release_path="$1"
7
8 cd "${release_path}"
9 if [ -f "${release_path}/.deploy/deploy.sh" ]; then
10 /bin/bash .deploy/deploy.sh
11 else
12 echo "Starting deployment in ${release_path}"
13 docker compose up -d
14 fi
15}
16
17stop() {
18 local release_path="$1"
19
20 cd "${release_path}"
21 if [ -f "${release_path}/.deploy/stop.sh" ]; then
22 /bin/bash .deploy/stop.sh
23 else
24 echo "Stopping deployment in ${release_path}"
25 docker compose down
26 fi
27}
28
29cleanup() {
30 local base_dir="$1"
31 local current_release="$2"
32 local release
33 local listing=()
34 local releases=()
35
36 cd "${base_dir}"
37
38 # Get listing of directories, sorted chronologically, newest first
39 mapfile -t listing < <(ls -t -d -- */)
40
41 # Filter out symlinks for current and previous, and what was just released
42 for release in "${listing[@]}"; do
43 case "${release}" in
44 current/|previous/|"${current_release}/")
45 true
46 ;;
47 *)
48 releases+=( "${release}" )
49 ;;
50 esac
51 done
52
53 # Keep only the most recent 5 releases
54 if [[ ${#releases[@]} -gt 5 ]]; then
55 echo "Removing old releases"
56 for release in "${releases[@]:5}"; do
57 echo "- Removing ${release}"
58 rm -rf "${base_dir:?}/${release}"
59 done
60 fi
61}
62
63if [ "${GITHUB_TOKEN}" == "" ] || [ "${GITHUB_USERNAME}" == "" ];then
64 echo "Missing github login information"
65 exit 1;
66fi
67
68if [ $# -lt 2 ];then
69 echo "Missing required arguments"
70 echo ""
71 echo "Usage:"
72 echo " ${0} <repo> <sha>"
73 echo ""
74 echo "where <repo> is a repository under github.com/${GITHUB_USERNAME}, and"
75 echo "<sha> is the commit to deploy."
76 exit 1;
77fi
78
79# Get just the repo name
80REPO=${1#*/}
81SHA=$2
82BASEDIR="/var/web/${REPO}"
83# This directory must exist; usually it will be a mount to S3-compatible
84# object storage
85SITE_CONFIG_DIR="/mnt/site-config"
86PREVIOUS=
87
88# Prepare deployment directory, if it does not exist
89if [ ! -d "${BASEDIR}" ];then
90 echo "Creating deployment directory ${BASEDIR}"
91 mkdir -p "${BASEDIR}"
92fi
93
94# Memoize "current" directory as PREVIOUS, if it exists
95if [ -d "${BASEDIR}/current" ];then
96 PREVIOUS=$(realpath "${BASEDIR}/current")
97fi
98
99# Prepare new release
100echo "Preparing release directory based on commit ${SHA}"
101DEPLOY_DIR="${BASEDIR}/${SHA}"
102git clone --depth=1 --recurse-submodules "https://${GITHUB_USERNAME}:${GITHUB_TOKEN}@github.com/${GITHUB_USERNAME}/${REPO}.git" "${DEPLOY_DIR}"
103cd "${DEPLOY_DIR}"
104git checkout "${SHA}"
105
106# Get env file
107if [ -f "${DEPLOY_DIR}/env-version" ];then
108 echo "Found env-version file; fetching production env"
109 ENV_FILE="${SITE_CONFIG_DIR}/$(cat "${DEPLOY_DIR}/env-version")"
110
111 if [ ! -f "${ENV_FILE}" ];then
112 echo "FAILED - site config file specified in env-version not found"
113 exit 1;
114 fi
115
116 cp "${ENV_FILE}" "${DEPLOY_DIR}/.env"
117fi
118
119# Build
120cd "${DEPLOY_DIR}"
121
122if [ -f "${DEPLOY_DIR}/.deploy/build.sh" ]; then
123 /bin/bash .deploy/build.sh
124else
125 if [ -f "${DEPLOY_DIR}/.deploy/pre-build.sh" ];then
126 # This can be used to do things like create volumes
127 echo "Building containers"
128 echo "- Executing pre-build step"
129 /bin/bash .deploy/pre-build.sh
130 fi
131 docker compose build
132fi
133
134# DEPLOY
135
136# Stop previous
137if [ "${PREVIOUS}" != "" ];then
138 stop "${PREVIOUS}"
139fi
140
141# Start new
142echo "Starting deployment"
143
144set +e
145if ! deploy "${DEPLOY_DIR}"; then
146 echo "FAILED deploying ${SHA}; rolling back"
147 echo "- Stopping deployment"
148 stop "${DEPLOY_DIR}"
149
150 if [ "${PREVIOUS}" != "" ];then
151 echo "- Restarting previous deployment"
152 deploy "${PREVIOUS}"
153 fi
154 exit 1
155fi
156set -e
157
158# SUCCESS
159cd "${BASEDIR}"
160if [ "${PREVIOUS}" != "" ];then
161 ln -fsn "$(basename "${PREVIOUS}")" previous
162fi
163ln -fsn "${SHA}" current
164echo "SUCCESS deploying ${SHA}"
165
166# CLEANUP
167cleanup "${BASEDIR}" "${SHA}"