diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 21c6ef9..c2ce5e3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -135,7 +135,10 @@ jobs: release: name: Publish release archives - if: startsWith(github.ref, 'refs/tags/v') + # PR builds never receive release write permissions. + if: >- + github.event_name != 'pull_request' && + (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')) needs: package runs-on: ubuntu-24.04 permissions: @@ -153,8 +156,35 @@ jobs: shell: bash run: | set -euo pipefail - if gh release view "$GITHUB_REF_NAME" >/dev/null 2>&1; then - gh release upload "$GITHUB_REF_NAME" release-artifacts/* --clobber + prerelease=true + latest=false + if [[ "$GITHUB_REF" == refs/tags/v* ]]; then + tag="$GITHUB_REF_NAME" + title="Apeiron $tag" + tag_args=(--verify-tag) + # Only a complete version without a prerelease suffix is stable. + if [[ "$tag" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(\+[0-9A-Za-z.-]+)?$ ]]; then + prerelease=false + latest=true + fi else - gh release create "$GITHUB_REF_NAME" release-artifacts/* --verify-tag --generate-notes + # One immutable tag per run; retries reuse it, never move a tag. + tag="preview-${GITHUB_RUN_ID}" + title="Apeiron preview #${GITHUB_RUN_NUMBER}" + tag_args=(--target "$GITHUB_SHA") fi + shopt -s nullglob + assets=(release-artifacts/*.zip release-artifacts/*.tar.gz) + # All three platform archives must exist before creating a release. + test "${#assets[@]}" -eq 3 || { echo "expected three platform archives"; exit 1; } + if gh release view "$tag" >/dev/null 2>&1; then + gh release upload "$tag" "${assets[@]}" --clobber + else + gh release create "$tag" "${assets[@]}" "${tag_args[@]}" \ + --title "$title" --generate-notes --draft \ + --prerelease="$prerelease" --latest="$latest" + fi + # Publish only after every asset upload succeeds; also recover drafts + # left by an interrupted previous attempt. + gh release edit "$tag" --draft=false \ + --prerelease="$prerelease" --latest="$latest" diff --git a/docs/BUILDING.md b/docs/BUILDING.md index 77490e3..c8cfebb 100644 --- a/docs/BUILDING.md +++ b/docs/BUILDING.md @@ -108,3 +108,24 @@ architecture and checks it before compiling, so archive names match the executab ARM64 manual jobs may still queue when GitHub has insufficient capacity. Runner labels: https://docs.github.com/en/actions/reference/runners/github-hosted-runners + + +## Automatic releases + +After all three Build jobs compile, self-check and upload their archives: + +- A push to `main` publishes a **Pre-release** named `Apeiron preview #N`, + using a unique `preview-` tag pointing at the exact built commit. +- A tag such as `v1.2.3-beta.1` or `v1.2.3-rc.1` publishes a **Pre-release**. +- A complete version tag such as `v1.2.3` publishes a stable release and marks + it as Latest. Other `v*` tags are conservatively treated as previews. +- Manual Build runs publish previews on `main`, or the corresponding release + when run against a `v*` tag. Manual builds on other branches only upload + Actions artifacts. PR builds never publish releases. + +Preview releases do not replace the Latest stable release. New releases stay +in draft until all assets upload successfully; rerunning the same workflow run +reuses its tag and can finish an interrupted draft. No existing tag is moved. +The release job requires all three package jobs to succeed. Download the archives +from the repository's Releases page; Actions artifacts remain available for +14 days as well. This automation takes effect after the workflow change merges.