scripts/gitea-release.py : ensure_asset (upload + vérif nom/taille + retry PATCH + échec bruyant) — les ?name=/PATCH pouvaient être ignorés (v1.2.6/v1.2.10) ; docs §16.bis/§14 #37
This commit is contained in:
parent
15c667132b
commit
3f1378f6ba
@ -665,6 +665,10 @@ Historique complet — **à ne pas réintroduire** (utile pour diff/revert) :
|
||||
d'unicité dès la moindre donnée existante → import échouait. → mode
|
||||
ÉCRASEMENT (effacement ordonné enfants→parents puis restauration) +
|
||||
restauration du tConfig + reprogrammation des rappels.
|
||||
37. **Upload d'asset Gitea instable** (v1.2.10) : le `?name=` du POST et le
|
||||
PATCH de renommage peuvent être ignorés (asset au nom générique, APK
|
||||
release disparu de la release). → `ensure_asset` dans le script :
|
||||
upload + vérification nom/taille + retry PATCH + échec bruyant.
|
||||
36. **Sens des boutons de zoom inversé** (v1.2.10, retour utilisateur) :
|
||||
le « + » dézoomait (fenêtre plus longue) et le « − » zoomait — contre
|
||||
la convention carte. → « + » = zoom avant (fenêtre courte), « − » =
|
||||
@ -788,10 +792,11 @@ Le script :
|
||||
- crée la release si absente, sinon **met à jour le corps** (PATCH) ;
|
||||
- attache l'APK (remplace l'asset du même nom si présent) — appeler le script
|
||||
DEUX FOIS pour publier les deux APK (noms distincts) ;
|
||||
⚠️ renommage défensif : un asset peut se retrouver au nom générique après
|
||||
une session d'upload interrompue (extinction machine — arrivé en v1.2.9) →
|
||||
le script RENOMME l'asset via l'API d'édition (`PATCH …/assets/{id}`)
|
||||
après chaque upload — ne pas retirer ;
|
||||
⚠️ vérification intégrée (`ensure_asset`) : le `?name=` de l'upload et/ou
|
||||
le PATCH peuvent être ignorés par les instances (assets au nom générique /
|
||||
APK disparu — v1.2.6, v1.2.10) → le script vérifie **nom ET taille** après
|
||||
chaque upload, retente le PATCH une fois, et **échoue bruyamment** si
|
||||
l'asset ne colle pas — ne pas retirer ;
|
||||
`HormoneTrack-vX.Y.Z-release.apk` (**recommandé**, R8) et
|
||||
`HormoneTrack-vX.Y.Z-debug.apk` ;
|
||||
- lit le token Gitea dans le trousseau macOS (`security find-internet-password`) ;
|
||||
|
||||
@ -20,6 +20,7 @@ Pour ajouter un token au trousseau :
|
||||
-w <TOKEN> -U
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
@ -83,6 +84,36 @@ def changelog_section(version: str) -> str:
|
||||
return m.group(1).strip()
|
||||
|
||||
|
||||
def ensure_asset(base: str, token: str, release_id: int, name: str, path: str) -> dict:
|
||||
"""Upload + vérification (nom ET taille) + retry PATCH — échec bruyant.
|
||||
Le ?name= de l'upload et/ou le PATCH peuvent être ignorés par certaines
|
||||
instances (v1.2.6/v1.2.10 : asset au nom générique, APK release disparu)."""
|
||||
import uuid
|
||||
expected = os.path.getsize(path)
|
||||
boundary = uuid.uuid4().hex
|
||||
with open(path, "rb") as f:
|
||||
data = (f"--{boundary}\r\nContent-Disposition: form-data; name=\"attachment\"; "
|
||||
f"filename=\"{name}\"\r\n"
|
||||
f"Content-Type: application/vnd.android.package-archive\r\n\r\n").encode() \
|
||||
+ f.read() + f"\r\n--{boundary}--\r\n".encode()
|
||||
req = urllib.request.Request(f"{base}/releases/{release_id}/assets?name={name}",
|
||||
method="POST",
|
||||
headers={"Authorization": f"token {token}",
|
||||
"Content-Type": f"multipart/form-data; boundary={boundary}"})
|
||||
req.data = data
|
||||
uploaded = json.loads(urllib.request.urlopen(req, timeout=300).read().decode())
|
||||
|
||||
for _ in range(2):
|
||||
release = request(f"{base}/releases/{release_id}", token=token)
|
||||
current = next((a for a in release["assets"] if a["id"] == uploaded["id"]), None)
|
||||
if current and current["name"] == name and abs(current["size"] - expected) < 1000:
|
||||
return current
|
||||
request(f"{base}/releases/{release_id}/assets/{uploaded['id']}",
|
||||
"PATCH", token=token, data={"name": name})
|
||||
sys.exit(f"✗ ÉCHEC : l'asset {name} n'a pas le bon nom/taille après retry — "
|
||||
f"la release est incomplète, publier manuellement.")
|
||||
|
||||
|
||||
def main():
|
||||
args = sys.argv[1:]
|
||||
# Premier argument = instance s'il n'est pas un tag (un tag commence par « v »)
|
||||
@ -128,16 +159,11 @@ def main():
|
||||
if asset["name"] == asset_name:
|
||||
request(f"{base}/releases/{release_id}/assets/{asset['id']}",
|
||||
"DELETE", token=token)
|
||||
with open(apk_path, "rb") as f:
|
||||
asset = request(
|
||||
f"{base}/releases/{release_id}/assets?name={asset_name}",
|
||||
"POST", token=token,
|
||||
files={"name": asset_name, "data": f.read()},
|
||||
)
|
||||
# ⚠️ Renommage défensif : le nom d'asset peut se retrouver générique
|
||||
# (ex. nom générique observé après une session d'upload INTERROMPUE —
|
||||
# extinction machine en plein script) → renommage explicite via l'API
|
||||
# d'édition d'asset, systématique après chaque upload.
|
||||
# ⚠️ Renommage défensif + VÉRIFICATION : le ?name= de l'upload et/ou le
|
||||
# PATCH peuvent être ignorés par certaines instances (nom générique
|
||||
# observé en v1.2.6/10) → vérifier nom + taille après upload, retenter
|
||||
# le PATCH une fois, et ÉCHOUER bruyamment si l'asset ne colle pas.
|
||||
ensure_asset(base, token, release_id, asset_name, apk_path)
|
||||
request(f"{base}/releases/{release_id}/assets/{asset['id']}",
|
||||
"PATCH", token=token, data={"name": asset_name})
|
||||
link = asset.get("browser_download_url", "?")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user