feat(pkg-nsis): add Windows installer workflow
This commit is contained in:
@@ -208,6 +208,52 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
pkg-nsis:
|
||||
name: Windows installer
|
||||
needs: release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
|
||||
- name: Build NSIS installer
|
||||
run: |
|
||||
set -euo pipefail
|
||||
VERSION="${{ github.event.inputs.tag || github.ref_name }}"
|
||||
PKGVER="${VERSION#v}"
|
||||
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y nsis
|
||||
|
||||
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build \
|
||||
-trimpath \
|
||||
-ldflags "-X main.version=${PKGVER}" \
|
||||
-o pgtidy.exe \
|
||||
./cmd/pgtidy
|
||||
|
||||
makensis -DVERSION="${PKGVER}" -DSRC_EXE="$(pwd)/pgtidy.exe" windows/installer.nsi
|
||||
|
||||
- name: Upload to release
|
||||
run: |
|
||||
set -euo pipefail
|
||||
TAG="${{ github.event.inputs.tag || github.ref_name }}"
|
||||
RELEASE=$(curl -s "${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/releases/tags/${TAG}" \
|
||||
-H "Authorization: token ${GITHUB_TOKEN}")
|
||||
UPLOAD_URL=$(echo "$RELEASE" | grep -o '"upload_url":"[^"]*"' | cut -d'"' -f4 | sed 's/{[^}]*}//')
|
||||
[ -z "$UPLOAD_URL" ] && { echo "upload_url not found: $RELEASE"; exit 1; }
|
||||
for f in windows/pgtidy-setup-*.exe; do
|
||||
echo "Uploading $(basename "$f")..."
|
||||
curl -s -X POST "${UPLOAD_URL}?name=$(basename "$f")" \
|
||||
-H "Authorization: token ${GITHUB_TOKEN}" \
|
||||
-H "Content-Type: application/octet-stream" \
|
||||
--data-binary "@${f}" > /dev/null
|
||||
done
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
pkg-aur:
|
||||
name: AUR package
|
||||
needs: release
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
; PgTidy Windows installer
|
||||
;
|
||||
; Build with (VERSION must match the release tag, without the leading "v"):
|
||||
; makensis /DVERSION=1.2.3 /DSRC_EXE=path\to\pgtidy.exe windows\installer.nsi
|
||||
;
|
||||
; Installs pgtidy.exe into Program Files, adds the install dir to the
|
||||
; machine-wide PATH, and on startup checks the git.warky.dev Gitea API for a
|
||||
; newer release than the one being installed.
|
||||
|
||||
!ifndef VERSION
|
||||
!define VERSION "0.0.0"
|
||||
!endif
|
||||
!ifndef SRC_EXE
|
||||
!define SRC_EXE "..\dist\pgtidy.exe"
|
||||
!endif
|
||||
|
||||
!define PRODUCT_NAME "PgTidy"
|
||||
!define PRODUCT_PUBLISHER "Warky Devs"
|
||||
!define PRODUCT_HOMEPAGE "https://git.warky.dev/wdevs/pgtidy"
|
||||
!define RELEASES_API_URL "https://git.warky.dev/api/v1/repos/wdevs/pgtidy/releases/latest"
|
||||
!define UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\PgTidy"
|
||||
!define ENV_KEY 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
|
||||
|
||||
!include "MUI2.nsh"
|
||||
!include "LogicLib.nsh"
|
||||
|
||||
Name "${PRODUCT_NAME} ${VERSION}"
|
||||
OutFile "pgtidy-setup-${VERSION}.exe"
|
||||
InstallDir "$PROGRAMFILES64\PgTidy"
|
||||
InstallDirRegKey HKLM "${UNINST_KEY}" "InstallLocation"
|
||||
RequestExecutionLevel admin
|
||||
Unicode true
|
||||
|
||||
!define MUI_ABORTWARNING
|
||||
!define MUI_ICON "..\assets\logo_128.ico"
|
||||
!define MUI_UNICON "..\assets\logo_128.ico"
|
||||
|
||||
!insertmacro MUI_PAGE_WELCOME
|
||||
!insertmacro MUI_PAGE_LICENSE "..\LICENSE"
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
!insertmacro MUI_PAGE_FINISH
|
||||
|
||||
!insertmacro MUI_UNPAGE_CONFIRM
|
||||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
|
||||
!insertmacro MUI_LANGUAGE "English"
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; Check the Gitea releases API for a newer version than the one we are about
|
||||
; to install. Best-effort only: any failure (offline, API down, no
|
||||
; PowerShell) is swallowed and the installer proceeds silently.
|
||||
; ---------------------------------------------------------------------------
|
||||
Function .onInit
|
||||
StrCpy $1 "$TEMP\pgtidy-latest-version.txt"
|
||||
Delete "$1"
|
||||
|
||||
DetailPrint "Checking ${PRODUCT_HOMEPAGE} for a newer release..."
|
||||
nsExec::ExecToLog 'powershell -NoProfile -NonInteractive -Command "try { $$r = Invoke-RestMethod -Uri ''${RELEASES_API_URL}'' -UseBasicParsing -TimeoutSec 5; $$r.tag_name | Out-File -Encoding ascii -NoNewline ''$1'' } catch { exit 0 }"'
|
||||
|
||||
${IfNot} ${FileExists} "$1"
|
||||
Return
|
||||
${EndIf}
|
||||
|
||||
FileOpen $2 "$1" r
|
||||
FileRead $2 $3
|
||||
FileClose $2
|
||||
Delete "$1"
|
||||
|
||||
StrCpy $4 $3
|
||||
; Trim a leading "v" if the tag is e.g. "v1.2.3"
|
||||
StrCpy $5 $4 1
|
||||
${If} $5 == "v"
|
||||
StrCpy $4 $4 "" 1
|
||||
${EndIf}
|
||||
|
||||
${If} $4 != ""
|
||||
${AndIf} $4 != "${VERSION}"
|
||||
MessageBox MB_YESNO|MB_ICONINFORMATION \
|
||||
"A newer version of PgTidy is available: $4 (this installer is ${VERSION}).$\n$\nOpen the releases page to download it now?$\n$\nChoosing No continues installing ${VERSION}." \
|
||||
IDNO +2
|
||||
ExecShell "open" "${PRODUCT_HOMEPAGE}/releases/latest"
|
||||
${EndIf}
|
||||
FunctionEnd
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; Adds $INSTDIR to the machine PATH if it isn't already present.
|
||||
; ---------------------------------------------------------------------------
|
||||
Function AddToPath
|
||||
ReadRegStr $0 ${ENV_KEY} "Path"
|
||||
Push "$0"
|
||||
Push "$INSTDIR"
|
||||
Call StrContains
|
||||
Pop $1
|
||||
${If} $1 == ""
|
||||
${If} $0 == ""
|
||||
StrCpy $0 "$INSTDIR"
|
||||
${Else}
|
||||
StrCpy $0 "$0;$INSTDIR"
|
||||
${EndIf}
|
||||
WriteRegExpandStr ${ENV_KEY} "Path" "$0"
|
||||
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
|
||||
${EndIf}
|
||||
FunctionEnd
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; Removes $INSTDIR from the machine PATH.
|
||||
; ---------------------------------------------------------------------------
|
||||
Function un.RemoveFromPath
|
||||
ReadRegStr $0 ${ENV_KEY} "Path"
|
||||
Push "$0;"
|
||||
Push "$INSTDIR;"
|
||||
Push ""
|
||||
Call un.StrReplace
|
||||
Pop $0
|
||||
Push "$0"
|
||||
Push "$INSTDIR"
|
||||
Push ""
|
||||
Call un.StrReplace
|
||||
Pop $0
|
||||
; Drop a trailing separator left behind by the replacements above.
|
||||
StrCpy $1 $0 1 -1
|
||||
${If} $1 == ";"
|
||||
StrCpy $0 $0 -1
|
||||
${EndIf}
|
||||
WriteRegExpandStr ${ENV_KEY} "Path" "$0"
|
||||
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
|
||||
FunctionEnd
|
||||
|
||||
; Returns the index of needle in haystack via $R0, or "" if absent.
|
||||
; Push haystack, Push needle -> Pop result
|
||||
Function StrContains
|
||||
Exch $R1 ; needle
|
||||
Exch
|
||||
Exch $R2 ; haystack
|
||||
Push $R3
|
||||
Push $R4
|
||||
Push $R5
|
||||
StrLen $R3 $R1
|
||||
StrCpy $R4 0
|
||||
${Do}
|
||||
StrCpy $R5 $R2 $R3 $R4
|
||||
${If} $R5 == $R1
|
||||
StrCpy $R0 $R4
|
||||
${ExitDo}
|
||||
${EndIf}
|
||||
${If} $R5 == ""
|
||||
StrCpy $R0 ""
|
||||
${ExitDo}
|
||||
${EndIf}
|
||||
IntOp $R4 $R4 + 1
|
||||
${Loop}
|
||||
Pop $R5
|
||||
Pop $R4
|
||||
Pop $R3
|
||||
Pop $R2
|
||||
Pop $R1
|
||||
Push $R0
|
||||
Exch
|
||||
Pop $R0
|
||||
FunctionEnd
|
||||
|
||||
; Push string, Push search, Push replace -> Pop result
|
||||
Function un.StrReplace
|
||||
Exch $R0 ; replace
|
||||
Exch
|
||||
Exch $R1 ; search
|
||||
Exch 2
|
||||
Exch $R2 ; string
|
||||
Push $R3
|
||||
Push $R4
|
||||
Push $R5
|
||||
Push $R6
|
||||
StrLen $R3 $R1
|
||||
StrCpy $R4 ""
|
||||
${Do}
|
||||
StrCpy $R5 $R2 $R3
|
||||
${If} $R5 == $R1
|
||||
StrCpy $R4 "$R4$R0"
|
||||
StrCpy $R2 $R2 "" $R3
|
||||
${ElseIf} $R2 == ""
|
||||
${ExitDo}
|
||||
${Else}
|
||||
StrCpy $R6 $R2 1
|
||||
StrCpy $R4 "$R4$R6"
|
||||
StrCpy $R2 $R2 "" 1
|
||||
${EndIf}
|
||||
${Loop}
|
||||
Pop $R6
|
||||
Pop $R5
|
||||
Pop $R4
|
||||
Pop $R3
|
||||
Pop $R2
|
||||
Pop $R1
|
||||
Pop $R0
|
||||
Push $R4
|
||||
FunctionEnd
|
||||
|
||||
Section "PgTidy" SEC_MAIN
|
||||
SectionIn RO
|
||||
SetOutPath "$INSTDIR"
|
||||
File "${SRC_EXE}"
|
||||
File "..\LICENSE"
|
||||
|
||||
Call AddToPath
|
||||
|
||||
WriteRegStr HKLM "${UNINST_KEY}" "DisplayName" "${PRODUCT_NAME}"
|
||||
WriteRegStr HKLM "${UNINST_KEY}" "DisplayVersion" "${VERSION}"
|
||||
WriteRegStr HKLM "${UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
|
||||
WriteRegStr HKLM "${UNINST_KEY}" "InstallLocation" "$INSTDIR"
|
||||
WriteRegStr HKLM "${UNINST_KEY}" "UninstallString" "$INSTDIR\uninstall.exe"
|
||||
WriteRegStr HKLM "${UNINST_KEY}" "QuietUninstallString" "$INSTDIR\uninstall.exe /S"
|
||||
WriteRegDWORD HKLM "${UNINST_KEY}" "NoModify" 1
|
||||
WriteRegDWORD HKLM "${UNINST_KEY}" "NoRepair" 1
|
||||
|
||||
WriteUninstaller "$INSTDIR\uninstall.exe"
|
||||
SectionEnd
|
||||
|
||||
Section "Uninstall"
|
||||
Call un.RemoveFromPath
|
||||
Delete "$INSTDIR\pgtidy.exe"
|
||||
Delete "$INSTDIR\LICENSE"
|
||||
Delete "$INSTDIR\uninstall.exe"
|
||||
RMDir "$INSTDIR"
|
||||
DeleteRegKey HKLM "${UNINST_KEY}"
|
||||
SectionEnd
|
||||
Reference in New Issue
Block a user