Skip to content

Commit 254fc0d

Browse files
Add Windows installer CI and WiX packaging
Extend CI to produce Windows builds and installers: update ci-rust workflow to include Windows/ARM64 target, upload Windows build artifacts, and add a windows_installer job that packages MSI installers with cargo-wix/WiX, signs executables/installers via Azure Trusted Signing when configured, and archives artifacts. Wire Azure signing inputs/secrets through ci.yml. Add cargo-wix to crates/server/Cargo.toml and add a WiX manifest at crates/server/wix/main.wxs to define the installer layout and shortcuts.
1 parent 5e2aeda commit 254fc0d

6 files changed

Lines changed: 306 additions & 3 deletions

File tree

.github/workflows/ci-coverage.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ jobs:
2121
- x86_64-apple-darwin
2222
- aarch64-apple-darwin
2323
- x86_64-pc-windows-msvc
24+
- aarch64-pc-windows-msvc
2425
name: Coverage (${{ matrix.target }})
2526
permissions:
2627
contents: read

.github/workflows/ci-rust.yml

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ jobs:
6464
container: ''
6565
cargo_features: ''
6666
shell: bash
67+
- target: aarch64-pc-windows-msvc # Windows/ARM64
68+
os: windows-11-arm
69+
container: ''
70+
cargo_features: ''
71+
shell: bash
6772
name: ${{ inputs.job_name }} (${{ matrix.target }})
6873
permissions:
6974
contents: read
@@ -160,7 +165,7 @@ jobs:
160165
if: inputs.run_tests
161166
run: |
162167
tarpaulin_args=()
163-
if [[ "${{ matrix.target }}" == "aarch64-unknown-linux-gnu" ]]; then
168+
if [[ "${{ matrix.target }}" == "aarch64-unknown-linux-gnu" || "${{ matrix.target }}" == "aarch64-pc-windows-msvc" ]]; then
164169
tarpaulin_args+=(--jobs 1)
165170
fi
166171
@@ -191,7 +196,7 @@ jobs:
191196
run: cargo build --locked ${{ matrix.cargo_features }} --target ${{ matrix.target }} --release
192197

