#!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # shellcheck source=lib/common.sh source "${SCRIPT_DIR}/lib/common.sh" usage() { cat >&2 <<'EOF' Usage: release.sh [--name NAME] [--notes TEXT] [--target BRANCH] [--draft] [--prerelease] [--asset PATH]... [--repo NAME] tag_name;若 tag 不存在 Gitea 會在 target 自動建 --name release 標題(預設同 tag) --notes release 說明 --target target_commitish;預設 HEAD 所在分支 --draft 建成 draft --prerelease 標記 prerelease --asset PATH 要上傳的附件(可重複) --repo NAME 指定 repo;省略則從 cwd origin 推斷 EOF exit 1 } [[ $# -ge 1 ]] || usage TAG="" NAME="" NOTES="" TARGET="" DRAFT=false PRERELEASE=false ASSETS=() REPO_OVERRIDE="" while [[ $# -gt 0 ]]; do case "$1" in --name) [[ $# -ge 2 ]] || { log_err "--name 需要值"; exit 1; }; NAME="$2"; shift 2 ;; --notes) [[ $# -ge 2 ]] || { log_err "--notes 需要值"; exit 1; }; NOTES="$2"; shift 2 ;; --target) [[ $# -ge 2 ]] || { log_err "--target 需要值"; exit 1; }; TARGET="$2"; shift 2 ;; --draft) DRAFT=true; shift ;; --prerelease) PRERELEASE=true; shift ;; --asset) [[ $# -ge 2 ]] || { log_err "--asset 需要值"; exit 1; }; ASSETS+=("$2"); shift 2 ;; --repo) [[ $# -ge 2 ]] || { log_err "--repo 需要值"; exit 1; }; REPO_OVERRIDE="$2"; shift 2 ;; -h|--help) usage ;; -*) log_err "未知參數:$1"; usage ;; *) if [[ -z "$TAG" ]]; then TAG="$1"; else log_err "多餘參數:$1"; usage; fi shift ;; esac done [[ -n "$TAG" ]] || usage NAME="${NAME:-$TAG}" load_config require_cmd jq if [[ -n "$REPO_OVERRIDE" ]]; then OWNER_REPO="${GITEA_USER}/${REPO_OVERRIDE}" else if ! OWNER_REPO="$(infer_repo_from_cwd)"; then log_err "無法從 cwd 推斷 repo;請加 --repo" exit 1 fi fi if [[ -z "$TARGET" ]]; then if git rev-parse --git-dir >/dev/null 2>&1; then TARGET="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || true)" fi fi # 驗證 asset 路徑 for a in "${ASSETS[@]+"${ASSETS[@]}"}"; do if [[ ! -f "$a" ]]; then log_err "找不到 asset 檔案:$a" exit 1 fi done # 組 release body BODY="$(jq -n \ --arg tag "$TAG" \ --arg name "$NAME" \ --arg body "$NOTES" \ --arg target "$TARGET" \ --argjson draft "$DRAFT" \ --argjson prerelease "$PRERELEASE" \ '{tag_name:$tag, name:$name, body:$body, draft:$draft, prerelease:$prerelease} + (if $target == "" then {} else {target_commitish:$target} end)')" log_info "建立 release ${OWNER_REPO} / ${TAG}" gitea_api POST "/repos/${OWNER_REPO}/releases" "$BODY" case "$HTTP_CODE" in 201) log_ok "release 已建立" ;; 404) log_err "找不到 repo:${OWNER_REPO}"; exit 1 ;; *) log_err "建立 release 失敗 (HTTP ${HTTP_CODE})"; { cat "$GITEA_API_RESP_FILE"; echo ""; } >&2; exit 1 ;; esac RELEASE_ID="$(jq -r '.id' < "$GITEA_API_RESP_FILE")" RELEASE_URL="$(jq -r '.html_url' < "$GITEA_API_RESP_FILE")" # stdout 先印 release URL echo "$RELEASE_URL" # 上傳 asset FAILED=() for a in "${ASSETS[@]+"${ASSETS[@]}"}"; do local_name="$(basename "$a")" log_info "上傳 asset:${local_name}" UP_RESP="$(mktemp)" UP_CODE="$(curl -sS -o "$UP_RESP" -w '%{http_code}' \ -X POST \ -H "Authorization: token ${GITEA_TOKEN}" \ -F "attachment=@${a};filename=${local_name}" \ "${GITEA_URL}/api/v1/repos/${OWNER_REPO}/releases/${RELEASE_ID}/assets?name=${local_name}")" case "$UP_CODE" in 201) ASSET_URL="$(jq -r '.browser_download_url' < "$UP_RESP")" log_ok "$local_name" echo "$ASSET_URL" ;; *) log_err "上傳 ${local_name} 失敗 (HTTP ${UP_CODE})" cat "$UP_RESP" >&2 echo "" >&2 FAILED+=("$local_name") ;; esac rm -f "$UP_RESP" done if [[ ${#FAILED[@]} -gt 0 ]]; then log_err "部分 asset 上傳失敗:${FAILED[*]}" exit 1 fi log_done "完成"