44import hashlib
55from github import Github , Auth
66import socket
7+ import subprocess
8+ import shlex
79from typing import List
810
911
@@ -160,12 +162,13 @@ def sync_to_gitee(tag: str, body: str, files: slice, asset_links=None):
160162
161163 # 附件上传回退开关与出错是否继续
162164 allow_partial = os .environ .get ('SYNC_CONTINUE_ON_UPLOAD_ERROR' , 'false' ).lower () == 'true'
163- # 链接模式:跳过上传,直接把 GitHub 资产链接写入 release body
165+ # 链接模式:跳过上传(用户要求真实上传,此处默认关闭)
164166 link_only = os .environ .get ('SYNC_LINK_ONLY' , 'false' ).lower () == 'true'
165167 try :
166- link_threshold_mb = float (os .environ .get ('SYNC_LINK_THRESHOLD_MB' , '16' ))
168+ # 默认不启用按大小走链接模式(需显式设置该环境变量)
169+ link_threshold_mb = float (os .environ .get ('SYNC_LINK_THRESHOLD_MB' , '0' ))
167170 except ValueError :
168- link_threshold_mb = 16 .0
171+ link_threshold_mb = 0 .0
169172
170173 if asset_links is None :
171174 asset_links = {}
@@ -211,7 +214,8 @@ def sync_to_gitee(tag: str, body: str, files: slice, asset_links=None):
211214 resp = api_client .post (
212215 asset_api_uri ,
213216 data = {'access_token' : access_token },
214- files = {'file' : (file_name , fh , 'application/octet-stream' )},
217+ # Gitee attach_files 接口参数名为 files(可多文件)
218+ files = {'files' : (file_name , fh , 'application/octet-stream' )},
215219 headers = {'Expect' : '100-continue' },
216220 timeout = UPLOAD_TIMEOUT ,
217221 )
@@ -237,7 +241,7 @@ def sync_to_gitee(tag: str, body: str, files: slice, asset_links=None):
237241 resp2 = api_client .post (
238242 asset_api_uri ,
239243 params = {'access_token' : access_token },
240- files = {'file ' : (file_name , fh , 'application/octet-stream' )},
244+ files = {'files ' : (file_name , fh , 'application/octet-stream' )},
241245 timeout = UPLOAD_TIMEOUT ,
242246 )
243247 if resp2 .status_code == 201 :
@@ -253,8 +257,44 @@ def sync_to_gitee(tag: str, body: str, files: slice, asset_links=None):
253257 success = True
254258 break
255259 print (f"Alt upload failed (status { resp2 .status_code } ) for { file_path } . Body: { txt2 [:256 ]} " )
260+ # 第三通道:使用 curl(对某些服务器/网络更稳定)
261+ curl_cmd = (
262+ f"curl -sS -f -X POST "
263+ f"--connect-timeout 10 --max-time { UPLOAD_SOCKET_TIMEOUT } "
264+ f"-F files=@{ shlex .quote (file_path )} ;type=application/octet-stream "
265+ f"-F access_token={ shlex .quote (access_token )} "
266+ f"{ shlex .quote (asset_api_uri )} "
267+ )
268+ try :
269+ r = subprocess .run (curl_cmd , shell = True , capture_output = True , text = True )
270+ if r .returncode == 0 :
271+ print (f"Successfully uploaded via curl: { file_name } !" )
272+ success = True
273+ break
274+ else :
275+ print (f"curl upload failed (exit { r .returncode } ) for { file_name } . stderr: { r .stderr [:256 ]} " )
276+ except Exception as ce :
277+ print (f"curl upload error for { file_name } : { ce } " )
256278 except requests .RequestException as e2 :
257279 print (f"Alt upload error for { file_path } : { e2 } " )
280+ # 在请求异常时也尝试 curl
281+ curl_cmd = (
282+ f"curl -sS -f -X POST "
283+ f"--connect-timeout 10 --max-time { UPLOAD_SOCKET_TIMEOUT } "
284+ f"-F files=@{ shlex .quote (file_path )} ;type=application/octet-stream "
285+ f"-F access_token={ shlex .quote (access_token )} "
286+ f"{ shlex .quote (asset_api_uri )} "
287+ )
288+ try :
289+ r = subprocess .run (curl_cmd , shell = True , capture_output = True , text = True )
290+ if r .returncode == 0 :
291+ print (f"Successfully uploaded via curl (exception path): { file_name } !" )
292+ success = True
293+ break
294+ else :
295+ print (f"curl upload failed (exit { r .returncode } ) for { file_name } . stderr: { r .stderr [:256 ]} " )
296+ except Exception as ce :
297+ print (f"curl upload error for { file_name } : { ce } " )
258298 except requests .RequestException as e :
259299 print (f"Upload error for { file_path } : { e } (attempt { attempt } /{ MAX_UPLOAD_RETRIES } )" )
260300 time .sleep (min (60 , 2 ** (attempt - 1 )))
@@ -283,6 +323,25 @@ def sync_to_gitee(tag: str, body: str, files: slice, asset_links=None):
283323 print (f"Fallback: attachments API did not return a URL. Resp: { aj } " )
284324 else :
285325 print (f"Fallback: attachments upload failed { ar .status_code } { ar .text [:256 ]} " )
326+ if not success :
327+ # 尝试使用 curl 走 attachments 接口
328+ curl_cmd = (
329+ f"curl -sS -f -X POST "
330+ f"--connect-timeout 10 --max-time { UPLOAD_SOCKET_TIMEOUT } "
331+ f"-F file=@{ shlex .quote (file_path )} ;type=application/octet-stream "
332+ f"-F access_token={ shlex .quote (access_token )} "
333+ f"https://gitee.com/api/v5/repos/{ owner } /{ repo } /attachments"
334+ )
335+ try :
336+ r = subprocess .run (curl_cmd , shell = True , capture_output = True , text = True )
337+ if r .returncode == 0 :
338+ print (f"Fallback via curl: uploaded attachment for { file_name } . Will add link if API returns it on body update." )
339+ # 我们无法直接得到URL,留给后续人工查看附件列表或忽略
340+ success = True
341+ else :
342+ print (f"curl attachments failed (exit { r .returncode } ) for { file_name } . stderr: { r .stderr [:256 ]} " )
343+ except Exception as ce :
344+ print (f"curl attachments error for { file_name } : { ce } " )
286345 except requests .RequestException as ae :
287346 print (f"Fallback attachments error: { ae } " )
288347 if not success :
0 commit comments