feat/release-page #1

Merged
notazof merged 6 commits from feat/release-page into main 2026-08-17 16:10:54 +01:00
2 changed files with 329 additions and 289 deletions
Showing only changes of commit e6fd22f8a1 - Show all commits

switch release workflow from GitHub Actions to Forgejo Actions
Some checks failed
release.yml / switch release workflow from GitHub Actions to Forgejo Actions (push) Failing after 0s
release.yml / switch release workflow from GitHub Actions to Forgejo Actions (pull_request) Failing after 0s

The GitHub channel gave nothing but chaos (failed runs on tag push,
auth issues with gh CLI on this side). Forgejo is the source of
truth (cf. USER.md 'Remote setup' for the yavsc mirror setup), so
move the .deb release workflow there.

- Remove .github/workflows/build-and-release-deb.yml.
- Add .forgejo/workflows/release.yml, mirroring the structure of
  yavsc/.forgejo/workflows/release.yml (single job, no Node, bash
  + jq + curl). amd64 and arm64 .deb built sequentially (matrix
  is impossible because actions/upload-artifact needs Node, which
  the runner image pazof/yavsc-build-env doesn't ship — same
  constraint as documented in MEMORY.md).
- Reuse existing release on tag collision (PATCH instead of POST)
  to keep the /releases/tag/<tag> permalink stable — re-tag = le
  mal, but a re-build of the same tag should not duplicate releases.
Paul Schneider 2026-08-17 15:28:39 +01:00
No known key found for this signature in database
GPG key ID: 1E66C65EE2B46F1B

View file

