#!/usr/bin/env bash # Upload release assets to a GitCode release. # # The endpoint shapes are asymmetric and both differ from the "obvious" guess: # # GET /releases/tags/{tag} → read a release # GET /releases/{tag}/upload_url → get a presigned PUT (NO "tags/") # PUT {presigned url} → upload, REPLAYING the headers verbatim # # Two mistakes cost real time on v1.9.5 before this script existed: # # 1. POSTing straight to /releases/{tag}/assets returns 404 — that endpoint # does not exist. It reads as "authentication failed" if you only check # the status code. # 2. PUTting without the headers fails with an opaque storage error, not a # permission one, so it looks like a size limit or a corrupt file. # # The x-obs-* headers are part of the signature: dropping any one of them turns # the request into an unsigned one. set -uo pipefail TOKEN="$(tr -d '\n\r' < /tmp/gc_token)" REPO="HeNanMU-EEA/ModelRouter" TAG="${1:?usage: upload-release.sh ...}" shift API="https://gitcode.com/api/v5/repos/${REPO}" for f in "$@"; do name="$(basename "$f")" size="$(stat -c%s "$f")" printf ' %-46s %10s bytes ' "$name" "$size" # 1) presigned upload location. The file name must be URL-encoded; the v1.9.4 # assets show "~" surviving in a stored name, so encoding is per-component. enc="$(python3 -c 'import urllib.parse,sys; print(urllib.parse.quote(sys.argv[1]))' "$name")" resp="$(curl -sS -m 60 -H "Authorization: Bearer ${TOKEN}" \ "${API}/releases/${TAG}/upload_url?file_name=${enc}" 2>&1)" url="$(printf '%s' "$resp" | python3 -c 'import json,sys try: d = json.load(sys.stdin) print(d.get("url") or d.get("uploadUrl") or "") except Exception: print("")' 2>/dev/null)" if [ -z "$url" ]; then echo "FAIL 取得上传地址失败: ${resp:0:140}" continue fi # 2) PUT with the headers replayed exactly as returned. code="$(printf '%s' "$resp" | python3 -c 'import json,sys try: print(json.dumps(json.load(sys.stdin).get("headers") or {})) except Exception: print("{}")' 2>/dev/null | python3 -c ' import json, subprocess, sys headers = json.load(sys.stdin) args = ["curl", "-sS", "-o", "/dev/null", "-w", "%{http_code}", "-X", "PUT"] for k, v in headers.items(): args += ["-H", f"{k}: {v}"] args += ["--data-binary", "@" + sys.argv[1], sys.argv[2]] print(subprocess.run(args, capture_output=True, text=True).stdout) ' "$f" "$url" 2>/dev/null)" if [ "$code" = "200" ] || [ "$code" = "201" ] || [ "$code" = "204" ]; then echo "OK HTTP=$code" else echo "FAIL HTTP=$code" fi sleep 1 done