Files
drover-go/.forgejo/workflows/release.yml
T
root 4e19d8eeb1 release.yml: install Inno Setup via innoextract (no Wine GUI install)
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>
2026-05-01 01:44:05 +03:00

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."