diff options
Diffstat (limited to 'src/scripts/cicd.sh')
-rwxr-xr-x | src/scripts/cicd.sh | 168 |
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 |