summaryrefslogtreecommitdiff
path: root/src/scripts/cicd.sh
diff options
context:
space:
mode:
Diffstat (limited to 'src/scripts/cicd.sh')
-rwxr-xr-xsrc/scripts/cicd.sh168
1 files changed, 168 insertions, 0 deletions
diff --git a/src/scripts/cicd.sh b/src/scripts/cicd.sh
new file mode 100755
index 0000000..58f4fce
--- /dev/null
+++ b/src/scripts/cicd.sh
@@ -0,0 +1,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