build: finish cross-platform release tooling
This commit is contained in:
Executable
+102
@@ -0,0 +1,102 @@
|
||||
#!/usr/bin/env bash
|
||||
# Upload release files to the Gitea release vVERSION, creating the release
|
||||
# (and its tag at HEAD) when missing.
|
||||
# GITEA_TOKEN=... scripts/release.sh FILE...
|
||||
# Each FILE's FILE.sha256 is uploaded too when it exists; assets of the same
|
||||
# name are replaced. Several CI jobs may call this at once: the first creates
|
||||
# the release, the others find it. The token is only read from the
|
||||
# environment and handed to curl on stdin: it never appears in argv, on disk
|
||||
# or in the output.
|
||||
#
|
||||
# CI: set GITEA_TOKEN (or GITHUB_TOKEN), CST_GITEA, CST_REPO. The remote-branch
|
||||
# check is skipped under GITEA_ACTIONS / GITHUB_ACTIONS / CI.
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
SERVER="${CST_GITEA:-${GITHUB_SERVER_URL:-https://git.whcself.xyz}}"
|
||||
REPO="${CST_REPO:-${GITHUB_REPOSITORY:-WHC/CST-agent}}"
|
||||
API="$SERVER/api/v1/repos/$REPO"
|
||||
|
||||
TOKEN="${GITEA_TOKEN:-${GITHUB_TOKEN:-}}"
|
||||
[[ -n "$TOKEN" ]] || {
|
||||
echo "set GITEA_TOKEN (a Gitea token with write:repository)" >&2
|
||||
exit 1
|
||||
}
|
||||
[[ $# -gt 0 ]] || { echo "usage: $0 FILE..." >&2; exit 1; }
|
||||
command -v python3 >/dev/null || { echo "missing python3" >&2; exit 1; }
|
||||
|
||||
files=()
|
||||
for f in "$@"; do
|
||||
[[ -f "$f" ]] || { echo "missing $f" >&2; exit 1; }
|
||||
f="$(cd "$(dirname "$f")" && pwd)/$(basename "$f")"
|
||||
files+=("$f")
|
||||
[[ "$f" != *.sha256 && -f "$f.sha256" ]] && files+=("$f.sha256")
|
||||
done
|
||||
cd "$ROOT"
|
||||
|
||||
ver="$(sed -n 's/^#define CST_VERSION_\(MAJOR\|MINOR\|PATCH\) \([0-9]*\)$/\2/p' include/cst_version.h | paste -sd.)"
|
||||
tag="v$ver"
|
||||
|
||||
# If this job was triggered by a version tag, it must match cst_version.h.
|
||||
if [[ "${GITHUB_REF:-}" == refs/tags/v* ]]; then
|
||||
ref_tag="${GITHUB_REF#refs/tags/}"
|
||||
if [[ "$ref_tag" != "$tag" ]]; then
|
||||
echo "pushed tag $ref_tag != cst_version.h $tag; bump include/cst_version.h" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
api() { # METHOD PATH [curl args...]
|
||||
local m="$1" p="$2"
|
||||
shift 2
|
||||
printf 'Authorization: token %s\n' "$TOKEN" |
|
||||
curl -fsS -X "$m" -H @- "$API$p" "$@"
|
||||
}
|
||||
json() { # CODE [ARGS...]: d = the JSON on stdin, ARGS in sys.argv[1:]
|
||||
local code="$1"
|
||||
shift
|
||||
python3 -c "import json,sys; d=json.load(sys.stdin); $code" "$@"
|
||||
}
|
||||
|
||||
BODY="Linux (static, musl, any distro): cst-agent-$ver-linux-{x86_64,x86,aarch64}.tar.gz -- extract and run ./cst-agent, or copy it onto PATH.
|
||||
|
||||
Windows x86_64: cst-agent-$ver-windows-x86_64-setup.exe installs per user (no admin rights) and adds PATH; cst-agent-$ver-windows-x86_64.zip is the portable build (install_windows.ps1 inside).
|
||||
|
||||
Every file has a .sha256 next to it."
|
||||
|
||||
if rel="$(api GET "/releases/tags/$tag" 2>/dev/null)"; then
|
||||
echo "==> release $tag exists"
|
||||
else
|
||||
head="$(git rev-parse HEAD)"
|
||||
if [[ -z "${CI:-}${GITEA_ACTIONS:-}${GITHUB_ACTIONS:-}" ]]; then
|
||||
if ! git branch -r --contains "$head" 2>/dev/null | grep -q .; then
|
||||
echo "HEAD $head is not on any remote branch; push it first" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
echo "==> creating release $tag at $head"
|
||||
body="$(python3 -c 'import json,sys; print(json.dumps({"tag_name": sys.argv[1], "target_commitish": sys.argv[2], "name": "CST-Agent " + sys.argv[1], "body": sys.argv[3]}))' "$tag" "$head" "$BODY")"
|
||||
if ! rel="$(api POST /releases -H 'Content-Type: application/json' -d "$body" 2>/dev/null)"; then
|
||||
# Another job created it first (409).
|
||||
rel=""
|
||||
for _ in 1 2 3 4 5 6; do
|
||||
sleep 5
|
||||
rel="$(api GET "/releases/tags/$tag" 2>/dev/null)" && break
|
||||
rel=""
|
||||
done
|
||||
[[ -n "$rel" ]] || { echo "could not create or find release $tag" >&2; exit 1; }
|
||||
echo "==> release $tag created by another job"
|
||||
fi
|
||||
fi
|
||||
id="$(json 'print(d["id"])' <<<"$rel")"
|
||||
|
||||
for f in "${files[@]}"; do
|
||||
name="$(basename "$f")"
|
||||
old="$(json "print(' '.join(str(a['id']) for a in d.get('assets') or [] if a['name'] == sys.argv[1]))" "$name" <<<"$rel")"
|
||||
for aid in $old; do
|
||||
echo "==> replacing $name"
|
||||
api DELETE "/releases/$id/assets/$aid" >/dev/null
|
||||
done
|
||||
echo "==> upload $name"
|
||||
api POST "/releases/$id/assets?name=$name" -F "attachment=@$f" >/dev/null
|
||||
done
|
||||
echo "$SERVER/$REPO/releases/tag/$tag"
|
||||
Reference in New Issue
Block a user