13 Commits
Author SHA1 Message Date
fristy f28d26b585 feat: BE prefix filter, fail-loud error notifications
CI / build-and-test (push) Successful in 1m27s
CI / release (push) Successful in 2m30s
2026-09-05 18:20:54 +03:00
fristy a7413c4b0e ci: invoke vpk.dll directly, slim restore step
CI / release (push) Successful in 13m54s
CI / build-and-test (push) Successful in 5m24s
2026-09-05 16:23:07 +03:00
fristy ead3315170 ci: diagnose tool restore environment
CI / build-and-test (push) Successful in 4m58s
CI / release (push) Failing after 8m23s
2026-09-05 15:57:22 +03:00
fristy 0a0ce5c267 ci: explicit tool manifest path for tool restore
CI / build-and-test (push) Successful in 1m31s
CI / release (push) Failing after 44s
2026-09-05 15:27:46 +03:00
fristy 01f3544f78 ci: fail loud on velopack errors, guard release assets
CI / release (push) Failing after 1m8s
CI / build-and-test (push) Successful in 1m42s
2026-09-05 15:06:50 +03:00
fristy 8d806d5bff ci: fix tool restore, enable cache, pin actions, merge build+test, guard releases
CI / release (push) Successful in 1m45s
CI / build-and-test (push) Successful in 2m4s
2026-09-05 14:51:21 +03:00
fristy 3a268dcaf1 ci: add dotnet tools caching to speed up tool restore (was 32 min)
CI / test (push) Successful in 55s
CI / release (push) Canceled after 0s
CI / build (push) Canceled after 2m33s
2026-09-05 14:31:49 +03:00
fristy 2de313c966 ci: fix Restore step to use powershell shell for gitea-act runner
CI / build (push) Canceled after 38m40s
CI / test (push) Successful in 54s
CI / release (push) Canceled after 0s
2026-09-05 13:53:43 +03:00
fristy 198ba358dd ci: fix Restore tools step to use powershell shell for gitea-act runner
CI / build (push) Failing after 1m1s
CI / release (push) Skipped
CI / test (push) Successful in 52s
2026-09-05 13:50:27 +03:00
fristy 5a36cd9b21 ci: replace all pwsh with powershell for gitea-act runner compatibility
CI / test (push) Successful in 48s
CI / build (push) Failing after 48s
CI / release (push) Skipped
2026-09-05 13:45:55 +03:00
fristy de22472482 ci: fix cache status step shell from pwsh to powershell for gitea-act runner
CI / test (push) Failing after 48s
CI / build (push) Failing after 51s
CI / release (push) Skipped
2026-09-05 13:43:01 +03:00
fristy 14f989f35a ci: downgrade actions/cache to v3 to fix pwsh path issue on gitea-act runner
CI / build (push) Failing after 48s
CI / test (push) Failing after 54s
CI / release (push) Skipped
2026-09-05 13:37:12 +03:00
fristy 188187bf83 update test: bump to 0.3.1
CI / test (push) Failing after 48s
CI / release (push) Skipped
CI / build (push) Failing after 1m3s
2026-09-05 12:53:23 +03:00
7 changed files with 114 additions and 117 deletions

No files matched your search

