Compare commits

..

26 commits

Author SHA1 Message Date
da3534bd34 Merge branch 'main' into feat/postit-acl
All checks were successful
Dotnet build and test / log-the-inputs (pull_request) Successful in 15s
Dotnet build and test / build (pull_request) Successful in 5m44s
2026-08-18 01:03:03 +01:00
f4d4c786b4 Merge pull request 'release/1.0.6' (#28) from release/1.0.6 into main
All checks were successful
Dotnet build and test / log-the-inputs (push) Successful in 19s
Dotnet build and test / build (push) Successful in 7m33s
Reviewed-on: #28
2026-08-18 01:02:44 +01:00
a4792a7a83
ci(forgejo): put asset name in URL query string, not as curl arg
All checks were successful
Dotnet build and test / log-the-inputs (pull_request) Successful in 46s
Dotnet build and test / build (pull_request) Successful in 12m18s
Forgejo Release / release (push) Successful in 6m34s
Le run #102 (re-publication du tag 1.0.6 après le fix jq + bump image v2)
a passé le PATCH /releases/10706 (jq a bien extrait l'id racine, plus
de 404), mais l'upload d'asset a planté avec un 400 "Missing 'name'
parameter".

Cause : sur l'appel curl de l'upload d'asset, l'argument `?name=...`
était passé en argument positionnel entre `--data-binary @file` et
l'URL. curl l'interprète comme un second fichier d'input (un fichier
nommé '?name=...'), pas comme un query param, et l'API Forgejo ne
voit jamais le name.

Fix : concaténer `?name=PostIt.Android.apk` à l'URL directement.
L'API Forgejo accepte le name en query string sur POST /releases/{id}/assets.
2026-08-17 05:44:12 +01:00
77fda10347
chore(release): update 1.0.6 CHANGELOG section (image v2, jq fix)
Some checks failed
Dotnet build and test / log-the-inputs (pull_request) Successful in 8s
Dotnet build and test / build (pull_request) Failing after 7m7s
Forgejo Release / release (push) Failing after 10m7s
La section [1.0.6] - stable du CHANGELOG mentionnait encore
debian12-dotnet10-android36-v1 et ne décrivait pas le fix du PATCH
release qui tombait en 404 à cause du sed greedy + JSON minifié.
Mets à jour avant de relancer la publication de la release
1.0.6 (workflow_dispatch), pour que le body publié reflète l'état
réel de l'infra (image v2 avec jq) et du workflow.
2026-08-17 05:25:20 +01:00
b390eb7be9 Merge pull request 'fix/forgejo-release-json-field-id' (#31) from fix/forgejo-release-json-field-id into release/1.0.6
All checks were successful
Dotnet build and test / log-the-inputs (pull_request) Successful in 14s
Dotnet build and test / build (pull_request) Successful in 9m40s
Reviewed-on: #31
2026-08-17 05:07:39 +01:00
c3c54ba5d5
ci(forgejo): build JSON bodies with jq instead of hand-rolled sed
All checks were successful
Dotnet build and test / log-the-inputs (pull_request) Successful in 8s
Dotnet build and test / build (pull_request) Successful in 13m27s
L'image runner pazof/yavsc-build-env installe jq (>= 1.7) à partir
de debian12-dotnet10-android36-v2 (Dockerfile du repo
dotnet-android-build-image, commit e06f096 "adds jq"). On en
profite pour supprimer json_escape et json_field à base de sed,
qui étaient fragiles :

  * sed est greedy par défaut : sur du JSON minifié d'une seule
    ligne (ce que renvoie l'API Forgejo de cette instance pour
    /releases/tags/<tag>), la regex s/.*"id".../\1/p attrape la
    DERNIÈRE occurrence de "id":<digits> sur la ligne, qui est
    l'id de l'auteur de la release (1, premier user du repo),
    pas l'id de la release (10706).
  * Le head -3 ajouté en PR #30 ne tient pas sur du JSON minifié :
    il n'isole rien et le sed greedy continue à capturer
    l'id de l'auteur.
  * PATCH /releases/1 tombait alors en 404 "The target couldn't
    be found" (cf. run échoué du 2026-08-17 04:05 sur le tag
    1.0.6).

