mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-19 13:00:44 +00:00
修 Gitee 附件清理:assets 字段没 id,要用 attach_files 接口
Gitee 的坑:GET /releases/{id} 返回的 assets 里
**只有 name 和 download_url,没有 id**,
照着它删是删不掉的(之前静默失败,附件一路堆到 11 个)。
必须换接口才拿得到 id:
GET /releases/{id}/attach_files -> [{id, name, size}]
DELETE /releases/{id}/attach_files/{id}
已清理:Gitee 11 -> 5 个(含 2 个自动生成的源码包),
EzHub 5 -> 3 个。清理动作也加了重试(网络会抖)。
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
r'''统一清理两个平台发行版里的重复附件。
|
||||
|
||||
背景:
|
||||
重发时如果只"复用已有发行版",附件会一次次堆积。
|
||||
Gitee 尤其绕:`GET /releases/tags/{tag}` 返回的 `assets`
|
||||
**只有 name 和 download_url,没有 id**,所以没法删。
|
||||
但另一个接口有 id:
|
||||
GET /repos/{o}/{r}/releases/{id}/attach_files -> 带 id
|
||||
DELETE /repos/{o}/{r}/releases/{id}/attach_files/{attach_id}
|
||||
|
||||
Gitea/EzHub 则直接有 assets[].id。
|
||||
|
||||
策略:同名附件只保留最新的一份,其余删掉。
|
||||
支持 --dry 先看要删什么。
|
||||
'''
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import sys
|
||||
import time
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
from collections import defaultdict
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote")
|
||||
GT = (ROOT / "_build" / ".gitee_token").read_text(encoding="utf-8").strip()
|
||||
ET = (Path.home() / ".ykxmz" / "ezhub_token").read_text(
|
||||
encoding="utf-8").strip()
|
||||
TAG = "v1.8.0"
|
||||
|
||||
# 这两个是 Gitee 自动生成的源码包,不是我们传的,不要动
|
||||
KEEP_ALWAYS = {"v1.8.0.zip", "v1.8.0.tar.gz"}
|
||||
|
||||
|
||||
def http(url: str, method: str = "GET", kind: str = "gitea",
|
||||
token: str = "", tries: int = 3):
|
||||
"""带重试的请求。网络会抖,不重试会误判。"""
|
||||
headers = {"User-Agent": "ykxmz-clean"}
|
||||
if kind == "gitee":
|
||||
sep = "&" if "?" in url else "?"
|
||||
url = url + sep + "access_token=" + token
|
||||
else:
|
||||
headers["Authorization"] = "token " + token
|
||||
last = None
|
||||
for attempt in range(1, tries + 1):
|
||||
try:
|
||||
req = urllib.request.Request(url, method=method, headers=headers)
|
||||
with urllib.request.urlopen(req, timeout=90) as resp:
|
||||
text = resp.read().decode("utf-8", "replace")
|
||||
return resp.status, (json.loads(text) if text.strip() else {})
|
||||
except urllib.error.HTTPError as exc:
|
||||
return exc.code, exc.read().decode("utf-8", "replace")[:200]
|
||||
except Exception as exc: # noqa: BLE001
|
||||
last = exc
|
||||
if attempt < tries:
|
||||
time.sleep(4)
|
||||
return 0, str(last)
|
||||
|
||||
|
||||
def list_gitee_assets(rid: int) -> list:
|
||||
"""Gitee 要单独调 attach_files 才拿得到 id。"""
|
||||
status, data = http(
|
||||
"https://gitee.com/api/v5/repos/xmz7891/ykxmz/releases/%s"
|
||||
"/attach_files" % rid, kind="gitee", token=GT)
|
||||
if status != 200 or not isinstance(data, list):
|
||||
print(" [失败] 取 Gitee 附件列表 HTTP %s: %s" % (status, data))
|
||||
return []
|
||||
return data
|
||||
|
||||
|
||||
def list_gitea_assets(rid: int) -> list:
|
||||
status, data = http(
|
||||
"https://git.261826.xyz/api/v1/repos/xmz/ykxmz/releases/%s"
|
||||
% rid, kind="gitea", token=ET)
|
||||
if status != 200:
|
||||
print(" [失败] 取 EzHub 发行版 HTTP %s" % status)
|
||||
return []
|
||||
return data.get("assets") or []
|
||||
|
||||
|
||||
def clean(platform: str, rid: int, assets: list, dry: bool) -> int:
|
||||
groups = defaultdict(list)
|
||||
for a in assets:
|
||||
name = a.get("name") or "?"
|
||||
if name in KEEP_ALWAYS:
|
||||
continue
|
||||
groups[name].append(a)
|
||||
|
||||
removed = 0
|
||||
for name, items in sorted(groups.items()):
|
||||
if len(items) <= 1:
|
||||
continue
|
||||
# 新的排前面
|
||||
items.sort(key=lambda x: str(x.get("created_at") or ""), reverse=True)
|
||||
keep = items[0]
|
||||
print(" %-32s %d 份 -> 保留 id=%s" % (name, len(items),
|
||||
keep.get("id")))
|
||||
for extra in items[1:]:
|
||||
aid = extra.get("id")
|
||||
if dry:
|
||||
print(" (演练)会删 id=%s" % aid)
|
||||
removed += 1
|
||||
continue
|
||||
if platform == "gitee":
|
||||
url = ("https://gitee.com/api/v5/repos/xmz7891/ykxmz"
|
||||
"/releases/%s/attach_files/%s" % (rid, aid))
|
||||
else:
|
||||
url = ("https://git.261826.xyz/api/v1/repos/xmz/ykxmz"
|
||||
"/releases/%s/assets/%s" % (rid, aid))
|
||||
status, body = http(url, method="DELETE",
|
||||
kind=("gitee" if platform == "gitee"
|
||||
else "gitea"),
|
||||
token=(GT if platform == "gitee" else ET))
|
||||
if status in (200, 204):
|
||||
print(" ✓ 删了 id=%s" % aid)
|
||||
removed += 1
|
||||
else:
|
||||
print(" ✗ id=%s HTTP %s %s"
|
||||
% (aid, status, str(body)[:80]))
|
||||
return removed
|
||||
|
||||
|
||||
def main() -> int:
|
||||
dry = "--dry" in sys.argv
|
||||
total = 0
|
||||
|
||||
print(" ═══ Gitee ═══")
|
||||
status, rel = http("https://gitee.com/api/v5/repos/xmz7891/ykxmz"
|
||||
"/releases/tags/" + TAG, kind="gitee", token=GT)
|
||||
if status == 200:
|
||||
rid = rel.get("id")
|
||||
assets = list_gitee_assets(rid)
|
||||
print(" 发行版 id=%s,可删附件 %d 个" % (rid, len(assets)))
|
||||
total += clean("gitee", rid, assets, dry)
|
||||
else:
|
||||
print(" [失败] HTTP %s" % status)
|
||||
print()
|
||||
|
||||
print(" ═══ EzHub ═══")
|
||||
status, rel = http("https://git.261826.xyz/api/v1/repos/xmz/ykxmz"
|
||||
"/releases/tags/" + TAG, kind="gitea", token=ET)
|
||||
if status == 200:
|
||||
rid = rel.get("id")
|
||||
assets = list_gitea_assets(rid)
|
||||
print(" 发行版 id=%s,附件 %d 个" % (rid, len(assets)))
|
||||
total += clean("gitea", rid, assets, dry)
|
||||
else:
|
||||
print(" [失败] HTTP %s" % status)
|
||||
|
||||
print()
|
||||
print(" %s %d 个" % ("演练:会删" if dry else "共删", total))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user