blob: 07d65b5c3bda5cf6d0469f20f091a8fe50342cc4 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
|
#!/usr/bin/env bash
# Upload web/ and verify every published artifact (GUI app and installers,
# terminal client and server) over the public URL.
#
# Usage:
# ./scripts/deploy.sh user@host:/srv/zagan.bet https://zagan.bet/
# ./scripts/deploy.sh /srv/staging http://127.0.0.1:8899/
# ./scripts/deploy.sh --verify-only user@host:/srv/zagan.bet https://zagan.bet/
#
# The target may be a local directory, which is handy for staging and for
# testing the verification itself. Old versions are left in place on purpose;
# prune them by hand when you want to drop them.
#
# Environment:
# DEPLOY_TARGET, DEPLOY_URL same as the two arguments
# SSH_PORT ssh port for a remote target
set -euo pipefail
ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
cd "$ROOT"
die() { echo "deploy: $*" >&2; exit 1; }
VERIFY_ONLY=0
if [ "${1:-}" = "--verify-only" ]; then
VERIFY_ONLY=1
shift
fi
TARGET=${1:-${DEPLOY_TARGET:-}}
URL=${2:-${DEPLOY_URL:-}}
if [ -z "$TARGET" ] || [ -z "$URL" ]; then
cat >&2 <<'EOF'
usage: scripts/deploy.sh [--verify-only] <target> <url>
target user@host:/srv/zagan.bet or a local directory
url public URL of the page, e.g. https://zagan.bet/
--verify-only skips the upload and only checks the live page
environment:
DEPLOY_TARGET, DEPLOY_URL same as the two arguments
SSH_PORT ssh port for a remote target
EOF
exit 2
fi
for tool in rsync curl sha256sum; do
command -v "$tool" >/dev/null || die "$tool is required"
done
[ -f web/index.php ] || die "web/index.php is missing"
shopt -s nullglob
artifacts=(
web/bin/gui/zagan-bet-*
web/bin/client/zagan-bet-*
web/bin/server/zagan-bet-*
)
shopt -u nullglob
[ ${#artifacts[@]} -gt 0 ] || die "no artifacts in web/bin; run scripts/publish.sh first"
if [ "$VERIFY_ONLY" -eq 0 ]; then
echo "==> uploading web/ to $TARGET"
# --delay-updates writes to temp names and renames at the end, so a visitor
# never sees a half-written binary. Old versions are kept: no --delete.
RSYNC_FLAGS=(
-a --delay-updates --human-readable --chmod=D755,F644
--exclude=README.md --exclude=.gitignore
--exclude=play/node_modules
)
if [[ "$TARGET" == *:* ]]; then
host=${TARGET%%:*}
path=${TARGET#*:}
ssh_args=()
if [ -n "${SSH_PORT:-}" ]; then
ssh_args+=(-p "$SSH_PORT")
fi
ssh ${ssh_args[@]+"${ssh_args[@]}"} "$host" "mkdir -p $(printf '%q' "$path")"
rsync "${RSYNC_FLAGS[@]}" -e "ssh ${ssh_args[*]:-}" web/ "$host:$path/"
else
mkdir -p "$TARGET"
rsync "${RSYNC_FLAGS[@]}" web/ "$TARGET/"
fi
fi
echo "==> verifying $URL"
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
curl -fsSL --max-time 30 "$URL" -o "$tmp/page.html" \
|| die "could not fetch $URL"
origin=$(printf '%s' "$URL" | sed -E 's#^(https?://[^/]+).*#\1#')
grep -oE '[0-9a-f]{64} [A-Za-z0-9._-]+' "$tmp/page.html" > "$tmp/sums" || true
[ -s "$tmp/sums" ] || die "no SHA-256 lines on the page (is index.php being served?)"
for script in install.sh install.ps1; do
grep -qE "href=\"[^\"]*/$script\"" "$tmp/page.html" \
|| die "$script is not linked from the page"
curl -fsSL --max-time 30 "$origin/$script" -o "$tmp/$script" \
|| die "could not fetch $script"
cmp -s "web/$script" "$tmp/$script" \
|| die "$script served from the site differs from the local file"
done
curl -fsSL --max-time 30 "$origin/latest.php" -o "$tmp/latest.txt" \
|| die "could not fetch latest.php"
newest=$(awk '$1 == "version" { print $2; exit }' "$tmp/latest.txt")
[ -n "$newest" ] || die "latest.php has no version line"
failed=0
verified=0
for local in "${artifacts[@]}"; do
[ -f "$local" ] || continue
file=$(basename "$local")
kind=$(basename "$(dirname "$local")")
local_hash=$(sha256sum "$local" | cut -d' ' -f1)
href=$(grep -oE "href=\"[^\"]*/bin/$kind/$file\"" "$tmp/page.html" | head -1 \
| sed 's/^href="//;s/"$//' || true)
if [ -z "$href" ]; then
echo " $file: not listed on the page"
failed=1
continue
fi
shown=$(awk -v name="$file" '$2 == name { print $1 }' "$tmp/sums" | head -1)
if [ "$shown" != "$local_hash" ]; then
echo " $file: page shows ${shown:-nothing}, local is $local_hash"
failed=1
continue
fi
if ! curl -fsSL --max-time 120 "$origin$href" -o "$tmp/$file"; then
echo " $file: download failed"
failed=1
continue
fi
remote_hash=$(sha256sum "$tmp/$file" | cut -d' ' -f1)
if [ "$remote_hash" != "$local_hash" ]; then
echo " $file: downloaded bytes differ from local"
failed=1
continue
fi
version=$(printf '%s' "$file" | sed -E 's/^zagan-bet-[a-z]+-([0-9]+\.[0-9]+\.[0-9]+)-.*/\1/')
if [ "$version" = "$newest" ]; then
latest_hash=$(awk -v kind="$kind" -v name="$file" '$1 == kind && $5 == name { print $6 }' "$tmp/latest.txt")
if [ "$latest_hash" != "$local_hash" ]; then
echo " $file: latest.php shows ${latest_hash:-nothing}, local is $local_hash"
failed=1
continue
fi
fi
echo " $file: ok"
verified=$((verified + 1))
done
curl -fsSL --max-time 30 "$origin/robots.txt" -o "$tmp/robots.txt" \
|| die "could not fetch robots.txt"
grep -q "^Disallow: /$" "$tmp/robots.txt" \
|| die "robots.txt does not disallow crawlers"
curl -fsSL --max-time 30 "$origin/play/" -o "$tmp/play.html" \
|| die "could not fetch the browser app at /play/"
grep -q 'app.js' "$tmp/play.html" || die "/play/ does not reference app.js"
for asset in app.js style.css; do
curl -fsSL --max-time 30 "$origin/play/$asset" -o "$tmp/$asset" \
|| die "could not fetch /play/$asset"
cmp -s "web/play/$asset" "$tmp/$asset" \
|| die "/play/$asset served from the site differs from the local file"
done
[ "$failed" -eq 0 ] || die "verification failed"
echo "==> $verified artifact(s) and the browser app verified at $URL"
|