mirror of
https://gitcode.com/JianFeeeee/webui4frpc.git
synced 2026-09-19 16:38:31 +00:00
默认文件筛选原来只匹配 tar.gz/zip/SHA256SUMS,deb/rpm/pkg/setup.exe 必须逐个显式传参才会上传(v0.1.0 与 v0.1.1 都是分两趟传的)。 改为按发布产物后缀白名单筛选;用 -setup.exe 而非裸 .exe,避免误收 bin/ 下的裸二进制。
89 lines
2.9 KiB
Python
Executable File
89 lines
2.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
||
"""上传 release 资产到 gitcode(两步:取签名 URL → PUT 到 OBS)。
|
||
|
||
用法: upload_assets.py <version> <token> [file...]
|
||
不传 file 时上传该版本目录下全部发布产物:
|
||
tar.gz / zip / deb / rpm / pkg / -setup.exe / SHA256SUMS
|
||
"""
|
||
import json
|
||
import os
|
||
import sys
|
||
import urllib.request
|
||
import urllib.parse
|
||
|
||
REPO = "JianFeeeee/webui4frpc"
|
||
API = "https://gitcode.com/api/v5/repos"
|
||
|
||
|
||
def get_upload_url(version: str, token: str, filename: str) -> tuple[str, dict]:
|
||
q = urllib.parse.urlencode({"file_name": filename})
|
||
url = f"{API}/{REPO}/releases/v{version}/upload_url?{q}"
|
||
req = urllib.request.Request(url, headers={"private-token": token})
|
||
with urllib.request.urlopen(req, timeout=20) as r:
|
||
data = json.loads(r.read())
|
||
return data["url"], data.get("headers", {})
|
||
|
||
|
||
def put_file(url: str, headers: dict, path: str) -> tuple[int, str]:
|
||
size = os.path.getsize(path)
|
||
with open(path, "rb") as f:
|
||
body = f.read()
|
||
req = urllib.request.Request(url, data=body, method="PUT")
|
||
for k, v in headers.items():
|
||
req.add_header(k, v)
|
||
req.add_header("Content-Length", str(size))
|
||
try:
|
||
with urllib.request.urlopen(req, timeout=300) as r:
|
||
return r.status, r.read().decode("utf-8", "replace")[:300]
|
||
except urllib.error.HTTPError as e:
|
||
return e.code, e.read().decode("utf-8", "replace")[:300]
|
||
|
||
|
||
# 发布产物后缀:免安装包 + 原生安装包。
|
||
# 注意 -setup.exe 而不是裸 .exe,避开 bin/ 里的裸二进制。
|
||
ARTIFACT_SUFFIXES = (
|
||
".tar.gz", ".zip", # 免安装
|
||
".deb", ".rpm", ".pkg", # linux / macOS 安装包
|
||
"-setup.exe", # windows 安装器
|
||
)
|
||
|
||
|
||
def is_artifact(name: str) -> bool:
|
||
return name == "SHA256SUMS" or name.endswith(ARTIFACT_SUFFIXES)
|
||
|
||
|
||
def main() -> int:
|
||
if len(sys.argv) < 3:
|
||
print(__doc__)
|
||
return 2
|
||
version, token = sys.argv[1], sys.argv[2]
|
||
outdir = os.path.join(
|
||
os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
|
||
"dist", "artifacts", version,
|
||
)
|
||
files = sys.argv[3:] or sorted(f for f in os.listdir(outdir) if is_artifact(f))
|
||
failed = 0
|
||
for name in files:
|
||
path = os.path.join(outdir, name)
|
||
if not os.path.isfile(path):
|
||
print(f"skip (missing): {name}")
|
||
continue
|
||
print(f"==> {name} ({os.path.getsize(path)/1048576:.1f} MiB)")
|
||
try:
|
||
url, headers = get_upload_url(version, token, name)
|
||
except Exception as e: # noqa: BLE001
|
||
print(f" upload_url FAILED: {e}")
|
||
failed += 1
|
||
continue
|
||
status, body = put_file(url, headers, path)
|
||
ok = 200 <= status < 300
|
||
print(f" PUT -> {status} {'OK' if ok else body}")
|
||
if not ok:
|
||
failed += 1
|
||
print(f"\n{'ALL OK' if failed == 0 else f'{failed} FAILED'}")
|
||
return 1 if failed else 0
|
||
|
||
|
||
if __name__ == "__main__":
|
||
sys.exit(main())
|