Files
setlist/scripts/release-gitea.sh
T
2026-07-19 20:39:54 -07:00

204 lines
6.2 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
repo_root="$(git rev-parse --show-toplevel)"
cd "$repo_root"
if [[ -f .env ]]; then
set -a
# shellcheck source=/dev/null
. ./.env
set +a
fi
project="Setlist/Setlist.csproj"
manifest="Setlist/manifest.json"
assembly_info="Setlist/Properties/AssemblyInfo.cs"
version="${1:-$(jq -r '.version' "$manifest")}"
tag="v${version}"
game_version="$(jq -r '.gameVersion' "$manifest")"
require() {
if ! command -v "$1" >/dev/null 2>&1; then
echo "error: required command not found: $1" >&2
exit 1
fi
}
require curl
require dotnet
require git
require jq
require rg
require zip
if [[ -z "${GITEA_AGENT_TOKEN:-}" ]]; then
echo "error: GITEA_AGENT_TOKEN is not set; add it to .env or export it" >&2
exit 1
fi
manifest_version="$(jq -r '.version' "$manifest")"
if [[ "$version" != "$manifest_version" ]]; then
echo "error: requested version $version does not match manifest version $manifest_version" >&2
exit 1
fi
if ! rg -q "\\[assembly: AssemblyVersion\\(\"${version}\\.0\"\\)\\]" "$assembly_info"; then
echo "error: AssemblyVersion does not match ${version}.0" >&2
exit 1
fi
if ! rg -q "\\[assembly: AssemblyFileVersion\\(\"${version}\\.0\"\\)\\]" "$assembly_info"; then
echo "error: AssemblyFileVersion does not match ${version}.0" >&2
exit 1
fi
if ! git diff --quiet --exit-code -- . ':(exclude)Setlist/bin' ':(exclude)Setlist/obj'; then
echo "error: tracked worktree changes are present; commit them before releasing" >&2
exit 1
fi
branch="$(git symbolic-ref --quiet --short HEAD)"
if [[ -z "$branch" ]]; then
echo "error: releases must be run from a branch, not detached HEAD" >&2
exit 1
fi
origin_url="$(git remote get-url origin)"
case "$origin_url" in
git@*:*|gitea@*:*)
host_part="${origin_url%%:*}"
host="${host_part#*@}"
repo_path="${origin_url#*:}"
;;
ssh://*@*/*)
without_scheme="${origin_url#ssh://}"
without_user="${without_scheme#*@}"
host="${without_user%%/*}"
repo_path="${without_user#*/}"
;;
http://*/*|https://*/*)
without_scheme="${origin_url#*://}"
host="${without_scheme%%/*}"
repo_path="${without_scheme#*/}"
;;
*)
echo "error: cannot parse origin URL: $origin_url" >&2
exit 1
;;
esac
repo_path="${repo_path%.git}"
api_base="${GITEA_API_BASE:-https://${host}/api/v1}"
echo "Restoring $project"
dotnet restore "$project"
echo "Building $project Release"
dotnet build "$project" -c Release
short_sha="$(git rev-parse --short=7 HEAD)"
asset_name="Setlist-${version}-bs${game_version}-${short_sha}.zip"
asset_dir="Setlist/bin/Release/zip"
asset_path="${asset_dir}/${asset_name}"
package_root="$(mktemp -d)"
response_body="$(mktemp)"
request_body="$(mktemp)"
curl_config="$(mktemp)"
cleanup() {
rm -rf "$package_root"
rm -f "$response_body" "$request_body" "$curl_config"
}
trap cleanup EXIT
chmod 600 "$curl_config"
{
printf 'silent\n'
printf 'show-error\n'
printf 'header = "Authorization: token %s"\n' "$GITEA_AGENT_TOKEN"
} > "$curl_config"
mkdir -p "$asset_dir" "$package_root/Plugins"
cp Setlist/bin/Release/Setlist.dll "$package_root/Plugins/Setlist.dll"
cp Setlist/bin/Release/Setlist.pdb "$package_root/Plugins/Setlist.pdb"
rm -f "$asset_path"
(cd "$package_root" && zip -qr "$repo_root/$asset_path" Plugins)
echo "Packaged $asset_path"
sha256sum "$asset_path"
if git rev-parse -q --verify "refs/tags/$tag" >/dev/null; then
tag_target="$(git rev-list -n 1 "$tag")"
head_target="$(git rev-parse HEAD)"
if [[ "$tag_target" != "$head_target" ]]; then
echo "error: local tag $tag points at $tag_target, not HEAD $head_target" >&2
exit 1
fi
else
git tag -a "$tag" -m "Setlist $tag"
fi
echo "Pushing $branch and $tag to origin"
git push origin "HEAD:${branch}"
git push origin "$tag"
release_url="${api_base}/repos/${repo_path}/releases/tags/${tag}"
status="$(curl --config "$curl_config" -o "$response_body" -w '%{http_code}' "$release_url" || true)"
if [[ "$status" == "200" ]]; then
release_id="$(jq -r '.id' "$response_body")"
echo "Using existing Gitea release $tag"
elif [[ "$status" == "404" ]]; then
jq -n \
--arg tag "$tag" \
--arg name "$tag" \
--arg body "Release ${tag} for Beat Saber ${game_version}." \
--arg target "$branch" \
'{tag_name:$tag, target_commitish:$target, name:$name, body:$body, draft:false, prerelease:false}' \
> "$request_body"
status="$(curl --config "$curl_config" -X POST -H 'Content-Type: application/json' --data @"$request_body" -o "$response_body" -w '%{http_code}' "${api_base}/repos/${repo_path}/releases" || true)"
if [[ "$status" != "201" ]]; then
echo "error: failed to create release; Gitea returned HTTP $status" >&2
cat "$response_body" >&2
exit 1
fi
release_id="$(jq -r '.id' "$response_body")"
echo "Created Gitea release $tag"
else
echo "error: failed to inspect release; Gitea returned HTTP $status" >&2
cat "$response_body" >&2
exit 1
fi
assets_url="${api_base}/repos/${repo_path}/releases/${release_id}/assets"
status="$(curl --config "$curl_config" -o "$response_body" -w '%{http_code}' "$assets_url" || true)"
if [[ "$status" != "200" ]]; then
echo "error: failed to list release assets; Gitea returned HTTP $status" >&2
cat "$response_body" >&2
exit 1
fi
existing_asset_id="$(jq -r --arg name "$asset_name" '.[] | select(.name == $name) | .id' "$response_body" | head -n 1)"
if [[ -n "$existing_asset_id" ]]; then
echo "Deleting existing asset $asset_name"
status="$(curl --config "$curl_config" -X DELETE -o "$response_body" -w '%{http_code}' "${assets_url}/${existing_asset_id}" || true)"
if [[ "$status" != "204" ]]; then
echo "error: failed to delete existing asset; Gitea returned HTTP $status" >&2
cat "$response_body" >&2
exit 1
fi
fi
status="$(curl --config "$curl_config" -X POST -H 'Content-Type: application/zip' --data-binary @"$asset_path" -o "$response_body" -w '%{http_code}' "${assets_url}?name=${asset_name}" || true)"
if [[ "$status" != "201" ]]; then
echo "error: failed to upload release asset; Gitea returned HTTP $status" >&2
cat "$response_body" >&2
exit 1
fi
html_url="$(jq -r '.browser_download_url // .download_url // empty' "$response_body")"
echo "Uploaded $asset_name"
if [[ -n "$html_url" ]]; then
echo "$html_url"
fi