304 lines
14 KiB
YAML
304 lines
14 KiB
YAML
name: Release (Stable)
|
|
|
|
on:
|
|
push:
|
|
tags:
|
|
- 'stable-v*'
|
|
- 'v20*'
|
|
|
|
concurrency:
|
|
group: release-stable-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
# ─────────────────────────────────────────────────────────────
|
|
# Phase 1: Compute the stable version string once
|
|
# ─────────────────────────────────────────────────────────────
|
|
version:
|
|
name: Compute stable version
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
version: ${{ steps.ver.outputs.version }}
|
|
display_version: ${{ steps.ver.outputs.display_version }}
|
|
tag: ${{ steps.ver.outputs.tag }}
|
|
steps:
|
|
- id: ver
|
|
shell: bash
|
|
run: |
|
|
python3 <<'PY' > version.env
|
|
import os
|
|
import re
|
|
from datetime import date
|
|
|
|
tag = os.environ["GITHUB_REF_NAME"]
|
|
legacy_match = re.fullmatch(r"stable-v(\d{4})\.(\d{1,2})\.(\d{1,2})", tag)
|
|
date_match = re.fullmatch(r"v(\d{4})-(\d{2})-(\d{2})", tag)
|
|
|
|
if date_match:
|
|
year, month, day = map(int, date_match.groups())
|
|
date(year, month, day)
|
|
version = f"{year}.{month}.{day}"
|
|
display_version = tag
|
|
elif legacy_match:
|
|
year, month, day = map(int, legacy_match.groups())
|
|
date(year, month, day)
|
|
version = f"{year}.{month}.{day}"
|
|
display_version = version
|
|
else:
|
|
raise SystemExit(f"Stable tags must use vYYYY-MM-DD or stable-vYYYY.M.D, got {tag}")
|
|
|
|
print(f"version={version}")
|
|
print(f"display_version={display_version}")
|
|
print(f"tag={tag}")
|
|
PY
|
|
|
|
cat version.env >> "$GITHUB_OUTPUT"
|
|
DISPLAY_VERSION=$(grep '^display_version=' version.env | cut -d= -f2-)
|
|
echo "### Stable version: \`$DISPLAY_VERSION\`" >> "$GITHUB_STEP_SUMMARY"
|
|
|
|
# -------------------------------------------------------------
|
|
# Phase 2: Build shared release artifacts
|
|
# -------------------------------------------------------------
|
|
build-artifacts:
|
|
name: Build release artifacts
|
|
needs: version
|
|
uses: ./.github/workflows/release-build-artifacts.yml
|
|
with:
|
|
version: ${{ needs.version.outputs.version }}
|
|
macos_bundles: ""
|
|
upload_macos_dmg: true
|
|
# One-time stable promotion exceptions while Windows certificate secrets
|
|
# are still being provisioned. Future stable tags must keep Authenticode.
|
|
require_windows_authenticode: ${{ !contains(fromJson('["v2026-06-01","v2026-06-06"]'), needs.version.outputs.tag) }}
|
|
secrets: inherit
|
|
|
|
# ─────────────────────────────────────────────────────────────
|
|
# Phase 3: Publish GitHub Release
|
|
# ─────────────────────────────────────────────────────────────
|
|
release:
|
|
name: GitHub Release (stable)
|
|
needs: [version, build-artifacts]
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: write
|
|
pages: write
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Download all artifacts
|
|
uses: actions/download-artifact@v4
|
|
|
|
- name: Normalize macOS release artifact names
|
|
run: |
|
|
normalize_macos_artifacts() {
|
|
local arch="$1"
|
|
local normalized_updater="$2"
|
|
local normalized_dmg="$3"
|
|
local updater_dir="updater-${arch}"
|
|
local updater_file
|
|
updater_file=$(find "$updater_dir" -maxdepth 1 -name "*.app.tar.gz" -print -quit)
|
|
if [ -z "$updater_file" ]; then
|
|
echo "::error::Missing macOS updater artifact in ${updater_dir}" >&2
|
|
return 1
|
|
fi
|
|
|
|
local sig_file="${updater_file}.sig"
|
|
if [ ! -f "$sig_file" ]; then
|
|
echo "::error::Missing macOS updater signature for ${updater_file}" >&2
|
|
return 1
|
|
fi
|
|
|
|
local normalized_sig="${normalized_updater}.sig"
|
|
if [ "$updater_file" != "$normalized_updater" ]; then
|
|
mv "$updater_file" "$normalized_updater"
|
|
fi
|
|
if [ "$sig_file" != "$normalized_sig" ]; then
|
|
mv "$sig_file" "$normalized_sig"
|
|
fi
|
|
|
|
local dmg_dir="dmg-${arch}"
|
|
local dmg_file
|
|
dmg_file=$(find "$dmg_dir" -maxdepth 1 -name "*.dmg" -print -quit)
|
|
if [ -z "$dmg_file" ]; then
|
|
echo "::error::Missing macOS DMG artifact in ${dmg_dir}" >&2
|
|
return 1
|
|
fi
|
|
|
|
if [ "$dmg_file" != "$normalized_dmg" ]; then
|
|
mv "$dmg_file" "$normalized_dmg"
|
|
fi
|
|
}
|
|
|
|
normalize_macos_artifacts aarch64 \
|
|
"updater-aarch64/Tolaria_${{ needs.version.outputs.version }}_macOS_Silicon.app.tar.gz" \
|
|
"dmg-aarch64/Tolaria_${{ needs.version.outputs.version }}_macOS_Silicon.dmg"
|
|
normalize_macos_artifacts x86_64 \
|
|
"updater-x86_64/Tolaria_${{ needs.version.outputs.version }}_macOS_Intel.app.tar.gz" \
|
|
"dmg-x86_64/Tolaria_${{ needs.version.outputs.version }}_macOS_Intel.dmg"
|
|
|
|
- name: Generate release notes
|
|
run: |
|
|
NOTES_FILE="release-notes/${{ needs.version.outputs.tag }}.md"
|
|
if [ -f "$NOTES_FILE" ]; then
|
|
cat "$NOTES_FILE" > release_notes.md
|
|
else
|
|
PREV_TAG=$(git for-each-ref --sort=-creatordate --format='%(refname:short)' refs/tags/v20* refs/tags/stable-v* | grep -vx "${{ needs.version.outputs.tag }}" | head -n 1 || echo "")
|
|
if [ -z "$PREV_TAG" ]; then
|
|
NOTES=$(git log --oneline --no-merges -20)
|
|
else
|
|
NOTES=$(git log --oneline --no-merges "${PREV_TAG}..${{ needs.version.outputs.tag }}")
|
|
fi
|
|
{
|
|
echo "## What's Changed"
|
|
echo ""
|
|
echo "$NOTES" | while IFS= read -r line; do echo "- $line"; done
|
|
} > release_notes.md
|
|
fi
|
|
{
|
|
echo ""
|
|
echo "---"
|
|
echo "**Stable release — manually promoted from \`main\`**"
|
|
echo ""
|
|
echo "**Includes macOS (Apple Silicon and Intel), Windows x64, and Linux x64 bundles**"
|
|
echo ""
|
|
echo "*Built from \`$(git rev-parse --short ${{ needs.version.outputs.tag }})\` on $(date -u +%Y-%m-%d)*"
|
|
} >> release_notes.md
|
|
|
|
- name: Build stable-latest.json
|
|
run: |
|
|
VERSION="${{ needs.version.outputs.version }}"
|
|
TAG="${{ needs.version.outputs.tag }}"
|
|
REPO="${GITHUB_REPOSITORY}"
|
|
REPO_NAME="${REPO#*/}"
|
|
PAGES_URL="https://refactoringhq.github.io/${REPO_NAME}/"
|
|
|
|
find_required() {
|
|
local patterns=("$@")
|
|
for pattern in "${patterns[@]}"; do
|
|
set -- $pattern
|
|
if [ -e "$1" ]; then
|
|
printf '%s\n' "$1"
|
|
return 0
|
|
fi
|
|
done
|
|
echo "::error::Missing required artifact matching one of: ${patterns[*]}" >&2
|
|
return 1
|
|
}
|
|
|
|
ARM_SIG_FILE=$(find_required "updater-aarch64/*.app.tar.gz.sig")
|
|
ARM_UPDATER_FILE="${ARM_SIG_FILE%.sig}"
|
|
ARM_SIG=$(cat "$ARM_SIG_FILE")
|
|
ARM_TARBALL=$(basename "$ARM_UPDATER_FILE")
|
|
ARM_DMG=$(basename "$(find_required "dmg-aarch64/*.dmg")")
|
|
|
|
INTEL_SIG_FILE=$(find_required "updater-x86_64/*.app.tar.gz.sig")
|
|
INTEL_UPDATER_FILE="${INTEL_SIG_FILE%.sig}"
|
|
INTEL_SIG=$(cat "$INTEL_SIG_FILE")
|
|
INTEL_TARBALL=$(basename "$INTEL_UPDATER_FILE")
|
|
INTEL_DMG=$(basename "$(find_required "dmg-x86_64/*.dmg")")
|
|
|
|
LINUX_SIG_FILE=$(find_required "linux-x86_64-bundles/*/*.AppImage.sig" "linux-x86_64-bundles/*/*.AppImage.tar.gz.sig" "linux-x86_64-bundles/*/*.deb.sig" "linux-x86_64-bundles/*.AppImage.sig" "linux-x86_64-bundles/*.AppImage.tar.gz.sig" "linux-x86_64-bundles/*.deb.sig")
|
|
LINUX_UPDATER_FILE="${LINUX_SIG_FILE%.sig}"
|
|
LINUX_SIG=$(cat "$LINUX_SIG_FILE")
|
|
LINUX_UPDATER=$(basename "$LINUX_UPDATER_FILE")
|
|
LINUX_DOWNLOAD=$(basename "$(find_required "linux-x86_64-bundles/*/*.AppImage" "linux-x86_64-bundles/*/*.deb" "linux-x86_64-bundles/*/*.AppImage.tar.gz" "linux-x86_64-bundles/*.AppImage" "linux-x86_64-bundles/*.deb" "linux-x86_64-bundles/*.AppImage.tar.gz")")
|
|
|
|
WINDOWS_SIG_FILE=$(find_required "windows-x86_64-bundles/*/*-setup.exe.sig" "windows-x86_64-bundles/*/*.msi.sig" "windows-x86_64-bundles/*/*.nsis.zip.sig" "windows-x86_64-bundles/*/*.msi.zip.sig" "windows-x86_64-bundles/*-setup.exe.sig" "windows-x86_64-bundles/*.msi.sig" "windows-x86_64-bundles/*.nsis.zip.sig" "windows-x86_64-bundles/*.msi.zip.sig")
|
|
WINDOWS_UPDATER_FILE="${WINDOWS_SIG_FILE%.sig}"
|
|
WINDOWS_SIG=$(cat "$WINDOWS_SIG_FILE")
|
|
WINDOWS_UPDATER=$(basename "$WINDOWS_UPDATER_FILE")
|
|
WINDOWS_DOWNLOAD=$(basename "$(find_required "windows-x86_64-bundles/*/*-setup.exe" "windows-x86_64-bundles/*/*.msi" "windows-x86_64-bundles/*/*.nsis.zip" "windows-x86_64-bundles/*/*.msi.zip" "windows-x86_64-bundles/*-setup.exe" "windows-x86_64-bundles/*.msi" "windows-x86_64-bundles/*.nsis.zip" "windows-x86_64-bundles/*.msi.zip")")
|
|
|
|
cat > stable-latest.json << EOF
|
|
{
|
|
"version": "${VERSION}",
|
|
"notes": "Stable release. See ${PAGES_URL} for full release notes.",
|
|
"pub_date": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
|
|
"platforms": {
|
|
"darwin-aarch64": {
|
|
"signature": "${ARM_SIG}",
|
|
"url": "https://github.com/${REPO}/releases/download/${TAG}/${ARM_TARBALL}",
|
|
"dmg_url": "https://github.com/${REPO}/releases/download/${TAG}/${ARM_DMG}"
|
|
},
|
|
"darwin-x86_64": {
|
|
"signature": "${INTEL_SIG}",
|
|
"url": "https://github.com/${REPO}/releases/download/${TAG}/${INTEL_TARBALL}",
|
|
"dmg_url": "https://github.com/${REPO}/releases/download/${TAG}/${INTEL_DMG}"
|
|
},
|
|
"linux-x86_64": {
|
|
"signature": "${LINUX_SIG}",
|
|
"url": "https://github.com/${REPO}/releases/download/${TAG}/${LINUX_UPDATER}",
|
|
"download_url": "https://github.com/${REPO}/releases/download/${TAG}/${LINUX_DOWNLOAD}"
|
|
},
|
|
"windows-x86_64": {
|
|
"signature": "${WINDOWS_SIG}",
|
|
"url": "https://github.com/${REPO}/releases/download/${TAG}/${WINDOWS_UPDATER}",
|
|
"download_url": "https://github.com/${REPO}/releases/download/${TAG}/${WINDOWS_DOWNLOAD}"
|
|
}
|
|
}
|
|
}
|
|
EOF
|
|
echo "stable-latest.json:"; cat stable-latest.json
|
|
|
|
- name: Publish GitHub Release
|
|
uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65
|
|
with:
|
|
tag_name: ${{ needs.version.outputs.tag }}
|
|
name: Tolaria ${{ needs.version.outputs.display_version }}
|
|
body_path: release_notes.md
|
|
draft: false
|
|
prerelease: false
|
|
files: |
|
|
dmg-aarch64/*.dmg
|
|
updater-aarch64/*.app.tar.gz
|
|
updater-aarch64/*.app.tar.gz.sig
|
|
dmg-x86_64/*.dmg
|
|
updater-x86_64/*.app.tar.gz
|
|
updater-x86_64/*.app.tar.gz.sig
|
|
linux-x86_64-bundles/*.deb
|
|
linux-x86_64-bundles/*.deb.sig
|
|
linux-x86_64-bundles/*.rpm
|
|
linux-x86_64-bundles/*.AppImage
|
|
linux-x86_64-bundles/*.AppImage.sig
|
|
linux-x86_64-bundles/*.AppImage.tar.gz
|
|
linux-x86_64-bundles/*.AppImage.tar.gz.sig
|
|
linux-x86_64-bundles/*/*.deb
|
|
linux-x86_64-bundles/*/*.deb.sig
|
|
linux-x86_64-bundles/*/*.rpm
|
|
linux-x86_64-bundles/*/*.AppImage
|
|
linux-x86_64-bundles/*/*.AppImage.sig
|
|
linux-x86_64-bundles/*/*.AppImage.tar.gz
|
|
linux-x86_64-bundles/*/*.AppImage.tar.gz.sig
|
|
windows-x86_64-bundles/*.exe
|
|
windows-x86_64-bundles/*.exe.sig
|
|
windows-x86_64-bundles/*.msi
|
|
windows-x86_64-bundles/*.msi.sig
|
|
windows-x86_64-bundles/*.zip
|
|
windows-x86_64-bundles/*.zip.sig
|
|
windows-x86_64-bundles/*/*.exe
|
|
windows-x86_64-bundles/*/*.exe.sig
|
|
windows-x86_64-bundles/*/*.msi
|
|
windows-x86_64-bundles/*/*.msi.sig
|
|
windows-x86_64-bundles/*/*.zip
|
|
windows-x86_64-bundles/*/*.zip.sig
|
|
stable-latest.json
|
|
|
|
# ─────────────────────────────────────────────────────────────
|
|
# Phase 4: Trigger the main-branch GitHub Pages deployment
|
|
# ─────────────────────────────────────────────────────────────
|
|
pages:
|
|
name: Update docs and release pages
|
|
needs: [version, release]
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
actions: write
|
|
steps:
|
|
- name: Dispatch docs deployment from main
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
gh workflow run deploy-docs.yml --repo ${{ github.repository }} --ref main
|
|
echo "Triggered deploy-docs.yml on main after publishing ${{ needs.version.outputs.tag }}."
|