@@ -30,25 +30,19 @@ jobs:
3030 fail-fast : false
3131 matrix :
3232 include :
33- # Windows MinGW (MSYS2 )
33+ # Windows (MSVC )
3434 - os : windows-latest
35- os_name : windows-mingw
36- architecture : x86_64
37- shell : msys2 {0}
38- build_type : mingw
39- # Windows MSVC (native)
40- - os : windows-latest
41- os_name : windows-msvc
35+ os_name : windows
4236 architecture : x86_64
4337 shell : pwsh
4438 build_type : msvc
45- # Linux (Ubuntu 22.04 for glibc 2.35 compatibility)
39+ # Linux
4640 - os : ubuntu-22.04
4741 os_name : linux
4842 architecture : x86_64
4943 shell : bash
5044 build_type : unix
51- # macOS (ARM64 - macos-latest uses M1 runners )
45+ # macOS (ARM64)
5246 - os : macos-latest
5347 os_name : macos
5448 architecture : arm64
@@ -112,55 +106,36 @@ jobs:
112106 brew install hidapi || true
113107 brew link hidapi || true
114108
115- # =========== Windows MinGW Setup ===========
116- - name : Setup MSYS2 (MinGW)
117- if : matrix.build_type == 'mingw'
118- uses : msys2/setup-msys2@4f806de0a5a7294ffabaff804b38a9b435a73bda # v2.30.0
119- with :
120- msystem : MINGW64
121- update : true
122- install : base-devel mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake mingw-w64-x86_64-hidapi make zip
123-
124- # =========== Windows MSVC Setup ===========
125- - name : Setup vcpkg (MSVC)
109+ # =========== Windows Setup ===========
110+ - name : Setup vcpkg (Windows)
126111 if : matrix.build_type == 'msvc'
127112 uses : lukka/run-vcpkg@5e0cab206a5ea620130caf672fce3e4a6b5666a1 # v11.5
128113 with :
129114 vcpkgGitCommitId : ' 84bab45d415d22042bd0b9081aea57f362da3f35' # 2025.12.12
130115 vcpkgJsonGlob : ' vcpkg.json'
131116
132- - name : Setup CMake and Ninja (MSVC )
117+ - name : Setup CMake and Ninja (Windows )
133118 if : matrix.build_type == 'msvc'
134119 uses : lukka/get-cmake@9e07ecdcee1b12e5037e42f410b67f03e2f626e1 # v4.2.1
135120
136- # =========== Linux/macOS CMake Setup ===========
121+ - name : Install NSIS (Windows)
122+ if : matrix.build_type == 'msvc'
123+ run : choco install nsis -y
124+
125+ # =========== Unix Setup ===========
137126 - name : Setup CMake and Ninja (Unix)
138127 if : matrix.build_type == 'unix'
139128 uses : lukka/get-cmake@9e07ecdcee1b12e5037e42f410b67f03e2f626e1 # v4.2.1
140129
141- # =========== Build Steps ===========
142-
143- # Windows MinGW Build
144- - name : Build and test (Windows MinGW)
145- if : matrix.build_type == 'mingw'
146- run : |
147- mkdir build
148- cd build
149- cmake -G"MSYS Makefiles" -DCMAKE_BUILD_TYPE=Release ..
150- make
151- ctest --output-on-failure
152- strip headsetcontrol.exe
153-
154- # Windows MSVC Build
155- - name : Build and test (Windows MSVC)
130+ # =========== Build ===========
131+ - name : Build and test (Windows)
156132 if : matrix.build_type == 'msvc'
157133 uses : lukka/run-cmake@af1be47fd7c933593f687731bc6fdbee024d3ff4 # v10.8
158134 with :
159135 configurePreset : ' windows-msvc'
160136 buildPreset : ' windows-msvc'
161137 testPreset : ' windows-msvc'
162138
163- # Linux/macOS Build
164139 - name : Build and test (Unix)
165140 if : matrix.build_type == 'unix'
166141 uses : lukka/run-cmake@af1be47fd7c933593f687731bc6fdbee024d3ff4 # v10.8
@@ -176,26 +151,18 @@ jobs:
176151 if : matrix.os_name == 'linux'
177152 run : ccache -s
178153
179- # =========== Post-Build ===========
180-
181- # Strip binaries (Unix only - Windows MinGW already stripped, MSVC doesn't use strip)
154+ # =========== Package ===========
182155 - name : Strip binaries (Unix)
183156 if : matrix.build_type == 'unix'
184157 run : strip build/headsetcontrol
185158
186- # Generate Linux packages (.deb, .rpm, AppImage)
159+ # Linux packages
187160 - name : Generate Linux packages
188161 if : matrix.os_name == 'linux'
189162 run : |
190163 cd build
191-
192- # Generate .deb package
193164 cpack -G DEB
194-
195- # Generate .rpm package
196165 cpack -G RPM
197-
198- # Generate checksums for .deb and .rpm
199166 for pkg in *.deb *.rpm; do
200167 sha256sum "$pkg" > "$pkg.sha256"
201168 done
@@ -205,7 +172,7 @@ jobs:
205172 run : |
206173 cd build
207174
208- # Use cached linuxdeploy or download if not cached
175+ # Use cached linuxdeploy or download
209176 if [ -f /tmp/linuxdeploy/linuxdeploy-x86_64.AppImage ]; then
210177 cp /tmp/linuxdeploy/linuxdeploy-x86_64.AppImage .
211178 else
@@ -215,72 +182,62 @@ jobs:
215182 fi
216183 chmod +x linuxdeploy-x86_64.AppImage
217184
218- # Minimal .desktop file (required, but hidden from app menus with NoDisplay=true)
185+ # Create .desktop file
219186 printf '%s\n' '[Desktop Entry]' 'Type=Application' 'Name=HeadsetControl' 'Exec=headsetcontrol' 'Icon=headsetcontrol' 'Categories=Utility;' 'Terminal=true' 'NoDisplay=true' > headsetcontrol.desktop
220187
221- # Copy icon from assets
222188 cp ../assets/headsetcontrol.png headsetcontrol.png
223189
224- # Build AppImage - linuxdeploy automatically bundles libhidapi and other dependencies
225- # Use --appimage-extract-and-run to avoid FUSE issues on GitHub Actions runners
226- # DEPLOY_LIBSTDCPP=1 bundles libstdc++ for compatibility with older systems
227190 DEPLOY_LIBSTDCPP=1 ./linuxdeploy-x86_64.AppImage --appimage-extract-and-run \
228191 --appdir AppDir \
229192 --executable headsetcontrol \
230193 --desktop-file headsetcontrol.desktop \
231194 --icon-file headsetcontrol.png \
232195 --output appimage
233196
234- # Rename to standard format
235197 mv HeadsetControl-*.AppImage headsetcontrol-${{ matrix.architecture }}.AppImage
236-
237- # Generate checksum
238198 sha256sum headsetcontrol-${{ matrix.architecture }}.AppImage > headsetcontrol-${{ matrix.architecture }}.AppImage.sha256
239199
240- # Package artifacts
241- - name : Package artifacts (MinGW)
242- if : matrix.build_type == 'mingw'
200+ - name : Package portable binary (Linux)
201+ if : matrix.os_name == 'linux'
243202 run : |
244203 cd build
245- zip -9 headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}.zip headsetcontrol.exe
204+ zip -9 headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}.zip headsetcontrol
246205 sha256sum headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}.zip > headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}.zip.sha256
247206
248- - name : Package artifacts (MSVC)
249- if : matrix.build_type == 'msvc'
250- run : |
251- cd build-msvc
252- Compress-Archive -Path headsetcontrol.exe -DestinationPath headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}.zip -CompressionLevel Optimal
253- $hash = (Get-FileHash -Algorithm SHA256 headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}.zip).Hash.ToLower()
254- $filename = "headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}.zip"
255- # Use Unix line endings for cross-platform compatibility
256- [System.IO.File]::WriteAllText("$filename.sha256", "$hash $filename`n")
257-
258- - name : Package artifacts (Unix)
259- if : matrix.build_type == 'unix'
207+ - name : Package portable binary (macOS)
208+ if : matrix.os_name == 'macos'
260209 run : |
261210 cd build
262211 zip -9 headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}.zip headsetcontrol
263- if [ "${{ matrix.os_name }}" = "macos" ]; then
264- shasum -a 256 headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}.zip > headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}.zip.sha256
265- else
266- sha256sum headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}.zip > headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}.zip.sha256
267- fi
212+ shasum -a 256 headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}.zip > headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}.zip.sha256
268213
269- - name : Upload build artifacts (MinGW)
270- if : matrix.build_type == 'mingw'
271- uses : actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
272- with :
273- name : headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}
274- path : |
275- build/headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}.zip
276- build/headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}.zip.sha256
277- retention-days : 90
214+ # Windows: installer + portable exe
215+ - name : Generate Windows installer
216+ if : matrix.build_type == 'msvc'
217+ run : |
218+ cd build-msvc
219+ cpack -G NSIS
220+ $installer = Get-ChildItem -Filter "headsetcontrol-*.exe" | Where-Object { $_.Name -ne "headsetcontrol.exe" } | Select-Object -First 1
221+ if ($installer) {
222+ Rename-Item -Path $installer.FullName -NewName "headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}-setup.exe"
223+ $hash = (Get-FileHash -Algorithm SHA256 "headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}-setup.exe").Hash.ToLower()
224+ [System.IO.File]::WriteAllText("headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}-setup.exe.sha256", "$hash headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}-setup.exe`n")
225+ }
226+
227+ - name : Package portable binary (Windows)
228+ if : matrix.build_type == 'msvc'
229+ run : |
230+ cd build-msvc
231+ Copy-Item headsetcontrol.exe "headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}.exe"
232+ $hash = (Get-FileHash -Algorithm SHA256 "headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}.exe").Hash.ToLower()
233+ [System.IO.File]::WriteAllText("headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}.exe.sha256", "$hash headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}.exe`n")
278234
279- - name : Upload build artifacts (Linux)
235+ # =========== Upload ===========
236+ - name : Upload artifacts (Linux)
280237 if : matrix.os_name == 'linux'
281238 uses : actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
282239 with :
283- name : headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}
240+ name : headsetcontrol-${{ matrix.os_name }}
284241 path : |
285242 build/headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}.zip
286243 build/headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}.zip.sha256
@@ -292,29 +249,31 @@ jobs:
292249 build/headsetcontrol-*.AppImage.sha256
293250 retention-days : 90
294251
295- - name : Upload build artifacts (macOS)
252+ - name : Upload artifacts (macOS)
296253 if : matrix.os_name == 'macos'
297254 uses : actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
298255 with :
299- name : headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}
256+ name : headsetcontrol-${{ matrix.os_name }}
300257 path : |
301258 build/headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}.zip
302259 build/headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}.zip.sha256
303260 retention-days : 90
304261
305- - name : Upload build artifacts (MSVC )
262+ - name : Upload artifacts (Windows )
306263 if : matrix.build_type == 'msvc'
307264 uses : actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
308265 with :
309- name : headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}
266+ name : headsetcontrol-${{ matrix.os_name }}
310267 path : |
311- build-msvc/headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}.zip
312- build-msvc/headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}.zip.sha256
268+ build-msvc/headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}-setup.exe
269+ build-msvc/headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}-setup.exe.sha256
270+ build-msvc/headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}.exe
271+ build-msvc/headsetcontrol-${{ matrix.os_name }}-${{ matrix.architecture }}.exe.sha256
313272 retention-days : 90
314273
315274 create-release :
316275 needs : [build]
317- if : github.ref == 'refs/heads/master' # Only create release from master
276+ if : github.ref == 'refs/heads/master'
318277 runs-on : ubuntu-latest
319278 permissions :
320279 contents : write
@@ -330,69 +289,58 @@ jobs:
330289 path : ./artifacts
331290
332291 - name : Generate changelog
333- id : changelog
334292 run : |
335- echo "## 🚀 Continuous Build" > CHANGELOG.md
336- echo "" >> CHANGELOG.md
337- echo "Latest automated build from \`master\` branch." >> CHANGELOG.md
338- echo "" >> CHANGELOG.md
339- echo "### 📦 Downloads" >> CHANGELOG.md
340- echo "" >> CHANGELOG.md
341- echo "#### Windows" >> CHANGELOG.md
342- for file in artifacts/*windows*.zip; do
343- if [ -f "$file" ]; then
344- name=$(basename "$file")
345- if [[ "$name" == *"msvc"* ]]; then
346- echo "- [${name}](https://github.com/${{ github.repository }}/releases/download/continuous/${name}) (MSVC - native Windows)" >> CHANGELOG.md
347- else
348- echo "- [${name}](https://github.com/${{ github.repository }}/releases/download/continuous/${name}) (MinGW)" >> CHANGELOG.md
349- fi
350- fi
293+ cat > CHANGELOG.md << 'HEADER'
294+ ## Continuous Build
295+
296+ Latest automated build from `master` branch.
297+
298+ ### Downloads
299+
300+ #### Windows
301+ HEADER
302+
303+ for file in artifacts/*-setup.exe; do
304+ [ -f "$file" ] && echo "- [$(basename "$file")](https://github.com/${{ github.repository }}/releases/download/continuous/$(basename "$file")) - Installer (recommended)" >> CHANGELOG.md
351305 done
306+ for file in artifacts/*windows*.exe; do
307+ [[ -f "$file" && ! "$file" == *-setup.exe ]] && echo "- [$(basename "$file")](https://github.com/${{ github.repository }}/releases/download/continuous/$(basename "$file")) - Portable" >> CHANGELOG.md
308+ done
309+
352310 echo "" >> CHANGELOG.md
353311 echo "#### Linux" >> CHANGELOG.md
354- for file in artifacts/headsetcontrol-*.AppImage; do
355- if [ -f "$file" ]; then
356- echo "- [$(basename "$file")](https://github.com/${{ github.repository }}/releases/download/continuous/$(basename "$file")) (AppImage - universal)" >> CHANGELOG.md
357- fi
312+ for file in artifacts/*.AppImage; do
313+ [ -f "$file" ] && echo "- [$(basename "$file")](https://github.com/${{ github.repository }}/releases/download/continuous/$(basename "$file")) - AppImage (universal)" >> CHANGELOG.md
358314 done
359315 for file in artifacts/*.deb; do
360- if [ -f "$file" ]; then
361- echo "- [$(basename "$file")](https://github.com/${{ github.repository }}/releases/download/continuous/$(basename "$file")) (Debian/Ubuntu)" >> CHANGELOG.md
362- fi
316+ [ -f "$file" ] && echo "- [$(basename "$file")](https://github.com/${{ github.repository }}/releases/download/continuous/$(basename "$file")) - Debian/Ubuntu" >> CHANGELOG.md
363317 done
364318 for file in artifacts/*.rpm; do
365- if [ -f "$file" ]; then
366- echo "- [$(basename "$file")](https://github.com/${{ github.repository }}/releases/download/continuous/$(basename "$file")) (Fedora/RHEL)" >> CHANGELOG.md
367- fi
319+ [ -f "$file" ] && echo "- [$(basename "$file")](https://github.com/${{ github.repository }}/releases/download/continuous/$(basename "$file")) - Fedora/RHEL" >> CHANGELOG.md
368320 done
369321 for file in artifacts/*linux*.zip; do
370- if [ -f "$file" ]; then
371- echo "- [$(basename "$file")](https://github.com/${{ github.repository }}/releases/download/continuous/$(basename "$file")) (portable binary)" >> CHANGELOG.md
372- fi
322+ [ -f "$file" ] && echo "- [$(basename "$file")](https://github.com/${{ github.repository }}/releases/download/continuous/$(basename "$file")) - Portable" >> CHANGELOG.md
373323 done
324+
374325 echo "" >> CHANGELOG.md
375326 echo "#### macOS" >> CHANGELOG.md
376327 for file in artifacts/*macos*.zip; do
377- if [ -f "$file" ]; then
378- echo "- [$(basename "$file")](https://github.com/${{ github.repository }}/releases/download/continuous/$(basename "$file"))" >> CHANGELOG.md
379- fi
328+ [ -f "$file" ] && echo "- [$(basename "$file")](https://github.com/${{ github.repository }}/releases/download/continuous/$(basename "$file")) - Portable" >> CHANGELOG.md
380329 done
381- echo "" >> CHANGELOG.md
382- echo "### 🔐 Checksums (SHA256)" >> CHANGELOG.md
383- echo '```' >> CHANGELOG.md
330+
331+ cat >> CHANGELOG.md << 'FOOTER'
332+
333+ ### Checksums (SHA256)
334+ ```
335+ FOOTER
384336 cat artifacts/*.sha256 >> CHANGELOG.md 2>/dev/null || true
385337 echo '```' >> CHANGELOG.md
386- echo "" >> CHANGELOG.md
387- echo "### 📝 Recent Changes" >> CHANGELOG.md
388- echo '```' >> CHANGELOG.md
389- git log --oneline -10 >> CHANGELOG.md
390- echo '```' >> CHANGELOG.md
338+
391339 echo "" >> CHANGELOG.md
392340 echo "---" >> CHANGELOG.md
393- echo "*Built from commit: \` ${{ github.sha }}\` *" >> CHANGELOG.md
341+ echo "*Built from [\`${GITHUB_SHA:0:7}\`](https://github.com/ ${{ github.repository }}/commit/${{ github. sha }}) *" >> CHANGELOG.md
394342
395- - name : Create/Update continuous release
343+ - name : Create/Update release
396344 uses : ncipollo/release-action@b7eabc95ff50cbeeedec83973935c8f306dfcd0b # v1.20.0
397345 with :
398346 tag : continuous
0 commit comments