diff --git a/.claude/skills/eas-build/SKILL.md b/.claude/skills/eas-build/SKILL.md index bc504a1..a609abd 100644 --- a/.claude/skills/eas-build/SKILL.md +++ b/.claude/skills/eas-build/SKILL.md @@ -15,10 +15,39 @@ user-invocable: true 1. Lire le `versionCode` actuel dans `app.json` 2. Incrementer `versionCode` (+1) — doit etre strictement superieur -3. Si demande par l'utilisateur : bumper `version` dans `app.json` + `package.json` -4. Commit : `chore: bump versionCode to ` -5. Build : `npx --yes eas-cli build --platform android --profile preview --non-interactive` -6. Quand le build est termine : creer une release Forgejo avec le lien APK +3. Si demande par l'utilisateur : bumper `version` dans `app.json` + `package.json` (et `npm install` pour synchroniser le lockfile) +4. Commit : `chore: bump versionCode to ` (ou `chore: bump version to X.Y.Z (versionCode N)` si version aussi bumpee) +5. Push commit sur master, puis tag `vX.Y.Z` et `git push origin vX.Y.Z` +6. Build : `npx --yes eas-cli build --platform android --profile preview --non-interactive` +7. Quand le build est termine : telecharger l'APK, creer la release Forgejo, attacher l'APK + +## Upload de l'APK — pattern resilient + +```bash +# 1. Telecharger +APK_URL=$(npx --yes eas-cli build:view --json | jq -r '.artifacts.buildUrl') +curl -L -o "/tmp/simpl-liste-vX.Y.Z.apk" "$APK_URL" + +# 2. Creer la release +TOKEN=$(cat ~/.forgejo-token) +RELEASE_ID=$(curl -s -X POST -H "Authorization: token $TOKEN" -H "Content-Type: application/json" \ + "https://git.lacompagniemaximus.com/api/v1/repos/maximus/simpl-liste/releases" \ + -d '{"tag_name":"vX.Y.Z","name":"vX.Y.Z","body":"...","draft":false,"prerelease":false}' \ + | jq -r '.id') + +# 3. Attacher l'APK — RETRY sur 502/504 (variance reseau, pas un probleme infra) +for i in 1 2 3 4 5; do + http=$(curl -X POST -H "Authorization: token $TOKEN" \ + "https://git.lacompagniemaximus.com/api/v1/repos/maximus/simpl-liste/releases/$RELEASE_ID/assets?name=simpl-liste-vX.Y.Z.apk" \ + -F "attachment=@/tmp/simpl-liste-vX.Y.Z.apk" \ + -o /tmp/asset-resp.json -w "%{http_code}" --max-time 300) + case "$http" in + 201) echo "Upload OK"; break;; + 502|504) echo "Attempt $i: gateway timeout, retry"; sleep 5;; + *) echo "Unexpected: HTTP $http"; cat /tmp/asset-resp.json; break;; + esac +done +``` ## Regles @@ -26,3 +55,22 @@ user-invocable: true - `autoIncrement` dans eas.json ne s'applique qu'au profil `production`, pas `preview` - Toujours utiliser `npx --yes eas-cli` (pas d'install globale) - Ne JAMAIS `git push --tags` — push les tags un par un si necessaire + +## Gotcha — Upload APK : 502/504 transitoire + +**Symptome** : `curl -X POST ... -F "attachment=@"` retourne HTTP 502 ou 504 apres ~60s. La progression curl montre upload coupe a 50-90% de progression. Affecte typiquement les APK ~90MB+. + +**Cause** : Traefik (devant Forgejo via Coolify) a un timeout de gateway de 60s sur la fin de requete. Quand la vitesse upload tombe sous ~1.5 MB/s (variance reseau classique sur connexions residentielles), un APK de 92 MB depasse le seuil et la requete est coupee. **Ce n'est pas un probleme de config infra** — c'est purement la vitesse upload du client a un instant donne. + +**Fix** : retry. La 2e ou 3e tentative passe quand la bande passante remonte (j'ai mesure 1.3 MB/s puis 17 MB/s a quelques minutes d'intervalle). Le pattern `for i in 1..5` ci-dessus est suffisant — pas besoin de toucher a Traefik ni Forgejo. + +**Verification que c'est bien le bon probleme** : +- L'APK precedent (~97 MB) a ete uploade avec succes les semaines passees → infra OK +- Un fichier de test de 11 octets sur la meme release passe en 0.1s → API OK +- HTTP 502 ou 504 apres 60s exactement → timeout gateway, pas erreur de logique +- Vitesse upload curl reportee < 1.5 MB/s → confirme la cause + +**Path API a connaitre** : +- Creer release : `POST /repos/{owner}/{repo}/releases` (renvoie `.id`) +- Attacher asset : `POST /repos/{owner}/{repo}/releases/{release_id}/assets?name=` (multipart `attachment`) +- Supprimer asset : `DELETE /repos/{owner}/{repo}/releases/{release_id}/assets/{asset_id}` — **inclure le release_id dans le path**, pas seulement l'asset id, sinon HTTP 404