#!/usr/bin/env sh # gitea.sh — Gitea API 工具(curl + GITEA_TOKEN)。 # 用法: # gitea.sh owners # 列出可讀取的 owner(自己 + 組織) # gitea.sh repos # 列出 owner 底下可讀取的 repo(全名) # gitea.sh default-branch / # 印出預設分支 # gitea.sh clone-url / # 印出 clone URL # gitea.sh wiki-repo # 解析頁面類型的 wiki 位置: # TYPE = QUESTION|PLAN|ANALYZE|MAINTAIN|REPO|LOG(即頁名前綴) # 依序取 JSC_WIKI_REPO_{TYPE} > JSC_WIKI_REPO;都未設定 exit 3(呼叫端須詢問使用者) # gitea.sh wiki-list / # 列出 wiki 頁名 # gitea.sh wiki-get / # 印出 wiki 頁 markdown;不存在時 exit 4 # gitea.sh wiki-put / # 建立或更新 wiki 頁(內容取自檔案) # gitea.sh pr-create / <body-file> # 建立 PR,印出 PR URL # gitea.sh api <METHOD> <path> [json-file] # 原始 API 呼叫(path 以 /repos/... 起始) # 環境變數: GITEA_HOST(例 https://gitea.jsc.idv.tw)、GITEA_TOKEN set -eu : "${GITEA_HOST:?GITEA_HOST is required}" : "${GITEA_TOKEN:?GITEA_TOKEN is required}" case "$GITEA_HOST" in http://*|https://*) HOST="$GITEA_HOST" ;; *) HOST="https://$GITEA_HOST" ;; esac API="${HOST%/}/api/v1" req() { # METHOD path [json-file] -> body(HTTP >= 400 時 exit 4) method="$1"; path="$2"; body_file="${3:-}" if [ -n "$body_file" ]; then out=$(curl -sS -w '\n%{http_code}' -X "$method" \ -H "Authorization: token $GITEA_TOKEN" -H "Content-Type: application/json" \ --data-binary "@$body_file" "$API$path") else out=$(curl -sS -w '\n%{http_code}' -X "$method" \ -H "Authorization: token $GITEA_TOKEN" "$API$path") fi code=$(printf '%s' "$out" | tail -n1) printf '%s\n' "$out" | sed '$d' [ "$code" -lt 400 ] } json_field() { # stdin JSON -> 每個物件的指定欄位一行(陣列或單一物件皆可) python3 -c ' import json,sys d=json.load(sys.stdin); k=sys.argv[1] items=d if isinstance(d,list) else [d] for i in items: v=i.get(k,"") if v!="" and v is not None: print(v) ' "$1" } cmd="${1:?usage: gitea.sh <command> ...}"; shift case "$cmd" in owners) { req GET "/user" | json_field login req GET "/user/orgs?limit=50" | json_field username; } | sort -u ;; repos) owner="${1:?owner required}" # 分頁抓 owner 的 repo(org 與 user 端點擇一成功) page=1 while :; do out=$(req GET "/orgs/$owner/repos?limit=50&page=$page" 2>/dev/null) \ || out=$(req GET "/users/$owner/repos?limit=50&page=$page") names=$(printf '%s' "$out" | json_field full_name) [ -n "$names" ] || break printf '%s\n' "$names" page=$((page+1)) done ;; default-branch) or="${1:?owner/repo required}" req GET "/repos/$or" | json_field default_branch ;; clone-url) or="${1:?owner/repo required}" req GET "/repos/$or" | json_field clone_url ;; wiki-repo) type=$(printf '%s' "${1:?TYPE required}" | tr a-z A-Z) eval "v=\${JSC_WIKI_REPO_$type:-}" [ -n "$v" ] || v="${JSC_WIKI_REPO:-}" if [ -n "$v" ]; then printf '%s\n' "$v"; else echo "no wiki repo configured for $type (set JSC_WIKI_REPO_$type or JSC_WIKI_REPO)" >&2; exit 3 fi ;; wiki-list) or="${1:?owner/repo required}" req GET "/repos/$or/wiki/pages?limit=200" | json_field title ;; wiki-get) or="${1:?owner/repo required}"; page="${2:?page required}" if ! out=$(req GET "/repos/$or/wiki/page/$page" 2>/dev/null); then echo "wiki page not found: $page" >&2; exit 4 fi printf '%s' "$out" | python3 -c ' import json,sys,base64 d=json.load(sys.stdin) sys.stdout.write(base64.b64decode(d.get("content_base64","")).decode("utf-8")) ' ;; wiki-put) or="${1:?owner/repo required}"; page="${2:?page required}"; file="${3:?content file required}" tmp=$(mktemp) python3 -c ' import json,sys,base64 title,path=sys.argv[1],sys.argv[2] content=open(path,"rb").read() print(json.dumps({"title":title,"content_base64":base64.b64encode(content).decode()})) ' "$page" "$file" > "$tmp" if req GET "/repos/$or/wiki/page/$page" >/dev/null 2>&1; then req PATCH "/repos/$or/wiki/page/$page" "$tmp" >/dev/null else req POST "/repos/$or/wiki/new" "$tmp" >/dev/null fi rm -f "$tmp" echo "OK $page" ;; pr-create) or="${1:?owner/repo required}"; head="${2:?head required}"; base="${3:?base required}" title="${4:?title required}"; body_file="${5:?body file required}" tmp=$(mktemp) python3 -c ' import json,sys print(json.dumps({"head":sys.argv[1],"base":sys.argv[2],"title":sys.argv[3], "body":open(sys.argv[4],encoding="utf-8").read()})) ' "$head" "$base" "$title" "$body_file" > "$tmp" req POST "/repos/$or/pulls" "$tmp" | json_field html_url rm -f "$tmp" ;; api) method="${1:?METHOD}"; path="${2:?path}"; body="${3:-}" req "$method" "$path" $body ;; *) echo "unknown command: $cmd" >&2; exit 2 ;; esac