193198
- name: Create 7z archive
194-
if: inputs.run_build
199+
if: inputs.run_build && !contains(matrix.target, 'windows')
195200
run: |
196201
mkdir -p artifacts
197202
@@ -204,8 +209,18 @@ jobs:
204209
"./assets" \
205210
"./target/${{ matrix.target }}/release/koko${extension}"
206211
212+
- name: Upload Windows build artifact
213+
if: inputs.run_build && contains(matrix.target, 'windows')
214+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
215+
with:
216+
if-no-files-found: error
217+
name: windows-build-${{ matrix.target }}
218+
path: |
219+
target/${{ matrix.target }}/release/koko.exe
220+
crates/client-web/dist
221+
207222
- name: Upload Artifacts
208-
if: inputs.run_build
223+
if: inputs.run_build && !contains(matrix.target, 'windows')
209224
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
210225
with:
211226
if-no-files-found: error
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
---
2+
name: CI-Windows-Installer
3+
permissions: {}
4+
5+
on:
6+
workflow_call:
7+
inputs:
8+
azure_signing_account:
9+
default: ''
10+
required: false
11+
type: string
12+
azure_signing_cert_profile:
13+
default: ''
14+
required: false
15+
type: string
16+
azure_signing_endpoint:
17+
default: ''
18+
required: false
19+
type: string
20+
publish_release:
21+
default: false
22+
required: false
23+
type: boolean
24+
release_version:
25+
default: ''
26+
required: false
27+
type: string
28+
secrets:
29+
AZURE_CLIENT_ID:
30+
required: false
31+
AZURE_CLIENT_SECRET:
32+
required: false
33+
AZURE_TENANT_ID:
34+
required: false
35+
36+
jobs:
37+
windows_installer:
38+
name: Windows Installer (${{ matrix.target }})
39+
permissions:
40+
contents: read
41+
runs-on: windows-latest
42+
strategy:
43+
fail-fast: false
44+
matrix:
45+
include:
46+
- target: x86_64-pc-windows-msvc
47+
- target: aarch64-pc-windows-msvc
48+
env:
49+
CARGO_TERM_COLOR: always
50+
CARGO_WIX_REV: fde983c2e901970267e76b8fd68120fdd5457a57
51+
WIX_EXTENSION_VERSION: 7.0.0
52+
WIX_TOOL_PATH: ${{ github.workspace }}\.wix
53+
WIX_VERSION: 7.0.0
54+
steps:
55+
- name: Checkout
56+
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
57+
58+
- name: Download Windows build artifact
59+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
60+
with:
61+
name: windows-build-${{ matrix.target }}
62+
path: .
63+
64+
- name: Setup Rust
65+
uses: actions-rust-lang/setup-rust-toolchain@2b1f5e9b395427c92ee4e3331786ca3c37afe2d7 # v1.16.0
66+
with:
67+
target: ${{ matrix.target }}
68+
cache: true
69+
cache-on-failure: false
70+
71+
- name: Install cargo-edit
72+
if: inputs.publish_release
73+
run: cargo install cargo-edit
74+
75+
- name: Update Version
76+
if: inputs.publish_release
77+
env:
78+
INPUTS_RELEASE_VERSION: ${{ inputs.release_version }}
79+
shell: pwsh
80+
run: |
81+
cargo set-version $env:INPUTS_RELEASE_VERSION
82+
cargo update --workspace
83+
cargo metadata --locked --no-deps --format-version 1 > $null
84+
85+
- name: Setup dotnet
86+
uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 # v5.3.0
87+
with:
88+
dotnet-version: '10.x'
89+
90+
- name: Install WiX
91+
shell: pwsh
92+
run: |
93+
New-Item -ItemType Directory -Force -Path $env:WIX_TOOL_PATH | Out-Null
94+
dotnet tool install --tool-path $env:WIX_TOOL_PATH wix --version $env:WIX_VERSION
95+
$env:WIX_TOOL_PATH >> $env:GITHUB_PATH
96+
$env:PATH = "$env:WIX_TOOL_PATH;$env:PATH"
97+
wix eula accept wix7
98+
wix extension add "WixToolset.UI.wixext/$env:WIX_EXTENSION_VERSION"
99+
wix extension add "WixToolset.Util.wixext/$env:WIX_EXTENSION_VERSION"
100+
wix --version
101+
102+
- name: Install cargo-wix
103+
run: >-
104+
cargo install --locked
105+
--git https://github.com/volks73/cargo-wix.git
106+
--rev ${{ env.CARGO_WIX_REV }}
107+
cargo-wix
108+
109+
- name: Sign Windows executable
110+
if: inputs.publish_release && inputs.azure_signing_account != ''
111+
uses: azure/trusted-signing-action@c7ab2a863ab5f9a846ddb8265964877ef296ee82 # v2.0.0
112+
with:
113+
azure-client-id: ${{ secrets.AZURE_CLIENT_ID }}
114+
azure-client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
115+
azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }}
116+
certificate-profile-name: ${{ inputs.azure_signing_cert_profile }}
117+
endpoint: ${{ inputs.azure_signing_endpoint }}
118+
files: ${{ github.workspace }}\target\${{ matrix.target }}\release\koko.exe
119+
signing-account-name: ${{ inputs.azure_signing_account }}
120+
121+
- name: Create Windows archive
122+
shell: pwsh
123+
run: |
124+
New-Item -ItemType Directory -Force -Path artifacts | Out-Null
125+
7z a "artifacts\koko-${{ matrix.target }}.7z" `
126+
".\assets" `
127+
".\target\${{ matrix.target }}\release\koko.exe"
128+
129+
- name: Package Windows installer
130+
shell: pwsh
131+
run: |
132+
cargo wix `
133+
--toolset modern `
134+
--target ${{ matrix.target }} `
135+
--no-build `
136+
--target-bin-dir "${{ github.workspace }}\target\${{ matrix.target }}\release" `
137+
--package koko `
138+
--output "artifacts\koko-${{ matrix.target }}-installer.msi" `
139+
--nocapture `
140+
crates/server/Cargo.toml
141+
142+
- name: Sign Windows installer
143+
if: inputs.publish_release && inputs.azure_signing_account != ''
144+
uses: azure/trusted-signing-action@c7ab2a863ab5f9a846ddb8265964877ef296ee82 # v2.0.0
145+
with:
146+
azure-client-id: ${{ secrets.AZURE_CLIENT_ID }}
147+
azure-client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
148+
azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }}
149+
certificate-profile-name: ${{ inputs.azure_signing_cert_profile }}
150+
endpoint: ${{ inputs.azure_signing_endpoint }}
151+
files-folder: artifacts
152+
files-folder-filter: msi
153+
files-folder-recurse: false
154+
signing-account-name: ${{ inputs.azure_signing_account }}
155+
156+
- name: Upload Artifacts
157+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
158+
with:
159+
if-no-files-found: error
160+
name: koko-${{ matrix.target }}
161+
path: artifacts

