Watches any number of ARK:SE servers (RCON for players and chat, the query port for map, version and player cap), records joins, leaves, chat and an audit trail, and keeps a player database across servers. Control: save, broadcast, chat, whisper, kick, time of day, MOTD, wild dino wipe, a raw console with history and macros, restarts with timed warnings and a world save, optional start command and auto-start. Bans are kept by Megalodon: timed, cluster-wide and re-enforced when the player returns. Automation: schedules (every N or at times of day), Discord/ntfy/webhook notifications, welcome message, chat word filter. Access: viewer, moderator and admin roles, API tokens, Prometheus metrics. cmd/fakeark simulates a server for trying it out. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
72 lines
2.8 KiB
Bash
72 lines
2.8 KiB
Bash
#!/bin/sh
|
|
# Creates (or updates) the Gitea release for a tag and uploads what deploy/build.sh made.
|
|
#
|
|
# TOKEN=<access token that can write releases> deploy/publish-release.sh v0.2.0
|
|
#
|
|
# In Gitea Actions GITHUB_SERVER_URL and GITHUB_REPOSITORY are already set. Safe to
|
|
# re-run: an existing release is reused and assets with the same name are replaced.
|
|
set -eu
|
|
TAG=${1:?usage: publish-release.sh <tag>}
|
|
: "${TOKEN:?set TOKEN to a Gitea access token that can write releases}"
|
|
SERVER=${GITHUB_SERVER_URL:-${GITEA_SERVER_URL:-https://git.veillax.com}}
|
|
REPO=${GITHUB_REPOSITORY:-Veillax/megalodon}
|
|
API="$SERVER/api/v1/repos/$REPO"
|
|
AUTH="Authorization: token $TOKEN"
|
|
|
|
# a JSON helper without needing jq: any python will do
|
|
PY=python3
|
|
python3 -c 'pass' > /dev/null 2>&1 || PY=python
|
|
json() { "$PY" -c "$1"; }
|
|
|
|
# release notes: the commit subjects since the previous tag
|
|
prev=$(git describe --tags --abbrev=0 "$TAG^" 2>/dev/null || true)
|
|
if [ -n "$prev" ]; then
|
|
notes=$(git log --pretty='format:- %s' "$prev..$TAG")
|
|
else
|
|
notes=$(git log --pretty='format:- %s' "$TAG")
|
|
fi
|
|
prerelease=false
|
|
case "$TAG" in *-*) prerelease=true ;; esac
|
|
|
|
body=$(NOTES="$notes" TAG="$TAG" PRE="$prerelease" json '
|
|
import json, os
|
|
print(json.dumps({"tag_name": os.environ["TAG"], "name": os.environ["TAG"], "body": os.environ["NOTES"],
|
|
"draft": False, "prerelease": os.environ["PRE"] == "true"}))')
|
|
|
|
# reuse the release when a failed job is re-run
|
|
id=$(curl -fsS -H "$AUTH" "$API/releases/tags/$TAG" 2>/dev/null | json 'import sys, json; print(json.load(sys.stdin)["id"])' 2>/dev/null || true)
|
|
if [ -z "$id" ]; then
|
|
echo "creating release $TAG"
|
|
id=$(curl -fsS -X POST -H "$AUTH" -H 'Content-Type: application/json' -d "$body" "$API/releases" | json 'import sys, json; print(json.load(sys.stdin)["id"])')
|
|
else
|
|
echo "release $TAG already exists (id $id): replacing its files"
|
|
fi
|
|
|
|
# the ids of the release's assets with a given name (a failed upload can leave a partial one behind)
|
|
asset_ids() {
|
|
curl -fsS -H "$AUTH" "$API/releases/$id/assets" | "$PY" -c 'import sys, json
|
|
for a in json.load(sys.stdin):
|
|
if a["name"] == sys.argv[1]:
|
|
print(a["id"])' "$1"
|
|
}
|
|
|
|
for f in dist/*.tar.gz dist/*.zip dist/SHA256SUMS; do
|
|
[ -f "$f" ] || continue
|
|
name=$(basename "$f")
|
|
n=1
|
|
while :; do
|
|
for aid in $(asset_ids "$name"); do
|
|
curl -fsS -X DELETE -H "$AUTH" "$API/releases/$id/assets/$aid" > /dev/null
|
|
done
|
|
echo "uploading $name (attempt $n)"
|
|
if curl -fsS --max-time 1200 -X POST -H "$AUTH" -F "attachment=@$f" "$API/releases/$id/assets?name=$name" > /dev/null; then
|
|
break
|
|
fi
|
|
# large uploads can hit a proxy timeout (HTTP 502); try again
|
|
[ "$n" -lt 5 ] || { echo "giving up on $name after $n attempts" >&2; exit 1; }
|
|
n=$((n + 1))
|
|
sleep $((n * 10))
|
|
done
|
|
done
|
|
echo "published $SERVER/$REPO/releases/tag/$TAG"
|