Skip to content

Commit c3fce42

Browse files
committed
Update.
1 parent 989e521 commit c3fce42

2 files changed

Lines changed: 183 additions & 10 deletions

File tree

.github/sync.py

Lines changed: 181 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import hashlib
55
from github import Github, Auth
66
import socket
7+
import subprocess
8+
import shlex
79
from typing import List
810

911

@@ -98,11 +100,54 @@ def sync_to_gitee(tag: str, body: str, files: slice, asset_links=None):
98100
repo = os.environ.get('GITEE_REPO', 'ServerStatus')
99101
release_api_uri = f"https://gitee.com/api/v5/repos/{owner}/{repo}/releases"
100102
api_client = requests.Session()
103+
# 第2b通道:尝试字段名 file(有些实现要求 file 而非 files)
104+
with open(file_path, 'rb') as fh:
105+
resp2b = api_client.post(
106+
asset_api_uri,
107+
data={'access_token': access_token},
108+
files={'file': (file_name, fh, 'application/octet-stream')},
109+
headers={'Connection': 'close'},
110+
timeout=UPLOAD_TIMEOUT,
111+
)
112+
if resp2b.status_code == 201:
113+
asset_info = resp2b.json()
114+
asset_name = asset_info.get('name')
115+
print(f"Successfully uploaded via alt path (file field): {asset_name}!")
116+
success = True
117+
break
118+
else:
119+
txt2b = resp2b.text
120+
if resp2b.status_code in (400, 409, 422) and ('已存在' in txt2b or 'already exists' in txt2b):
121+
print(f"Asset {file_name} already exists (file field), treat as success.")
122+
success = True
123+
break
124+
print(f"Alt upload (file field) failed (status {resp2b.status_code}) for {file_path}. Body: {txt2b[:256]}")
125+
with open(file_path, 'rb') as fh:
126+
resp2c = api_client.post(
127+
asset_api_uri,
128+
params={'access_token': access_token},
129+
files={'file': (file_name, fh, 'application/octet-stream')},
130+
headers={'Connection': 'close'},
131+
timeout=UPLOAD_TIMEOUT,
132+
)
133+
if resp2c.status_code == 201:
134+
asset_info = resp2c.json()
135+
asset_name = asset_info.get('name')
136+
print(f"Successfully uploaded via alt path (params+file): {asset_name}!")
137+
success = True
138+
break
139+
else:
140+
txt2c = resp2c.text
141+
if resp2c.status_code in (400, 409, 422) and ('已存在' in txt2c or 'already exists' in txt2c):
142+
print(f"Asset {file_name} already exists (params+file), treat as success.")
143+
success = True
144+
break
145+
print(f"Alt upload (params+file) failed (status {resp2c.status_code}) for {file_path}. Body: {txt2c[:256]}")
101146
api_client.headers.update({
102147
'Accept': 'application/json',
103-
# 对于 form 提交不强制指定 JSON 头
148+
f"curl -sS -f --http1.1 -4 -X POST "
104149
})
105-
150+
f"-F files=@{shlex.quote(file_path)};type=application/octet-stream "
106151
access_token = os.environ['GITEE_TOKEN']
107152
release_form = {
108153
'access_token': access_token,
@@ -115,6 +160,21 @@ def sync_to_gitee(tag: str, body: str, files: slice, asset_links=None):
115160
# 优先尝试创建(表单提交)
116161
release_api_response = api_client.post(release_api_uri, data=release_form, timeout=REQUEST_TIMEOUT)
117162
if release_api_response.status_code == 201:
163+
# 再试一次使用字段名 file
164+
curl_cmd2 = (
165+
f"curl -sS -f --http1.1 -4 -X POST "
166+
f"--connect-timeout 10 --max-time {UPLOAD_SOCKET_TIMEOUT} "
167+
f"-F file=@{shlex.quote(file_path)};type=application/octet-stream "
168+
f"-F access_token={shlex.quote(access_token)} "
169+
f"{shlex.quote(asset_api_uri)}"
170+
)
171+
r2 = subprocess.run(curl_cmd2, shell=True, capture_output=True, text=True)
172+
if r2.returncode == 0:
173+
print(f"Successfully uploaded via curl(file field): {file_name}!")
174+
success = True
175+
break
176+
else:
177+
print(f"curl(file field) upload failed (exit {r2.returncode}) for {file_name}. stderr: {r2.stderr[:256]}")
118178
release_info = release_api_response.json()
119179
release_id = release_info.get('id')
120180
else:
@@ -160,12 +220,13 @@ def sync_to_gitee(tag: str, body: str, files: slice, asset_links=None):
160220

161221
# 附件上传回退开关与出错是否继续
162222
allow_partial = os.environ.get('SYNC_CONTINUE_ON_UPLOAD_ERROR', 'false').lower() == 'true'
163-
# 链接模式:跳过上传,直接把 GitHub 资产链接写入 release body
223+
# 链接模式:跳过上传(用户要求真实上传,此处默认关闭)
164224
link_only = os.environ.get('SYNC_LINK_ONLY', 'false').lower() == 'true'
165225
try:
166-
link_threshold_mb = float(os.environ.get('SYNC_LINK_THRESHOLD_MB', '16'))
226+
# 默认不启用按大小走链接模式(需显式设置该环境变量)
227+
link_threshold_mb = float(os.environ.get('SYNC_LINK_THRESHOLD_MB', '0'))
167228
except ValueError:
168-
link_threshold_mb = 16.0
229+
link_threshold_mb = 0.0
169230

170231
if asset_links is None:
171232
asset_links = {}
@@ -211,8 +272,9 @@ def sync_to_gitee(tag: str, body: str, files: slice, asset_links=None):
211272
resp = api_client.post(
212273
asset_api_uri,
213274
data={'access_token': access_token},
214-
files={'file': (file_name, fh, 'application/octet-stream')},
215-
headers={'Expect': '100-continue'},
275+
# Gitee attach_files 接口参数名为 files(可多文件)
276+
files={'files': (file_name, fh, 'application/octet-stream')},
277+
headers={'Expect': '100-continue', 'Connection': 'close'},
216278
timeout=UPLOAD_TIMEOUT,
217279
)
218280
finally:
@@ -237,7 +299,8 @@ def sync_to_gitee(tag: str, body: str, files: slice, asset_links=None):
237299
resp2 = api_client.post(
238300
asset_api_uri,
239301
params={'access_token': access_token},
240-
files={'file': (file_name, fh, 'application/octet-stream')},
302+
files={'files': (file_name, fh, 'application/octet-stream')},
303+
headers={'Connection': 'close'},
241304
timeout=UPLOAD_TIMEOUT,
242305
)
243306
if resp2.status_code == 201:
@@ -253,10 +316,83 @@ def sync_to_gitee(tag: str, body: str, files: slice, asset_links=None):
253316
success = True
254317
break
255318
print(f"Alt upload failed (status {resp2.status_code}) for {file_path}. Body: {txt2[:256]}")
319+
# 第三通道:使用 curl(对某些服务器/网络更稳定)
320+
curl_cmd = (
321+
f"curl -sS -f -X POST "
322+
f"--connect-timeout 10 --max-time {UPLOAD_SOCKET_TIMEOUT} "
323+
f"-F files=@{shlex.quote(file_path)};type=application/octet-stream "
324+
f"-F access_token={shlex.quote(access_token)} "
325+
f"{shlex.quote(asset_api_uri)}"
326+
)
327+
try:
328+
r = subprocess.run(curl_cmd, shell=True, capture_output=True, text=True)
329+
if r.returncode == 0:
330+
print(f"Successfully uploaded via curl: {file_name}!")
331+
success = True
332+
break
333+
else:
334+
print(f"curl upload failed (exit {r.returncode}) for {file_name}. stderr: {r.stderr[:256]}")
335+
except Exception as ce:
336+
print(f"curl upload error for {file_name}: {ce}")
256337
except requests.RequestException as e2:
257338
print(f"Alt upload error for {file_path}: {e2}")
339+
# 在请求异常时也尝试 curl
340+
curl_cmd = (
341+
f"curl -sS -f -X POST "
342+
f"--connect-timeout 10 --max-time {UPLOAD_SOCKET_TIMEOUT} "
343+
f"-F files=@{shlex.quote(file_path)};type=application/octet-stream "
344+
f"-F access_token={shlex.quote(access_token)} "
345+
f"{shlex.quote(asset_api_uri)}"
346+
)
347+
try:
348+
r = subprocess.run(curl_cmd, shell=True, capture_output=True, text=True)
349+
if r.returncode == 0:
350+
print(f"Successfully uploaded via curl (exception path): {file_name}!")
351+
success = True
352+
break
353+
else:
354+
print(f"curl upload failed (exit {r.returncode}) for {file_name}. stderr: {r.stderr[:256]}")
355+
except Exception as ce:
356+
print(f"curl upload error for {file_name}: {ce}")
258357
except requests.RequestException as e:
259358
print(f"Upload error for {file_path}: {e} (attempt {attempt}/{MAX_UPLOAD_RETRIES})")
359+
# 异常路径:立刻尝试备用 requests 通道与 curl
360+
try:
361+
with open(file_path, 'rb') as fh:
362+
resp2 = api_client.post(
363+
asset_api_uri,
364+
params={'access_token': access_token},
365+
files={'files': (file_name, fh, 'application/octet-stream')},
366+
timeout=UPLOAD_TIMEOUT,
367+
)
368+
if resp2.status_code == 201:
369+
asset_info = resp2.json()
370+
asset_name = asset_info.get('name')
371+
print(f"Successfully uploaded via alt path (exception): {asset_name}!")
372+
success = True
373+
break
374+
else:
375+
print(f"Alt path (exception) failed (status {resp2.status_code}) for {file_path}. Body: {resp2.text[:256]}")
376+
except requests.RequestException as e3:
377+
print(f"Alt path request error (exception) for {file_path}: {e3}")
378+
# 尝试 curl
379+
curl_cmd = (
380+
f"curl -sS -f -X POST "
381+
f"--connect-timeout 10 --max-time {UPLOAD_SOCKET_TIMEOUT} "
382+
f"-F files=@{shlex.quote(file_path)};type=application/octet-stream "
383+
f"-F access_token={shlex.quote(access_token)} "
384+
f"{shlex.quote(asset_api_uri)}"
385+
)
386+
try:
387+
r = subprocess.run(curl_cmd, shell=True, capture_output=True, text=True)
388+
if r.returncode == 0:
389+
print(f"Successfully uploaded via curl (exception outer): {file_name}!")
390+
success = True
391+
break
392+
else:
393+
print(f"curl (exception outer) failed (exit {r.returncode}) for {file_name}. stderr: {r.stderr[:256]}")
394+
except Exception as ce:
395+
print(f"curl (exception outer) error for {file_name}: {ce}")
260396
time.sleep(min(60, 2 ** (attempt - 1)))
261397
if not success:
262398
print(f"Primary upload failed for {file_name} after {MAX_UPLOAD_RETRIES} attempts, trying attachments fallback...")
@@ -268,6 +404,7 @@ def sync_to_gitee(tag: str, body: str, files: slice, asset_links=None):
268404
attach_uri,
269405
data={'access_token': access_token},
270406
files={'file': (file_name, fh, 'application/octet-stream')},
407+
headers={'Connection': 'close'},
271408
timeout=UPLOAD_TIMEOUT,
272409
)
273410
if ar.status_code in (200, 201):
@@ -283,8 +420,44 @@ def sync_to_gitee(tag: str, body: str, files: slice, asset_links=None):
283420
print(f"Fallback: attachments API did not return a URL. Resp: {aj}")
284421
else:
285422
print(f"Fallback: attachments upload failed {ar.status_code} {ar.text[:256]}")
423+
if not success:
424+
# 尝试使用 curl 走 attachments 接口
425+
curl_cmd = (
426+
f"curl -sS -f -X POST "
427+
f"--connect-timeout 10 --max-time {UPLOAD_SOCKET_TIMEOUT} "
428+
f"-F file=@{shlex.quote(file_path)};type=application/octet-stream "
429+
f"-F access_token={shlex.quote(access_token)} "
430+
f"https://gitee.com/api/v5/repos/{owner}/{repo}/attachments"
431+
)
432+
try:
433+
r = subprocess.run(curl_cmd, shell=True, capture_output=True, text=True)
434+
if r.returncode == 0:
435+
print(f"Fallback via curl: uploaded attachment for {file_name}. Will add link if API returns it on body update.")
436+
# 我们无法直接得到URL,留给后续人工查看附件列表或忽略
437+
success = True
438+
else:
439+
print(f"curl attachments failed (exit {r.returncode}) for {file_name}. stderr: {r.stderr[:256]}")
440+
except Exception as ce:
441+
print(f"curl attachments error for {file_name}: {ce}")
286442
except requests.RequestException as ae:
287443
print(f"Fallback attachments error: {ae}")
444+
# 尝试使用 curl 走 attachments 接口
445+
curl_cmd = (
446+
f"curl -sS -f -X POST "
447+
f"--connect-timeout 10 --max-time {UPLOAD_SOCKET_TIMEOUT} "
448+
f"-F file=@{shlex.quote(file_path)};type=application/octet-stream "
449+
f"-F access_token={shlex.quote(access_token)} "
450+
f"https://gitee.com/api/v5/repos/{owner}/{repo}/attachments"
451+
)
452+
try:
453+
r = subprocess.run(curl_cmd, shell=True, capture_output=True, text=True)
454+
if r.returncode == 0:
455+
print(f"Fallback via curl: uploaded attachment for {file_name}.")
456+
success = True
457+
else:
458+
print(f"curl attachments (exception) failed (exit {r.returncode}) for {file_name}. stderr: {r.stderr[:256]}")
459+
except Exception as ce:
460+
print(f"curl attachments (exception) error for {file_name}: {ce}")
288461
if not success:
289462
msg = f"Failed to upload {file_path} after {MAX_UPLOAD_RETRIES} attempts"
290463
if allow_partial:

.github/workflows/sync-release.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ jobs:
1010
env:
1111
GITEE_TOKEN: ${{ secrets.GITEE_TOKEN }}
1212
GH_TOKEN: ${{ github.token }}
13-
# 临时:跳过大文件上传,直接把 GitHub 资产链接追加到 Gitee Release 说明
14-
SYNC_LINK_ONLY: true
13+
# 如需跳过大文件上传,打开并设置阈值:
14+
# SYNC_LINK_ONLY: true
1515
# 若仅想跳过大于阈值(MiB)的文件,可改用如下设置(默认16):
1616
# SYNC_LINK_THRESHOLD_MB: '16'
1717
# 如需不中断整个任务,即便单个上传失败:

0 commit comments

Comments
 (0)