.github/workflows/ci.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,25 @@ jobs:
8686
run_build: true
8787
run_tests: false
8888

89+
build_windows_installer:
90+
name: Build Windows Installer
91+
needs:
92+
- setup_release
93+
- build
94+
permissions:
95+
contents: read
96+
uses: ./.github/workflows/ci-windows-installer.yml
97+
with:
98+
azure_signing_account: ${{ vars.AZURE_SIGNING_ACCOUNT }}
99+
azure_signing_cert_profile: ${{ vars.AZURE_SIGNING_CERT_PROFILE }}
100+
azure_signing_endpoint: ${{ vars.AZURE_SIGNING_ENDPOINT }}
101+
publish_release: ${{ needs.setup_release.outputs.publish_release == 'true' }}
102+
release_version: ${{ needs.setup_release.outputs.release_version }}
103+
secrets:
104+
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
105+
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
106+
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
107+
89108
build_flatpak:
90109
name: Build Flatpak
91110
needs: setup_release
@@ -119,6 +138,7 @@ jobs:
119138
- clippy
120139
- test
121140
- build
141+
- build_windows_installer
122142
- build_flatpak
123143
permissions:
124144
contents: read

crates/server/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,3 +109,4 @@ cargo-run-bin = "1.7.4"
109109
[package.metadata.bin]
110110
cargo-edit = { version = "0.13.1" }
111111
cargo-tarpaulin = { version = "0.31.5" }
112+
cargo-wix = { version = "0.3.9" }

