summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile88
-rw-r--r--deps.mk5
-rwxr-xr-xmkdeps.sh13
-rwxr-xr-xsrc/cicd50
-rwxr-xr-xsrc/cicd-run136
-rwxr-xr-xsrc/cicdd8
-rwxr-xr-xsrc/post-receive34
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:
diff --git a/deps.mk b/deps.mk
new file mode 100644
index 0000000..7894a69
--- /dev/null
+++ b/deps.mk
@@ -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"