jq résout les deux problèmes en une fois :
  * jq -r '.id' retourne le champ id racine, pas l'id imbriqué
    dans author.
  * jq -n --arg body "$RELEASE_BODY" '{body: $body, prerelease:
    $prerelease}' construit un body JSON proprement échappé
    (backslashes, guillemets, newlines, caractères de contrôle
    Unicode) sans avoir à le reproduire à la main.

Effet de bord : les bodies PATCH et POST sont écrits dans
/tmp/patch.json et /tmp/post.json puis passés à curl via
--data-binary @<file> au lieu d'une variable shell. Plus de
problème de quoting en chaîne shell, plus de collision avec
les espaces ou les caractères spéciaux du body.

Pré-requis côté runner : image pazof/yavsc-build-env:debian12-
dotnet10-android36-v2 (avec jq) + maj du label correspondant
dans la config du runner Forgejo.
2026-08-17 04:35:00 +01:00
2f443e5450 Merge pull request 'ci(forgejo): limit json_field extraction to top-level keys' (#30) from fix/forgejo-release-json-field-id into release/1.0.6
Some checks failed
Dotnet build and test / log-the-inputs (pull_request) Successful in 20s
Dotnet build and test / build (pull_request) Successful in 5m7s
Forgejo Release / release (push) Failing after 10m25s
Reviewed-on: #30
2026-08-17 03:26:53 +01:00
5186ffb7c8
ci(forgejo): limit json_field extraction to top-level keys
L'API Forgejo renvoie pour /releases/tags/<tag> un objet JSON
pretty-printed où l'id racine (release.id, ex. 10706) est sur la
première ligne, mais l'objet author contient aussi un id (souvent 1
pour le premier user du repo). L'ancienne regex sed matchait la
première occurrence globale de "id" dans le fichier, donc elle
retombait sur author.id=1 et le PATCH /releases/1 tombait en 404
'The target couldn't be found'.

