#!/usr/bin/env bash # Upload all files in a directory as attachments on a Gitea release (create release if missing). # # Usage: # export GITEA_BASE_URL=https://git.example.com # export GITEA_TOKEN=gta_... # export GITEA_OWNER=myorg # export GITEA_REPO=fractured-patches # export GITEA_TARGET_REF=main # optional, used when creating a new release (tag must not exist yet) # ./upload-release-to-gitea.sh /path/to/combined v1.0.0 # set -euo pipefail SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) # shellcheck source=release-sync-filters.sh . "$SCRIPT_DIR/release-sync-filters.sh" COMBINED_DIR="${1:?first arg: directory of files to attach}" TAG="${2:?second arg: release tag (e.g. v1.0.0)}" : "${GITEA_BASE_URL:?Set GITEA_BASE_URL (no trailing slash required)}" : "${GITEA_TOKEN:?Set GITEA_TOKEN}" : "${GITEA_OWNER:?Set GITEA_OWNER}" : "${GITEA_REPO:?Set GITEA_REPO}" BASE="${GITEA_BASE_URL%/}" API="$BASE/api/v1" TARGET="${GITEA_TARGET_REF:-main}" AUTH_H=(-H "Authorization: token ${GITEA_TOKEN}" -H "Accept: application/json") TAG_ENC=$(python3 -c "import urllib.parse,sys; print(urllib.parse.quote(sys.argv[1], safe=''))" "$TAG") REL_JSON=$(mktemp) trap 'rm -f "$REL_JSON"' EXIT code=$(curl -sS -o "$REL_JSON" -w "%{http_code}" "${AUTH_H[@]}" \ "$API/repos/${GITEA_OWNER}/${GITEA_REPO}/releases/tags/${TAG_ENC}") if [ "$code" = "200" ]; then rel_id=$(jq -r '.id' "$REL_JSON") elif [ "$code" = "404" ]; then body=$(jq -n \ --arg tag "$TAG" \ --arg name "Fractured $TAG" \ --arg body "Synced from GitHub Actions (Fractured)." \ --arg target "$TARGET" \ '{tag_name:$tag,name:$name,body:$body,draft:false,prerelease:false,target_commitish:$target}') code=$(curl -sS -o "$REL_JSON" -w "%{http_code}" -X POST "${AUTH_H[@]}" \ -H "Content-Type: application/json" \ -d "$body" \ "$API/repos/${GITEA_OWNER}/${GITEA_REPO}/releases") if [ "$code" != "201" ] && [ "$code" != "200" ]; then echo "Gitea create release failed HTTP $code:" >&2 cat "$REL_JSON" >&2 if [ "$code" = "422" ] && jq -e '.message == "repo is empty"' "$REL_JSON" >/dev/null 2>&1; then echo >&2 echo "Gitea does not allow releases on a repo with zero commits. Fix: push at least one commit" >&2 echo "to ${GITEA_OWNER}/${GITEA_REPO} (e.g. add README.md on branch ${TARGET} via web UI or git push)," >&2 echo "or set Actions variable GITEA_TARGET_REF to an existing default branch name." >&2 fi exit 1 fi rel_id=$(jq -r '.id' "$REL_JSON") else echo "Gitea GET release by tag failed HTTP $code:" >&2 cat "$REL_JSON" >&2 exit 1 fi if [ -z "$rel_id" ] || [ "$rel_id" = "null" ]; then echo "Could not resolve Gitea release id" >&2 exit 1 fi shopt -s nullglob files=("$COMBINED_DIR"/*) if [ "${#files[@]}" -eq 0 ]; then echo "No files in $COMBINED_DIR" >&2 exit 1 fi uploadable=0 for f in "${files[@]}"; do [ -f "$f" ] || continue bn=$(basename "$f") if should_skip_gitea_upload "$bn"; then continue fi uploadable=$((uploadable + 1)) done if [ "$uploadable" -eq 0 ]; then echo "No files to upload after exclusions (check $COMBINED_DIR) — not clearing Gitea attachments." >&2 exit 1 fi while read -r aid; do [ -z "$aid" ] || [ "$aid" = "null" ] && continue curl -fsS -X DELETE "${AUTH_H[@]}" \ "$API/repos/${GITEA_OWNER}/${GITEA_REPO}/releases/${rel_id}/assets/${aid}" || true done < <(jq -r '(.attachments // .assets // [])[] | .id' "$REL_JSON") uploaded=0 for f in "${files[@]}"; do [ -f "$f" ] || continue bn=$(basename "$f") if should_skip_gitea_upload "$bn"; then echo "Skipping upload (excluded): $bn" continue fi echo "Uploading $bn …" curl -fsS -X POST "${AUTH_H[@]}" \ -F "attachment=@${f}" \ "$API/repos/${GITEA_OWNER}/${GITEA_REPO}/releases/${rel_id}/assets" uploaded=$((uploaded + 1)) done echo "Gitea release $TAG (id=$rel_id) updated with $uploaded file(s)."