diff --git a/.github/workflows/publish-nuget.yml b/.github/workflows/publish-nuget.yml new file mode 100644 index 0000000..844a4c7 --- /dev/null +++ b/.github/workflows/publish-nuget.yml @@ -0,0 +1,35 @@ +name: Publish to NuGet + +on: + push: + tags: + - 'v*' + +jobs: + publish: + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + + steps: + - uses: actions/checkout@v5 + + - name: Setup .NET + uses: actions/setup-dotnet@v5 + with: + dotnet-version: '10.0.x' + + - name: Pack + run: | + dotnet pack src/MaksIT.Core.Desktop/MaksIT.Core.Desktop.csproj -c Release -o artifacts + dotnet pack src/MaksIT.Core.UI/MaksIT.Core.UI.csproj -c Release -o artifacts + + - name: NuGet login (OIDC) + id: login + uses: NuGet/login@v1 + with: + user: maks-it + + - name: Push to NuGet + run: dotnet nuget push artifacts/*.nupkg --api-key ${{ steps.login.outputs.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate diff --git a/CHANGELOG.md b/CHANGELOG.md index 29eef12..163f90c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.1] - 2026-10-27 + +### Changed + +- **MaksIT.Core.UI:** Avalonia and Avalonia.Desktop 12.1.2 → 12.1.4. +- Release packs both libraries for the GitHub release; nuget.org publish uses GitHub Actions Trusted Publishing instead of local `DotNetNuGet`. + +### Fixed + +- Sync RepoUtils release engine (`-InstallOnly` / Helm install helpers) and bump test packages (xunit.v3, coverlet.MTP). + ## [0.1.0] - 2026-10-10 ### Added diff --git a/README.md b/README.md index be8e54b..7b7fd73 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # MaksIT.Core desktop UI ![Line Coverage](https://img.shields.io/badge/Line%20Coverage-36.7%25-yellow) -![Branch Coverage](https://img.shields.io/badge/Branch%20Coverage-38.2%25-yellow) +![Branch Coverage](https://img.shields.io/badge/Branch%20Coverage-38.1%25-yellow) ![Method Coverage](https://img.shields.io/badge/Method%20Coverage-52.3%25-yellowgreen) Shared .NET 10 libraries for MaksIT desktop apps. Install from NuGet. Do not reference this folder from another repository. diff --git a/src/MaksIT.Core.Desktop.Tests/MaksIT.Core.Desktop.Tests.csproj b/src/MaksIT.Core.Desktop.Tests/MaksIT.Core.Desktop.Tests.csproj index 170e2e9..a84d07e 100644 --- a/src/MaksIT.Core.Desktop.Tests/MaksIT.Core.Desktop.Tests.csproj +++ b/src/MaksIT.Core.Desktop.Tests/MaksIT.Core.Desktop.Tests.csproj @@ -11,8 +11,8 @@ - - + + diff --git a/src/MaksIT.Core.Desktop/MaksIT.Core.Desktop.csproj b/src/MaksIT.Core.Desktop/MaksIT.Core.Desktop.csproj index 2deebc8..dae5aeb 100644 --- a/src/MaksIT.Core.Desktop/MaksIT.Core.Desktop.csproj +++ b/src/MaksIT.Core.Desktop/MaksIT.Core.Desktop.csproj @@ -10,7 +10,7 @@ $(NoWarn);CS1591 MaksIT.Core.Desktop - 0.1.0 + 0.1.1 Maksym Sadovnychyy MAKS-IT MaksIT.Core.Desktop diff --git a/src/MaksIT.Core.UI.Tests/MaksIT.Core.UI.Tests.csproj b/src/MaksIT.Core.UI.Tests/MaksIT.Core.UI.Tests.csproj index a16ee84..f946318 100644 --- a/src/MaksIT.Core.UI.Tests/MaksIT.Core.UI.Tests.csproj +++ b/src/MaksIT.Core.UI.Tests/MaksIT.Core.UI.Tests.csproj @@ -11,8 +11,8 @@ - - + + diff --git a/src/MaksIT.Core.UI/MaksIT.Core.UI.csproj b/src/MaksIT.Core.UI/MaksIT.Core.UI.csproj index c4f35e7..7aa867e 100644 --- a/src/MaksIT.Core.UI/MaksIT.Core.UI.csproj +++ b/src/MaksIT.Core.UI/MaksIT.Core.UI.csproj @@ -11,7 +11,7 @@ $(NoWarn);CS1591 MaksIT.Core.UI - 0.1.0 + 0.1.1 Maksym Sadovnychyy MAKS-IT MaksIT.Core.UI @@ -43,8 +43,8 @@ - - + + diff --git a/utils/engines/release/Invoke-ReleasePackage.ps1 b/utils/engines/release/Invoke-ReleasePackage.ps1 index 887e7a7..f8d45f5 100644 --- a/utils/engines/release/Invoke-ReleasePackage.ps1 +++ b/utils/engines/release/Invoke-ReleasePackage.ps1 @@ -8,6 +8,10 @@ .NOTES Per-plugin dryRun on mutatesRemote plugins validates without remote mutation. There is no engine-wide dryRun switch — set dryRun on each plugin as needed. + + -InstallOnly (Install-Helm-*.bat) keeps the version plugin and HelmSelfDeploy. + Compile, test, image build, image push, and HelmPush are skipped. The chart + must already be in OCI at the version the version plugin reports. #> # Keep a plain param block so unbound launcher arguments remain in $args for @@ -17,6 +21,17 @@ param() $ErrorActionPreference = 'Stop' Set-Location $PSScriptRoot +$installOnly = $false +$extensionArgs = [System.Collections.Generic.List[object]]::new() +foreach ($argument in @($args)) { + if ([string]$argument -eq '-InstallOnly') { + $installOnly = $true + continue + } + + $extensionArgs.Add($argument) +} + $srcDir = (Resolve-Path (Join-Path $PSScriptRoot '..\..')).Path . (Join-Path $srcDir 'modules/Engine/Import-EngineModules.ps1') @@ -24,7 +39,7 @@ Import-EngineModules -Engine Release $releaseExtension = $null if (Get-Command Initialize-ReleaseExtension -ErrorAction SilentlyContinue) { - $releaseExtension = Initialize-ReleaseExtension -ScriptDir $PSScriptRoot -ArgumentList $args + $releaseExtension = Initialize-ReleaseExtension -ScriptDir $PSScriptRoot -ArgumentList @($extensionArgs) } $settings = if ($null -ne $releaseExtension) { @@ -35,9 +50,29 @@ else { } $configuredPlugins = Get-ConfiguredPlugins -Settings $settings +if ($installOnly) { + $enabledBefore = @($configuredPlugins | Where-Object { $_.enabled } | ForEach-Object { [string]$_.name }) + $configuredPlugins = @(Select-HelmInstallPlugins -Plugins $configuredPlugins -ScriptDir $PSScriptRoot) + $kept = @($configuredPlugins | ForEach-Object { [string]$_.name }) + $skipped = @($enabledBefore | Where-Object { $_ -notin $kept }) + if ($skipped.Count -gt 0) { + Write-Log -Level 'INFO' -Message "Install-only: skipping $($skipped -join ', '). Chart and images are taken from OCI." + } + + Write-Log -Level 'INFO' -Message "Install-only: running $($kept -join ', ')." +} + Initialize-RepoUtilsVaultSecrets -Settings $settings -Plugins $configuredPlugins -$releaseBanner = if ($null -ne $releaseExtension) { +$releaseBanner = if ($installOnly) { + $modeLabel = 'ha' + if ($null -ne $releaseExtension -and $releaseExtension.ContextData.PSObject.Properties.Name -contains 'deployMode') { + $modeLabel = [string]$releaseExtension.ContextData.deployMode + } + + "HELM INSTALL (deploy mode: $modeLabel; OCI chart, no build or push)" +} +elseif ($null -ne $releaseExtension) { $releaseExtension.StepBanner } else { @@ -97,7 +132,11 @@ if (-not $releaseStageInitialized) { Write-Log -Level 'OK' -Message '==================================================' if ($releaseHadPluginFailures) { - Write-Log -Level 'ERROR' -Message 'RELEASE FAILED' + $failureLabel = if ($installOnly) { 'HELM INSTALL FAILED' } else { 'RELEASE FAILED' } + Write-Log -Level 'ERROR' -Message $failureLabel +} +elseif ($installOnly) { + Write-Log -Level 'OK' -Message 'HELM INSTALL COMPLETE' } elseif ($engineContext.PSObject.Properties.Name -contains 'skipPublishPlugins' -and $engineContext.skipPublishPlugins) { Write-Log -Level 'OK' -Message 'RUN COMPLETE (publish skipped by ReleasePublishGuard)' @@ -110,7 +149,7 @@ else { } Write-Log -Level 'OK' -Message '==================================================' -if ($engineContext.isNonReleaseBranch -and -not ($engineContext.PSObject.Properties.Name -contains 'skipPublishPlugins' -and $engineContext.skipPublishPlugins)) { +if (-not $installOnly -and $engineContext.isNonReleaseBranch -and -not ($engineContext.PSObject.Properties.Name -contains 'skipPublishPlugins' -and $engineContext.skipPublishPlugins)) { $preferredReleaseBranch = Get-PreferredReleaseBranch -EngineContext $engineContext Write-Log -Level 'INFO' -Message "For publish, use an allowed branch (see ReleasePublishGuard.branches), e.g. '$preferredReleaseBranch', and satisfy the guard requirements." } diff --git a/utils/engines/release/scriptSettings.json b/utils/engines/release/scriptSettings.json index edb2505..5d48d2b 100644 --- a/utils/engines/release/scriptSettings.json +++ b/utils/engines/release/scriptSettings.json @@ -1,7 +1,7 @@ { "$schema": "https://json-schema.org/draft-07/schema", "title": "Release Package Script Settings", - "description": "Invoke-ReleasePackage.ps1 plugin settings. Place ReleasePublishGuard before GitHub/DotNetNuGet. Publish plugins omit per-plugin branches. Semver comes from DotNetReleaseVersion (projectFiles). DotNetPack packs the first projectFiles entry only, so each library is packed and pushed as its own pair.", + "description": "Invoke-ReleasePackage.ps1 plugin settings. Place ReleasePublishGuard before GitHub. Publish plugins omit per-plugin branches. Semver comes from DotNetReleaseVersion (projectFiles). DotNetPack packs the first projectFiles entry only, so each library is packed for GitHub assets; nuget.org publish is GHA Trusted Publishing.", "repoUtilsSecretsShared": "RepoUtilsSecretsShared", "repoUtilsSecrets": "RepoUtilsSecrets", "plugins": [ @@ -47,13 +47,6 @@ ], "artifactsDir": "..\\..\\..\\releases" }, - { - "name": "DotNetNuGet", - "stageLabel": "release", - "enabled": true, - "nugetSecret": "NuGet", - "source": "https://api.nuget.org/v3/index.json" - }, { "name": "DotNetPack", "stageLabel": "build", @@ -63,13 +56,6 @@ ], "artifactsDir": "..\\..\\..\\releases" }, - { - "name": "DotNetNuGet", - "stageLabel": "release", - "enabled": true, - "nugetSecret": "NuGet", - "source": "https://api.nuget.org/v3/index.json" - }, { "name": "AttachNuGetPackages", "stageLabel": "release", diff --git a/utils/modules/Engine/ReleaseSupport.psm1 b/utils/modules/Engine/ReleaseSupport.psm1 index 6dc2ffb..055a9cb 100644 --- a/utils/modules/Engine/ReleaseSupport.psm1 +++ b/utils/modules/Engine/ReleaseSupport.psm1 @@ -266,4 +266,61 @@ function Get-PreferredReleaseBranch { return "main" } -Export-ModuleMember -Function Assert-WorkingTreeClean, Initialize-ReleaseStageContext, New-EngineContext, Get-PreferredReleaseBranch +function Select-HelmInstallPlugins { + <# + .SYNOPSIS + Keeps the release version plugin and HelmSelfDeploy for an OCI install without build or push. + + .DESCRIPTION + Install-Helm-*.bat passes -InstallOnly. The chart and images are already in OCI, so compile, + test, image build, image push, and HelmPush are not run. The version plugin still supplies + the chart tag (shared.version). HelmSelfDeploy dryRun is rejected: that path needs the local + package HelmPush keeps in the same run. + #> + param( + [Parameter(Mandatory = $true)] + [AllowEmptyCollection()] + [object[]]$Plugins, + + [Parameter(Mandatory = $true)] + [string]$ScriptDir + ) + + $versionPlugins = @(Get-EnabledVersionPlugins -Plugins $Plugins -ScriptDir $ScriptDir) + if ($versionPlugins.Count -eq 0) { + throw "Install-only Helm requires exactly one enabled release version plugin (providesVersion) so the OCI chart tag can be resolved. Build and push plugins are not run." + } + + if ($versionPlugins.Count -gt 1) { + $names = ($versionPlugins | ForEach-Object { [string]$_.name }) -join ', ' + throw "Install-only Helm requires exactly one enabled release version plugin. Found: $names." + } + + $deployPlugins = @($Plugins | Where-Object { + $null -ne $_ -and + $_.enabled -and + [string]$_.name -eq 'HelmSelfDeploy' + }) + + if ($deployPlugins.Count -eq 0) { + throw "Install-only Helm requires an enabled HelmSelfDeploy plugin. The chart is installed from OCI; image build, image push, and HelmPush are not run." + } + + if ($deployPlugins.Count -gt 1) { + throw "Install-only Helm found multiple enabled HelmSelfDeploy plugins." + } + + $deployPlugin = $deployPlugins[0] + if ($deployPlugin.PSObject.Properties.Name -contains 'dryRun' -and $null -ne $deployPlugin.dryRun -and [bool]$deployPlugin.dryRun) { + throw "Install-only Helm cannot use HelmSelfDeploy dryRun. That path needs the local package from HelmPush in the same run. Omit dryRun to install the chart already published to OCI." + } + + $versionName = [string]$versionPlugins[0].name + return @($Plugins | Where-Object { + $null -ne $_ -and + $_.enabled -and + ([string]$_.name -eq $versionName -or [string]$_.name -eq 'HelmSelfDeploy') + }) +} + +Export-ModuleMember -Function Assert-WorkingTreeClean, Initialize-ReleaseStageContext, New-EngineContext, Get-PreferredReleaseBranch, Select-HelmInstallPlugins