| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- #!/usr/bin/env bash
- # test.sh <path to a Go app repo with content/> (e.g. ~/src/posts)
- #
- # Runs release end to end in a throwaway sandbox: a local bare remote
- # instead of Gogs, and stand-in sudo/systemctl that record what they were
- # asked to do. Nothing on the real server is touched.
- set -euo pipefail
- here=$(cd "$(dirname "$0")" && pwd)
- src=$(cd "${1:?usage: test.sh <go app repo>}" && pwd)
- T=$(mktemp -d); trap 'rm -rf "$T"' EXIT
- pass=0; fail=0
- ok() { echo "ok $*"; pass=$((pass+1)); }
- bad() { echo "FAIL $*"; fail=$((fail+1)); }
- check() { local what=$1; shift; if "$@"; then ok "$what"; else bad "$what"; fi; }
- # Remote: bajdev/posts (go app with content) and bajdev/site (static).
- mkdir -p "$T/remote/bajdev" "$T/apps/posts/content" "$T/vhosts/site.example" "$T/bin"
- git clone --quiet --bare "$src" "$T/remote/bajdev/posts.git"
- # Start from no deploy tags, whatever the source repo already has.
- git -C "$T/remote/bajdev/posts.git" tag -l 'deploy/*' | xargs -r git -C "$T/remote/bajdev/posts.git" tag -d >/dev/null
- git init --quiet -b main "$T/site" && mkdir "$T/site/public" && echo hi > "$T/site/public/index.html"
- git -C "$T/site" add . && git -C "$T/site" -c user.name=t -c user.email=t@t commit --quiet -m init
- git clone --quiet --bare "$T/site" "$T/remote/bajdev/site.git"
- echo stale > "$T/apps/posts/content/removed-post.md"
- cat > "$T/sites.json" <<EOF
- {
- "bajdev/posts": { "kind": "go", "name": "posts", "content": "content" },
- "bajdev/site": { "kind": "static", "host": "site.example" }
- }
- EOF
- # Stand-ins: sudo just runs the command; systemctl logs and reports active
- # unless SYSTEMCTL_FAIL is set.
- printf '#!/bin/sh\n[ "$1" = -n ] && shift\nexec "$@"\n' > "$T/bin/sudo"
- printf '#!/bin/sh\necho "$*" >> "%s/systemctl.log"\n[ "$1" = is-active ] && [ -n "$SYSTEMCTL_FAIL" ] && exit 3\nexit 0\n' "$T" > "$T/bin/systemctl"
- chmod +x "$T/bin/sudo" "$T/bin/systemctl"
- export PATH="$T/bin:$PATH" RELEASE_CONF="$T/sites.json" RELEASE_GIT_BASE="$T/remote/" \
- RELEASE_WORK="$T/work" RELEASE_APPS="$T/apps" RELEASE_VHOSTS="$T/vhosts" RELEASE_LOG="$T/deploys.log" \
- GIT_AUTHOR_NAME=deploy GIT_AUTHOR_EMAIL=deploy@test GIT_COMMITTER_NAME=deploy GIT_COMMITTER_EMAIL=deploy@test
- R="$here/release"
- head=$(git -C "$src" rev-parse main)
- # 1. A normal release of the Go app.
- out=$(DEPLOY_BY="PR merged by bajdev" "$R" bajdev/posts "$head" 2>&1) || { bad "release posts: $out"; }
- check "binary built" test -x "$T/apps/posts/posts"
- check "no .new left behind" test ! -e "$T/apps/posts/posts.new"
- check "content synced" test -f "$T/apps/posts/content/2026-10-24-hello-world.md"
- check "deleted posts removed" test ! -e "$T/apps/posts/content/removed-post.md"
- check "service restarted" grep -qx "restart goapp@posts" "$T/systemctl.log"
- tag1=$(git -C "$T/remote/bajdev/posts.git" tag -l 'deploy/posts/*' | tail -1)
- check "deploy tag pushed" test -n "$tag1"
- check "tag is on the commit" test "$(git -C "$T/remote/bajdev/posts.git" rev-parse "$tag1^{commit}")" = "$head"
- check "log line written" grep -q "posts $head $tag1 PR merged by bajdev" "$T/deploys.log"
- # 2. Rollback to that tag (a second later, so the new tag name differs).
- sleep 1
- out=$(DEPLOY_BY="rollback by bajdev" "$R" bajdev/posts "$tag1" 2>&1) || bad "rollback: $out"
- check "rollback logged" grep -q "rollback by bajdev" "$T/deploys.log"
- check "rollback tagged" test "$(git -C "$T/remote/bajdev/posts.git" tag -l 'deploy/posts/*' | wc -l)" -eq 2
- # 3. Static site.
- out=$("$R" bajdev/site main 2>&1) || bad "release site: $out"
- check "static files synced" test -f "$T/vhosts/site.example/index.html"
- check "static tag pushed" test -n "$(git -C "$T/remote/bajdev/site.git" tag -l 'deploy/site.example/*')"
- # 4. Refusals.
- refused() { # <message the right guard prints> <args...>
- local want=$1; shift; local out
- if out=$("$R" "$@" 2>&1); then return 1; fi
- [[ $out == *"$want"* ]]
- }
- check "unknown repo refused" refused "unknown repo" bajdev/nope main
- check "../ repo name refused" refused "bad repo name" ../x main
- check "dot-leading name refused" refused "bad repo name" bajdev/.git main
- check "option-like ref refused" refused "bad ref" bajdev/posts --upload-pack=x
- check "wrong arg count refused" refused "usage:" bajdev/posts
- # 5. A service that fails to start: no tag, no log line.
- tags_before=$(git -C "$T/remote/bajdev/posts.git" tag -l 'deploy/posts/*' | wc -l)
- lines_before=$(wc -l < "$T/deploys.log")
- sleep 1
- check "failed start exits non-zero" bash -c '! SYSTEMCTL_FAIL=1 "$0" bajdev/posts main >/dev/null 2>&1' "$R"
- check "failed start not tagged" test "$(git -C "$T/remote/bajdev/posts.git" tag -l 'deploy/posts/*' | wc -l)" -eq "$tags_before"
- check "failed start not logged" test "$(wc -l < "$T/deploys.log")" -eq "$lines_before"
- # 6. What deployd sends: origin/main, after main has moved on since the work
- # clone was made (another PR merged meanwhile). The release must include it.
- up=$T/upstream
- git clone --quiet "$T/remote/bajdev/posts.git" "$up"
- printf -- '---\ntitle: Merged by another PR\n---\n\nHi.\n' > "$up/content/2026-12-01-other-pr.md"
- git -C "$up" add content && git -C "$up" commit --quiet -m "Another PR" && git -C "$up" push --quiet origin HEAD:main
- tip=$(git -C "$T/remote/bajdev/posts.git" rev-parse main)
- sleep 1
- out=$(DEPLOY_BY="PR merged by bajdev (head 0bfb14e)" "$R" bajdev/posts origin/main 2>&1) || bad "release origin/main: $out"
- check "origin/main includes the other PR" test -f "$T/apps/posts/content/2026-12-01-other-pr.md"
- tagN=$(git -C "$T/remote/bajdev/posts.git" tag -l 'deploy/posts/*' | tail -1)
- check "tag is on main's new tip" test "$(git -C "$T/remote/bajdev/posts.git" rev-parse "$tagN^{commit}")" = "$tip"
- check "log records main's tip" grep -q "posts $tip $tagN PR merged by bajdev (head 0bfb14e)" "$T/deploys.log"
- echo "$pass passed, $fail failed"
- [[ $fail -eq 0 ]]
|