Rend le job publish-release dépendant d'un nouveau job validate-release qui : - parse le tag (format MAJOR.MINOR.PATCH[-SUFFIX]) - classifie le canal : pair=stable, impair=preview, suffixe=instable - fail-fast sur instable sauf opt-in explicite via workflow_dispatch - vérifie que CHANGELOG.md contient une section ## [<tag>] - <canal> - expose le body de la section via $GITHUB_ENV pour le job de publication Le tag trigger passe de 'v*' à '*' (pas de préfixe sur les tags), et le corps de release GitHub est désormais curé via CHANGELOG.md plutôt que généré automatiquement. Cette convention de parité est partagée avec le dépôt postit-debian pour la production des paquets .deb (alignement à traiter dans une PR séparée).
177 lines
6.7 KiB
YAML
177 lines
6.7 KiB
YAML
name: Build and Push Yavsc Apk
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- main
|
|
tags:
|
|
- '*'
|
|
workflow_dispatch:
|
|
inputs:
|
|
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
|
|
|
|
# softprops/action-gh-release a besoin de contents: write
|
|
# pour publier une release + uploader un asset.
|
|
permissions:
|
|
contents: write
|
|
|
|
jobs:
|
|
apk-deploy:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout du code
|
|
uses: actions/checkout@v7
|
|
|
|
# 1. Votre étape de build actuelle (on nomme l'image "postit-android")
|
|
# --target build-env : on ne veut que le stage de build (qui
|
|
# contient les artefacts .apk). Sans --target, Docker ciblerait
|
|
# le DERNIER stage du Dockerfile (blogs-runtime, qui est une
|
|
# image ASP.NET runtime sans aucun APK à extraire).
|
|
- name: Build de l'image Docker
|
|
run: docker build --build-arg ANDROID_TARGET_RID=android-arm64 --target build-env -t postit-android .
|
|
# 2. EXTRACTION : Créer un conteneur éphémère pour copier l'APK vers l'hôte GitHub
|
|
- name: Extraire l'APK du conteneur Docker
|
|
run: |
|
|
docker create --name extractor postit-android
|
|
docker cp extractor:/src/src/PostIt/PostIt.Android/bin/Release/net10.0-android/android-arm64/com.CompanyName.PostIt-Signed.apk ./PostIt.Android.apk
|
|
docker rm extractor
|
|
|
|
- name: Téléverser l'APK en tant qu'Artéfact GitHub
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: application-apk-release
|
|
path: ./PostIt.Android.apk
|
|
retention-days: 7
|
|
|
|
# Job de validation : parse le tag, vérifie le format, applique la règle
|
|
# de parité du patch (pair=stable / impair=preview / suffixe=instable),
|
|
# et s'assure que CHANGELOG.md contient une section cohérente.
|
|
# Sans ce job, le job publish-release peut être bypassé (un attaquant
|
|
# qui contrôle un tag ne peut pas publier de release sans une section
|
|
# changelog cohérente).
|
|
validate-release:
|
|
if: startsWith(github.ref, 'refs/tags/')
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout du code
|
|
uses: actions/checkout@v7
|
|
|
|
- name: Valider le tag et la section CHANGELOG
|
|
env:
|
|
FORCE_UNSTABLE: ${{ inputs.force_unstable || github.event.inputs.force_unstable || 'false' }}
|
|
run: |
|
|
TAG="${GITHUB_REF_NAME}"
|
|
|
|
# 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 via workflow_dispatch.
|
|
if [[ "$CHANNEL" == "unstable" && "$FORCE_UNSTABLE" != "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.
|
|
BODY=$(awk -v tag="[$TAG]" '
|
|
/^## \[/ {
|
|
if (in_section) exit
|
|
if (index($0, tag) > 0) in_section=1
|
|
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".
|
|
if [[ "$BODY" != *" - $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
|
|
exit 1
|
|
fi
|
|
|
|
echo "Section CHANGELOG validée pour [$TAG] - $CHANNEL"
|
|
|
|
# Exposition aux étapes suivantes via $GITHUB_ENV.
|
|
# heredoc <<EOF pour le body multi-lignes (pattern GitHub Actions).
|
|
{
|
|
echo "RELEASE_BODY<<EOF"
|
|
echo "$BODY"
|
|
echo "EOF"
|
|
echo "RELEASE_CHANNEL=$CHANNEL"
|
|
if [[ "$CHANNEL" == "stable" ]]; then
|
|
echo "IS_PRERELEASE=false"
|
|
else
|
|
echo "IS_PRERELEASE=true"
|
|
fi
|
|
} >> "$GITHUB_ENV"
|
|
|
|
publish-release:
|
|
# Déclenché uniquement par un push de tag. Le job apk-deploy produit
|
|
# l'artefact ; validate-release garantit la cohérence du tag et du
|
|
# changelog avant publication.
|
|
if: startsWith(github.ref, 'refs/tags/')
|
|
needs: [apk-deploy, validate-release]
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Récupérer l'APK depuis l'artefact
|
|
uses: actions/download-artifact@v7
|
|
with:
|
|
name: application-apk-release
|
|
path: ./
|
|
|
|
- name: Publier la release GitHub et uploader l'APK
|
|
uses: softprops/action-gh-release@v2
|
|
with:
|
|
# Le nom de fichier final dans la release. C'est ce qui
|
|
# apparaîtra dans l'asset et donc dans le permalink :
|
|
# https://github.com/<owner>/<repo>/releases/latest/download/PostIt.Android.apk
|
|
files: ./PostIt.Android.apk
|
|
# Le body est extrait de la section CHANGELOG.md correspondant
|
|
# au tag, exposée par validate-release via $GITHUB_ENV.
|
|
body: ${{ env.RELEASE_BODY }}
|
|
# stable -> false (marque comme Latest).
|
|
# preview / unstable -> true (visible mais pas Latest).
|
|
prerelease: ${{ env.IS_PRERELEASE }}
|