+3 -2
View File
@@ -6,7 +6,8 @@
"version": "0.0.1298", "version": "0.0.1298",
"commands": [ "commands": [
"vpk" "vpk"
] ],
"rollForward": false
} }
} }
} }
+59 -106
View File
@@ -1,5 +1,4 @@
name: CI name: CI
on: on:
push: push:
branches: branches:
@@ -9,90 +8,47 @@ on:
pull_request: pull_request:
branches: branches:
- main - main
workflow_dispatch: concurrency:
group: ${{ gitea.workflow }}-${{ gitea.ref }}
cancel-in-progress: ${{ !startsWith(gitea.ref, 'refs/tags/') }}
env:
NUGET_PACKAGES: ${{ runner.temp }}\.nuget\packages
DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPT_OUT: true
jobs: jobs:
build: build-and-test:
runs-on: windows-latest runs-on: windows-latest
env: timeout-minutes: 20
NUGET_PACKAGES: ${{ runner.temp }}/.nuget/packages
DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPT_OUT: true
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
with: with:
fetch-depth: 1 fetch-depth: 1
- name: Setup .NET 8 SDK - name: Setup .NET 8 SDK
uses: actions/setup-dotnet@v4 uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9
with: with:
dotnet-version: 8.0.424 dotnet-version: 8.0.x
env:
DOTNET_INSTALL_DIR: ${{ runner.temp }}\dotnet
- name: Cache NuGet packages - name: Cache NuGet packages
id: nuget-cache uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830
uses: actions/cache@v4
continue-on-error: true
with: with:
path: ${{ runner.temp }}/.nuget/packages path: ${{ runner.temp }}\.nuget\packages
key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj', '.config/dotnet-tools.json') }} key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj', 'global.json', '.config/dotnet-tools.json') }}
restore-keys: | restore-keys: |
nuget-${{ runner.os }}- nuget-${{ runner.os }}-
- name: Cache status
if: always()
shell: pwsh
run: |
Write-Host "NuGet cache hit: ${{ steps.nuget-cache.outputs.cache-hit }}"
- name: Restore tools - name: Restore tools
run: dotnet tool restore shell: powershell
- name: Restore
run: dotnet restore src/RgbLedStripController/RgbLedStripController.csproj --configfile NuGet.Config
- name: Build (Release)
run: dotnet build src/RgbLedStripController/RgbLedStripController.csproj -c Release --no-restore
test:
runs-on: windows-latest
env:
NUGET_PACKAGES: ${{ runner.temp }}/.nuget/packages
DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPT_OUT: true
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Setup .NET 8 SDK
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.424
env:
DOTNET_INSTALL_DIR: ${{ runner.temp }}\dotnet
- name: Cache NuGet packages
id: nuget-cache
uses: actions/cache@v4
continue-on-error: true
with:
path: ${{ runner.temp }}/.nuget/packages
key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj', '.config/dotnet-tools.json') }}
restore-keys: |
nuget-${{ runner.os }}-
- name: Cache status
if: always()
shell: pwsh
run: | run: |
Write-Host "NuGet cache hit: ${{ steps.nuget-cache.outputs.cache-hit }}" $ErrorActionPreference = "Stop"
dotnet tool restore --tool-manifest .config/dotnet-tools.json
if ($LASTEXITCODE -ne 0) { throw "tool restore failed ($LASTEXITCODE)" }
- name: Restore
shell: powershell
run: dotnet restore src/RgbLedStripController/RgbLedStripController.csproj --configfile NuGet.Config
- name: Build (Release)
shell: powershell
run: dotnet build src/RgbLedStripController/RgbLedStripController.csproj -c Release --no-restore
- name: Run tests (if any test projects exist) - name: Run tests (if any test projects exist)
shell: pwsh shell: powershell
run: | run: |
$ErrorActionPreference = "Stop" $ErrorActionPreference = "Stop"
$tests = @(Get-ChildItem -Recurse -Filter "*Tests.csproj" | Where-Object { $_.FullName -notlike "*\obj\*" -and $_.FullName -notlike "*\bin\*" }) $tests = @(Get-ChildItem -Recurse -Filter "*Tests.csproj" | Where-Object { $_.FullName -notlike "*\obj\*" -and $_.FullName -notlike "*\bin\*" })
@@ -104,57 +60,54 @@ jobs:
dotnet test $t.FullName -c Release dotnet test $t.FullName -c Release
if ($LASTEXITCODE -ne 0) { throw "dotnet test failed for $($t.FullName)" } if ($LASTEXITCODE -ne 0) { throw "dotnet test failed for $($t.FullName)" }
} }
release: release:
needs: needs:
- build - build-and-test
- test if: startsWith(gitea.ref, 'refs/tags/v')
if: startsWith(gitea.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch'
runs-on: windows-latest runs-on: windows-latest
env: timeout-minutes: 30
NUGET_PACKAGES: ${{ runner.temp }}/.nuget/packages
DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPT_OUT: true
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
with: with:
fetch-depth: 1 fetch-depth: 1
- name: Setup .NET 8 SDK - name: Setup .NET 8 SDK
uses: actions/setup-dotnet@v4 uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9
with: with:
dotnet-version: 8.0.424 dotnet-version: 8.0.x
env:
DOTNET_INSTALL_DIR: ${{ runner.temp }}\dotnet
- name: Cache NuGet packages - name: Cache NuGet packages
id: nuget-cache uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830
uses: actions/cache@v4
continue-on-error: true
with: with:
path: ${{ runner.temp }}/.nuget/packages path: ${{ runner.temp }}\.nuget\packages
key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj', '.config/dotnet-tools.json') }} key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj', 'global.json', '.config/dotnet-tools.json') }}
restore-keys: | restore-keys: |
nuget-${{ runner.os }}- nuget-${{ runner.os }}-
- name: Cache status
if: always()
shell: pwsh
run: |
Write-Host "NuGet cache hit: ${{ steps.nuget-cache.outputs.cache-hit }}"
- name: Restore tools - name: Restore tools
run: dotnet tool restore shell: powershell
- name: Package with Velopack (Setup.exe + Portable.zip)
shell: pwsh
run: | run: |
$ErrorActionPreference = "Stop" $ErrorActionPreference = "Stop"
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts/release/package-velopack.ps1 dotnet tool restore --tool-manifest .config/dotnet-tools.json
if ($LASTEXITCODE -ne 0) { throw "tool restore failed ($LASTEXITCODE)" }
- name: Assert tag matches csproj version
shell: powershell
run: |
$ErrorActionPreference = "Stop"
$ref = "${{ gitea.ref_name }}"
$projXml = [xml](Get-Content src/RgbLedStripController/RgbLedStripController.csproj)
$version = $projXml.Project.PropertyGroup | Where-Object { $_.Version } | Select-Object -First 1 -ExpandProperty Version
if ("v$version" -ne $ref) { throw "Tag $ref does not match csproj version $version" }
- name: Package with Velopack (Setup.exe + Portable.zip)
shell: powershell
run: |
$ErrorActionPreference = "Stop"
& "$env:GITHUB_WORKSPACE/scripts/release/package-velopack.ps1"
if ($LASTEXITCODE -ne 0) { throw "package-velopack.ps1 failed ($LASTEXITCODE)" }
$out = Join-Path $env:GITHUB_WORKSPACE "artifacts/velopack/win-x64-stable"
foreach ($p in @("*.exe", "*.zip", "*.json", "*.nupkg")) {
if (@(Get-ChildItem -Path (Join-Path $out $p) -File -ErrorAction SilentlyContinue).Count -eq 0) { throw "Velopack output missing pattern $p in $out" }
}
- name: Create Gitea Release with assets - name: Create Gitea Release with assets
uses: akkuman/gitea-release-action@v1 uses: akkuman/gitea-release-action@5a83c90484ef4355121df5eb60558c8ce66e81ac
with: with:
token: ${{ secrets.API_TOKEN }} token: ${{ secrets.API_TOKEN }}
tag_name: ${{ gitea.ref_name }} tag_name: ${{ gitea.ref_name }}
@@ -167,8 +120,8 @@ jobs:
name: ${{ gitea.ref_name }} name: ${{ gitea.ref_name }}
body: | body: |
Release ${{ gitea.ref_name }} Release ${{ gitea.ref_name }}
- RGBLedStripController-Setup-${{ gitea.ref_name }}-x64.exe (Windows Installer) - RGBLedStripController-Setup-${{ gitea.ref_name }}-x64.exe (Windows Installer)
- RGBLedStripController-Portable-${{ gitea.ref_name }}-x64.zip (Portable) - RGBLedStripController-Portable-${{ gitea.ref_name }}-x64.zip (Portable)
draft: false draft: false
prerelease: false prerelease: false
+6
View File
@@ -0,0 +1,6 @@
{
"sdk": {
"version": "8.0.100",
"rollForward": "latestFeature"
}
}
+9 -3
View File
@@ -10,7 +10,7 @@
5. Çıktı: artifacts/velopack/win-x64-stable/ 5. Çıktı: artifacts/velopack/win-x64-stable/
.NOTES .NOTES
Velopack CLI: dotnet tool restore ile yüklenen vpk kullanılır Velopack CLI: NuGet paketinden dogrudan calistirilan vpk.dll kullanilir
Icon: Assets/AppIcon.ico (installer ikonu) Icon: Assets/AppIcon.ico (installer ikonu)
Velopack CLI args: camelCase (--outputDir, --packId, --packTitle, --packAuthors, --packVersion, --packDir, --mainExe) Velopack CLI args: camelCase (--outputDir, --packId, --packTitle, --packAuthors, --packVersion, --packDir, --mainExe)
#> #>
@@ -66,11 +66,16 @@ $publishArgs = @(
Write-Host "dotnet publish..." -ForegroundColor Cyan Write-Host "dotnet publish..." -ForegroundColor Cyan
if (-not $WhatIf) { if (-not $WhatIf) {
& dotnet $publishArgs & dotnet $publishArgs
if ($LASTEXITCODE -ne 0) { throw "dotnet publish failed ($LASTEXITCODE)" }
} else { } else {
Write-Host "[WhatIf] dotnet $publishArgs" Write-Host "[WhatIf] dotnet $publishArgs"
} }
# 2. vpk pack (args camelCase) # 2. vpk pack (args camelCase)
$nugetPkgs = $env:NUGET_PACKAGES
if (-not $nugetPkgs) { $nugetPkgs = Join-Path $env:USERPROFILE ".nuget/packages" }
$vpkDll = Join-Path $nugetPkgs "vpk/0.0.1298/tools/net8.0/any/vpk.dll"
if (-not (Test-Path $vpkDll)) { throw "vpk.dll not found at $vpkDll" }
$vpkArgs = @( $vpkArgs = @(
"pack", "pack",
"--outputDir", $velopackDir, "--outputDir", $velopackDir,
@@ -84,9 +89,10 @@ $vpkArgs = @(
) )
Write-Host "vpk pack..." -ForegroundColor Cyan Write-Host "vpk pack..." -ForegroundColor Cyan
if (-not $WhatIf) { if (-not $WhatIf) {
& dotnet tool run vpk $vpkArgs & dotnet $vpkDll $vpkArgs
if ($LASTEXITCODE -ne 0) { throw "vpk pack failed ($LASTEXITCODE)" }
} else { } else {
Write-Host "[WhatIf] dotnet tool run vpk $vpkArgs" Write-Host "[WhatIf] dotnet $vpkDll $vpkArgs"
} }
# 3. Sadece Setup.exe ve Portable.zip'i istenen formata rename et # 3. Sadece Setup.exe ve Portable.zip'i istenen formata rename et
@@ -4,10 +4,10 @@
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework> <TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
<UseWPF>true</UseWPF> <UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms> <UseWindowsForms>true</UseWindowsForms>
<Version>0.3.0</Version> <Version>0.3.2</Version>
<AssemblyVersion>0.3.0.0</AssemblyVersion> <AssemblyVersion>0.3.2.0</AssemblyVersion>
<FileVersion>0.3.0.0</FileVersion> <FileVersion>0.3.2.0</FileVersion>
<InformationalVersion>0.3.0</InformationalVersion> <InformationalVersion>0.3.2</InformationalVersion>
<AssemblyProduct>Fristy.RgbLedStripController</AssemblyProduct> <AssemblyProduct>Fristy.RgbLedStripController</AssemblyProduct>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
@@ -39,6 +39,7 @@ public sealed class BleDeviceService : IBleTransport
await MergeWindowsDeviceInventoryAsync(captures); await MergeWindowsDeviceInventoryAsync(captures);
return captures.Values return captures.Values
.Where(capture => IsSupportedAddress(capture.Address))
.Select(capture => new BleScanResult .Select(capture => new BleScanResult
{ {
DeviceId = FormatAddress(capture.Address), DeviceId = FormatAddress(capture.Address),
@@ -299,6 +300,9 @@ public sealed class BleDeviceService : IBleTransport
|| normalized.Contains("DUOCO"); || normalized.Contains("DUOCO");
} }
internal static bool IsSupportedAddress(ulong address)
=> FormatAddress(address).StartsWith("BE:", StringComparison.OrdinalIgnoreCase);
private static async Task RunScanPassAsync( private static async Task RunScanPassAsync(
ConcurrentDictionary<ulong, ScanCapture> captures, ConcurrentDictionary<ulong, ScanCapture> captures,
BluetoothLEScanningMode mode, BluetoothLEScanningMode mode,
@@ -360,7 +364,8 @@ public sealed class BleDeviceService : IBleTransport
if (!device.Properties.TryGetValue("System.Devices.Aep.DeviceAddress", out var addressValue) if (!device.Properties.TryGetValue("System.Devices.Aep.DeviceAddress", out var addressValue)
|| addressValue is not string addressText || addressValue is not string addressText
|| !TryParseBluetoothAddress(addressText, out var address)) || !TryParseBluetoothAddress(addressText, out var address)
|| !IsSupportedAddress(address))
{ {
continue; continue;
} }
@@ -99,6 +99,11 @@ public sealed class MultiDeviceController : IAsyncDisposable
public async Task<ConnectedDeviceViewModel> ConnectAsync(BleScanResult device, CancellationToken cancellationToken = default) public async Task<ConnectedDeviceViewModel> ConnectAsync(BleScanResult device, CancellationToken cancellationToken = default)
{ {
if (!BleDeviceService.IsSupportedAddress(device.AddressValue))
{
throw new ArgumentException($"Desteklenmeyen cihaz adresi: {device.BluetoothAddress}", nameof(device));
}
DeviceConnectionContext? existing; DeviceConnectionContext? existing;
lock (_stateLock) lock (_stateLock)
{ {
@@ -583,6 +588,11 @@ public sealed class MultiDeviceController : IAsyncDisposable
private void UpsertKnownDevice(BleScanResult device) private void UpsertKnownDevice(BleScanResult device)
{ {
if (!BleDeviceService.IsSupportedAddress(device.AddressValue))
{
return;
}
var alias = GetAlias(device.BluetoothAddress); var alias = GetAlias(device.BluetoothAddress);
var profile = new DeviceProfile( var profile = new DeviceProfile(
string.IsNullOrWhiteSpace(alias) ? device.NativeName : alias, string.IsNullOrWhiteSpace(alias) ? device.NativeName : alias,
@@ -675,6 +685,19 @@ public sealed class MultiDeviceController : IAsyncDisposable
: connections.Any(context => context.ViewModel.ConnectionStatus == DeviceConnectionStatus.Faulted) : connections.Any(context => context.ViewModel.ConnectionStatus == DeviceConnectionStatus.Faulted)
? DeviceConnectionStatus.Faulted ? DeviceConnectionStatus.Faulted
: DeviceConnectionStatus.Disconnected; : DeviceConnectionStatus.Disconnected;
if (State.ConnectionStatus == DeviceConnectionStatus.Faulted
&& !State.StatusText.Contains("Hata:", StringComparison.Ordinal))
{
var firstFault = connections
.Where(context => context.ViewModel.ConnectionStatus == DeviceConnectionStatus.Faulted)
.Select(context => context.ViewModel.StatusText)
.FirstOrDefault(text => !string.IsNullOrWhiteSpace(text));
if (!string.IsNullOrWhiteSpace(firstFault))
{
State.StatusText = firstFault;
}
}
} }
private void EnsureTargetsAvailable() private void EnsureTargetsAvailable()
@@ -708,7 +731,10 @@ public sealed class MultiDeviceController : IAsyncDisposable
: $"İşlem başarısız oldu: {firstFailureMessage}"; : $"İşlem başarısız oldu: {firstFailureMessage}";
} }
return $"{successMessage} {successCount}/{totalCount} hedef başarılı, {failureCount} hata."; var partialMessage = $"{successMessage} {successCount}/{totalCount} hedef başarılı, {failureCount} hata.";
return string.IsNullOrWhiteSpace(firstFailureMessage)
? partialMessage
: $"{partialMessage} Hata: {firstFailureMessage}";
} }
private sealed class DeviceConnectionContext private sealed class DeviceConnectionContext