Benchmarks / CPU and I/O (per commit) (push) Successful in 2m28s
Benchmarks / Frame budget (on demand) (push) Skipped
Build and test / Desktop (Linux) (push) Successful in 45m9s
Build and test / Layer separation (push) Successful in 38s
Traceability / Requirement traces (push) Successful in 44s
🐳 Android image / Build and push (push) Successful in 5s
🐳 Windows image / Build and push (push) Successful in 1s
Build and test / android-image (push) Successful in 5s
Build and test / windows-image (push) Successful in 1s
Build and test / Android (aarch64) (push) Successful in 14m25s
Build and test / Windows (x86_64, cross) (push) Successful in 34m30s
Build and test / Publish the release (push) Skipped
Nothing made a release. CI built the APK and the installer on the master push and kept them as workflow artefacts, the Linux binary was not kept at all, and most tags went out with no downloads until they were attached by hand. build-and-test now also runs on v* tags. On a tag the desktop job keeps its release binary, and a release job that needs desktop, Android and Windows collects the three, names them with the version and runs tools/publish-release.sh. The script titles and describes the release from the annotated tag's message as the server holds it, writes SHA256SUMS, and attaches what is not already there, so a re-run after an interrupted upload finishes the job instead of duplicating it. The same script is how a release is made or finished by hand. Tried on v0.14.1, whose release was made by hand with the same files: it found the release, reported all four files attached, and changed nothing.
101 lines
3.9 KiB
Bash
Executable File
101 lines
3.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Turn a pushed tag into a Gitea Release with the build's files attached.
|
|
#
|
|
# GITEA_TOKEN=... tools/publish-release.sh v0.14.1 FILE...
|
|
#
|
|
# The release is named and described by the tag's own message — its first
|
|
# line is the title, the rest the notes — so the notes are written once, in
|
|
# the annotated tag, and not restated anywhere. SHA256SUMS over the given
|
|
# files is written and attached alongside them.
|
|
#
|
|
# Run by CI's `release` job on every v* tag, and by hand with the same
|
|
# arguments when a release has to be made or finished from a workstation.
|
|
# It is safe to repeat: an existing release is reused, and a file already
|
|
# attached under the same name and size is skipped, so a second run after an
|
|
# interrupted upload attaches only what is missing.
|
|
#
|
|
# Before this existed nothing made a release: CI built the APK and the
|
|
# installer on the master push and kept them as workflow artefacts, and
|
|
# most tags went out with no downloads at all.
|
|
set -euo pipefail
|
|
|
|
GITEA_URL="${GITEA_URL:-https://gitea.tourolle.paris}"
|
|
GITEA_REPO="${GITEA_REPO:-dtourolle/DarkRoom}"
|
|
: "${GITEA_TOKEN:?set GITEA_TOKEN to a token that can write releases}"
|
|
|
|
if [[ $# -lt 2 ]]; then
|
|
echo "usage: tools/publish-release.sh <tag> <file>..." >&2
|
|
exit 2
|
|
fi
|
|
TAG="$1"
|
|
shift
|
|
|
|
API="${GITEA_URL}/api/v1/repos/${GITEA_REPO}"
|
|
AUTH=(-H "Authorization: token ${GITEA_TOKEN}")
|
|
|
|
for f in "$@"; do
|
|
[[ -f "${f}" ]] || { echo "error: ${f} does not exist" >&2; exit 1; }
|
|
done
|
|
|
|
# The checksums, beside the files they describe, named as they will be
|
|
# downloaded — `sha256sum -c SHA256SUMS` in a download folder has to work.
|
|
WORK="$(mktemp -d)"
|
|
trap 'rm -rf "${WORK}"' EXIT
|
|
(
|
|
for f in "$@"; do
|
|
printf '%s %s\n' "$(sha256sum "${f}" | cut -d' ' -f1)" "$(basename "${f}")"
|
|
done
|
|
) > "${WORK}/SHA256SUMS"
|
|
cat "${WORK}/SHA256SUMS"
|
|
|
|
# The notes, from the server's copy of the tag. A CI checkout of a tag can
|
|
# hold it as a lightweight ref with no message, so the local repository is
|
|
# not asked.
|
|
curl -fsS "${AUTH[@]}" "${API}/tags/${TAG}" > "${WORK}/tag.json" \
|
|
|| { echo "error: no tag ${TAG} on ${GITEA_REPO}" >&2; exit 1; }
|
|
|
|
RELEASE_ID="$(curl -sS "${AUTH[@]}" "${API}/releases/tags/${TAG}" \
|
|
| python3 -c 'import json,sys; print(json.load(sys.stdin).get("id") or "")' 2>/dev/null || true)"
|
|
|
|
if [[ -n "${RELEASE_ID}" ]]; then
|
|
echo "==> release ${TAG} exists (id ${RELEASE_ID}); attaching what is missing"
|
|
else
|
|
python3 - "${TAG}" "${WORK}/tag.json" > "${WORK}/release.json" <<'PY'
|
|
import json, sys
|
|
tag, path = sys.argv[1], sys.argv[2]
|
|
message = (json.load(open(path)).get("message") or "").strip()
|
|
if not message:
|
|
sys.exit(f"error: {tag} has no message; releases are cut from annotated tags")
|
|
title, _, body = message.partition("\n")
|
|
print(json.dumps({"tag_name": tag, "name": title.strip(), "body": body.strip(),
|
|
"draft": False, "prerelease": False}))
|
|
PY
|
|
RELEASE_ID="$(curl -fsS "${AUTH[@]}" -H 'Content-Type: application/json' \
|
|
--data @"${WORK}/release.json" "${API}/releases" \
|
|
| python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])')"
|
|
echo "==> created release ${TAG} (id ${RELEASE_ID})"
|
|
fi
|
|
|
|
curl -fsS "${AUTH[@]}" "${API}/releases/${RELEASE_ID}/assets" > "${WORK}/assets.json"
|
|
|
|
for f in "$@" "${WORK}/SHA256SUMS"; do
|
|
name="$(basename "${f}")"
|
|
size="$(stat -c%s "${f}")"
|
|
have="$(python3 -c 'import json,sys
|
|
for a in json.load(open(sys.argv[1])):
|
|
if a["name"] == sys.argv[2]: print(a["size"])' "${WORK}/assets.json" "${name}")"
|
|
if [[ "${have}" == "${size}" ]]; then
|
|
echo " ${name}: already attached"
|
|
continue
|
|
fi
|
|
if [[ -n "${have}" ]]; then
|
|
echo "error: ${name} is attached at ${have} bytes, not ${size}; remove it by hand" >&2
|
|
exit 1
|
|
fi
|
|
echo " ${name}: uploading ${size} bytes"
|
|
curl -fsS "${AUTH[@]}" -F "attachment=@${f}" \
|
|
"${API}/releases/${RELEASE_ID}/assets?name=${name}" > /dev/null
|
|
done
|
|
|
|
echo "==> ${GITEA_URL}/${GITEA_REPO}/releases/tag/${TAG}"
|