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.

matthew's Avatar matthew revised this gist 1729621834. Go to revision

1 file changed, 167 insertions

deploy.sh(file created)

@@ -0,0 +1,167 @@
1 + #!/bin/bash
2 +
3 + set -e
4 +
5 + deploy() {
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 +
17 + stop() {
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 +
29 + cleanup() {
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 +
63 + if [ "${GITHUB_TOKEN}" == "" ] || [ "${GITHUB_USERNAME}" == "" ];then
64 + echo "Missing github login information"
65 + exit 1;
66 + fi
67 +
68 + if [ $# -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;
77 + fi
78 +
79 + # Get just the repo name
80 + REPO=${1#*/}
81 + SHA=$2
82 + BASEDIR="/var/web/${REPO}"
83 + # This directory must exist; usually it will be a mount to S3-compatible
84 + # object storage
85 + SITE_CONFIG_DIR="/mnt/site-config"
86 + PREVIOUS=
87 +
88 + # Prepare deployment directory, if it does not exist
89 + if [ ! -d "${BASEDIR}" ];then
90 + echo "Creating deployment directory ${BASEDIR}"
91 + mkdir -p "${BASEDIR}"
92 + fi
93 +
94 + # Memoize "current" directory as PREVIOUS, if it exists
95 + if [ -d "${BASEDIR}/current" ];then
96 + PREVIOUS=$(realpath "${BASEDIR}/current")
97 + fi
98 +
99 + # Prepare new release
100 + echo "Preparing release directory based on commit ${SHA}"
101 + DEPLOY_DIR="${BASEDIR}/${SHA}"
102 + git clone --depth=1 --recurse-submodules "https://${GITHUB_USERNAME}:${GITHUB_TOKEN}@github.com/${GITHUB_USERNAME}/${REPO}.git" "${DEPLOY_DIR}"
103 + cd "${DEPLOY_DIR}"
104 + git checkout "${SHA}"
105 +
106 + # Get env file
107 + if [ -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"
117 + fi
118 +
119 + # Build
120 + cd "${DEPLOY_DIR}"
121 +
122 + if [ -f "${DEPLOY_DIR}/.deploy/build.sh" ]; then
123 + /bin/bash .deploy/build.sh
124 + else
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
132 + fi
133 +
134 + # DEPLOY
135 +
136 + # Stop previous
137 + if [ "${PREVIOUS}" != "" ];then
138 + stop "${PREVIOUS}"
139 + fi
140 +
141 + # Start new
142 + echo "Starting deployment"
143 +
144 + set +e
145 + if ! 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
155 + fi
156 + set -e
157 +
158 + # SUCCESS
159 + cd "${BASEDIR}"
160 + if [ "${PREVIOUS}" != "" ];then
161 + ln -fsn "$(basename "${PREVIOUS}")" previous
162 + fi
163 + ln -fsn "${SHA}" current
164 + echo "SUCCESS deploying ${SHA}"
165 +
166 + # CLEANUP
167 + cleanup "${BASEDIR}" "${SHA}"
Newer Older