From 11e7a7a452469cdc028187f5c1fdf8ecc8d52ae3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20K=C5=82ys?= Date: Tue, 29 Sep 2026 16:00:35 +0200 Subject: [PATCH 1/2] Publish signed module and NuGet assets in one GitHub release flow --- Build/Build-Release.ps1 | 27 +++++++++++++++++++- Build/Test-ReleaseConfiguration.ps1 | 21 ++++++++++------ Build/Test-ReleasePlans.ps1 | 4 +-- Build/module.json | 24 +----------------- Build/release.module.json | 13 ++++++++++ README.md | 7 +++--- Sources/PSEventViewer/packages.lock.json | 32 ++++++++++++------------ 7 files changed, 75 insertions(+), 53 deletions(-) diff --git a/Build/Build-Release.ps1 b/Build/Build-Release.ps1 index c2e8d19e..68961a49 100644 --- a/Build/Build-Release.ps1 +++ b/Build/Build-Release.ps1 @@ -18,4 +18,29 @@ if ($RunMode -eq 'Plan') { $invokeSplat.Plan = $true } -Invoke-PowerForgeRelease @invokeSplat +$originalGitHubToken = $env:GITHUB_TOKEN +$injectedGitHubToken = $false +try { + if ($RunMode -eq 'Publish' -and [string]::IsNullOrWhiteSpace($env:GITHUB_TOKEN)) { + $token = $env:GH_TOKEN + if ([string]::IsNullOrWhiteSpace($token) -and (Get-Command gh -ErrorAction SilentlyContinue)) { + $token = & gh auth token 2>$null + if ($LASTEXITCODE -ne 0) { $token = $null } + } + if ([string]::IsNullOrWhiteSpace($token)) { + throw 'GitHub release publishing requires GITHUB_TOKEN, GH_TOKEN, or an authenticated gh CLI.' + } + $env:GITHUB_TOKEN = $token.Trim() + $injectedGitHubToken = $true + } + + Invoke-PowerForgeRelease @invokeSplat +} finally { + if ($injectedGitHubToken) { + if ($null -eq $originalGitHubToken) { + Remove-Item Env:GITHUB_TOKEN -ErrorAction SilentlyContinue + } else { + $env:GITHUB_TOKEN = $originalGitHubToken + } + } +} diff --git a/Build/Test-ReleaseConfiguration.ps1 b/Build/Test-ReleaseConfiguration.ps1 index e86bbd55..7460d1da 100644 --- a/Build/Test-ReleaseConfiguration.ps1 +++ b/Build/Test-ReleaseConfiguration.ps1 @@ -51,8 +51,12 @@ if (@($release.Module.ArtifactPaths | Where-Object { $_ -like '*EventViewerX.Cli $moduleRelease = Get-Content -LiteralPath ` (Join-Path $RepositoryRoot 'Build\release.module.json') -Raw | ConvertFrom-Json -if ($null -ne $moduleRelease.Tools -or $null -ne $moduleRelease.GitHub) { - throw 'The module release must not include CLI tools or a unified GitHub release.' +if ($null -ne $moduleRelease.Tools -or + $moduleRelease.GitHub.Publish -ne $true -or + $moduleRelease.GitHub.TokenEnvName -ne 'GITHUB_TOKEN' -or + $moduleRelease.GitHub.GenerateReleaseNotes -ne $true -or + $moduleRelease.GitHub.TagTemplate -ne 'PSEventViewer-v{Version}') { + throw 'The module release must publish signed artifacts to GitHub with generated notes and no CLI tools.' } if ($moduleRelease.Module.IncludesPackages -ne $true -or [string] $moduleRelease.Module.ConfigPath -ne 'Build/module.json') { @@ -132,13 +136,14 @@ if ([System.IO.Path]::IsPathRooted($galleryKeyPath) -or [array] $legacyGitHubSegments = @($moduleBuild.Segments | Where-Object { $_.Type -eq 'GitHubNuget' }) -if (@($legacyGitHubSegments | Where-Object { - $_.Configuration.Enabled -eq $true -or - -not [string]::IsNullOrWhiteSpace([string] $_.Configuration.ApiKeyFilePath) -}).Count -ne 0) { - throw 'The legacy module GitHub lane must stay disabled and must not declare a token-file path.' +if ($legacyGitHubSegments.Count -ne 0) { + throw 'The legacy module GitHub lane must be absent; the release coordinator owns GitHub publication.' +} +[array] $publishOrder = @($moduleBuild.Segments | Where-Object { $_.Type -eq 'Release' } | + ForEach-Object { $_.Configuration.PublishOrder }) +if (($publishOrder -join ',') -ne 'NuGet,PowerShellGallery') { + throw 'The module pipeline must publish only to NuGet and PowerShell Gallery.' } - [pscustomobject] @{ NuGetCredential = $nuGetKeyPath GitHubCredential = 'GITHUB_TOKEN' diff --git a/Build/Test-ReleasePlans.ps1 b/Build/Test-ReleasePlans.ps1 index 605c207d..bb3bc00e 100644 --- a/Build/Test-ReleasePlans.ps1 +++ b/Build/Test-ReleasePlans.ps1 @@ -18,8 +18,8 @@ if (@($modulePlan.ModuleAssets | Where-Object { $_ -like '*EventViewerX.Cli.*.nu throw 'The module/package release plan must exclude the EventViewerX.Cli .NET tool package.' } if ($null -ne $modulePlan.DotNetToolPlan -or - $modulePlan.ModulePlan.UnifiedGitHubRelease -eq $true) { - throw 'The module/package release plan must exclude standalone CLI and unified GitHub publication.' + $modulePlan.ModulePlan.UnifiedGitHubRelease -ne $true) { + throw 'The module/package release plan must include GitHub publication without standalone CLI assets.' } $fullPlan = & $buildAllPath -RunMode Plan diff --git a/Build/module.json b/Build/module.json index 7ebfb02c..7baed929 100644 --- a/Build/module.json +++ b/Build/module.json @@ -355,8 +355,7 @@ ], "PublishOrder": [ "NuGet", - "PowerShellGallery", - "GitHub" + "PowerShellGallery" ] } }, @@ -404,27 +403,6 @@ }, "Type": "GalleryNuget" }, - { - "Configuration": { - "Destination": "GitHub", - "Tool": "Auto", - "ApiKey": "", - "Enabled": false, - "UserName": "EvotecIT", - "RepositoryName": "EventViewerX", - "Force": false, - "OverwriteTagName": "{ModuleName}-v{ModuleVersionWithPreRelease}", - "DoNotMarkAsPreRelease": false, - "GenerateReleaseNotes": true, - "ReuseExistingRelease": false, - "ReplaceExistingAssets": false, - "UseAsDependencyVersionSource": false, - "PublishRequiredModules": false, - "RequiredModuleSourceRepository": "PSGallery", - "Verbose": false - }, - "Type": "GitHubNuget" - }, { "Type": "Gate", "Configuration": { diff --git a/Build/release.module.json b/Build/release.module.json index 9a25e11b..5b43a4ca 100644 --- a/Build/release.module.json +++ b/Build/release.module.json @@ -38,5 +38,18 @@ "TimeoutSeconds": 1800 } ] + }, + "GitHub": { + "Publish": true, + "VersionSource": "Module", + "Owner": "EvotecIT", + "Repository": "EventViewerX", + "TokenEnvName": "GITHUB_TOKEN", + "GenerateReleaseNotes": true, + "IsPreRelease": false, + "ReuseExistingRelease": false, + "ReplaceExistingAssets": false, + "TagTemplate": "PSEventViewer-v{Version}", + "ReleaseNameTemplate": "EventViewerX / PSEventViewer {Version}" } } diff --git a/README.md b/README.md index a9995d2e..262e531f 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ High-performance Windows Event Log tooling for .NET and PowerShell. -> **Release state:** PSEventViewer 4.0.0 is available on PowerShell Gallery, -> and the five EventViewerX 4.0.0 libraries are available on NuGet. The +> **Release state:** PSEventViewer 4.0.1 is available on PowerShell Gallery, +> and the five EventViewerX 4.0.1 libraries are available on NuGet. The > `EventViewerX.Cli` .NET tool and platform ZIPs have not been published. > CLI examples below describe the source-built command until that release lane > is available. @@ -1196,7 +1196,8 @@ Install or update PSPublishModule to the latest version before running the relea .\Build\Build-Module.ps1 -RunMode Build # Resolve the configured 4.0.X version, publish the EventViewerX libraries to -# NuGet, and publish PSEventViewer to PowerShell Gallery. +# NuGet and PSEventViewer to PowerShell Gallery, then create a GitHub release +# with the signed packages, module archive, and generated release notes. .\Build\Build-Module.ps1 -RunMode Publish # Build the standalone CLI archives locally. This command does not upload them. diff --git a/Sources/PSEventViewer/packages.lock.json b/Sources/PSEventViewer/packages.lock.json index 1d66c522..b1c45bc6 100644 --- a/Sources/PSEventViewer/packages.lock.json +++ b/Sources/PSEventViewer/packages.lock.json @@ -428,7 +428,7 @@ "eventviewerx.detection": { "type": "Project", "dependencies": { - "EventViewerX": "[4.0.0, )", + "EventViewerX": "[4.0.1, )", "JsonSchema.Net": "[9.4.0, )", "System.Text.Json": "[10.0.11, )", "YamlDotNet": "[18.1.0, )" @@ -437,14 +437,14 @@ "eventviewerx.evtx": { "type": "Project", "dependencies": { - "EventViewerX": "[4.0.0, )", + "EventViewerX": "[4.0.1, )", "evtx": "[1.5.2, )" } }, "eventviewerx.reporting": { "type": "Project", "dependencies": { - "EventViewerX": "[4.0.0, )", + "EventViewerX": "[4.0.1, )", "HtmlForgeX": "[0.56.0, )", "HtmlForgeX.Email": "[1.6.0, )", "Microsoft.Bcl.AsyncInterfaces": "[10.0.11, )", @@ -456,7 +456,7 @@ "type": "Project", "dependencies": { "DBAClientX.SQLite": "[1.0.8, )", - "EventViewerX": "[4.0.0, )", + "EventViewerX": "[4.0.1, )", "Microsoft.Bcl.AsyncInterfaces": "[10.0.11, )" } } @@ -892,7 +892,7 @@ "eventviewerx.detection": { "type": "Project", "dependencies": { - "EventViewerX": "[4.0.0, )", + "EventViewerX": "[4.0.1, )", "JsonSchema.Net": "[9.4.0, )", "YamlDotNet": "[18.1.0, )" } @@ -900,14 +900,14 @@ "eventviewerx.evtx": { "type": "Project", "dependencies": { - "EventViewerX": "[4.0.0, )", + "EventViewerX": "[4.0.1, )", "evtx": "[1.5.2, )" } }, "eventviewerx.reporting": { "type": "Project", "dependencies": { - "EventViewerX": "[4.0.0, )", + "EventViewerX": "[4.0.1, )", "HtmlForgeX": "[0.56.0, )", "HtmlForgeX.Email": "[1.6.0, )", "OfficeIMO.CSV": "[3.2.4, )", @@ -918,7 +918,7 @@ "type": "Project", "dependencies": { "DBAClientX.SQLite": "[1.0.8, )", - "EventViewerX": "[4.0.0, )" + "EventViewerX": "[4.0.1, )" } } }, @@ -1200,7 +1200,7 @@ "eventviewerx.detection": { "type": "Project", "dependencies": { - "EventViewerX": "[4.0.0, )", + "EventViewerX": "[4.0.1, )", "JsonSchema.Net": "[9.4.0, )", "YamlDotNet": "[18.1.0, )" } @@ -1208,14 +1208,14 @@ "eventviewerx.evtx": { "type": "Project", "dependencies": { - "EventViewerX": "[4.0.0, )", + "EventViewerX": "[4.0.1, )", "evtx": "[1.5.2, )" } }, "eventviewerx.reporting": { "type": "Project", "dependencies": { - "EventViewerX": "[4.0.0, )", + "EventViewerX": "[4.0.1, )", "HtmlForgeX": "[0.56.0, )", "HtmlForgeX.Email": "[1.6.0, )", "OfficeIMO.CSV": "[3.2.4, )", @@ -1226,7 +1226,7 @@ "type": "Project", "dependencies": { "DBAClientX.SQLite": "[1.0.8, )", - "EventViewerX": "[4.0.0, )" + "EventViewerX": "[4.0.1, )" } } }, @@ -1502,7 +1502,7 @@ "eventviewerx.detection": { "type": "Project", "dependencies": { - "EventViewerX": "[4.0.0, )", + "EventViewerX": "[4.0.1, )", "JsonSchema.Net": "[9.4.0, )", "YamlDotNet": "[18.1.0, )" } @@ -1510,14 +1510,14 @@ "eventviewerx.evtx": { "type": "Project", "dependencies": { - "EventViewerX": "[4.0.0, )", + "EventViewerX": "[4.0.1, )", "evtx": "[1.5.2, )" } }, "eventviewerx.reporting": { "type": "Project", "dependencies": { - "EventViewerX": "[4.0.0, )", + "EventViewerX": "[4.0.1, )", "HtmlForgeX": "[0.56.0, )", "HtmlForgeX.Email": "[1.6.0, )", "OfficeIMO.CSV": "[3.2.4, )", @@ -1528,7 +1528,7 @@ "type": "Project", "dependencies": { "DBAClientX.SQLite": "[1.0.8, )", - "EventViewerX": "[4.0.0, )" + "EventViewerX": "[4.0.1, )" } } }, From f75c19fd87b427270a7b23e077f016d35e32c875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20K=C5=82ys?= Date: Tue, 29 Sep 2026 17:06:28 +0200 Subject: [PATCH 2/2] Use PowerForge token file for module GitHub release --- Build/Build-Release.ps1 | 27 +-------------------------- Build/Test-ReleaseConfiguration.ps1 | 3 ++- Build/release.module.json | 1 + 3 files changed, 4 insertions(+), 27 deletions(-) diff --git a/Build/Build-Release.ps1 b/Build/Build-Release.ps1 index 68961a49..c2e8d19e 100644 --- a/Build/Build-Release.ps1 +++ b/Build/Build-Release.ps1 @@ -18,29 +18,4 @@ if ($RunMode -eq 'Plan') { $invokeSplat.Plan = $true } -$originalGitHubToken = $env:GITHUB_TOKEN -$injectedGitHubToken = $false -try { - if ($RunMode -eq 'Publish' -and [string]::IsNullOrWhiteSpace($env:GITHUB_TOKEN)) { - $token = $env:GH_TOKEN - if ([string]::IsNullOrWhiteSpace($token) -and (Get-Command gh -ErrorAction SilentlyContinue)) { - $token = & gh auth token 2>$null - if ($LASTEXITCODE -ne 0) { $token = $null } - } - if ([string]::IsNullOrWhiteSpace($token)) { - throw 'GitHub release publishing requires GITHUB_TOKEN, GH_TOKEN, or an authenticated gh CLI.' - } - $env:GITHUB_TOKEN = $token.Trim() - $injectedGitHubToken = $true - } - - Invoke-PowerForgeRelease @invokeSplat -} finally { - if ($injectedGitHubToken) { - if ($null -eq $originalGitHubToken) { - Remove-Item Env:GITHUB_TOKEN -ErrorAction SilentlyContinue - } else { - $env:GITHUB_TOKEN = $originalGitHubToken - } - } -} +Invoke-PowerForgeRelease @invokeSplat diff --git a/Build/Test-ReleaseConfiguration.ps1 b/Build/Test-ReleaseConfiguration.ps1 index 7460d1da..f6569076 100644 --- a/Build/Test-ReleaseConfiguration.ps1 +++ b/Build/Test-ReleaseConfiguration.ps1 @@ -53,6 +53,7 @@ $moduleRelease = Get-Content -LiteralPath ` ConvertFrom-Json if ($null -ne $moduleRelease.Tools -or $moduleRelease.GitHub.Publish -ne $true -or + [string]::IsNullOrWhiteSpace([string] $moduleRelease.GitHub.TokenFilePath) -or $moduleRelease.GitHub.TokenEnvName -ne 'GITHUB_TOKEN' -or $moduleRelease.GitHub.GenerateReleaseNotes -ne $true -or $moduleRelease.GitHub.TagTemplate -ne 'PSEventViewer-v{Version}') { @@ -146,7 +147,7 @@ if (($publishOrder -join ',') -ne 'NuGet,PowerShellGallery') { } [pscustomobject] @{ NuGetCredential = $nuGetKeyPath - GitHubCredential = 'GITHUB_TOKEN' + GitHubCredential = 'TokenFilePath or GITHUB_TOKEN' PowerShellGalleryCredential = $galleryKeyPath LocalRuntimeAndOutputExcluded = $true CliStagingIsolated = $true diff --git a/Build/release.module.json b/Build/release.module.json index 5b43a4ca..0d534022 100644 --- a/Build/release.module.json +++ b/Build/release.module.json @@ -44,6 +44,7 @@ "VersionSource": "Module", "Owner": "EvotecIT", "Repository": "EventViewerX", + "TokenFilePath": "C:\\Support\\Important\\GithubAPI.txt", "TokenEnvName": "GITHUB_TOKEN", "GenerateReleaseNotes": true, "IsPreRelease": false,