4e19d8eeb1
Previous attempt (rc1, rc2) tried to run innosetup-6.7.1.exe under xvfb-run wine /VERYSILENT — silently failed (|| true masked it), ISCC.exe never appeared at C:\InnoSetup\ISCC.exe. Switch strategy: apt-get install innoextract (Debian package), use it to unpack the Inno Setup installer's payload directly to disk, then copy the extracted Inno Setup tree into the Wine prefix where ISCC.exe can be invoked normally. Wine is still needed to run ISCC itself, but no longer for the install step. Also: ignore /.claude/ directory (local Claude Code session settings). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
192 lines
8.4 KiB
YAML
192 lines
8.4 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 (via innoextract, no Wine GUI install)
|
|
run: |
|
|
set -e
|
|
dpkg --add-architecture i386
|
|
apt-get update
|
|
# innoextract unpacks Inno Setup .exe installers without running them
|
|
# under Wine. We then copy the extracted compiler files into the Wine
|
|
# prefix and call ISCC.exe via Wine — much more reliable than running
|
|
# the whole interactive installer through Wine + Xvfb (which failed
|
|
# silently in the previous iteration).
|
|
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
|
wine wine64 innoextract xvfb curl ca-certificates \
|
|
>/dev/null
|
|
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
|
|
# Pin Inno Setup version. Upstream lives on GitHub now; old
|
|
# https://files.jrsoftware.org/is/6/ layout returns 404.
|
|
INNO_VERSION="6.7.1"
|
|
INNO_TAG="is-6_7_1"
|
|
curl -fsSL -o /tmp/innosetup.exe \
|
|
"https://github.com/jrsoftware/issrc/releases/download/${INNO_TAG}/innosetup-${INNO_VERSION}.exe"
|
|
# innoextract unpacks the installer payload to ./app — that's the
|
|
# full Inno Setup directory tree (ISCC.exe + support DLLs/scripts).
|
|
mkdir -p /tmp/inno-extract
|
|
( cd /tmp/inno-extract && innoextract /tmp/innosetup.exe )
|
|
# Place it where Windows-style paths can resolve. Wine maps
|
|
# C:\InnoSetup to ~/.wine/drive_c/InnoSetup so we copy there.
|
|
mkdir -p "$HOME/.wine/drive_c/InnoSetup"
|
|
cp -a /tmp/inno-extract/app/. "$HOME/.wine/drive_c/InnoSetup/"
|
|
# Sanity check
|
|
ls -la "$HOME/.wine/drive_c/InnoSetup/ISCC.exe"
|
|
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."
|