feat(gitea): 支援回覆 PR 留言

This commit is contained in:
2026-08-28 09:30:02 +08:00
parent 8483f8d1bb
commit 3fe9b55840
6 changed files with 38 additions and 12 deletions
+29 -5
View File
@@ -17,7 +17,9 @@
# gitea.sh pr-status <owner>/<repo> <pr-index> # 印出「{state} {merged} {mergeable}」
# gitea.sh pr-get <owner>/<repo> <pr-index> # 印出 PR 的標題、base 分支與描述,供比對用
# gitea.sh pr-edit <owner>/<repo> <pr-index> <title> <body-file> # 更新 PR 的標題與描述
# gitea.sh pr-comments <owner>/<repo> <pr-index> # 印出所有留言(issue 留言、審查評語、行內留言),依時間排序
# gitea.sh pr-comments <owner>/<repo> <pr-index> # 印出所有留言(issue 留言、審查評語、行內留言),第三欄帶 #id
# gitea.sh comment-reply <owner>/<repo> <pr-index> <issue|review|inline> <comment-id> <body-file>
# 回覆本輪處理過的 PR 留言;inline 走 review comment reply,其餘補一則 PR 留言
# gitea.sh pr-depend <owner>/<repo> <pr-index> <dep-owner>/<dep-repo> <dep-index>
# 把 PR 掛上前置 PR 依賴;依賴未關閉前 Gitea 會阻擋合併
# gitea.sh repo-set <owner>/<repo> <description> [website] # 設定 repo 描述與網頁
@@ -258,15 +260,16 @@ print(json.dumps({"title":sys.argv[1],"body":open(sys.argv[2],encoding="utf-8").
rm -f "$tmp"
echo "OK $or#$idx" ;;
pr-comments)
# 印出 PR 的所有留言,每行「{時間}<TAB>{作者}<TAB>{類型}<TAB>{內容單行化}」。
# 印出 PR 的所有留言,每行「{時間}<TAB>{作者}<TAB>{類型}#{id}<TAB>{內容單行化}」。
# 三個來源都要讀:issue 留言、review 本體的評語、review 內逐行的程式碼留言。
# 只讀 issue 留言會漏掉真正的審查意見,那正是需要修正的部分。
# 類型欄保留在第三欄,僅追加 id;呼叫端用第一欄做 since 比對時不受影響。
or="${1:?owner/repo required}"; idx="${2:?pr index required}"
{ req GET "/repos/$or/issues/$idx/comments?limit=100" | python3 -c '
import json,sys
for c in json.load(sys.stdin):
body=" ".join((c.get("body") or "").split())
if body: print("%s\t%s\t留言\t%s" % (c.get("created_at",""), (c.get("user") or {}).get("login","?"), body))
if body: print("%s\t%s\t留言#%s\t%s" % (c.get("created_at",""), (c.get("user") or {}).get("login","?"), c.get("id","?"), body))
'
reviews=$(req GET "/repos/$or/pulls/$idx/reviews?limit=100")
printf '%s' "$reviews" | python3 -c '
@@ -276,7 +279,7 @@ for r in json.load(sys.stdin):
st=r.get("state","")
# 沒有評語的審查照樣要印:APPROVED 代表可以合併,REQUEST_CHANGES 代表被要求修改,
# 兩者都是呼叫端要據以決策的事實,過濾掉會看不見 PR 真正的狀態。
print("%s\t%s\t審查(%s)\t%s" % (r.get("submitted_at",""), (r.get("user") or {}).get("login","?"), st, body or "(無評語)"))
print("%s\t%s\t審查#%s(%s)\t%s" % (r.get("submitted_at",""), (r.get("user") or {}).get("login","?"), r.get("id","?"), st, body or "(無評語)"))
'
for rid in $(printf '%s' "$reviews" | python3 -c '
import json,sys
@@ -289,10 +292,31 @@ try: d=json.load(sys.stdin)
except Exception: raise SystemExit
for c in d:
body=" ".join((c.get("body") or "").split())
if body: print("%s\t%s\t行內(%s:%s)\t%s" % (c.get("created_at",""), (c.get("user") or {}).get("login","?"), c.get("path",""), c.get("original_position") or c.get("position") or "", body))
if body: print("%s\t%s\t行內#%s(%s:%s)\t%s" % (c.get("created_at",""), (c.get("user") or {}).get("login","?"), c.get("id","?"), c.get("path",""), c.get("original_position") or c.get("position") or "", body))
' || true
done
} | sort ;;
comment-reply)
or="${1:?owner/repo required}"; idx="${2:?pr index required}"
kind="${3:?kind required}"; cid="${4:?comment id required}"; body_file="${5:?body file required}"
[ -f "$body_file" ] || { echo "找不到回覆檔: $body_file" >&2; exit 2; }
case "$kind" in issue|review|inline) ;; *) echo "kind must be issue, review, or inline" >&2; exit 2 ;; esac
tmp=$(mktemp)
python3 -c '
import json,sys
print(json.dumps({"body":open(sys.argv[1],encoding="utf-8").read()}))
' "$body_file" > "$tmp"
case "$kind" in
inline)
path="/repos/$or/pulls/$idx/comments/$cid/replies" ;;
issue|review)
path="/repos/$or/issues/$idx/comments" ;;
esac
if ! out=$(req POST "$path" "$tmp"); then
rm -f "$tmp"; printf '%s\n' "$out" >&2; exit 4
fi
rm -f "$tmp"
printf '%s' "$out" | json_field html_url ;;
pr-depend)
or="${1:?owner/repo required}"; idx="${2:?pr index required}"
dep_or="${3:?dep owner/repo required}"; dep_idx="${4:?dep index required}"