crates/server/wix/main.wxs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
2+
xmlns:ui="http://wixtoolset.org/schemas/v4/wxs/ui">
3+
<Package
4+
Name="Koko"
5+
Manufacturer="LizardByte"
6+
Version="$(var.Version)"
7+
UpgradeCode="28905BC1-502E-4F02-BE83-65F6DF8D4A1D"
8+
Language="1033"
9+
Codepage="1252"
10+
InstallerVersion="500"
11+
Scope="perMachine">
12+
<SummaryInformation
13+
Keywords="Installer"
14+
Manufacturer="LizardByte"
15+
Description="Koko self-hosted media server." />
16+
17+
<MajorUpgrade
18+
Schedule="afterInstallInitialize"
19+
DowngradeErrorMessage="A newer version of [ProductName] is already installed. Setup will now exit." />
20+
21+
<MediaTemplate EmbedCab="yes" />
22+
<SetProperty Id="ARPINSTALLLOCATION" Value="[INSTALLFOLDER]" After="CostFinalize" />
23+
<Property Id="DiskPrompt" Value="Koko Installation" />
24+
<Property Id="ARPHELPLINK" Value="https://app.lizardbyte.dev/support" />
25+
<Property Id="ARPURLINFOABOUT" Value="https://app.lizardbyte.dev" />
26+
<Icon Id="ProductIcon" SourceFile="$(var.CargoTargetDir)\..\assets\icon.ico" />
27+
<Property Id="ARPPRODUCTICON" Value="ProductIcon" />
28+
29+
<Feature
30+
Id="ApplicationFeature"
31+
Title="Koko"
32+
Description="Installs Koko and its required web client files."
33+
Level="1"
34+
ConfigurableDirectory="INSTALLFOLDER"
35+
AllowAdvertise="no"
36+
AllowAbsent="no">
37+
<ComponentRef Id="ApplicationExecutable" />
38+
<ComponentRef Id="LicenseFile" />
39+
<ComponentRef Id="StartMenuShortcut" />
40+
<Files Directory="INSTALLFOLDER" Include="$(var.CargoTargetDir)\..\assets\**" Subdirectory="assets" />
41+
<Files Directory="INSTALLFOLDER" Include="$(var.CargoTargetDir)\..\crates\client-web\dist\**" Subdirectory="crates\client-web\dist" />
42+
</Feature>
43+
44+
<UI>
45+
<ui:WixUI Id="WixUI_FeatureTree" />
46+
<Publish
47+
Dialog="WelcomeDlg"
48+
Control="Next"
49+
Event="NewDialog"
50+
Value="CustomizeDlg"
51+
Order="99"
52+
Condition="1" />
53+
<Publish
54+
Dialog="CustomizeDlg"
55+
Control="Back"
56+
Event="NewDialog"
57+
Value="WelcomeDlg"
58+
Order="99"
59+
Condition="1" />
60+
</UI>
61+
62+
<StandardDirectory Id="ProgramFilesFolder">
63+
<Directory Id="INSTALLFOLDER" Name="Koko">
64+
<Component Id="ApplicationExecutable" Guid="*">
65+
<File
66+
Id="KokoExe"
67+
Name="koko.exe"
68+
Source="$(var.CargoTargetBinDir)\koko.exe"
69+
KeyPath="yes" />
70+
</Component>
71+
<Component Id="LicenseFile" Guid="*">
72+
<File
73+
Id="KokoLicense"
74+
Name="LICENSE"
75+
Source="$(var.CargoTargetDir)\..\LICENSE"
76+
KeyPath="yes" />
77+
</Component>
78+
</Directory>
79+
</StandardDirectory>
80+
81+
<StandardDirectory Id="ProgramMenuFolder">
82+
<Directory Id="ProgramMenuLizardByteFolder" Name="LizardByte">
83+
<Directory Id="ProgramMenuKokoFolder" Name="Koko">
84+
<Component Id="StartMenuShortcut" Guid="*">
85+
<Shortcut
86+
Id="ApplicationStartMenuShortcut"
87+
Name="Koko"
88+
Description="Koko self-hosted media server"
89+
Target="[INSTALLFOLDER]koko.exe"
90+
WorkingDirectory="INSTALLFOLDER" />
91+
<RemoveFolder Id="RemoveProgramMenuKokoFolder" Directory="ProgramMenuKokoFolder" On="uninstall" />
92+
<RemoveFolder Id="RemoveProgramMenuLizardByteFolder" Directory="ProgramMenuLizardByteFolder" On="uninstall" />
93+
<RegistryValue
94+
Root="HKCU"
95+
Key="Software\LizardByte\Koko"
96+
Name="installed"
97+
Type="integer"
98+
Value="1"
99+
KeyPath="yes" />
100+
</Component>
101+
</Directory>
102+
</Directory>
103+
</StandardDirectory>
104+
</Package>
105+
</Wix>

0 commit comments

Comments
 (0)