@ -0,0 +1,329 @@
# Build and publish a postit-debian release on the Forgejo instance.
#
# Triggered by a push of a git tag. Validates the tag/changelog pair,
# builds the .deb for amd64 and arm64 (sequential cross-RID .NET
# publishes on a single amd64 runner container — matrix is not used
# here because the runner image pazof/yavsc-build-env has no Node,
# so actions/upload-artifact and actions/download-artifact (which
# require Node) cannot be used to pass the .deb files between jobs.
# All in one job, like yavsc's .forgejo/workflows/release.yml.),
# then publishes a Forgejo release via the REST API and uploads both
# .deb files as assets.
#
# 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, actions/upload-artifact,
# actions/download-artifact, etc. fails with "executable file not
# found in $PATH". Same constraint as yavsc's
# .forgejo/workflows/release.yml.
#
# Re-tag policy (cf. AGENTS.md "Re-tag = le mal") : on push de tag
# ou dispatch, on *réutilise* la release existante (via PATCH) au
# lieu d'en créer une nouvelle. Un tag Git pointe vers un commit
# fixe ; si le binaire change (rebuild après modif du packaging),
# on met à jour la release existante plutôt que d'en multiplier
# pour un même tag. Le permalien /releases/tag/<tag> reste stable.
name: Forgejo Release postit-deb
on:
push:
tags:
- '*'
workflow_dispatch:
inputs:
tag:
description: 'Tag pazof/yavsc à packager (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 amd64 + build
# arm64 + publication via l'API REST Forgejo (pas d'actions
# tierces Node).
release:
runs-on: docker
container:
image: docker.io/pazof/yavsc-build-env:debian12-dotnet10-android36-v2
steps:
- name: Installer les pré-requis de build (debhelper + icônes)
# L'image runner fournit déjà dotnet-sdk-10.0, git, jq,
# curl. On ajoute les outils spécifiques au packaging
# Debian (debhelper, imagemagick pour les icônes .png
# via `convert`, librsvg2-bin pour le SVG).
run: |
apt-get update
apt-get install -y --no-install-recommends \
build-essential debhelper imagemagick librsvg2-bin \
ca-certificates
rm -rf /var/lib/apt/lists/*
- name: Clone du repo au tag demandé
env:
TAG: ${{ github.event_name == 'push' && github.ref_name || inputs.tag }}
run: |
if [[ -z "$TAG" ]]; then
echo "::error::No tag provided. In workflow_dispatch, set the 'tag' input."
exit 1
fi
cd /src
if [[ ! -d _src/.git ]]; then
# Clone unshallow pour préserver l'historique — utile
# si un futur test en a besoin. Le coût est marginal
# pour ce repo (< 50 commits).
git clone https://forgejo.pschneider.fr/notazof/postit-debian.git _src
fi
cd _src
git fetch --tags --force --prune origin
git checkout "$TAG"
echo "Checked out at $(git rev-parse HEAD) on tag $TAG"
- 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.
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 garde le titre
# (ligne `## [TAG] - channel`) pour la vérification du
# canal, puis on l'exclut du body envoyé à la release.
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 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
RELEASE_BODY=$(echo "$BODY" | tail -n +2)
IS_PRERELEASE=$([ "$CHANNEL" = "stable" ] && echo false || echo true)
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 "$RELEASE_BODY" >> "$GITHUB_ENV"
echo "EOF" >> "$GITHUB_ENV"
echo "IS_PRERELEASE=$IS_PRERELEASE" >> "$GITHUB_ENV"
- name: Build .deb amd64
env:
POSTIT_GIT_TAG: ${{ github.event_name == 'push' && github.ref_name || inputs.tag }}
POSTIT_RUNTIME: linux-x64
run: |
cd /src/_src
echo "→ Building amd64 for POSTIT_GIT_TAG=$POSTIT_GIT_TAG"
make deb POSTIT_GIT_TAG="$POSTIT_GIT_TAG" POSTIT_RUNTIME=linux-x64
- name: Build .deb arm64
env:
POSTIT_GIT_TAG: ${{ github.event_name == 'push' && github.ref_name || inputs.tag }}
POSTIT_RUNTIME: linux-arm64
run: |
cd /src/_src
echo "→ Building arm64 for POSTIT_GIT_TAG=$POSTIT_GIT_TAG"
# Cross-RID .NET depuis un hôte amd64 : standard, pas
# besoin de runner arm64 natif.
make deb POSTIT_GIT_TAG="$POSTIT_GIT_TAG" POSTIT_RUNTIME=linux-arm64
- name: Localiser les .deb produits
env:
LOOKUP_TAG: ${{ github.event_name == 'push' && github.ref_name || inputs.tag }}
run: |
cd /src
DEB_AMD64=$(find . -maxdepth 3 -name "postit_*${LOOKUP_TAG}-1_amd64.deb" \
-not -path "./_src/debian/*" -printf '%p\n' | head -1)
DEB_ARM64=$(find . -maxdepth 3 -name "postit_*${LOOKUP_TAG}-1_arm64.deb" \
-not -path "./_src/debian/*" -printf '%p\n' | head -1)
if [[ -z "$DEB_AMD64" || -z "$DEB_ARM64" ]]; then
echo "::error::Missing .deb files. amd64='$DEB_AMD64' arm64='$DEB_ARM64'"
ls -la /src/ 2>/dev/null || true
exit 1
fi
echo "DEB_AMD64=/src/$DEB_AMD64" >> "$GITHUB_ENV"
echo "DEB_ARM64=/src/$DEB_ARM64" >> "$GITHUB_ENV"
echo "✓ Found both .deb files"
- name: Publier la release Forgejo via l'API REST
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}"
# 1. Vérifier si la release existe déjà pour ce tag.
# Politique : on réutilise (PATCH) plutôt que d'en
# créer une nouvelle — cf. note "Re-tag policy" en
# tête de fichier.
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 les .deb en assets. Le nom du fichier passe
# en query string (?name=...), pas en argument
# positionnel entre --data-binary et l'URL.
for entry in "amd64:$DEB_AMD64" "arm64:$DEB_ARM64"; do
arch="${entry%%:*}"
deb="${entry#*:}"
echo "::group::Upload asset for arch=$arch: $deb"
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 "@$deb" \
"$API_BASE/api/v1/repos/$GITHUB_REPOSITORY/releases/$RELEASE_ID/assets?name=$(basename "$deb")")
echo "POST asset ($arch) -> HTTP $HTTP"
echo "::endgroup::"
if [[ "$HTTP" != "201" ]]; then
echo "::error::Asset upload failed for $arch (HTTP $HTTP):"
cat /tmp/asset.json
exit 1
fi
done
echo "Release publiée : $API_BASE/$GITHUB_REPOSITORY/releases/tag/$TAG"

View file

@ -1,289 +0,0 @@
name: Build and Release postit-deb
# Ce workflow est destiné à **GitHub Actions uniquement** (paths
# /home/runner/..., ubuntu-latest, softprops/action-gh-release@v2).
# Pour Forgejo Actions (pazof/yavsc-build-env, paths différents,
# pas de Node), il faudrait un pendant dans .forgejo/workflows/ —
# non écrit à ce jour.
on:
push:
branches:
- main
tags:
- '*'
workflow_dispatch:
inputs:
tag:
description: 'Tag de pazof/yavsc à packager (ex. 1.0.6, 1.0.7-rc1). Requis pour un build ad-hoc.'
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
force_republish:
description: 'Re-publier une release dont le tag existe déjà. Par défaut refusé (re-tag = le mal).'
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:
# Build matrix : un .deb par architecture. Le tag Git poussé sur
# ce dépôt devient POSTIT_GIT_TAG pour `make deb`, qui clone
# l'amont pazof/yavsc à ce tag et produit le .deb correspondant.
# Sur amd64, la cross-compilation linux-arm64 marche nativement
# (dotnet publish --runtime linux-arm64 depuis un hôte amd64).
# On évite donc les runners arm64 natifs (qui existent mais sont
# récents et plus chers en minutes).
deb-build:
name: Build .deb (${{ matrix.runtime }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- runtime: linux-x64
arch: amd64
artifact_name: postit-amd64
- runtime: linux-arm64
arch: arm64
artifact_name: postit-arm64
steps:
- name: Checkout postit-debian
uses: actions/checkout@v7
with:
fetch-depth: 0
fetch-tags: true
- name: Installer les pré-requis de build (debhelper + icônes)
run: |
sudo apt-get update
sudo apt-get install -y \
build-essential debhelper imagemagick librsvg2-bin \
git ca-certificates
- name: Installer .NET SDK 10
uses: microsoft/setup-dotnet@v4
with:
dotnet-version: '10.0.x'
- name: Déterminer POSTIT_GIT_TAG
id: tag
run: |
# Sur un push de branche (pas un tag), github.ref_name est
# 'main' — `make deb POSTIT_GIT_TAG=main` clone pazof/yavsc
# sur la branche main et produit un .deb à jour. Sur un push
# de tag, c'est le numéro de tag (ex. '1.0.6'). Sur
# workflow_dispatch, on lit l'input `tag`.
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
TAG="${{ inputs.tag }}"
else
TAG="${{ github.ref_name }}"
fi
if [[ -z "$TAG" ]]; then
echo "::error::POSTIT_GIT_TAG is empty. Pour workflow_dispatch, l'input 'tag' est obligatoire."
exit 1
fi
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
echo "→ POSTIT_GIT_TAG=$TAG"
- name: Build du .deb via make deb
env:
POSTIT_GIT_TAG: ${{ steps.tag.outputs.tag }}
POSTIT_RUNTIME: ${{ matrix.runtime }}
run: |
echo "→ Building for POSTIT_GIT_TAG=$POSTIT_GIT_TAG POSTIT_RUNTIME=$POSTIT_RUNTIME"
make deb POSTIT_GIT_TAG="$POSTIT_GIT_TAG" POSTIT_RUNTIME="$POSTIT_RUNTIME"
- name: Localiser le .deb produit
id: locate
run: |
# Le Makefile mv les .deb vers $POSTIT_OUT_DIR (par défaut
# le répertoire parent du repo). Sur GitHub Actions, c'est
# le workspace parent : /home/runner/work/.. Le .deb est
# nommé d'après le tag brut (avec ou sans 'v', tel quel
# poussé sur le remote), on cherche donc avec ref_name.
DEB=$(find /home/runner -maxdepth 4 -name "postit_*${{ github.ref_name }}-1_${{ matrix.arch }}.deb" \
-not -path "*/debian/*" \
-printf '%p\n' | head -1)
if [[ -z "$DEB" ]]; then
echo "::error::No .deb matching postit_*${{ github.ref_name }}-1_${{ matrix.arch }}.deb found."
echo "Files in parent dir:"
ls -la /home/runner/work/ 2>/dev/null || true
exit 1
fi
echo "deb_path=$DEB" >> "$GITHUB_OUTPUT"
echo "✓ Found $DEB"
- name: Téléverser le .deb en tant qu'Artéfact GitHub
uses: actions/upload-artifact@v7
with:
name: ${{ matrix.artifact_name }}
path: ${{ steps.locate.outputs.deb_path }}
retention-days: 7
# Validation : parse le tag, applique la parité patch (pair=stable /
# impair=preview / suffixe=instable), vérifie que CHANGELOG.md
# contient une section cohérente, et — point non négociable —
# refuse de re-publier un tag qui existe déjà (re-tag = le mal).
validate-release:
# Tourne sur push de tag (release officielle) ou sur workflow_dispatch
# avec un tag explicite (release ad-hoc). Sur push de branche, on
# ne publie pas — les jobs de build suffisent (artefacts seulement).
if: startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
steps:
- name: Checkout postit-debian
uses: actions/checkout@v7
with:
fetch-depth: 0
fetch-tags: true
- name: Déterminer le tag à publier
id: pick_tag
run: |
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
TAG="${{ inputs.tag }}"
else
TAG="${{ github.ref_name }}"
fi
if [[ -z "$TAG" ]]; then
echo "::error::Tag is empty. Sur workflow_dispatch, l'input 'tag' est obligatoire."
exit 1
fi
# Strip leading 'v' (git tag convention).
if [[ "$TAG" =~ ^v(.*)$ ]]; then
TAG="${BASH_REMATCH[1]}"
echo "Stripped leading 'v' — using TAG=$TAG for validation."
fi
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
- name: Valider le tag, le CHANGELOG et l'unicité du tag
env:
FORCE_UNSTABLE: ${{ inputs.force_unstable || github.event.inputs.force_unstable || 'false' }}
FORCE_REPUBLISH: ${{ inputs.force_republish || github.event.inputs.force_republish || 'false' }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG="${{ steps.pick_tag.outputs.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.
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" != "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]. awk en mode paragraphe.
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é.
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 header: $HEADER"
exit 1
fi
echo "Section CHANGELOG validée pour [$TAG] - $CHANNEL"
# Anti-re-tag : refuse de publier si une release existe déjà
# pour ce tag. softprops/action-gh-release créerait sinon une
# nouvelle release par-dessus (re-tag = le mal). Opt-in via
# workflow_dispatch + force_republish=true uniquement.
if gh release view "$TAG" >/dev/null 2>&1; then
if [[ "$FORCE_REPUBLISH" != "true" ]]; then
echo "::error::Release for tag '$TAG' already exists. Refusing to re-tag."
echo "Set force_republish=true via workflow_dispatch to override."
exit 1
else
echo "::warning::Release '$TAG' already exists — force_republish=true, proceeding."
fi
else
echo "✓ No existing release for tag '$TAG'."
fi
# Exposition aux étapes suivantes via $GITHUB_ENV.
{
echo "RELEASE_BODY<<EOF"
echo "$BODY"
echo "EOF"
echo "RELEASE_TAG=$TAG"
echo "RELEASE_CHANNEL=$CHANNEL"
if [[ "$CHANNEL" == "stable" ]]; then
echo "IS_PRERELEASE=false"
else
echo "IS_PRERELEASE=true"
fi
} >> "$GITHUB_ENV"
publish-release:
if: startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch'
needs: [deb-build, validate-release]
runs-on: ubuntu-latest
steps:
- name: Récupérer les .deb depuis les artefacts
uses: actions/download-artifact@v7
with:
path: ./
merge-multiple: true
- name: Lister les .deb téléchargés
run: ls -la ./
- name: Publier la release GitHub et uploader les .deb
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ env.RELEASE_TAG }}
files: |
./postit-amd64/*.deb
./postit-arm64/*.deb
body: ${{ env.RELEASE_BODY }}
prerelease: ${{ env.IS_PRERELEASE }}