From 0b3c482960ca271a9f9a97ff180e40f1a9c3cc35 Mon Sep 17 00:00:00 2001 From: Maksym Sadovnychyy Date: Fri, 27 Feb 2026 18:51:03 +0100 Subject: [PATCH] (chore): migrate to .slnx and refine release scripts/docs --- CONTRIBUTING.md | 4 +- README.md | 9 +- src/MaksIT.Core.sln | 31 ---- src/MaksIT.Core.slnx | 4 + .../Force-AmendTaggedCommit.ps1 | 30 +++- .../Release-NuGetPackage.ps1 | 152 +++++++----------- .../Release-NuGetPackage/scriptsettings.json | 4 +- 7 files changed, 99 insertions(+), 135 deletions(-) delete mode 100644 src/MaksIT.Core.sln create mode 100644 src/MaksIT.Core.slnx diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 603ac9f..4922ff5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -21,7 +21,7 @@ Thank you for your interest in contributing to MaksIT.Core! This document provid ```bash cd src -dotnet build MaksIT.Core.sln +dotnet build MaksIT.Core.slnx ``` ### Running Tests @@ -246,4 +246,4 @@ If the release partially failed (e.g., NuGet succeeded but GitHub failed): ## License -By contributing, you agree that your contributions will be licensed under the MIT License. +By contributing, you agree that your contributions are licensed under the terms in `LICENSE.md`. diff --git a/README.md b/README.md index d0213ef..86b9638 100644 --- a/README.md +++ b/README.md @@ -1614,7 +1614,10 @@ string completedName = completed.GetDisplayName(); // "Completed" ## Contact -For any inquiries or contributions, feel free to reach out: +If you have any questions or need further assistance, feel free to reach out: -- **Email**: maksym.sadovnychyy@gmail.com -- **Author**: Maksym Sadovnychyy (MAKS-IT) \ No newline at end of file +- **Email**: [maksym.sadovnychyy@gmail.com](mailto:maksym.sadovnychyy@gmail.com) + +## License + +See `LICENSE.md`. \ No newline at end of file diff --git a/src/MaksIT.Core.sln b/src/MaksIT.Core.sln deleted file mode 100644 index d10e2d8..0000000 --- a/src/MaksIT.Core.sln +++ /dev/null @@ -1,31 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.5.002.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MaksIT.Core", "MaksIT.Core\MaksIT.Core.csproj", "{4AE39520-D4F7-4C5F-ACE9-9E79AEAF3228}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MaksIT.Core.Tests", "MaksIT.Core.Tests\MaksIT.Core.Tests.csproj", "{B67A43DA-AFFC-4510-8D51-08F1FF84CC5B}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {4AE39520-D4F7-4C5F-ACE9-9E79AEAF3228}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4AE39520-D4F7-4C5F-ACE9-9E79AEAF3228}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4AE39520-D4F7-4C5F-ACE9-9E79AEAF3228}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4AE39520-D4F7-4C5F-ACE9-9E79AEAF3228}.Release|Any CPU.Build.0 = Release|Any CPU - {B67A43DA-AFFC-4510-8D51-08F1FF84CC5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B67A43DA-AFFC-4510-8D51-08F1FF84CC5B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B67A43DA-AFFC-4510-8D51-08F1FF84CC5B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B67A43DA-AFFC-4510-8D51-08F1FF84CC5B}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {9BCC72D1-8BE8-4924-AF73-C8E86E16EC59} - EndGlobalSection -EndGlobal diff --git a/src/MaksIT.Core.slnx b/src/MaksIT.Core.slnx new file mode 100644 index 0000000..6114519 --- /dev/null +++ b/src/MaksIT.Core.slnx @@ -0,0 +1,4 @@ + + + + diff --git a/utils/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 b/utils/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 index ca2a8b0..bca2946 100644 --- a/utils/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 +++ b/utils/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 @@ -66,6 +66,29 @@ Import-Module $gitToolsModulePath -Force #endregion +#region Helpers + +function Select-PreferredHeadTag { + param( + [Parameter(Mandatory = $true)] + [string[]]$Tags + ) + + # Pick the latest tag on HEAD by git's own ordering (no tag-name parsing assumptions). + $ordered = (& git tag --points-at HEAD --sort=-creatordate 2>$null) + if ($LASTEXITCODE -eq 0 -and $ordered) { + $orderedTags = @($ordered | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | ForEach-Object { $_.Trim() }) + if ($orderedTags.Count -gt 0) { + return $orderedTags[0] + } + } + + # Fallback: keep script functional even if sorting is unavailable. + return $Tags[0] +} + +#endregion + #region Load Settings $settings = Get-ScriptSettings -ScriptDir $scriptDir @@ -116,8 +139,11 @@ if ($tags.Count -eq 0) { exit 1 } -# If multiple tags exist, use the first one returned by git. -$TagName = $tags[0] +# If multiple tags exist, choose the latest one on HEAD by git ordering. +if ($tags.Count -gt 1) { + Write-Log -Level "WARN" -Message "Multiple tags found on HEAD: $($tags -join ', ')" +} +$TagName = Select-PreferredHeadTag -Tags $tags Write-Log -Level "OK" -Message "Found tag: $TagName" # 4. Inspect pending changes before amend diff --git a/utils/Release-NuGetPackage/Release-NuGetPackage.ps1 b/utils/Release-NuGetPackage/Release-NuGetPackage.ps1 index 2bf1c50..3556b1a 100644 --- a/utils/Release-NuGetPackage/Release-NuGetPackage.ps1 +++ b/utils/Release-NuGetPackage/Release-NuGetPackage.ps1 @@ -17,7 +17,7 @@ - Generates test result artifacts (TRX format) and coverage reports - Displays test results with pass/fail counts and coverage percentage - Publishes to NuGet.org - - Creates a GitHub release with changelog and package assets + - Creates a GitHub release with changelog and NuGet package assets - Shows timing summary for all steps .REQUIREMENTS @@ -213,12 +213,11 @@ if ($csprojPaths.Count -eq 0) { } $testResultsDir = [System.IO.Path]::GetFullPath((Join-Path $scriptDir $settings.paths.testResultsDir)) -$stagingDir = [System.IO.Path]::GetFullPath((Join-Path $scriptDir $settings.paths.stagingDir)) $releaseDir = [System.IO.Path]::GetFullPath((Join-Path $scriptDir $settings.paths.releaseDir)) $changelogPath = [System.IO.Path]::GetFullPath((Join-Path $scriptDir $settings.paths.changelogPath)) $testProjectPath = [System.IO.Path]::GetFullPath((Join-Path $scriptDir $settings.paths.testProject)) -# Release naming patterns +# Release naming pattern $zipNamePattern = $settings.release.zipNamePattern $releaseTitlePattern = $settings.release.releaseTitlePattern @@ -248,21 +247,6 @@ function Get-CsprojPropertyValue { return $null } -# Helper: resolve output assembly name for published exe -function Resolve-ProjectExeName { - param( - [Parameter(Mandatory=$true)][string]$projPath - ) - - [xml]$csproj = Get-Content $projPath - $assemblyName = Get-CsprojPropertyValue -csproj $csproj -propertyName "AssemblyName" - if ($assemblyName) { - return $assemblyName - } - - return [System.IO.Path]::GetFileNameWithoutExtension($projPath) -} - # Helper: check for uncommitted changes function Assert-WorkingTreeClean { param( @@ -443,78 +427,18 @@ Write-Log -Level "INFO" -Message " Method Coverage: $($testResult.MethodRate)%" #region Build And Publish -# 7. Prepare staging directory -Write-Log -Level "STEP" -Message "Preparing staging directory..." -if (Test-Path $stagingDir) { - Remove-Item $stagingDir -Recurse -Force -} - -New-Item -ItemType Directory -Path $stagingDir | Out-Null - -$binDir = Join-Path $stagingDir "bin" - -# 8. Publish the project to staging/bin - -Write-Log -Level "STEP" -Message "Publishing projects to bin folder..." -$publishSuccess = $true -$publishedProjects = @() - -foreach ($projPath in $csprojPaths) { - $projName = [System.IO.Path]::GetFileNameWithoutExtension($projPath) - $projBinDir = Join-Path $binDir $projName - - dotnet publish $projPath -c Release -o $projBinDir - if ($LASTEXITCODE -ne 0) { - Write-Error "dotnet publish failed for $projName." - $publishSuccess = $false - } - else { - $exeBaseName = Resolve-ProjectExeName -projPath $projPath - $publishedProjects += [PSCustomObject]@{ - ProjPath = $projPath - ProjName = $projName - BinDir = $projBinDir - ExeBaseName = $exeBaseName - } - - Write-Log -Level "OK" -Message " Published $projName successfully to: $projBinDir" - } -} - -if (-not $publishSuccess) { - exit 1 -} - - -# 12. Prepare release directory +# 7. Prepare release directory if (!(Test-Path $releaseDir)) { New-Item -ItemType Directory -Path $releaseDir | Out-Null } -# 13. Create zip file -$zipName = $zipNamePattern -$zipName = $zipName -replace '\{version\}', $version -$zipPath = Join-Path $releaseDir $zipName - -if (Test-Path $zipPath) { - Remove-Item $zipPath -Force -} - -Write-Log -Level "STEP" -Message "Creating archive $zipName..." -Compress-Archive -Path "$stagingDir\*" -DestinationPath $zipPath -Force - -if (-not (Test-Path $zipPath)) { - Write-Error "Failed to create archive $zipPath" - exit 1 -} - -Write-Log -Level "OK" -Message " Archive created: $zipPath" - -# 14. Pack NuGet package and resolve produced .nupkg file +# 8. Pack NuGet package and resolve produced .nupkg/.snupkg files $packageProjectPath = $csprojPaths[0] Write-Log -Level "STEP" -Message "Packing NuGet package..." -dotnet pack $packageProjectPath -c Release -o $releaseDir --nologo +dotnet pack $packageProjectPath -c Release -o $releaseDir --nologo ` + -p:IncludeSymbols=true ` + -p:SymbolPackageFormat=snupkg if ($LASTEXITCODE -ne 0) { Write-Error "dotnet pack failed for $packageProjectPath." exit 1 @@ -536,7 +460,44 @@ if (-not $packageFile) { Write-Log -Level "OK" -Message " Package ready: $($packageFile.FullName)" -# 15. Extract release notes from CHANGELOG.md +# Find the symbols package if available +$symbolsPackageFile = Get-ChildItem -Path $releaseDir -Filter "*.snupkg" | + Where-Object { $_.Name -like "*$version*.snupkg" } | + Sort-Object LastWriteTime -Descending | + Select-Object -First 1 + +if ($symbolsPackageFile) { + Write-Log -Level "OK" -Message " Symbols package ready: $($symbolsPackageFile.FullName)" +} +else { + Write-Log -Level "WARN" -Message " Symbols package (.snupkg) not found for version $version." +} + +# 9. Create release archive with NuGet package artifacts +Write-Log -Level "STEP" -Message "Creating release archive..." +$resolvedZipNamePattern = if ([string]::IsNullOrWhiteSpace($zipNamePattern)) { "release-{version}.zip" } else { $zipNamePattern } +$zipFileName = $resolvedZipNamePattern -replace '\{version\}', $version +$zipPath = Join-Path $releaseDir $zipFileName + +if (Test-Path $zipPath) { + Remove-Item $zipPath -Force +} + +$archiveArtifacts = @($packageFile.FullName) +if ($symbolsPackageFile) { + $archiveArtifacts += $symbolsPackageFile.FullName +} + +Compress-Archive -Path $archiveArtifacts -DestinationPath $zipPath -CompressionLevel Optimal -Force + +if (-not (Test-Path $zipPath)) { + Write-Error "Failed to create release archive at: $zipPath" + exit 1 +} + +Write-Log -Level "OK" -Message " Release archive ready: $zipPath" + +# 10. Extract release notes from CHANGELOG.md Write-Log -Level "STEP" -Message "Extracting release notes..." $pattern = "(?ms)^##\s+v$([regex]::Escape($version))\b.*?(?=^##\s+v\d+\.\d+\.\d+|\Z)" $match = [regex]::Match($changelog, $pattern) @@ -549,7 +510,7 @@ if (-not $match.Success) { $releaseNotes = $match.Value.Trim() Write-Log -Level "OK" -Message " Release notes extracted." -# 16. Get repository info +# 11. Get repository info $remoteUrl = git config --get remote.origin.url if ($LASTEXITCODE -ne 0 -or -not $remoteUrl) { Write-Error "Could not determine git remote origin URL." @@ -572,7 +533,7 @@ Write-Log -Level "INFO" -Message " Repository: $repo" Write-Log -Level "INFO" -Message " Tag: $tag" Write-Log -Level "INFO" -Message " Title: $releaseName" -# 17. Check if tag is pushed to remote (skip on dev branch) +# 12. Check if tag is pushed to remote (skip on dev branch) if (-not $isDevBranch) { @@ -615,7 +576,7 @@ if (-not $isDevBranch) { } Write-Log -Level "OK" -Message " GitHub CLI authenticated." - # 18. Create or update GitHub release + # 13. Create or update GitHub release Write-Log -Level "STEP" -Message "Creating GitHub release..." # gh release subcommands do not support custom auth headers. @@ -646,8 +607,12 @@ if (-not $isDevBranch) { $notesFilePath = Join-Path $releaseDir "release-notes-temp.md" [System.IO.File]::WriteAllText($notesFilePath, $releaseNotes, [System.Text.UTF8Encoding]::new($false)) - $createReleaseArgs = @( - "release", "create", $tag, $zipPath + $releaseAssets = @($packageFile.FullName) + if ($symbolsPackageFile) { + $releaseAssets += $symbolsPackageFile.FullName + } + + $createReleaseArgs = @("release", "create", $tag) + $releaseAssets + @( "--repo", $repo "--title", $releaseName "--notes-file", $notesFilePath @@ -707,15 +672,14 @@ else { #endregion #region Cleanup -if (Test-Path $stagingDir) { - Remove-Item $stagingDir -Recurse -Force - Write-Log -Level "INFO" -Message " Cleaned up staging directory." -} - if (Test-Path $testResultsDir) { Remove-Item $testResultsDir -Recurse -Force Write-Log -Level "INFO" -Message " Cleaned up test results directory." } + +Get-ChildItem -Path $releaseDir -File | + Where-Object { $_.Name -like "*$version*.nupkg" -or $_.Name -like "*$version*.snupkg" } | + Remove-Item -Force -ErrorAction SilentlyContinue #endregion #region Summary diff --git a/utils/Release-NuGetPackage/scriptsettings.json b/utils/Release-NuGetPackage/scriptsettings.json index eecf793..7a7953d 100644 --- a/utils/Release-NuGetPackage/scriptsettings.json +++ b/utils/Release-NuGetPackage/scriptsettings.json @@ -24,7 +24,6 @@ "..\\..\\src\\MaksIT.Core\\MaksIT.Core.csproj" ], "testResultsDir": "..\\..\\testResults", - "stagingDir": "..\\..\\staging", "releaseDir": "..\\..\\release", "changelogPath": "..\\..\\CHANGELOG.md", "testProject": "..\\..\\src\\MaksIT.Core.Tests" @@ -36,7 +35,7 @@ }, "release": { - "zipNamePattern": "maksit.core-{version}.zip", + "zipNamePattern": "maksit.dapr-{version}.zip", "releaseTitlePattern": "Release {version}" }, @@ -58,7 +57,6 @@ "paths": { "csprojPaths": "List of project files used for version discovery and publish output.", "testResultsDir": "Directory where test artifacts are written.", - "stagingDir": "Temporary staging directory before archive creation.", "releaseDir": "Output directory for release archives and artifacts.", "changelogPath": "Path to CHANGELOG.md used for version and release notes extraction.", "testProject": "Test project path used by TestRunner."