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
|
#!/bin/sh
set -eu
usage() {
cat <<-'EOF'
Usage:
cicd [-n] NAME [SHA]
cicd -h
EOF
}
help() {
cat <<-'EOF'
Options:
-n build the system, but don't switch to it (dry-run)
-h, --help show this message
NAME the name of the project
SHA the repository SHA to checkout (default: main)
Do a CI/CD run of the project called NAME, located at
/srv/git/$NAME.git. If -n is given, only build, otherwise
also do the deploy when the build is successfull.
A "build" consists of:
- doing a fresh clone of the project on a temporary directory;
- checkout the project to version $SHA;
- when a "manifest.scm" file exists in the root of the project,
use it to launch a containerized Guix shell; otherwise use a
fallback template for a containerized Guix shell;
- build the "dev" target of the Makefile via "make dev".
A "deploy" consists of:
- copying the "description" metadata file to
/srv/git/$NAME.git/description, in order to update the project
repository's description;
- upgrading the "pre-receive" Git hook, so that future runs are
affected by it;
- copying the "public/" directory that the "dev" target built to
the /srv/www/s/$NAME/ directory, so that the projects "public/"
directory is accessible via the web address
"https://euandre.org/s/$NAME/".
This command must be ran as root.
Examples:
Build and deploy the "remembering" project on the default branch:
$ sudo cicd remembering
Build the "urubu" project on a specific commit, but don't deploy:
$ sudo cicd -n urubu 916dafc092f797349a54515756f2c8e477326511
EOF
}
for flag in "$@"; do
case "$flag" in
--)
break
;;
--help)
usage
help
exit
;;
*)
;;
esac
done
DRY_RUN=false
while getopts 'nh' flag; do
case "$flag" in
n)
DRY_RUN=true
;;
h)
usage
help
exit
;;
*)
usage >&2
exit 2
;;
esac
done
shift $((OPTIND - 1))
NAME="${1:-}"
SHA="${2:-main}"
REPO="/srv/git/$NAME.git"
if [ -z "$NAME" ]; then
printf 'Missing NAME.\n\n' >&2
usage >&2
exit 2
fi
if [ "$(id -un)" != 'root' ]; then
printf 'This script must be run as root.\n\n' >&2
usage >&2
exit 2
fi
set +eu
# shellcheck source=/dev/null
. /etc/rc
set -eu
uuid() {
od -xN20 /dev/urandom |
head -n1 |
awk '{OFS="-"; print $2$3,$4,$5,$6,$7$8$9}'
}
tmpname() {
printf '%s/uuid-tmpname with spaces.%s' "${TMPDIR:-/tmp}" "$(uuid)"
}
mkdtemp() {
name="$(tmpname)"
mkdir -- "$name"
printf '%s' "$name"
}
TMP="$(mkdtemp)"
trap 'rm -rf "$TMP"' EXIT
set -x
chown deployer:deployer "$TMP"
cd "$TMP"
sudo -u deployer git clone "$REPO" .
sudo -u deployer --preserve-env=GIT_CONFIG_GLOBAL git checkout "$SHA"
guix system describe
if [ -f manifest.scm ]; then
guix shell -Cv3 -m manifest.scm -- make dev
else
guix shell -Cv3 -- make dev
fi
if [ "$DRY_RUN" = false ]; then
# COMMENT: pre-receive is always running the previous version!
# The same is true for the reconfigure script itself.
sudo cp description "$REPO"/description
sudo cp aux/ci/git-pre-receive.sh "$REPO"/hooks/pre-receive
sudo -u deployer rsync \
--delete \
--chmod=D775,F664 \
--chown=deployer:deployer \
--exclude 'ci/*' \
-a \
public/ /srv/www/s/"$NAME"/
fi
|