Fix : on pipe le fichier dans 'head -3' pour ne matcher que les
premières lignes (couvre largement le préambule de l'objet release).
Si Forgejo renvoie du JSON minifié (une seule ligne), head -3
renvoie toute la ligne et la regex matche le premier id (la racine,
parce que les champs auteur sont après les champs racine).
2026-08-17 03:26:11 +01:00
3222c56ddb Merge pull request 'ci(forgejo): build JSON bodies in pure bash, no python3' (#29) from fix/forgejo-release-bash-json into release/1.0.6
Some checks failed
Dotnet build and test / log-the-inputs (pull_request) Successful in 19s
Dotnet build and test / build (pull_request) Successful in 5m20s
Forgejo Release / release (push) Failing after 7m52s
Reviewed-on: #29
2026-08-17 02:18:09 +01:00
bbe483cb24
ci(forgejo): build JSON bodies in pure bash, no python3
L'image runner pazof/yavsc-build-env n'a pas python3 (ni jq, ni
node). Le step de publication Forgejo utilisait python3 pour générer
les bodies JSON (POST /releases, PATCH /releases/{id}) et pour
extraire le 'id' de la réponse.

Fix : deux fonctions bash :
- json_escape : escaping JSON des chaînes (\\, \", \n, \r, \t)
- json_field : extraction d'un champ scalaire d'un fichier JSON via sed

Suffisant pour les bodies qu'on envoie (tag_name, name, body,
prerelease) et les champs qu'on lit (id).
2026-08-17 02:16:46 +01:00
63c7dbbd9b
Merge remote-tracking branch 'github/main' into fix/forgejo-release-build-no-docker
Some checks failed
Dotnet build and test / log-the-inputs (pull_request) Successful in 35s
Dotnet build and test / build (pull_request) Has been cancelled
2026-08-17 02:05:51 +01:00
739cd716ec
Merge pull request #70 from pazof/copilot/fix-validate-release-job
fix(ci): validate-release channel check always failed for stable/preview tags
2026-08-17 02:05:01 +01:00
copilot-swe-agent[bot]
843d6b227f
fix(ci): fix validate-release CHANGELOG channel check to inspect heading line
Co-authored-by: pazof <3072814+pazof@users.noreply.github.com>
2026-08-17 01:02:14 +00:00
copilot-swe-agent[bot]
704f7565fe
Initial plan 2026-08-17 01:00:12 +00:00
f5b1ccee5e Merge pull request 'ci(forgejo): build .NET projects directly, skip docker' (#27) from fix/forgejo-release-build-no-docker into release/1.0.6
Some checks failed
Forgejo Release / release (push) Failing after 10m11s
Reviewed-on: #27
2026-08-17 01:56:42 +01:00
44edf71b12
ci(forgejo): build .NET projects directly, skip docker
L'image runner pazof/yavsc-build-env a le SDK .NET 10 et le workload
Android, mais PAS le binaire 'docker' ni de daemon Docker. Le
'Build de l'image Docker' du workflow plantait avec 'docker: command
not found'.

Fix : on exécute directement les commandes dotnet du Dockerfile
(restore + build Yavsc.Org/Api/Blogs + build PostIt.Android -r
android-arm64), puis on copie l'APK depuis le chemin de sortie
standard bin/Release/net10.0-android/android-arm64/.

Note : le Dockerfile reste la voie canonique pour les builds en
local et via GitHub Actions (qui a docker). Ce fix concerne
uniquement le workflow Forgejo Actions où le runner n'a pas Docker.
2026-08-17 01:56:01 +01:00
69677727cb Merge pull request 'ci(forgejo): check CHANGELOG channel suffix on the section title' (#26) from fix/forgejo-release-changelog-title-check into release/1.0.6
Some checks failed
Forgejo Release / release (push) Failing after 13s
Reviewed-on: #26
2026-08-17 01:50:17 +01:00
5e600c11e1
ci(forgejo): check CHANGELOG channel suffix on the section title
The previous awk extracted the section body but excluded the title
line (## [TAG] - channel), so the '* - $CHANNEL*' pattern never
matched. Fix: include the title line in the extracted body, verify
the channel suffix on the title, then strip the title before passing
the body to the release API.
2026-08-17 01:49:45 +01:00
f2776b34e3 Merge pull request 'ci(forgejo): rewrite release workflow in pure bash + curl' (#25) from fix/forgejo-release-native-bash into release/1.0.6
Some checks failed
Forgejo Release / release (push) Failing after 13s
Reviewed-on: #25
2026-08-17 01:45:54 +01:00
5b957c6cbb
ci(forgejo): replace all Node-based actions with bash + curl
The runner's docker label points at pazof/yavsc-build-env, a Debian
image without Node.js. Any action like actions/checkout@v7,
actions/upload-artifact@v7, rasterstate/forgejo-release-action, etc.
fails at container start with 'executable file not found in /usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/home/paul/.dotnet/tools:/opt/android-sdk/cmdline-tools/latest/bin:/opt/android-sdk/platform-tools:/home/paul/.nvm/versions/node/v22.23.0/bin:/home/paul/.local/bin:/home/paul/.npm-global/bin:/home/paul/bin:/home/paul/.nix-profile/bin'.

This workflow is rewritten in pure bash:
- replace actions/checkout with explicit git clone + checkout (full
  history + tags so GitVersion.MsBuild is happy);
- merge the two jobs into one (no inter-job artifacts needed since
  everything shares the runner's filesystem);
- replace rasterstate/forgejo-release-action with direct calls to the
  Forgejo REST API (/api/v1/repos/.../releases, .../assets), with
  python3 used to build and parse JSON bodies (jq not guaranteed in
  the runner image).

Auth: ${{ secrets.GITHUB_TOKEN }} (runner-provided). The
rasterstate action or any other Node-based action can be reinstated
later if the runner image is swapped for one with Node installed.
2026-08-17 01:45:22 +01:00
19da7909ce Merge pull request 'ci(github): backport fetch-depth fix on apk-deploy checkout to release/1.0.6' (#24) from fix/github-apk-checkout-fetch-depth-backport into release/1.0.6
Some checks failed
Forgejo Release / validate-release (push) Failing after 10s
Forgejo Release / release (push) Has been skipped
Reviewed-on: #24
2026-08-17 01:37:50 +01:00
b69c382beb
Checkout
1. complet de l’historique Git et des tags dans le job qui build l’APK via Docker:
2. with tags
2026-08-17 01:36:55 +01:00
c5c4d6b59a Merge pull request 'ci(forgejo): use runner-provided GITHUB_TOKEN for release workflow' (#23) from fix/forgejo-release-use-runner-token into release/1.0.6
Reviewed-on: #23
2026-08-17 01:25:13 +01:00
80cb8c46fc
ci(forgejo): use runner-provided GITHUB_TOKEN for release workflow
Repo-level secrets creation is broken on this Forgejo instance
(InsertEncryptedSecret fails with UTF-8 byte-sequence error, likely
a text-vs-bytea column type on the secret table). The fix is in
upstream Forgejo v16; until then, ${{ secrets.GITHUB_TOKEN }} (auto-
provided by the runner, scoped to contents: write for the current
repo) keeps the release workflow operational without any UI setup.

When the instance is upgraded and the secret table is migrated,
revert this commit to switch back to ${{ secrets.RELEASE_TOKEN }}
for least-privilege.
2026-08-17 01:23:44 +01:00
70a69779fa Merge pull request 'ci(forgejo): publish release with PostIt APK on tag push' (#22) from feat/forgejo-release-page into release/1.0.6
Some checks failed
Forgejo Release / validate-release (push) Failing after 23s
Forgejo Release / release (push) Has been skipped
Reviewed-on: #22
2026-08-17 00:53:59 +01:00
3dd4700404
ci(forgejo): publish release with PostIt APK on tag push
Adds .forgejo/workflows/release.yml: triggered by tag push or
workflow_dispatch, it validates the tag/CHANGELOG parity (stable /
preview / unstable), builds the PostIt Android APK via the existing
Dockerfile (--target build-env), and publishes a Forgejo release with
the APK as an asset via rasterstate/forgejo-release-action@v1.

Mirrors the validate-release logic of .github/workflows/docker-publish-android.yml
so the two channels (Forgejo source-of-truth + GitHub mirror) stay
consistent. Authentication uses ${{ secrets.RELEASE_TOKEN }}, a Forgejo
PAT scoped to write:repository configured in the repository's Actions
secrets.
2026-08-17 00:46:51 +01:00
3 changed files with 346 additions and 5 deletions

View file

@ -0,0 +1,331 @@
# Build and publish a release on the Forgejo source-of-truth instance
# with the PostIt Android APK as an attached asset.
#
# Triggered by a push of a git tag. Validates the tag/changelog pair,
# builds the APK using the existing Dockerfile (--target build-env), then
# publishes a Forgejo release via the Forgejo REST API and uploads the
# APK as an asset.
#
# Authentication uses ${{ secrets.GITHUB_TOKEN }} (auto-provided by the
# Forgejo runner, scoped to contents: write for the current repo). A
# dedicated PAT (${{ secrets.RELEASE_TOKEN }}) was the preferred option
# for least-privilege, but creating repo-level secrets is currently
# broken on this Forgejo instance (InsertEncryptedSecret fails with a
# UTF-8 byte-sequence error, probably a text-vs-bytea column type on
# the secret table). Bumping to Forgejo v16 should fix it; until then,
# the runner-provided token keeps the workflow operational.
#
# Why bash + jq + curl, no third-party actions: the runner's docker
# label points at pazof/yavsc-build-env, a Debian image with jq but
# without Node.js or python3. Any action like actions/checkout,
# rasterstate/forgejo-release-action, etc. fails with "executable
# file not found in $PATH". jq is shipped in the image from
# debian12-dotnet10-android36-v2 onward; earlier tags fell back to
# hand-rolled JSON building via sed, which was fragile (cf. PR #30:
# sed greedy + head -3 still matched author.id instead of the
# release id on the minified JSON this instance returns, PATCH
# /releases/1 → 404). Same constraint as
# .forgejo/workflows/buildAndTest.yml.
#
# This workflow complements .github/workflows/docker-publish-android.yml
# which targets the GitHub mirror; the validate-release logic mirrors
# the GitHub-side job so the two channels stay consistent.
name: Forgejo Release
on:
push:
tags:
- '*'
workflow_dispatch:
inputs:
tag:
description: 'Tag à publier (requis en dispatch, ex. 1.0.6 ou 1.0.7-rc1).'
required: true
type: string
force_unstable:
description: 'Publier une release avec suffixe (ex. 1.0.0-rc1) malgré le fail-fast par défaut.'
required: false
type: boolean
default: false
permissions:
contents: write
jobs:
# Job unique : validation tag/CHANGELOG + build APK + publication
# via l'API REST Forgejo (pas d'actions tierces Node).
release:
runs-on: docker
steps:
- name: Clone du repo au tag demandé
env:
# En push tag : github.ref_name est le tag.
# En workflow_dispatch : on lit l'input 'tag'.
TAG: ${{ github.event_name == 'push' && github.ref_name || inputs.tag }}
FORCE_UNSTABLE: ${{ inputs.force_unstable || 'false' }}
run: |
if [[ -z "$TAG" ]]; then
echo "::error::No tag provided. In workflow_dispatch, set the 'tag' input."
exit 1
fi
# WORKDIR de l'image (cf. dotnet-android-build-image/Dockerfile).
cd /src
# Clone unshallow pour que GitVersion.MsBuild ait l'historique
# et les tags (sinon MSB3073 sur la cible Android cf. PR #21).
if [[ ! -d _src/.git ]]; then
git clone https://forgejo.pschneider.fr/notazof/yavsc.git _src
fi
cd _src
git fetch --tags --force --prune origin
git checkout "$TAG"
echo "Checked out at $(git rev-parse HEAD) on $(git describe --tags --always 2>/dev/null || echo unknown)"
- name: Valider le tag et la section CHANGELOG
run: |
cd /src/_src
TAG="$(git describe --tags --exact-match HEAD 2>/dev/null || git rev-parse --short HEAD)"
echo "Validating tag $TAG"
# Parse semver : MAJOR.MINOR.PATCH[-SUFFIX]
if [[ ! "$TAG" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)(-.*)?$ ]]; then
echo "::error::Tag '$TAG' does not match MAJOR.MINOR.PATCH[-SUFFIX] format."
exit 1
fi
MAJOR="${BASH_REMATCH[1]}"
MINOR="${BASH_REMATCH[2]}"
PATCH="${BASH_REMATCH[3]}"
SUFFIX="${BASH_REMATCH[4]}"
# Classification du canal par parité du patch.
# Patch pair + pas de suffixe -> stable.
# Patch impair + pas de suffixe -> preview.
# Suffixe présent -> instable.
if [[ -n "$SUFFIX" ]]; then
CHANNEL="unstable"
elif (( PATCH % 2 == 0 )); then
CHANNEL="stable"
else
CHANNEL="preview"
fi
echo "Tag $TAG classifié comme channel=$CHANNEL"
# Fail-fast sur instable sauf opt-in explicite.
if [[ "$CHANNEL" == "unstable" && "${FORCE_UNSTABLE:-false}" != "true" ]]; then
echo "::error::Tag '$TAG' is unstable (suffix '$SUFFIX'). Refusing to publish."
echo "Set force_unstable=true via workflow_dispatch to override."
exit 1
fi
# Lecture du CHANGELOG.md (doit exister à la racine du repo).
if [[ ! -f CHANGELOG.md ]]; then
echo "::error::CHANGELOG.md not found at repo root."
exit 1
fi
# Extraction de la section [TAG]. On cherche la première ligne
# commençant par '## [' qui contient '[TAG]' (entre '## [' et
# la prochaine ligne '## [' ou fin de fichier). awk en mode
# paragraphe suffit et reste POSIX. On garde aussi le titre
# (ligne `## [TAG] - channel`) pour la vérification du canal.
BODY=$(awk -v tag="[$TAG]" '
/^## \[/ {
if (in_section) exit
if (index($0, tag) > 0) {
in_section=1
print
next
}
}
in_section { print }
' CHANGELOG.md)
if [[ -z "$BODY" ]]; then
echo "::error::No section matching '## [$TAG]' found in CHANGELOG.md."
echo "Add a '## [$TAG] - $CHANNEL' section before tagging."
exit 1
fi
# Vérification cohérence du canal déclaré dans le suffixe.
# Format attendu : "## [TAG] - stable" / "- preview" / "- unstable".
# On lit la première ligne du body qui contient le titre.
TITLE=$(echo "$BODY" | head -1)
if [[ "$TITLE" != *" - $CHANNEL"* ]]; then
echo "::error::Section title '$TITLE' must declare suffix '- $CHANNEL' to match tag parity."
exit 1
fi
# Body pour la release : retire la première ligne (titre).
BODY=$(echo "$BODY" | tail -n +2)
echo "Section CHANGELOG validée pour [$TAG] - $CHANNEL"
# Expose channel + body pour les étapes suivantes via $GITHUB_ENV.
echo "RELEASE_CHANNEL=$CHANNEL" >> "$GITHUB_ENV"
echo "RELEASE_BODY<<EOF" >> "$GITHUB_ENV"
echo "$BODY" >> "$GITHUB_ENV"
echo "EOF" >> "$GITHUB_ENV"
echo "IS_PRERELEASE=$([ "$CHANNEL" = "stable" ] && echo false || echo true)" >> "$GITHUB_ENV"
- name: Build des projets .NET (sans docker)
# L'image runner (pazof/yavsc-build-env) a le SDK .NET 10 + le
# workload Android, mais PAS le binaire `docker` ni de daemon
# Docker. On exécute donc les commandes dotnet directement
# au lieu de passer par `docker build`.
# Equivalent des stages build-env du Dockerfile (lignes
# restore + build Yavsc.Org + build Yavsc.Api + build
# Yavsc.Blogs + build PostIt.Android -r android-arm64).
run: |
cd /src/_src
dotnet restore
dotnet build src/Yavsc.Org/Yavsc.Org.csproj -c Release --no-restore -clp:ErrorsOnly
dotnet build src/Yavsc.Api/Yavsc.Api.csproj -c Release --no-restore -clp:ErrorsOnly
dotnet build src/Yavsc.Blogs/Yavsc.Blogs.csproj -c Release --no-restore -clp:ErrorsOnly
dotnet build src/PostIt/PostIt.Android/PostIt.Android.csproj \
-c Release --no-restore -clp:ErrorsOnly -r android-arm64
- name: Copier l'APK signé vers un emplacement connu
# Le build Android avec -r android-arm64 produit l'APK dans
# bin/Release/net10.0-android/android-arm64/. On le copie à
# la racine du checkout pour que l'étape d'upload le trouve.
run: |
cd /src/_src
APK=src/PostIt/PostIt.Android/bin/Release/net10.0-android/android-arm64/com.CompanyName.PostIt-Signed.apk
if [[ ! -f "$APK" ]]; then
echo "::error::APK not found at $APK"
ls -la src/PostIt/PostIt.Android/bin/Release/net10.0-android/ 2>/dev/null || true
exit 1
fi
cp "$APK" /src/_src/PostIt.Android.apk
ls -la /src/_src/PostIt.Android.apk
- name: Publier la release Forgejo via l'API REST
# Pas d'action tierce (pas de Node dans l'image runner).
# On parle à l'API Forgejo directement via curl.
# Docs : https://forgejo.pschneider.fr/api/swagger#/repository/release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_API_URL: ${{ github.api_url }}
GITHUB_REPOSITORY: ${{ github.repository }}
TAG: ${{ github.event_name == 'push' && github.ref_name || inputs.tag }}
RELEASE_BODY: ${{ env.RELEASE_BODY }}
IS_PRERELEASE: ${{ env.IS_PRERELEASE }}
run: |
if [[ -z "$TAG" ]]; then
echo "::error::No tag resolved for the API call."
exit 1
fi
# Le runner Forgejo expose l'API sur github.api_url (par
# défaut http://…/api/v1). On retire le suffixe /api/v1 s'il
# est présent pour dériver la base du serveur, puis on
# reconstruit l'URL de l'API proprement.
API_BASE="${GITHUB_API_URL%/}"
API_BASE="${API_BASE%/api/v1}"
# Construction des bodies JSON et extraction de champs via
# jq. L'image runner pazof/yavsc-build-env installe jq
# (>= 1.7) depuis debian12-dotnet10-android36-v2. La
# chaîne de construction --arg/--argjson garantit un
# escaping correct (backslashes, guillemets, newlines,
# caractères de contrôle Unicode) sans avoir à le
# reproduire à la main.
#
# json_escape et json_field à base de sed ont vécu : le
# sed greedy matche la dernière occurrence d'un champ
# dans la ligne, et l'API renvoie sur cette instance un
# JSON minifié d'une seule ligne où l'id de l'auteur
# (1, premier user du repo) suit l'id de la release
# (10706). PATCH /releases/<sed-captured-id> tombait
# alors en 404 "The target couldn't be found". jq
# résout les deux problèmes en une fois.
# 1. Vérifier si la release existe déjà pour ce tag.
echo "::group::Check existing release for tag $TAG"
HTTP=$(curl -sS -o /tmp/existing.json -w '%{http_code}' \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/json" \
"$API_BASE/api/v1/repos/$GITHUB_REPOSITORY/releases/tags/$TAG")
echo "GET releases/tags/$TAG -> HTTP $HTTP"
EXISTING_ID=""
if [[ "$HTTP" == "200" ]]; then
EXISTING_ID=$(jq -r '.id // empty' /tmp/existing.json)
echo "Existing release id: ${EXISTING_ID:-none}"
fi
echo "::endgroup::"
# 2. Créer ou mettre à jour la release.
if [[ -n "$EXISTING_ID" ]]; then
echo "::group::Update release id=$EXISTING_ID"
jq -n \
--arg body "$RELEASE_BODY" \
--argjson prerelease "$IS_PRERELEASE" \
'{body: $body, prerelease: $prerelease}' \
> /tmp/patch.json
HTTP=$(curl -sS -o /tmp/release.json -w '%{http_code}' \
-X PATCH \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
--data-binary @/tmp/patch.json \
"$API_BASE/api/v1/repos/$GITHUB_REPOSITORY/releases/$EXISTING_ID")
echo "PATCH release -> HTTP $HTTP"
echo "::endgroup::"
else
echo "::group::Create release"
jq -n \
--arg tag "$TAG" \
--arg name "$TAG" \
--arg body "$RELEASE_BODY" \
--argjson prerelease "$IS_PRERELEASE" \
'{tag_name: $tag, name: $name, body: $body, prerelease: $prerelease}' \
> /tmp/post.json
HTTP=$(curl -sS -o /tmp/release.json -w '%{http_code}' \
-X POST \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
--data-binary @/tmp/post.json \
"$API_BASE/api/v1/repos/$GITHUB_REPOSITORY/releases")
echo "POST release -> HTTP $HTTP"
echo "::endgroup::"
fi
if [[ "$HTTP" != "200" && "$HTTP" != "201" ]]; then
echo "::error::Release creation/update failed (HTTP $HTTP):"
cat /tmp/release.json
exit 1
fi
RELEASE_ID=$(jq -r '.id' /tmp/release.json)
echo "Release id=$RELEASE_ID"
# 3. Upload l'APK en asset.
# Le nom du fichier passe en query string (?name=...), pas
# en argument positionnel entre --data-binary et l'URL :
# sinon curl l'interprète comme un second fichier d'input
# (un fichier nommé '?name=PostIt.Android.apk') et l'API
# Forgejo renvoie 400 "Missing 'name' parameter".
echo "::group::Upload APK asset"
HTTP=$(curl -sS -o /tmp/asset.json -w '%{http_code}' \
-X POST \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Content-Type: application/octet-stream" \
-H "Accept: application/json" \
--data-binary "@/src/_src/PostIt.Android.apk" \
"$API_BASE/api/v1/repos/$GITHUB_REPOSITORY/releases/$RELEASE_ID/assets?name=PostIt.Android.apk")
echo "POST asset -> HTTP $HTTP"
echo "::endgroup::"
if [[ "$HTTP" != "201" ]]; then
echo "::error::Asset upload failed (HTTP $HTTP):"
cat /tmp/asset.json
exit 1
fi
echo "Release publiée: $API_BASE/$GITHUB_REPOSITORY/releases/tag/$TAG"

View file

@ -129,12 +129,12 @@ jobs:
exit 1
fi
# Vérification cohérence du canal déclaré dans le suffixe.
# Vérification cohérence du canal déclaré dans le titre de section.
# Format attendu : "## [TAG] - stable" / "- preview" / "- unstable".
if [[ "$BODY" != *" - $CHANNEL"* ]]; then
HEADER=$(grep -m1 "^## \[$TAG\]" CHANGELOG.md)
if [[ "$HEADER" != *" - $CHANNEL"* ]]; then
echo "::error::Section '## [$TAG]' must declare suffix '- $CHANNEL' to match tag parity."
echo "Current section body (first 5 lines):"
echo "$BODY" | head -5
echo "Current section header: $HEADER"
exit 1
fi

View file

@ -31,9 +31,13 @@ pour la production des paquets `.deb`.
### Added
- Self-hosted Forgejo Actions runner now drives the CI build for the
yavsc repository, using the
`pazof/yavsc-build-env:debian12-dotnet10-android36-v1` image pulled
`pazof/yavsc-build-env:debian12-dotnet10-android36-v2` image pulled
from Docker Hub. Workflow runs end-to-end: clone, restore, build,
test, with NuGet.config picking up the `isn.pschneider.fr` feed.
- The build-env image now ships `jq` (Debian package, ≥ 1.7), so the
release workflow can build JSON bodies and parse API responses
without a hand-rolled `sed`-based extractor that was matching the
wrong `id` field on minified responses.
### Changed
- CI workflow `.forgejo/workflows/buildAndTest.yml` no longer relies on
@ -47,6 +51,12 @@ pour la production des paquets `.deb`.
Actions APK build (`--allow-insecure-connections` on an HTTPS
endpoint, exit 1). `NuGet.config` at the repo root supplies the
`isn.pschneider.fr` feed for every restore, including inside Docker.
- `.forgejo/workflows/release.yml`: PATCH on `/releases/{id}` no longer
404s on existing releases. The previous `sed`-based `json_field`
matched the last `id` on the line (the author's), so it tried to
PATCH `/releases/1` (the first user of the instance) instead of the
actual release id. Switched to `jq` for both body construction and
field extraction.
[Unreleased]: https://github.com/pazof/yavsc/compare/HEAD
[1.0.6]: https://github.com/pazof/yavsc/compare/1.0.5...1.0.6