Files
wehub-resource-sync 5b99bf6bca
CI / test (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:34:54 +08:00

134 lines
5.9 KiB
YAML

name: Release
on:
push:
tags:
- 'v*'
jobs:
release:
name: Build & publish
runs-on: macos-14
permissions:
contents: write # create releases and commit appcast
steps:
- uses: actions/checkout@v5
with:
# Fetch full history so we can push the appcast commit back.
fetch-depth: 0
# Admin PAT so the appcast commit can be pushed to the protected
# `main` branch. The default GITHUB_TOKEN/bot is not an admin and is
# blocked by the required `test` status check.
token: ${{ secrets.RELEASE_TOKEN }}
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest-stable
- name: Cache .build
uses: actions/cache@v5
with:
path: .build
key: spm-v2-${{ runner.os }}-${{ hashFiles('Package.resolved') }}
restore-keys: spm-v2-${{ runner.os }}-
- name: Build app bundle
run: ./scripts/build-app.sh
# create-dmg 8.x requires Node >= 20; pin it so the runner's default node
# version can't break the release.
- uses: actions/setup-node@v4
with:
node-version: 20
- name: Install create-dmg
# sindresorhus/create-dmg is the npm package (NOT the homebrew
# create-dmg/create-dmg tool, which has an incompatible CLI).
run: npm install --global create-dmg
- name: Create DMG
run: |
VERSION="$(/usr/libexec/PlistBuddy -c 'Print CFBundleShortVersionString' Info.plist)"
echo "VERSION=$VERSION" >> "$GITHUB_ENV"
# create-dmg exits 2 when it can't Developer-ID-sign / notarize the
# image (we ship ad-hoc only) but still produces the .dmg — so don't
# let that non-zero status fail the job.
create-dmg build/Edmund.app build/ || true
# It names the output "Edmund <version>.dmg"; normalize to a
# hyphenated, URL-friendly name and fail loudly if none was produced.
DMG_SRC="$(ls build/Edmund*.dmg 2>/dev/null | head -1)"
if [ -z "$DMG_SRC" ]; then
echo "create-dmg produced no .dmg" >&2
exit 1
fi
mv "$DMG_SRC" "build/Edmund-${VERSION}.dmg"
- name: Sign archive (EdDSA)
env:
SPARKLE_ED_PRIVATE_KEY: ${{ secrets.SPARKLE_ED_PRIVATE_KEY }}
run: |
SIGN_UPDATE="$(find .build -name sign_update -type f | head -1)"
# Pass the key on stdin via --ed-key-file -. The deprecated `-s <key>`
# is fatal for newly generated keys ("no longer supported").
SIG_OUTPUT="$(echo "$SPARKLE_ED_PRIVATE_KEY" | "$SIGN_UPDATE" --ed-key-file - "build/Edmund-${VERSION}.dmg")"
echo "ED_SIG=$(echo "$SIG_OUTPUT" | grep -o 'sparkle:edSignature="[^"]*"')" >> "$GITHUB_ENV"
echo "LENGTH=$(echo "$SIG_OUTPUT" | grep -o 'length="[^"]*"' | head -1)" >> "$GITHUB_ENV"
- name: Create GitHub Release
id: create_release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
awk "BEGIN{p=0} /^## \[${VERSION}\]/{p=1;next} p && /^## \[/{exit} p{print}" \
CHANGELOG.md > release-notes.txt
if [ ! -s release-notes.txt ]; then
echo "See CHANGELOG for details." > release-notes.txt
fi
gh release create "v${VERSION}" "build/Edmund-${VERSION}.dmg" \
--title "Edmund ${VERSION}" \
--notes-file release-notes.txt \
--latest
- name: Update appcast.xml
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
REPO="${{ github.repository }}"
ASSET_URL="https://github.com/${REPO}/releases/download/v${VERSION}/Edmund-${VERSION}.dmg"
PUB_DATE="$(date -u '+%a, %d %b %Y %H:%M:%S +0000')"
BUILD="$(/usr/libexec/PlistBuddy -c 'Print CFBundleVersion' Info.plist)"
# Release notes for Sparkle's update dialog (scrollable pane), built
# from this version's CHANGELOG section. Omitted if the section is missing.
# Built with printf (not a literal multi-line string) so this step's
# `run: |` block scalar doesn't contain an unindented line, which
# breaks YAML parsing of the whole workflow file.
# $(...) strips trailing newlines, so DESC_BLOCK can't carry its own
# trailing separator — NEW_ITEM's printf adds it explicitly instead.
DESC_HTML="$(python3 scripts/changelog-to-html.py "$VERSION")"
DESC_BLOCK=""
if [ -n "$DESC_HTML" ]; then
DESC_BLOCK="$(printf ' <description><![CDATA[\n%s\n]]></description>' "$DESC_HTML")"
fi
# Built with printf (one logical YAML line) rather than a literal
# multi-line string: an unindented line inside this value would
# break this run block's YAML indentation (as DESC_BLOCK did above).
NEW_ITEM="$(printf ' <item>\n <title>Edmund %s</title>\n <pubDate>%s</pubDate>\n%s\n <enclosure url="%s"\n sparkle:version="%s"\n sparkle:shortVersionString="%s"\n %s\n %s\n type="application/x-apple-diskimage"/>\n </item>' "$VERSION" "$PUB_DATE" "$DESC_BLOCK" "$ASSET_URL" "$BUILD" "$VERSION" "$ED_SIG" "$LENGTH")"
python3 - "$NEW_ITEM" <<'PYEOF'
import sys
new_item = sys.argv[1]
with open("appcast.xml", "r") as f:
content = f.read()
content = content.replace(" </channel>", new_item + "\n </channel>")
with open("appcast.xml", "w") as f:
f.write(content)
PYEOF
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add appcast.xml
git commit -m "appcast: add Edmund ${VERSION}"
git push origin HEAD:main