Deploy configuration site to Bunny
successSet up job
successactions/checkout@v4 <1s
successactions/setup-node@v4 5s
Environment details
successnpm ci <1s
npm ci
successBuild static configuration page <1s
npm run build:config-page
successBack up mutable production files 12s
set -euo pipefail
[[ -n "$BUNNY_STORAGE_ENDPOINT" ]] || { echo "Missing required production variable BUNNY_STORAGE_ENDPOINT" >&2; exit 1; }
[[ -n "$BUNNY_STORAGE_PASSWORD" ]] || { echo "Missing required production secret BUNNY_STORAGE_PASSWORD" >&2; exit 1; }
endpoint="${BUNNY_STORAGE_ENDPOINT%/}"
case "$endpoint" in
https://*) ;;
*) echo "BUNNY_STORAGE_ENDPOINT must use HTTPS" >&2; exit 1 ;;
esac
mkdir -p var/deploy-backup/files
: > var/deploy-backup/missing
# Feed the loop through a plain pipe. Process substitution exposes
# the file list as a /dev/fd path, which is unavailable on some
# hardened runners and aborts the backup before any upload.
find var/config-site -type f -print0 \
| while IFS= read -r -d '' file; do
relative_path="${file#var/config-site/}"
case "$relative_path" in
*[!A-Za-z0-9._/-]* | /* | *../*)
echo "Refusing unsafe backup path: $relative_path" >&2
exit 1
;;
esac
target="var/deploy-backup/files/$relative_path"
mkdir -p "$(dirname "$target")"
status="$(curl --silent --show-error \
--output "$target" \
--write-out '%{http_code}' \
--header "AccessKey: $BUNNY_STORAGE_PASSWORD" \
"$endpoint/$relative_path")"
case "$status" in
200) ;;
404)
rm -f "$target"
printf '%s\0' "$relative_path" >> var/deploy-backup/missing
;;
*)
echo "Could not back up $relative_path: HTTP $status" >&2
exit 1
;;
esac
done
successRetain rollback bundle 2s
successUpload static site to Bunny Storage 20s
set -euo pipefail
test -n "$BUNNY_STORAGE_ENDPOINT"
test -n "$BUNNY_STORAGE_PASSWORD"
endpoint="${BUNNY_STORAGE_ENDPOINT%/}"
case "$endpoint" in
https://*) ;;
*) echo "BUNNY_STORAGE_ENDPOINT must use HTTPS" >&2; exit 1 ;;
esac
upload_file() {
local file="$1"
local relative_path="${file#var/config-site/}"
local mime_type
case "$relative_path" in
*[!A-Za-z0-9._/-]* | /* | *../*)
echo "Refusing unsafe deployment path: $relative_path" >&2
exit 1
;;
esac
mime_type="$(file --brief --mime-type "$file")"
echo "Uploading $relative_path"
curl --fail --silent --show-error \
--retry 3 --retry-all-errors \
--request PUT \
--header "AccessKey: $BUNNY_STORAGE_PASSWORD" \
--header "Content-Type: $mime_type" \
--upload-file "$file" \
"$endpoint/$relative_path"
}
export endpoint BUNNY_STORAGE_PASSWORD
export -f upload_file
find var/config-site -type f -print0 \
| xargs -0 --no-run-if-empty --max-args=1 --max-procs=32 \
bash -c 'upload_file "$1"' _
successPurge Bunny CDN cache <1s
set -euo pipefail test -n "$BUNNY_API_KEY" test -n "$BUNNY_PULL_ZONE_ID" curl --fail --silent --show-error \ --retry 3 --retry-all-errors \ --request POST \ --header "AccessKey: $BUNNY_API_KEY" \ "https://api.bunny.net/pullzone/$BUNNY_PULL_ZONE_ID/purgeCache"
successVerify served static site 1s
for attempt in 1 2 3; do
if npm run verify:config-site -- --page-only; then
exit 0
fi
if [[ "$attempt" != 3 ]]; then sleep 10; fi
done
exit 1
skippedRestore previous mutable files after failure
set -euo pipefail
endpoint="${BUNNY_STORAGE_ENDPOINT%/}"
case "$endpoint" in
https://*) ;;
*) echo "BUNNY_STORAGE_ENDPOINT must use HTTPS" >&2; exit 1 ;;
esac
restore_file() {
local file="$1"
local relative_path="${file#var/deploy-backup/files/}"
local mime_type
mime_type="$(file --brief --mime-type "$file")"
echo "Restoring $relative_path"
curl --fail --silent --show-error \
--request PUT \
--header "AccessKey: $BUNNY_STORAGE_PASSWORD" \
--header "Content-Type: $mime_type" \
--upload-file "$file" \
"$endpoint/$relative_path"
}
export endpoint BUNNY_STORAGE_PASSWORD
export -f restore_file
find var/deploy-backup/files -type f -print0 \
| xargs -0 --no-run-if-empty --max-args=1 --max-procs=16 \
bash -c 'restore_file "$1"' _
while IFS= read -r -d '' relative_path; do
echo "Removing newly introduced mutable file $relative_path"
status="$(curl --silent --show-error \
--request DELETE \
--header "AccessKey: $BUNNY_STORAGE_PASSWORD" \
--output /dev/null \
--write-out '%{http_code}' \
"$endpoint/$relative_path")"
case "$status" in
200 | 201 | 204 | 404) ;;
*)
echo "Could not remove $relative_path during rollback: HTTP $status" >&2
exit 1
;;
esac
done < var/deploy-backup/missing
curl --fail --silent --show-error \
--request POST \
--header "AccessKey: $BUNNY_API_KEY" \
"https://api.bunny.net/pullzone/$BUNNY_PULL_ZONE_ID/purgeCache"
Post actions/setup-node@v4
No test reports for this run.
Tell a job where its test runner writes its report and this tab fills in: how many tests passed, failed and were skipped, a bar of the result at a glance, then every failure first — with the assertion that failed and the output around it — over a per-suite list of cases and their durations. No scrolling a log for the word FAIL.
It is one reports: key on the job — a job key, not a step, so the report is collected whatever the job concluded. JUnit XML and go test -json are both understood, and most runners already emit one of them. reports: is a rickub extension and works only in .rickub/workflows/; in .github/workflows/ it is a parse error on purpose, because those files are also meant to run on github.com.