ca90facbdd
Triggered on `push` of any `v*` tag. Single `release` job on the `go`
runner produces and uploads four assets to the matching Forgejo release:
- drover-vX.Y.Z-windows-amd64.exe (cross-compiled portable binary)
- drover-vX.Y.Z-windows-amd64.zip (portable bundle + WinDivert + docs)
- drover-vX.Y.Z-setup.exe (Inno Setup installer via Wine)
- SHA256SUMS.txt (sha256 of the three above)
The asset names match what internal/updater/updater.go looks for, so
selfupdate keeps working on tagged releases.
Notes mirroring build.yml constraints:
- manual git clone instead of actions/checkout (no Node in golang
image; JS-based actions fail with `node: not found`)
- apt-get installs wine/wine32:i386/xvfb/zip/jq in-job
- Inno Setup 6.4.0 pinned, /VERYSILENT /CURRENTUSER install under Wine
- prerelease auto-detected from a hyphen in the version (rc/beta/alpha)
- curl uses -fsS so 409 (release exists) and other API errors fail loud
- secrets.GITHUB_TOKEN handles both clone and Forgejo REST API writes
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
185 lines
7.8 KiB
YAML
185 lines
7.8 KiB
YAML
name: Release
|
|
|
|
on:
|
|
push:
|
|
tags:
|
|
- 'v*'
|
|
|
|
# We only ever publish a tag once. Don't cancel a running release —
|
|
# if the user re-pushed the same tag, that's a manual action and
|
|
# should fail loudly via Forgejo's "release exists" 409 from the API.
|
|
concurrency:
|
|
group: release-${{ github.ref }}
|
|
cancel-in-progress: false
|
|
|
|
jobs:
|
|
release:
|
|
runs-on: go
|
|
steps:
|
|
- name: Checkout
|
|
run: |
|
|
git clone --no-checkout "https://forgejo-runner:${GITHUB_TOKEN}@git.okcu.io/${GITHUB_REPOSITORY}.git" /tmp/src
|
|
git -C /tmp/src checkout "$GITHUB_SHA"
|
|
cp -a /tmp/src/. .
|
|
|
|
- name: Extract version from tag
|
|
id: version
|
|
run: |
|
|
TAG="${GITHUB_REF#refs/tags/}"
|
|
VERSION="${TAG#v}"
|
|
echo "tag=${TAG}" | tee -a "$GITHUB_OUTPUT"
|
|
echo "version=${VERSION}" | tee -a "$GITHUB_OUTPUT"
|
|
|
|
- name: Cross-compile drover.exe (windows/amd64)
|
|
env:
|
|
GOOS: windows
|
|
GOARCH: amd64
|
|
CGO_ENABLED: '0'
|
|
run: |
|
|
set -e
|
|
BUILD_DATE="$(date -u +%Y-%m-%d)"
|
|
SHORT_SHA="${GITHUB_SHA:0:7}"
|
|
mkdir -p dist
|
|
go build -trimpath -ldflags="-s -w \
|
|
-X main.Version=${{ steps.version.outputs.version }} \
|
|
-X main.Commit=${SHORT_SHA} \
|
|
-X main.BuildDate=${BUILD_DATE}" \
|
|
-o "dist/drover-${{ steps.version.outputs.tag }}-windows-amd64.exe" \
|
|
./cmd/drover
|
|
|
|
- name: Build portable zip
|
|
run: |
|
|
set -e
|
|
# Stage files for the zip in a clean directory so the archive root
|
|
# contains exactly what users see when they unpack.
|
|
apt-get update >/dev/null
|
|
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends zip >/dev/null
|
|
STAGE="$(mktemp -d)"
|
|
cp "dist/drover-${{ steps.version.outputs.tag }}-windows-amd64.exe" "$STAGE/drover.exe"
|
|
mkdir -p "$STAGE/windivert"
|
|
cp third_party/windivert/WinDivert.dll "$STAGE/windivert/"
|
|
cp third_party/windivert/WinDivert64.sys "$STAGE/windivert/"
|
|
cp third_party/windivert/LICENSE-LGPL "$STAGE/windivert/"
|
|
cp third_party/windivert/README.md "$STAGE/windivert/"
|
|
cp LICENSE "$STAGE/LICENSE.txt"
|
|
cp README.md "$STAGE/README.md"
|
|
# zip from inside STAGE so paths are relative
|
|
( cd "$STAGE" && zip -r9 - . ) > "dist/drover-${{ steps.version.outputs.tag }}-windows-amd64.zip"
|
|
|
|
- name: Install Wine + Inno Setup
|
|
run: |
|
|
set -e
|
|
dpkg --add-architecture i386
|
|
apt-get update
|
|
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
|
wine wine64 wine32:i386 cabextract xvfb curl ca-certificates \
|
|
>/dev/null
|
|
# Headless Wine prefix; suppress wineboot first-run banner.
|
|
export WINEPREFIX="$HOME/.wine"
|
|
export WINEDLLOVERRIDES="mscoree,mshtml="
|
|
export DISPLAY=":99"
|
|
Xvfb :99 -screen 0 1024x768x16 &
|
|
sleep 1
|
|
wineboot --init >/dev/null 2>&1 || true
|
|
# Download Inno Setup 6.4 — pinned to a known-good build to keep
|
|
# builds reproducible. Using upstream installer is more robust
|
|
# against link rot than third-party redistributions.
|
|
INNO_VERSION="6.4.0"
|
|
curl -fsSL -o /tmp/innosetup.exe \
|
|
"https://files.jrsoftware.org/is/6/innosetup-${INNO_VERSION}.exe"
|
|
# Silent install. /CURRENTUSER avoids needing admin in Wine.
|
|
xvfb-run -a wine /tmp/innosetup.exe /VERYSILENT /SUPPRESSMSGBOXES /CURRENTUSER /NORESTART \
|
|
/DIR="C:\\InnoSetup" \
|
|
>/dev/null 2>&1 || true
|
|
# Sanity-check ISCC was installed
|
|
ISCC_LIN="$HOME/.wine/drive_c/InnoSetup/ISCC.exe"
|
|
ls -la "$ISCC_LIN"
|
|
xvfb-run -a wine "C:\\InnoSetup\\ISCC.exe" /? 2>&1 | head -5 || true
|
|
|
|
- name: Compile Inno Setup installer
|
|
env:
|
|
DISPLAY: ":99"
|
|
WINEDLLOVERRIDES: "mscoree,mshtml="
|
|
run: |
|
|
set -e
|
|
export WINEPREFIX="$HOME/.wine"
|
|
# installer.iss references "..\drover.exe" relative to installer/,
|
|
# i.e. expects a plain drover.exe at repo root. Stage a copy of the
|
|
# versioned binary there before invoking ISCC.
|
|
cp "dist/drover-${{ steps.version.outputs.tag }}-windows-amd64.exe" drover.exe
|
|
# Inno Setup wants Windows-style /D defines and the script path
|
|
# in DOS form. We invoke from repo root; iss script resolves its
|
|
# own ..\ paths from installer/.
|
|
mkdir -p installer/Output
|
|
xvfb-run -a wine "C:\\InnoSetup\\ISCC.exe" \
|
|
"/DMyAppVersion=${{ steps.version.outputs.version }}" \
|
|
"installer\\installer.iss"
|
|
# Inno Setup default OutputDir is "installer/Output/" (relative
|
|
# to the .iss). Move the produced exe to dist/ with the canonical
|
|
# asset name.
|
|
mv "installer/Output/drover-${{ steps.version.outputs.version }}-setup.exe" \
|
|
"dist/drover-${{ steps.version.outputs.tag }}-setup.exe"
|
|
ls -la dist/
|
|
|
|
- name: Compute SHA256SUMS.txt
|
|
run: |
|
|
set -e
|
|
( cd dist && sha256sum \
|
|
"drover-${{ steps.version.outputs.tag }}-windows-amd64.exe" \
|
|
"drover-${{ steps.version.outputs.tag }}-windows-amd64.zip" \
|
|
"drover-${{ steps.version.outputs.tag }}-setup.exe" \
|
|
) > dist/SHA256SUMS.txt
|
|
cat dist/SHA256SUMS.txt
|
|
|
|
- name: Create Forgejo release and upload assets
|
|
env:
|
|
FJ_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
FJ_HOST: git.okcu.io
|
|
FJ_REPO: ${{ github.repository }}
|
|
TAG: ${{ steps.version.outputs.tag }}
|
|
VERSION: ${{ steps.version.outputs.version }}
|
|
run: |
|
|
set -e
|
|
# jq is used to build the JSON body safely. Install if missing.
|
|
command -v jq >/dev/null || {
|
|
apt-get update >/dev/null
|
|
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends jq >/dev/null
|
|
}
|
|
# Detect prerelease from tag (anything with a hyphen after the version
|
|
# number, e.g. v0.1.0-rc.1, v0.1.0-beta) is a prerelease.
|
|
PRERELEASE="false"
|
|
case "$VERSION" in
|
|
*-*) PRERELEASE="true" ;;
|
|
esac
|
|
|
|
# 1. Create the release. If a release for this tag already exists,
|
|
# Forgejo returns 409 and we exit non-zero so the user sees the
|
|
# real reason in the log instead of getting silent overwrites.
|
|
BODY=$(jq -n \
|
|
--arg tag "$TAG" \
|
|
--arg name "Drover-Go $TAG" \
|
|
--argjson prerelease "$PRERELEASE" \
|
|
--arg body "Automated release built from commit $GITHUB_SHA. See [docs](https://git.okcu.io/$FJ_REPO/src/tag/$TAG/docs/) for installation and troubleshooting." \
|
|
'{tag_name: $tag, name: $name, prerelease: $prerelease, body: $body, draft: false}')
|
|
RELEASE_JSON=$(curl -fsS -X POST \
|
|
-H "Authorization: token $FJ_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d "$BODY" \
|
|
"https://$FJ_HOST/api/v1/repos/$FJ_REPO/releases")
|
|
RELEASE_ID=$(echo "$RELEASE_JSON" | jq -r '.id')
|
|
echo "Created release id=$RELEASE_ID"
|
|
|
|
# 2. Upload each asset via multipart/form-data
|
|
for asset in dist/*.exe dist/*.zip dist/SHA256SUMS.txt; do
|
|
[ -f "$asset" ] || continue
|
|
name="$(basename "$asset")"
|
|
echo "Uploading $name..."
|
|
curl -fsS -X POST \
|
|
-H "Authorization: token $FJ_TOKEN" \
|
|
-F "attachment=@$asset;filename=$name" \
|
|
"https://$FJ_HOST/api/v1/repos/$FJ_REPO/releases/$RELEASE_ID/assets?name=$name" \
|
|
>/dev/null
|
|
done
|
|
|
|
echo "Release $TAG published with $(ls dist | wc -l) assets."
|