diff options
Diffstat (limited to 'share/aux-repo')
-rw-r--r-- | share/aux-repo/aux/.gitignore | 1 | ||||
-rwxr-xr-x | share/aux-repo/aux/ci/ci-build.sh | 66 | ||||
-rwxr-xr-x | share/aux-repo/aux/ci/git-post-receive.sh | 22 | ||||
-rwxr-xr-x | share/aux-repo/aux/ci/git-pre-push.sh | 22 | ||||
-rwxr-xr-x | share/aux-repo/aux/ci/report.sh | 158 | ||||
-rw-r--r-- | share/aux-repo/aux/lib.sh | 33 | ||||
-rw-r--r-- | share/aux-repo/aux/tld.txt | 1 | ||||
-rwxr-xr-x | share/aux-repo/aux/workflow/TODOs.sh | 65 | ||||
-rw-r--r-- | share/aux-repo/aux/workflow/favicon.svg | 62 | ||||
-rw-r--r-- | share/aux-repo/aux/workflow/head.html | 2 | ||||
-rwxr-xr-x | share/aux-repo/aux/workflow/md2html.sh | 87 | ||||
-rw-r--r-- | share/aux-repo/aux/workflow/preamble.md.in | 16 | ||||
-rw-r--r-- | share/aux-repo/aux/workflow/style.css | 80 |
13 files changed, 615 insertions, 0 deletions
diff --git a/share/aux-repo/aux/.gitignore b/share/aux-repo/aux/.gitignore new file mode 100644 index 0000000..93cad91 --- /dev/null +++ b/share/aux-repo/aux/.gitignore @@ -0,0 +1 @@ +/workflow/preamble.md diff --git a/share/aux-repo/aux/ci/ci-build.sh b/share/aux-repo/aux/ci/ci-build.sh new file mode 100755 index 0000000..8d49779 --- /dev/null +++ b/share/aux-repo/aux/ci/ci-build.sh @@ -0,0 +1,66 @@ +#!/bin/sh +set -eux + +PROJECT="$1" +LOGS_DIR="$2" +SHA="$3" +FILENAME="$(date -Is)-$SHA.log" +LOGFILE="$LOGS_DIR/$FILENAME" + +mkdtemp() { + name="$(echo 'mkstemp(template)' | + m4 -D template="${TMPDIR:-/tmp}/m4-tmpname.")" + rm -f "$name" + mkdir "$name" + echo "$name" +} + +{ + echo "Starting CI job at: $(date -Is)" + + finish() { + STATUS="$?" + printf "\n\n>>> exit status was %s\n" "$STATUS" + echo "Finishing CI job at: $(date -Is)" + cd - + 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 +EOF +) + git notes --ref=refs/notes/ci-data add -f -m "$STATUS $FILENAME" + git notes --ref=refs/notes/ci-logs add -f -F "$LOGFILE" + git notes append -m "$NOTE" + + cd - + git fetch origin refs/notes/*:refs/notes/* + sh aux/ci/report.sh -n "$PROJECT" -o public + rsync -av public/ "/opt/www/$TLD/static/$PROJECT/" + + tar \ + -C "/opt/www/$TLD/git/repos" \ + -c \ + -f "/opt/www/$TLD/static/$PROJECT/repo.tar.gz" \ + "$PROJECT".git + + printf '\n>>>\n>>> CI logs added as Git note.\n>>>\n>>> Run status was %s\n>>>\n\n' \ + "$STATUS" + } + trap finish EXIT + + unset GIT_DIR + REMOTE="$PWD" + cd "$(mkdtemp)" + git clone "$REMOTE" . + git config --global user.email git@euandre.org + git config --global user.name 'EuAndreh CI' + + if [ -e aux/with-container ]; then + RUNNER='sh aux/with-container' + else + RUNNER='sh -c' + fi + + $RUNNER 'make clean dev-check' +} 2>&1 | tee "$LOGFILE" diff --git a/share/aux-repo/aux/ci/git-post-receive.sh b/share/aux-repo/aux/ci/git-post-receive.sh new file mode 100755 index 0000000..f813259 --- /dev/null +++ b/share/aux-repo/aux/ci/git-post-receive.sh @@ -0,0 +1,22 @@ +#!/bin/sh +set -eu + +for n in $(seq 0 $((GIT_PUSH_OPTION_COUNT - 1))); do + opt="$(eval "echo \$GIT_PUSH_OPTION_$n")" + if [ "$opt" = skip-ci ] || [ "$opt" = ci-skip ]; then + printf "\n'%s' option detected, not running ci-build.sh\n\n" \ + "$opt" + exit 0 + fi +done + +# shellcheck disable=2034 +read -r _oldrev SHA _refname + +PROJECT="$(basename "$PWD" | cut -d. -f1)" # remove .git suffix +LOGS_DIR="/opt/ci/$PROJECT/logs" +sh "/opt/ci/$PROJECT/ci-build.sh" "$PROJECT" "$LOGS_DIR" "$SHA" ||: + +echo 'To retrigger the build, run:' +echo "cd /opt/www/$TLD/git/repos/$PROJECT.git/" +echo "sh /opt/www/$TLD/git/ci/$PROJECT/ci-build.sh" "$PROJECT" "$LOGS_DIR" "$SHA" diff --git a/share/aux-repo/aux/ci/git-pre-push.sh b/share/aux-repo/aux/ci/git-pre-push.sh new file mode 100755 index 0000000..9883769 --- /dev/null +++ b/share/aux-repo/aux/ci/git-pre-push.sh @@ -0,0 +1,22 @@ +#!/bin/sh +set -eux + +TLD="$(cat aux/tld.txt)" +. aux/lib.sh + +PROJECT="$(basename "$PWD")" +LOGS_DIR="/opt/www/$TLD/git/ci/$PROJECT/logs" +REMOTE_GIT_DIR="/opt/www/$TLD/git/repos/$PROJECT.git" + +DESCRIPTION="$(mkstemp)" +if [ -f description ] +then + cp description "$DESCRIPTION" +else + git config euandreh.description > "$DESCRIPTION" +fi + +scp "$DESCRIPTION" "$TLD:$REMOTE_GIT_DIR/description" +ssh "$TLD" mkdir -p "$LOGS_DIR" +scp aux/ci/ci-build.sh "$TLD:$(dirname "$LOGS_DIR")/ci-build.sh" +scp aux/ci/git-post-receive.sh "$TLD:$REMOTE_GIT_DIR/hooks/post-receive" diff --git a/share/aux-repo/aux/ci/report.sh b/share/aux-repo/aux/ci/report.sh new file mode 100755 index 0000000..21cc54e --- /dev/null +++ b/share/aux-repo/aux/ci/report.sh @@ -0,0 +1,158 @@ +#!/bin/sh +set -eu + +TLD="$(cat aux/tld.txt)" +. aux/lib.sh + + +usage() { + cat <<-'EOF' + Usage: + aux/ci/report.sh -n NAME -o OUTDIR + aux/ci/report.sh -h + EOF +} + +help() { + cat <<-'EOF' + + + Options: + -n NAME the lowercase name of the project + -o OUTDIR directory where to write the files + -h, --help show this message + + + Generate static HTML files CI report from data stored in git + notes. The metadata about the CI runs are stored in the ref + "refs/notes/ci-data", in the format described by + "aux/ci/run.sh", and the raw logs are stored under the ref + "refs/notes/ci-logs". + + + Examples: + + Generate report for project "myapp" in "public/ci/": + + $ sh aux/ci/report.sh -n myapp -o public/ci + EOF +} + + +for flag in "$@"; do + case "$flag" in + --) + break + ;; + --help) + usage + help + exit + ;; + *) + ;; + esac +done + +while getopts 'n:o:h' flag; do + case "$flag" in + n) + NAME="$OPTARG" + ;; + o) + OUTDIR="$OPTARG" + ;; + h) + usage + help + exit + ;; + *) + usage >&2 + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + + +eval "$(assert_arg "${NAME:-}" '-n NAME')" +eval "$(assert_arg "${OUTDIR:-}" '-o OUTDIR')" + +PASS='✅' +FAIL='❌' + +mkdir -p "$OUTDIR"/logs "$OUTDIR"/data + +for c in $(git notes list | cut -d' ' -f2); do + DATA="$(git notes --ref=refs/notes/ci-data show "$c")" + FILENAME="$(echo "$DATA" | cut -d' ' -f2)" + echo "$DATA" > "$OUTDIR/data/$FILENAME" + git notes --ref=refs/notes/ci-logs show "$c" \ + > "$OUTDIR/logs/$FILENAME" +done + +{ + cat <<-EOF + <!DOCTYPE html> + <html lang="en"> + <head> + <meta charset="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1" /> + <meta name="description" content="CI logs for $NAME" /> + <link rel="icon" type="image/svg+xml" href="favicon.svg" /> + <title>$NAME - CI logs</title> + + <style> + EOF + + cat aux/workflow/style.css | sed 's|^| |' + + cat <<-EOF + </style> + + <style> + pre { + display: inline; + } + ol { + list-style-type: disc; + } + </style> + </head> + <body> + <main> + <h1> + CI logs for + <a href="https://$TLD/$NAME/en/">$NAME</a> + </h1> + <ol> + EOF + + for f in $(find "$OUTDIR/data/" -type f | LANG=C.UTF-8 sort -r); do + DATA="$(cat "$f")" + STATUS="$(echo "$DATA" | cut -d\ -f1)" + FILENAME="$(echo "$DATA" | cut -d\ -f2)" + + if [ "$STATUS" = 0 ]; then + STATUS_MARKER="$PASS" + else + STATUS_MARKER="$FAIL" + fi + + cat <<-EOF + <li> + <a href="logs/$FILENAME">$STATUS_MARKER <pre>$FILENAME</pre></a> + </li> + EOF + done + + cat <<-EOF + </ol> + </main> + </body> + </html> + EOF +} > "$OUTDIR"/index.html.tmp + +mv "$OUTDIR"/index.html.tmp "$OUTDIR"/index.html diff --git a/share/aux-repo/aux/lib.sh b/share/aux-repo/aux/lib.sh new file mode 100644 index 0000000..9d183f9 --- /dev/null +++ b/share/aux-repo/aux/lib.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +assert_arg() { + if [ -z "$1" ]; then + printf 'Missing %s.\n\n' "$2" >&2 + cat <<-'EOF' + usage >&2 + exit 2 + EOF + fi +} + +uuid() { + od -xN20 /dev/urandom | + head -n1 | + awk '{OFS="-"; print $2$3,$4,$5,$6,$7$8$9}' +} + +tmpname() { + echo "${TMPDIR:-/tmp}/uuid-tmpname with spaces.$(uuid)" +} + +mkstemp() { + name="$(tmpname)" + touch "$name" + echo "$name" +} + +mkdtemp() { + name="$(tmpname)" + mkdir "$name" + echo "$name" +} diff --git a/share/aux-repo/aux/tld.txt b/share/aux-repo/aux/tld.txt new file mode 100644 index 0000000..058a2d6 --- /dev/null +++ b/share/aux-repo/aux/tld.txt @@ -0,0 +1 @@ +euandre.org
\ No newline at end of file diff --git a/share/aux-repo/aux/workflow/TODOs.sh b/share/aux-repo/aux/workflow/TODOs.sh new file mode 100755 index 0000000..8b06d15 --- /dev/null +++ b/share/aux-repo/aux/workflow/TODOs.sh @@ -0,0 +1,65 @@ +#!/bin/sh +set -eu + +TLD="$(cat aux/tld.txt)" +PROJECT_UC= +while getopts 'n:N:m:o:' flag; do + case "$flag" in + n) + PROJECT="$OPTARG" + ;; + N) + PROJECT_UC="$OPTARG" + ;; + m) + MAILING_LIST="$OPTARG" + ;; + o) + OUTDIR="$OPTARG" + ;; + *) + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + +assert_arg() { + if [ -z "$1" ]; then + echo "Missing $2" >&2 + exit 2 + fi +} + +assert_arg "${PROJECT:-}" '-n PROJECT' +assert_arg "${MAILING_LIST:-}" '-m MAILING_LIST' +assert_arg "${OUTDIR:-}" '-o OUTDIR' + +if [ -z "${PROJECT_UC:-}" ]; then + PROJECT_UC="$PROJECT" +fi + + +td -H | + cat aux/workflow/preamble.md - | + sed \ + -e "s:@PROJECT_UC@:$PROJECT_UC:g" \ + -e "s:@PROJECT@:$PROJECT:g" \ + -e "s:@MAILING_LIST@:$MAILING_LIST:g" \ + -e "s:@TLD@:$TLD:g" | + pandoc \ + --toc \ + --highlight-style pygments \ + --toc-depth=2 \ + -s \ + --metadata title="$PROJECT_UC - TODOs" \ + --metadata lang=en \ + -r commonmark \ + -w html \ + -H aux/workflow/favicon.html \ + -H aux/workflow/style.css | + sed \ + -e 's:<a><a:<a:g' \ + -e 's:</a></a>:</a>:g' + +# FIXME: check TODOs.sh from euandre.org diff --git a/share/aux-repo/aux/workflow/favicon.svg b/share/aux-repo/aux/workflow/favicon.svg new file mode 100644 index 0000000..ce566b2 --- /dev/null +++ b/share/aux-repo/aux/workflow/favicon.svg @@ -0,0 +1,62 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"> + <path d="M 0 8 L 1 8 L 1 9 L 0 9 L 0 8 Z" /> + <path d="M 0 13 L 1 13 L 1 14 L 0 14 L 0 13 Z" /> + <path d="M 1 8 L 2 8 L 2 9 L 1 9 L 1 8 Z" /> + <path d="M 1 13 L 2 13 L 2 14 L 1 14 L 1 13 Z" /> + <path d="M 2 8 L 3 8 L 3 9 L 2 9 L 2 8 Z" /> + <path d="M 2 13 L 3 13 L 3 14 L 2 14 L 2 13 Z" /> + <path d="M 3 8 L 4 8 L 4 9 L 3 9 L 3 8 Z" /> + <path d="M 3 13 L 4 13 L 4 14 L 3 14 L 3 13 Z" /> + <path d="M 4 7 L 5 7 L 5 8 L 4 8 L 4 7 Z" /> + <path d="M 4 8 L 5 8 L 5 9 L 4 9 L 4 8 Z" /> + <path d="M 4 13 L 5 13 L 5 14 L 4 14 L 4 13 Z" /> + <path d="M 5 6 L 6 6 L 6 7 L 5 7 L 5 6 Z" /> + <path d="M 5 7 L 6 7 L 6 8 L 5 8 L 5 7 Z" /> + <path d="M 5 13 L 6 13 L 6 14 L 5 14 L 5 13 Z" /> + <path d="M 6 5 L 7 5 L 7 6 L 6 6 L 6 5 Z" /> + <path d="M 6 6 L 7 6 L 7 7 L 6 7 L 6 6 Z" /> + <path d="M 6 14 L 7 14 L 7 15 L 6 15 L 6 14 Z" /> + <path d="M 7 1 L 8 1 L 8 2 L 7 2 L 7 1 Z" /> + <path d="M 7 14 L 8 14 L 8 15 L 7 15 L 7 14 Z" /> + <path d="M 7 15 L 8 15 L 8 16 L 7 16 L 7 15 Z" /> + <path d="M 7 2 L 8 2 L 8 3 L 7 3 L 7 2 Z" /> + <path d="M 7 3 L 8 3 L 8 4 L 7 4 L 7 3 Z" /> + <path d="M 7 4 L 8 4 L 8 5 L 7 5 L 7 4 Z" /> + <path d="M 7 5 L 8 5 L 8 6 L 7 6 L 7 5 Z" /> + <path d="M 8 1 L 9 1 L 9 2 L 8 2 L 8 1 Z" /> + <path d="M 8 15 L 9 15 L 9 16 L 8 16 L 8 15 Z" /> + <path d="M 9 1 L 10 1 L 10 2 L 9 2 L 9 1 Z" /> + <path d="M 9 2 L 10 2 L 10 3 L 9 3 L 9 2 Z" /> + <path d="M 9 6 L 10 6 L 10 7 L 9 7 L 9 6 Z" /> + <path d="M 9 15 L 10 15 L 10 16 L 9 16 L 9 15 Z" /> + <path d="M 10 2 L 11 2 L 11 3 L 10 3 L 10 2 Z" /> + <path d="M 10 3 L 11 3 L 11 4 L 10 4 L 10 3 Z" /> + <path d="M 10 4 L 11 4 L 11 5 L 10 5 L 10 4 Z" /> + <path d="M 10 5 L 11 5 L 11 6 L 10 6 L 10 5 Z" /> + <path d="M 10 6 L 11 6 L 11 7 L 10 7 L 10 6 Z" /> + <path d="M 11 6 L 12 6 L 12 7 L 11 7 L 11 6 Z" /> + <path d="M 11 8 L 12 8 L 12 9 L 11 9 L 11 8 Z" /> + <path d="M 10 15 L 11 15 L 11 16 L 10 16 L 10 15 Z" /> + <path d="M 11 10 L 12 10 L 12 11 L 11 11 L 11 10 Z" /> + <path d="M 11 12 L 12 12 L 12 13 L 11 13 L 11 12 Z" /> + <path d="M 11 14 L 12 14 L 12 15 L 11 15 L 11 14 Z" /> + <path d="M 11 15 L 12 15 L 12 16 L 11 16 L 11 15 Z" /> + <path d="M 12 6 L 13 6 L 13 7 L 12 7 L 12 6 Z" /> + <path d="M 12 8 L 13 8 L 13 9 L 12 9 L 12 8 Z" /> + <path d="M 12 10 L 13 10 L 13 11 L 12 11 L 12 10 Z" /> + <path d="M 12 12 L 13 12 L 13 13 L 12 13 L 12 12 Z" /> + <path d="M 12 14 L 13 14 L 13 15 L 12 15 L 12 14 Z" /> + <path d="M 13 6 L 14 6 L 14 7 L 13 7 L 13 6 Z" /> + <path d="M 13 8 L 14 8 L 14 9 L 13 9 L 13 8 Z" /> + <path d="M 13 10 L 14 10 L 14 11 L 13 11 L 13 10 Z" /> + <path d="M 13 12 L 14 12 L 14 13 L 13 13 L 13 12 Z" /> + <path d="M 13 13 L 14 13 L 14 14 L 13 14 L 13 13 Z" /> + <path d="M 13 14 L 14 14 L 14 15 L 13 15 L 13 14 Z" /> + <path d="M 14 7 L 15 7 L 15 8 L 14 8 L 14 7 Z" /> + <path d="M 14 8 L 15 8 L 15 9 L 14 9 L 14 8 Z" /> + <path d="M 14 9 L 15 9 L 15 10 L 14 10 L 14 9 Z" /> + <path d="M 14 10 L 15 10 L 15 11 L 14 11 L 14 10 Z" /> + <path d="M 14 11 L 15 11 L 15 12 L 14 12 L 14 11 Z" /> + <path d="M 14 12 L 15 12 L 15 13 L 14 13 L 14 12 Z" /> +</svg> diff --git a/share/aux-repo/aux/workflow/head.html b/share/aux-repo/aux/workflow/head.html new file mode 100644 index 0000000..3902690 --- /dev/null +++ b/share/aux-repo/aux/workflow/head.html @@ -0,0 +1,2 @@ +<link rel="icon" href="favicon.svg" type="image/svg+xml" /> +<link rel="stylesheet" href="style.css" type="text/css" /> diff --git a/share/aux-repo/aux/workflow/md2html.sh b/share/aux-repo/aux/workflow/md2html.sh new file mode 100755 index 0000000..957bfc2 --- /dev/null +++ b/share/aux-repo/aux/workflow/md2html.sh @@ -0,0 +1,87 @@ +#!/bin/sh +set -eu + +. aux/lib.sh + +usage() { + cat <<-'EOF' + Usage: + aux/workflow/md2html.sh -N NAME_UC -T TITLE [-D TOC_DEPTH] < FILE.md + aux/workflow/md2html.sh -h + EOF +} + +help() { + cat <<-'EOF' + + Options: + -N NAME_UC the uppercased name of the project + -T TITLE the required title of the generated HTML + document + -D TOC_DEPTH the depth of the generated table of + contents (default: 2) + -h, --help show this message + + + Read markdown text from STDIN and emit HTML to STDOUT. + EOF +} + +for flag in "$@"; do + case "$flag" in + --) + break + ;; + --help) + usage + help + exit + ;; + *) + ;; + esac +done + +TOC_DEPTH=2 +while getopts 'N:T:D:h' flag; do + case "$flag" in + N) + NAME_UC="$OPTARG" + ;; + T) + TITLE="$OPTARG" + ;; + D) + TOC_DEPTH="$OPTARG" + ;; + h) + usage + help + exit + ;; + *) + usage >&2 + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + +eval "$(assert_arg "${NAME_UC:-}" '-T TITLE')" +eval "$(assert_arg "${TITLE:-}" '-T TITLE')" + +THE_LANG='en' + +ALTERNATES=/dev/null + +pandoc \ + -s \ + --toc \ + --toc-depth="$TOC_DEPTH" \ + --highlight-style=pygments \ + --metadata lang="$THE_LANG" \ + --metadata title="$TITLE - $NAME_UC" \ + -r commonmark \ + -w html \ + -H aux/workflow/head.html \ + -H "$ALTERNATES" diff --git a/share/aux-repo/aux/workflow/preamble.md.in b/share/aux-repo/aux/workflow/preamble.md.in new file mode 100644 index 0000000..1d17997 --- /dev/null +++ b/share/aux-repo/aux/workflow/preamble.md.in @@ -0,0 +1,16 @@ +# About + +TODOs for [@PROJECT_UC@](https://@TLD@/@PROJECT@/en/). + +Register a new one at +<span id="new">[@MAILING_LIST@](mailto:@MAILING_LIST@?subject=%5B@PROJECT@%5D%20BUG%20or%20TASK%3A%20%3Cdescription%3E)</span> +and see [existing discussions](@LIST_SEARCH@). + +*Você também pode escrever em português*. + +*Vous pouvez aussi écrire en français*. + +*Vi povas ankaŭ skribi esperante*. + +*Tu también puedes escribir en español*. + diff --git a/share/aux-repo/aux/workflow/style.css b/share/aux-repo/aux/workflow/style.css new file mode 100644 index 0000000..4f3c83e --- /dev/null +++ b/share/aux-repo/aux/workflow/style.css @@ -0,0 +1,80 @@ +html { + line-height: 1.5; +} + +body { + max-width: 800px; + margin: 0 auto 0 auto; +} + +hr { + background-color: #ccc; +} + +.header-anchor { + opacity: 0.5; + display: inline-block; +} + +.tag { + font-family: monospace; + font-size: 70%; + background-color: lightgray; + color: black; + padding: 3px; + border-radius: 5px; +} + +.TODO { + color: brown; +} + +.DOING { + color: yellowgreen; +} + +.WAITING, .MEETING { + color: orange; +} + +.INACTIVE { + color: gray; +} + +.NEXT { + color: red; +} + +.CANCELLED, .DONE, .WONTFIX { + color: green; +} + +pre, code { + background-color: #ddd; + border-radius: 5px; + padding: 3px; +} + +pre > code { + overflow: auto; + white-space: pre; +} + +@media(prefers-color-scheme: dark) { + :root { + color: white; + background-color: black; + } + + a { + color: hsl(211, 100%, 60%); + } + + a:visited { + color: hsl(242, 100%, 80%); + } + + pre, code { + background-color: #222; + } +} |