diff options
-rw-r--r-- | Makefile | 88 | ||||
-rw-r--r-- | deps.mk | 5 | ||||
-rwxr-xr-x | mkdeps.sh | 13 | ||||
-rwxr-xr-x | src/cicd | 50 | ||||
-rwxr-xr-x | src/cicd-run | 136 | ||||
-rwxr-xr-x | src/cicdd | 8 | ||||
-rwxr-xr-x | src/post-receive | 34 |
7 files changed, 334 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0e40309 --- /dev/null +++ b/Makefile @@ -0,0 +1,88 @@ +.POSIX: +DATE = 1970-01-01 +VERSION = 0.1.0 +NAME = cicd +NAME_UC = $(NAME) +LANGUAGES = en +## Installation prefix. Defaults to "/usr". +PREFIX = /usr +BINDIR = $(PREFIX)/bin +LIBDIR = $(PREFIX)/lib +INCLUDEDIR = $(PREFIX)/include +SRCDIR = $(PREFIX)/src/$(NAME) +SHAREDIR = $(PREFIX)/share +LOCALEDIR = $(SHAREDIR)/locale +MANDIR = $(SHAREDIR)/man +EXEC = ./ +## Where to store the installation. Empty by default. +DESTDIR = +LDLIBS = + + + +.SUFFIXES: + + + +all: +include deps.mk + +sources = \ + $(sources.sh) \ + + +derived-assets = \ + +side-assets = \ + + + +## Default target. Builds all artifacts required for testing +## and installation. +all: $(derived-assets) + + + +check-unit: + + +check-integration: + + +## Run all tests. Each test suite is isolated, so that a parallel +## build can run tests at the same time. The required artifacts +## are created if missing. +check: check-unit check-integration + + + +## Remove *all* derived artifacts produced during the build. +## A dedicated test asserts that this is always true. +clean: + rm -rf $(derived-assets) $(side-assets) + + +## Installs into $(DESTDIR)$(PREFIX). Its dependency target +## ensures that all installable artifacts are crafted beforehand. +install: all + mkdir -p \ + '$(DESTDIR)$(BINDIR)' \ + '$(DESTDIR)$(SRCDIR)' \ + + cp $(sources.sh) '$(DESTDIR)$(BINDIR)' + cp $(sources) '$(DESTDIR)$(SRCDIR)' + + +## Uninstalls from $(DESTDIR)$(PREFIX). This is a perfect mirror +## of the "install" target, and removes *all* that was installed. +## A dedicated test asserts that this is always true. +uninstall: + rm -rf \ + '$(DESTDIR)$(SRCDIR)' \ + + for f in $(sources.sh); do \ + rm -f '$(DESTDIR)$(BINDIR)'/"$${f#src/}"; \ + done + + +ALWAYS: @@ -0,0 +1,5 @@ +sources.sh = \ + src/cicd \ + src/cicdd \ + src/post-receive \ + diff --git a/mkdeps.sh b/mkdeps.sh new file mode 100755 index 0000000..8204798 --- /dev/null +++ b/mkdeps.sh @@ -0,0 +1,13 @@ +#!/bin/sh +set -eu + +export LANG=POSIX.UTF-8 + +varlist() { + printf '%s = \\\n' "$1" + sort | sed 's|^\(.*\)$|\t\1 \\|' + printf '\n' +} + + +find src/* -type f -perm -111 | varlist 'sources.sh' diff --git a/src/cicd b/src/cicd new file mode 100755 index 0000000..0378f16 --- /dev/null +++ b/src/cicd @@ -0,0 +1,50 @@ +#!/bin/sh +set -eu + + +usage() { + cat <<-'EOF' + Usage: + cicd add [-n] [-V VERSION] [-R REFNAME] REPO... + cicd list + EOF +} + + +DEPLOY=true +VERSION=origin/main +REFNAME=origin/main +while getopts 'nV:R:' flag; do + case "$flag" in + (n) + DEPLOY=false + ;; + (V) + VERSION="$OPTARG" + ;; + (R) + REFNAME="$OPTARG" + ;; + (*) + usage >&2 + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + + +ACTION="${1:-}" +eval "$(assert-arg -- "$ACTION" 'ACTION')" +shift + + +for r in "$@"; do + cat <<-EOF | q cicd-inbox in + repo $r + now $(now) + deploy $DEPLOY + version $VERSION + refname $REFNAME + EOF +done diff --git a/src/cicd-run b/src/cicd-run new file mode 100755 index 0000000..66e5f8c --- /dev/null +++ b/src/cicd-run @@ -0,0 +1,136 @@ +#!/bin/sh +set -eu + + +usage() { + cat <<-'EOF' + Usage: cicdd + EOF +} + + +N=`nproc` + +if [ ! -e "$CLONE" ]; then + git clone "$REPO" "$CLONE" +fi + +cd "$CLONE" +git fetch +git checkout "$VERSION" + +MANIFEST_OPT= +if [ -f manifest.scm ]; then + MANIFEST_OPT='-m manifest.scm' +fi +guix shell -Cv3 $MANIFEST_OPT -- make -j$N all check + + + +NAME="$(basename "$PWD" .git)" +LOGS_DIR=/var/log/ci/"$NAME"/ +TIMESTAMP="$(now)" +FILENAME="$TIMESTAMP-$SHA.log" +LOGFILE="$LOGS_DIR/$FILENAME" +mkdir -p "$LOGS_DIR" + + +info() { + pre "$(color -c lightblueb 'CI')" +} + + + +{ + cat <<-EOF | info + Starting CI job at: $(now) + EOF + START="$(epoch)" + + duration() { + if [ "$RUN_DURATION" -gt 60 ]; then + cat <<-EOF + $(yellow 'WARNING'): run took more than 1 minute! ($RUN_DURATION seconds) + EOF + else + cat <<-EOF + Run took $RUN_DURATION seconds. + EOF + fi + } + + finish() { + STATUS="$?" + END="$(epoch)" + RUN_DURATION=$((END - START)) + cat <<-EOF | info + Finishing CI job at: $(now) + Exit status was $STATUS + Re-run with: + \$ $CMD + $(duration) + EOF + + NOTE="$( + cat <<-EOF + See CI logs with: + git notes --ref=refs/notes/ci-logs show $SHA + git notes --ref=refs/notes/ci-data show $SHA + + Exit status: $STATUS + Duration: $RUN_DURATION + EOF + )" + git notes --ref=refs/notes/ci-data add -f -m "$( + cat <<-EOF + status $STATUS + sha $SHA + filename $FILENAME + duration $RUN_DURATION + timestamp $TIMESTAMP + to-prod $TO_PROD + refname $REFNAME + EOF + )" "$SHA" + git notes --ref=refs/notes/ci-logs add -f -F "$LOGFILE" "$SHA" + git notes add -f -m "$NOTE" "$SHA" + + { + printf 'Git CI HTML report for %s (%s) started.\n' "$NAME" "$SHA" >&2 + DIR="$(mkdtemp)" + report -o "$DIR" + sudo -u deployer rsync \ + --chmod=D775,F664 \ + --chown=deployer:deployer \ + --delete \ + -a \ + "$DIR"/ "$HTML_OUTDIR_CI"/ + rm -rf "$DIR" + printf 'Git CI HTML report for %s (%s) finished.\n' "$NAME" "$SHA" >&2 + } 2>&1 | logger -i -p local0.warn -t git-ci 1>/dev/null 2>&1 & + } + trap finish EXIT + + unset GIT_DIR + + if [ "$REFNAME" = 'refs/heads/main' ] && [ "$SKIP_DEPLOY" = false ]; then + cat <<-EOF | info + In branch "main", running deploy for $SHA. + EOF + TO_PROD=true + CMD="sudo reconfigure $SHA" + else + if [ "$SKIP_DEPLOY" = true ]; then + cat <<-EOF | info + "deploy.skip" option detected, skipping deploy for $SHA. + EOF + else + cat <<-EOF | info + Not on branch "main", skipping deploy for $SHA. + EOF + fi + TO_PROD=false + CMD="sudo reconfigure -n $SHA" + fi + $CMD +} 2>&1 | ts -s '%.s' | tee "$LOGFILE" diff --git a/src/cicdd b/src/cicdd new file mode 100755 index 0000000..287d5eb --- /dev/null +++ b/src/cicdd @@ -0,0 +1,8 @@ +#!/bin/sh +set -eu + + +while true; do + job=get + cicd-run +done diff --git a/src/post-receive b/src/post-receive new file mode 100755 index 0000000..2dc4128 --- /dev/null +++ b/src/post-receive @@ -0,0 +1,34 @@ +#!/bin/sh +set -eu + + + +read -r _oldrev SHA REFNAME + +if [ "$SHA" = '0000000000000000000000000000000000000000' ]; then + exit +fi + + +DEPLOY_OPT= +for n in `seq 0 $((GIT_PUSH_OPTION_COUNT - 1))`; do + opt="$(eval "printf '%s' \"\$GIT_PUSH_OPTION_$n\"")" + case "$opt" in + (ci.skip) + cat <<-EOF >&2 + + "$opt" option detected, not running CI. + + EOF + exit + ;; + (deploy.skip) + DEPLOY_OPT=-n + ;; + (*) + ;; + esac +done + + +cicd add $DEPLOY_OPT -V "$SHA" -R "$REFNAME" "$PWD" |