Initial commit: RGB LED Strip Controller v0.3.0
- WPF + WinRT BLE controller for ELK-BLEDOM compatible LED strips - Multi-device control, effects, grayscale and temperature modes - Velopack updates via Gitea Releases, Gitea Actions CI
This commit is contained in:
40 files changed
+5411
No files matched your search
@@ -0,0 +1,271 @@
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string]$Project = "src/RgbLedStripController/RgbLedStripController.csproj",
|
||||
[string]$Configuration = "Release",
|
||||
[string]$Runtime = "win-x64",
|
||||
[string]$Channel = "win-x64-stable",
|
||||
[string]$PackId = "Fristy.RgbLedStripController",
|
||||
[string]$PackTitle = "RGB Led Strip Controller",
|
||||
[string]$PackAuthors = "fristy",
|
||||
[string]$GiteaRepoUrl = "https://git.fristy.net/fristy/rgb-led-strip-controller",
|
||||
[string]$InstallerIcon = "src/RgbLedStripController/Assets/AppIcon.ico",
|
||||
[string]$PfxPath = "",
|
||||
[string]$SignToolPath = "signtool.exe",
|
||||
[int]$SignParallel = 1,
|
||||
[switch]$SkipSigning,
|
||||
[switch]$SkipCloudCheck
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
Set-StrictMode -Version Latest
|
||||
|
||||
$repoRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot "..\.."))
|
||||
$projectPath = [System.IO.Path]::GetFullPath((Join-Path $repoRoot $Project))
|
||||
$nugetConfigPath = [System.IO.Path]::GetFullPath((Join-Path $repoRoot "NuGet.Config"))
|
||||
|
||||
if (-not (Test-Path -LiteralPath $projectPath)) {
|
||||
throw "Project file not found: $projectPath"
|
||||
}
|
||||
|
||||
[xml]$projectXml = Get-Content -Raw -LiteralPath $projectPath
|
||||
$versionNode = $null
|
||||
foreach ($propertyGroup in @($projectXml.Project.PropertyGroup)) {
|
||||
if ($propertyGroup.PSObject.Properties.Name -contains "Version" -and -not [string]::IsNullOrWhiteSpace($propertyGroup.Version)) {
|
||||
$versionNode = $propertyGroup.Version
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
$version = [string]$versionNode
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($version)) {
|
||||
throw "No <Version> found in project file: $projectPath"
|
||||
}
|
||||
|
||||
function Assert-WorkspacePath {
|
||||
param([string]$Path)
|
||||
|
||||
$fullPath = [System.IO.Path]::GetFullPath($Path)
|
||||
if (-not $fullPath.StartsWith($repoRoot, [System.StringComparison]::OrdinalIgnoreCase)) {
|
||||
throw "Refusing to use path outside workspace: $fullPath"
|
||||
}
|
||||
|
||||
return $fullPath
|
||||
}
|
||||
|
||||
function Resolve-AbsolutePath {
|
||||
param([string]$Path)
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($Path)) {
|
||||
throw "Path value cannot be empty."
|
||||
}
|
||||
|
||||
if ([System.IO.Path]::IsPathRooted($Path)) {
|
||||
return [System.IO.Path]::GetFullPath($Path)
|
||||
}
|
||||
|
||||
return [System.IO.Path]::GetFullPath((Join-Path $repoRoot $Path))
|
||||
}
|
||||
|
||||
function Get-GiteaReleaseTags {
|
||||
param([string]$RepoUrl)
|
||||
|
||||
$uri = [Uri]$RepoUrl
|
||||
$segments = $uri.AbsolutePath.Trim("/").Split("/") | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }
|
||||
if ($segments.Count -lt 2) {
|
||||
throw "Could not parse owner/repo from GiteaRepoUrl: $RepoUrl"
|
||||
}
|
||||
|
||||
$owner = $segments[-2]
|
||||
$repo = $segments[-1]
|
||||
$apiUrl = "{0}://{1}/api/v1/repos/{2}/{3}/releases?draft=false&limit=50" -f $uri.Scheme, $uri.Authority, $owner, $repo
|
||||
|
||||
try {
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||
$releases = Invoke-RestMethod -Uri $apiUrl -Method Get -ErrorAction Stop
|
||||
}
|
||||
catch {
|
||||
throw "Gitea releases could not be read: $apiUrl`n$($_.Exception.Message)"
|
||||
}
|
||||
|
||||
return @($releases | ForEach-Object { $_.tag_name } | Where-Object { -not [string]::IsNullOrWhiteSpace($_) })
|
||||
}
|
||||
|
||||
function Get-MaxVersionFromTags {
|
||||
param([string[]]$Tags)
|
||||
|
||||
$versions = @()
|
||||
foreach ($tag in $Tags) {
|
||||
$clean = $tag.TrimStart("v", "V")
|
||||
$parsed = $null
|
||||
if ([Version]::TryParse($clean, [ref]$parsed)) {
|
||||
$versions += $parsed
|
||||
}
|
||||
}
|
||||
|
||||
if ($versions.Count -eq 0) {
|
||||
return $null
|
||||
}
|
||||
|
||||
return ($versions | Sort-Object -Descending | Select-Object -First 1)
|
||||
}
|
||||
|
||||
function Read-SecretAsPlainText {
|
||||
param([string]$Prompt)
|
||||
|
||||
$secureString = Read-Host -Prompt $Prompt -AsSecureString
|
||||
if ($secureString.Length -eq 0) {
|
||||
throw "Empty password is not allowed."
|
||||
}
|
||||
|
||||
$bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($secureString)
|
||||
try {
|
||||
return [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr)
|
||||
}
|
||||
finally {
|
||||
if ($bstr -ne [IntPtr]::Zero) {
|
||||
[Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Resolve-SignToolExecutable {
|
||||
param([string]$RequestedPath)
|
||||
|
||||
if (Test-Path -LiteralPath $RequestedPath) {
|
||||
return [System.IO.Path]::GetFullPath($RequestedPath)
|
||||
}
|
||||
|
||||
$command = Get-Command -Name $RequestedPath -ErrorAction SilentlyContinue
|
||||
if ($null -ne $command) {
|
||||
return $command.Source
|
||||
}
|
||||
|
||||
throw "signtool.exe could not be resolved. Pass -SignToolPath with an absolute path if needed."
|
||||
}
|
||||
|
||||
$publishDir = Assert-WorkspacePath (Join-Path $repoRoot "artifacts\publish\$Runtime\$version")
|
||||
$releaseDir = Assert-WorkspacePath (Join-Path $repoRoot "artifacts\velopack\$Channel")
|
||||
$mainExe = "RgbLedStripController.exe"
|
||||
$dotnet = "dotnet"
|
||||
$signingEnabled = (-not $SkipSigning.IsPresent) -and (-not [string]::IsNullOrWhiteSpace($PfxPath))
|
||||
if ((-not $SkipSigning.IsPresent) -and [string]::IsNullOrWhiteSpace($PfxPath)) {
|
||||
Write-Warning "PfxPath not supplied; Authenticode signing will be skipped. Pass -PfxPath to enable it."
|
||||
}
|
||||
$signToolExecutable = $null
|
||||
$signToolDirectory = $null
|
||||
$plainPassword = $null
|
||||
$resolvedPfxPath = $null
|
||||
$resolvedInstallerIconPath = Resolve-AbsolutePath -Path $InstallerIcon
|
||||
$signParams = $null
|
||||
|
||||
if (-not (Test-Path -LiteralPath $resolvedInstallerIconPath)) {
|
||||
throw "Installer icon file not found: $resolvedInstallerIconPath"
|
||||
}
|
||||
|
||||
$env:DOTNET_CLI_HOME = Join-Path $repoRoot ".dotnet"
|
||||
$env:APPDATA = Join-Path $repoRoot ".appdata"
|
||||
$env:NUGET_PACKAGES = Join-Path $repoRoot ".nuget\packages"
|
||||
$env:NUGET_HTTP_CACHE_PATH = Join-Path $repoRoot ".nuget\http-cache"
|
||||
|
||||
$localVersion = [Version]$version
|
||||
$cloudVersion = $null
|
||||
if (-not $SkipCloudCheck.IsPresent) {
|
||||
$cloudVersion = Get-MaxVersionFromTags -Tags (Get-GiteaReleaseTags -RepoUrl $GiteaRepoUrl)
|
||||
}
|
||||
|
||||
if ($null -ne $cloudVersion) {
|
||||
if ($localVersion -lt $cloudVersion) {
|
||||
throw "Local version $version is older than Gitea version $cloudVersion. Bump the project version before packaging."
|
||||
}
|
||||
|
||||
if ($localVersion -eq $cloudVersion) {
|
||||
throw "Gitea already contains version $version. Packaging with the same version is blocked."
|
||||
}
|
||||
}
|
||||
|
||||
if ($signingEnabled) {
|
||||
$resolvedPfxPath = Resolve-AbsolutePath -Path $PfxPath
|
||||
if (-not (Test-Path -LiteralPath $resolvedPfxPath)) {
|
||||
throw "PFX file not found: $resolvedPfxPath"
|
||||
}
|
||||
|
||||
if ($SignParallel -lt 1) {
|
||||
throw "SignParallel must be at least 1."
|
||||
}
|
||||
|
||||
$signToolExecutable = Resolve-SignToolExecutable -RequestedPath $SignToolPath
|
||||
$signToolDirectory = Split-Path -Parent $signToolExecutable
|
||||
if (-not [string]::IsNullOrWhiteSpace($signToolDirectory)) {
|
||||
$env:PATH = $signToolDirectory + [System.IO.Path]::PathSeparator + $env:PATH
|
||||
}
|
||||
|
||||
$plainPassword = Read-SecretAsPlainText -Prompt "PFX password"
|
||||
$signParams = "/fd SHA256 /f `"$resolvedPfxPath`" /p `"$plainPassword`""
|
||||
}
|
||||
|
||||
if (Test-Path -LiteralPath $publishDir) {
|
||||
Remove-Item -LiteralPath $publishDir -Recurse -Force
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $publishDir | Out-Null
|
||||
New-Item -ItemType Directory -Force -Path $releaseDir | Out-Null
|
||||
|
||||
$publishArgs = @(
|
||||
"publish",
|
||||
$projectPath,
|
||||
"-c", $Configuration,
|
||||
"-r", $Runtime,
|
||||
"--self-contained", "true",
|
||||
"-p:PublishSingleFile=true",
|
||||
"-o", $publishDir,
|
||||
"--configfile", $nugetConfigPath
|
||||
)
|
||||
|
||||
& $dotnet @publishArgs
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "dotnet publish failed with exit code $LASTEXITCODE"
|
||||
}
|
||||
|
||||
$packArgs = @(
|
||||
"tool", "run", "vpk", "--",
|
||||
"pack",
|
||||
"--packId", $PackId,
|
||||
"--packVersion", $version,
|
||||
"--packDir", $publishDir,
|
||||
"--mainExe", $mainExe,
|
||||
"--packTitle", $PackTitle,
|
||||
"--packAuthors", $PackAuthors,
|
||||
"--runtime", $Runtime,
|
||||
"--channel", $Channel,
|
||||
"--icon", $resolvedInstallerIconPath,
|
||||
"--outputDir", $releaseDir
|
||||
)
|
||||
|
||||
if ($signingEnabled) {
|
||||
$packArgs += @(
|
||||
"--signParams", $signParams,
|
||||
"--signParallel", $SignParallel.ToString()
|
||||
)
|
||||
}
|
||||
|
||||
& $dotnet @packArgs
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "vpk pack failed with exit code $LASTEXITCODE"
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Velopack package build complete." -ForegroundColor Green
|
||||
Write-Host "Version: $version"
|
||||
Write-Host "Gitea: $(if ($null -ne $cloudVersion) { $cloudVersion.ToString() } else { 'none' })"
|
||||
Write-Host "Signing: $(if ($signingEnabled) { 'enabled' } else { 'skipped' })"
|
||||
if ($signingEnabled -and -not [string]::IsNullOrWhiteSpace($signToolExecutable)) {
|
||||
Write-Host "SignTool: $signToolExecutable"
|
||||
}
|
||||
Write-Host "Icon: $resolvedInstallerIconPath"
|
||||
Write-Host "PublishDir: $publishDir"
|
||||
Write-Host "ReleaseDir: $releaseDir"
|
||||
Write-Host "Gitea repo: $GiteaRepoUrl"
|
||||
Write-Host "Tag: v$version"
|
||||
Write-Host ""
|
||||
Write-Host "Upload with: scripts/release/upload-feed.ps1 (vpk upload gitea)." -ForegroundColor Yellow
|
||||
Reference in new issue
Block a user