Phase 6+7: Inno Setup installer + GitHub Actions release pipeline
CI / build (pull_request) Has been cancelled
CI / build (pull_request) Has been cancelled
installer/webhook-server.iss is an Inno Setup 6 script that: - Installs to %ProgramFiles%\WebhookServer - Creates Start Menu folder + GUI shortcut (and optional desktop icon) - Runs install-service.ps1 post-install to register the Windows Service - Runs uninstall-service.ps1 pre-uninstall to remove it - Bundles the webhook-server icon for the installer / uninstaller scripts/build-installer.ps1 is the local build helper: publishes both projects, finds ISCC.exe (PATH or standard install path), compiles the installer with the version pulled from Directory.Build.props, drops the output in dist/. .github/workflows/ci.yml runs build + test on every push/PR to main. .github/workflows/release.yml triggers on v* tags (or manual dispatch), runs tests, installs Inno Setup via choco, builds the installer, and attaches the .exe to a GitHub Release. Pre-1.0 versions are flagged prerelease automatically. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,27 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: windows-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup .NET
|
||||||
|
uses: actions/setup-dotnet@v4
|
||||||
|
with:
|
||||||
|
dotnet-version: '8.0.x'
|
||||||
|
|
||||||
|
- name: Restore
|
||||||
|
run: dotnet restore WebhookServer.sln
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: dotnet build WebhookServer.sln -c Release --no-restore
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: dotnet test WebhookServer.sln -c Release --no-build --verbosity normal
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
name: Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
version:
|
||||||
|
description: 'Version to build (e.g. 0.1.0). Defaults to Directory.Build.props.'
|
||||||
|
required: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-installer:
|
||||||
|
runs-on: windows-latest
|
||||||
|
permissions:
|
||||||
|
contents: write # needed to create releases / upload assets
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup .NET
|
||||||
|
uses: actions/setup-dotnet@v4
|
||||||
|
with:
|
||||||
|
dotnet-version: '8.0.x'
|
||||||
|
|
||||||
|
- name: Resolve version
|
||||||
|
id: ver
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
if ('${{ github.event_name }}' -eq 'push') {
|
||||||
|
$v = '${{ github.ref_name }}'.TrimStart('v')
|
||||||
|
} elseif ('${{ inputs.version }}') {
|
||||||
|
$v = '${{ inputs.version }}'
|
||||||
|
} else {
|
||||||
|
[xml]$p = Get-Content Directory.Build.props
|
||||||
|
$v = $p.Project.PropertyGroup.Version
|
||||||
|
}
|
||||||
|
"version=$v" | Out-File $env:GITHUB_OUTPUT -Append
|
||||||
|
Write-Host "Building version $v"
|
||||||
|
|
||||||
|
- name: Restore + test
|
||||||
|
run: |
|
||||||
|
dotnet restore WebhookServer.sln
|
||||||
|
dotnet test WebhookServer.sln -c Release
|
||||||
|
|
||||||
|
- name: Install Inno Setup
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
choco install innosetup --no-progress -y
|
||||||
|
Write-Host "ISCC at: $((Get-Command iscc).Path)"
|
||||||
|
|
||||||
|
- name: Build installer
|
||||||
|
shell: pwsh
|
||||||
|
run: ./scripts/build-installer.ps1 -VersionOverride ${{ steps.ver.outputs.version }}
|
||||||
|
|
||||||
|
- name: Upload installer artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: WebhookServer-Setup-${{ steps.ver.outputs.version }}
|
||||||
|
path: dist/WebhookServer-Setup-*.exe
|
||||||
|
|
||||||
|
- name: Create GitHub Release
|
||||||
|
if: startsWith(github.ref, 'refs/tags/v')
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
name: Webhook Server ${{ steps.ver.outputs.version }}
|
||||||
|
tag_name: ${{ github.ref_name }}
|
||||||
|
draft: false
|
||||||
|
prerelease: ${{ startsWith(steps.ver.outputs.version, '0.') }}
|
||||||
|
files: dist/WebhookServer-Setup-*.exe
|
||||||
|
generate_release_notes: true
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
; Inno Setup script for Webhook Server.
|
||||||
|
;
|
||||||
|
; Build: iscc /DAppVersion=0.1.0 webhook-server.iss
|
||||||
|
; Output: ..\dist\WebhookServer-Setup-{AppVersion}.exe
|
||||||
|
;
|
||||||
|
; The installer copies published binaries to {pf}\WebhookServer, installs the
|
||||||
|
; Windows Service via install-service.ps1 post-install, and removes the service
|
||||||
|
; via uninstall-service.ps1 pre-uninstall. Start Menu gets a single GUI shortcut.
|
||||||
|
|
||||||
|
#ifndef AppVersion
|
||||||
|
#define AppVersion "0.1.0"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define AppName "Webhook Server"
|
||||||
|
#define AppPublisher "Justin Paul"
|
||||||
|
#define AppURL "https://jpaul.me"
|
||||||
|
#define AppExeName "WebhookServer.Gui.exe"
|
||||||
|
#define ServiceExeName "WebhookServer.Service.exe"
|
||||||
|
#define ServiceName "WebhookServer"
|
||||||
|
#define RepoRoot "..\"
|
||||||
|
|
||||||
|
[Setup]
|
||||||
|
AppId={{6E3B3C1A-9C20-4F50-B6A8-2B6D6D7E2F11}
|
||||||
|
AppName={#AppName}
|
||||||
|
AppVersion={#AppVersion}
|
||||||
|
AppPublisher={#AppPublisher}
|
||||||
|
AppPublisherURL={#AppURL}
|
||||||
|
AppSupportURL=https://github.com/recklessop/webhook-server
|
||||||
|
AppUpdatesURL=https://github.com/recklessop/webhook-server/releases
|
||||||
|
DefaultDirName={autopf}\WebhookServer
|
||||||
|
DefaultGroupName={#AppName}
|
||||||
|
DisableProgramGroupPage=yes
|
||||||
|
OutputBaseFilename=WebhookServer-Setup-{#AppVersion}
|
||||||
|
OutputDir={#RepoRoot}dist
|
||||||
|
SetupIconFile={#RepoRoot}resources\webhook-server.ico
|
||||||
|
UninstallDisplayIcon={app}\{#AppExeName}
|
||||||
|
PrivilegesRequired=admin
|
||||||
|
ArchitecturesAllowed=x64compatible
|
||||||
|
ArchitecturesInstallIn64BitMode=x64compatible
|
||||||
|
Compression=lzma2/max
|
||||||
|
SolidCompression=yes
|
||||||
|
WizardStyle=modern
|
||||||
|
VersionInfoVersion={#AppVersion}.0
|
||||||
|
VersionInfoCompany={#AppPublisher}
|
||||||
|
VersionInfoProductName={#AppName}
|
||||||
|
|
||||||
|
[Languages]
|
||||||
|
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||||
|
|
||||||
|
[Tasks]
|
||||||
|
Name: "desktopicon"; Description: "Create a &desktop shortcut"; GroupDescription: "Additional shortcuts:"; Flags: unchecked
|
||||||
|
|
||||||
|
[Files]
|
||||||
|
Source: "{#RepoRoot}publish\service\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||||
|
Source: "{#RepoRoot}publish\gui\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||||
|
Source: "{#RepoRoot}scripts\install-service.ps1"; DestDir: "{app}\scripts"; Flags: ignoreversion
|
||||||
|
Source: "{#RepoRoot}scripts\uninstall-service.ps1"; DestDir: "{app}\scripts"; Flags: ignoreversion
|
||||||
|
Source: "{#RepoRoot}README.md"; DestDir: "{app}"; Flags: ignoreversion
|
||||||
|
Source: "{#RepoRoot}resources\webhook-server.ico"; DestDir: "{app}"; Flags: ignoreversion
|
||||||
|
|
||||||
|
[Icons]
|
||||||
|
Name: "{group}\{#AppName}"; Filename: "{app}\{#AppExeName}"; IconFilename: "{app}\webhook-server.ico"
|
||||||
|
Name: "{group}\Uninstall {#AppName}"; Filename: "{uninstallexe}"
|
||||||
|
Name: "{commondesktop}\{#AppName}"; Filename: "{app}\{#AppExeName}"; IconFilename: "{app}\webhook-server.ico"; Tasks: desktopicon
|
||||||
|
|
||||||
|
[Run]
|
||||||
|
Filename: "powershell.exe"; \
|
||||||
|
Parameters: "-NoProfile -ExecutionPolicy Bypass -File ""{app}\scripts\install-service.ps1"" -BinaryPath ""{app}\{#ServiceExeName}"""; \
|
||||||
|
StatusMsg: "Installing Windows Service..."; \
|
||||||
|
Flags: runhidden
|
||||||
|
Filename: "{app}\{#AppExeName}"; \
|
||||||
|
Description: "Launch {#AppName}"; \
|
||||||
|
Flags: postinstall nowait skipifsilent
|
||||||
|
|
||||||
|
[UninstallRun]
|
||||||
|
Filename: "powershell.exe"; \
|
||||||
|
Parameters: "-NoProfile -ExecutionPolicy Bypass -File ""{app}\scripts\uninstall-service.ps1"""; \
|
||||||
|
Flags: runhidden; \
|
||||||
|
RunOnceId: "RemoveWebhookService"
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
End-to-end installer build: publish service + GUI, then run Inno Setup
|
||||||
|
to produce dist/WebhookServer-Setup-{version}.exe.
|
||||||
|
|
||||||
|
.DESCRIPTION
|
||||||
|
Reads the version from Directory.Build.props. Requires Inno Setup 6 (ISCC.exe)
|
||||||
|
on PATH or in the standard install location. CI runs this same script after
|
||||||
|
setup-dotnet + winget install Inno Setup.
|
||||||
|
#>
|
||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[string]$Configuration = 'Release',
|
||||||
|
[string]$VersionOverride
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
$repoRoot = Split-Path -Parent $PSScriptRoot
|
||||||
|
|
||||||
|
function Get-RepoVersion {
|
||||||
|
$propsPath = Join-Path $repoRoot 'Directory.Build.props'
|
||||||
|
[xml]$props = Get-Content $propsPath
|
||||||
|
return $props.Project.PropertyGroup.Version
|
||||||
|
}
|
||||||
|
|
||||||
|
function Find-InnoCompiler {
|
||||||
|
$candidates = @(
|
||||||
|
'ISCC.exe', # on PATH
|
||||||
|
'C:\Program Files (x86)\Inno Setup 6\ISCC.exe',
|
||||||
|
'C:\Program Files\Inno Setup 6\ISCC.exe'
|
||||||
|
)
|
||||||
|
foreach ($c in $candidates) {
|
||||||
|
$cmd = Get-Command $c -ErrorAction SilentlyContinue
|
||||||
|
if ($cmd) { return $cmd.Path }
|
||||||
|
if (Test-Path $c) { return $c }
|
||||||
|
}
|
||||||
|
throw "Inno Setup compiler not found. Install with: winget install JRSoftware.InnoSetup"
|
||||||
|
}
|
||||||
|
|
||||||
|
$version = if ($VersionOverride) { $VersionOverride } else { Get-RepoVersion }
|
||||||
|
Write-Host "Building Webhook Server installer v$version" -ForegroundColor Cyan
|
||||||
|
|
||||||
|
# 1. Publish both projects.
|
||||||
|
$publishSvc = Join-Path $repoRoot 'publish\service'
|
||||||
|
$publishGui = Join-Path $repoRoot 'publish\gui'
|
||||||
|
Remove-Item -Recurse -Force $publishSvc, $publishGui -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
& dotnet publish (Join-Path $repoRoot 'src\WebhookServer.Service\WebhookServer.Service.csproj') `
|
||||||
|
-c $Configuration -r win-x64 --self-contained false -o $publishSvc | Out-Host
|
||||||
|
if ($LASTEXITCODE -ne 0) { throw 'service publish failed' }
|
||||||
|
|
||||||
|
& dotnet publish (Join-Path $repoRoot 'src\WebhookServer.Gui\WebhookServer.Gui.csproj') `
|
||||||
|
-c $Configuration -r win-x64 --self-contained false -o $publishGui | Out-Host
|
||||||
|
if ($LASTEXITCODE -ne 0) { throw 'GUI publish failed' }
|
||||||
|
|
||||||
|
# 2. Compile installer.
|
||||||
|
$iscc = Find-InnoCompiler
|
||||||
|
$iss = Join-Path $repoRoot 'installer\webhook-server.iss'
|
||||||
|
$dist = Join-Path $repoRoot 'dist'
|
||||||
|
New-Item -ItemType Directory -Path $dist -Force | Out-Null
|
||||||
|
|
||||||
|
Write-Host "Compiling installer with $iscc"
|
||||||
|
& $iscc "/DAppVersion=$version" $iss
|
||||||
|
if ($LASTEXITCODE -ne 0) { throw 'Inno Setup compile failed' }
|
||||||
|
|
||||||
|
$out = Get-Item (Join-Path $dist "WebhookServer-Setup-$version.exe")
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host ("Built: {0} ({1:n0} bytes)" -f $out.FullName, $out.Length) -ForegroundColor Green
|
||||||
Reference in New Issue
Block a user