🌟 [Major]: Publish stable releases from default-branch pushes - #512
Conversation
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Super-linter summary
All files and directories linted successfully For more information, see the GitHub Actions workflow run Powered by Super-linter |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Moves stable publication authority from merged-PR events to default-branch pushes.
Changes:
- Normalizes push, PR, and manual-dispatch release context.
- Updates publication, cleanup, concurrency, and site-deployment routing.
- Aligns dogfood workflows, tests, and documentation.
Reviewed changes
Copilot reviewed 34 out of 34 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
tests/srcWithManifestTestRepo/.github/PSModule.yml |
Skips fixture site deployment. |
tests/srcTestRepo/.github/PSModule.yml |
Skips fixture site deployment. |
docs/content/specification/spec.md |
Defines push-authorized releases. |
docs/content/specification/design.md |
Updates release architecture. |
docs/content/reference/settings.md |
Documents site and release settings. |
docs/content/reference/scenario-matrix.md |
Revises event/job routing. |
docs/content/reference/powershell-module-standard.md |
Updates pipeline standards. |
docs/content/reference/pipeline-stages.md |
Documents publication ordering. |
docs/content/index.md |
Updates lifecycle overview. |
docs/content/guides/versioning-and-releases.md |
Revises versioning guidance. |
docs/content/guides/calling-the-workflow.md |
Adds push and concurrency guidance. |
docs/content/get-started/your-first-release.md |
Explains push-based releases. |
docs/content/get-started/repository-setup.md |
Updates caller template. |
docs/content/get-started/module-bootstrap.md |
Updates first-release wording. |
docs/content/get-started/index.md |
Updates onboarding flow. |
.github/workflows/workflow.yml |
Revises orchestration and concurrency. |
.github/workflows/Workflow-Test-WithManifest.yml |
Adds push lifecycle dogfooding. |
.github/workflows/Workflow-Test-Default.yml |
Adds push lifecycle dogfooding. |
.github/workflows/Release.yml |
Makes release runs non-cancelling. |
.github/workflows/Publish-Module.yml |
Orders Gallery and GitHub publication. |
.github/actions/Resolve-PSModuleVersion/tests/Resolve-PSModuleVersion.Helpers.Tests.ps1 |
Tests normalized release decisions. |
.github/actions/Resolve-PSModuleVersion/src/Resolve-PSModuleVersion.Helpers.psm1 |
Resolves normalized event context. |
.github/actions/Resolve-PSModuleVersion/src/main.ps1 |
Passes settings into resolution. |
.github/actions/Release-PSModule/tests/Release-PSModule.WhatIf.Tests.ps1 |
Tests direct-push releases. |
.github/actions/Release-PSModule/src/release.ps1 |
Supports push-based release creation. |
.github/actions/Release-PSModule/action.yml |
Adds PR and commit inputs. |
.github/actions/Publish-PSModule/src/publish.ps1 |
Makes PR comments conditional. |
.github/actions/Publish-PSModule/action.yml |
Adds normalized PR input. |
.github/actions/Get-PSModuleSettings/tests/Get-PSModuleSettings.Helpers.Tests.ps1 |
Tests routing and association helpers. |
.github/actions/Get-PSModuleSettings/src/Settings.schema.json |
Adds site publication settings. |
.github/actions/Get-PSModuleSettings/src/main.ps1 |
Normalizes events and release routing. |
.github/actions/Get-PSModuleSettings/src/Get-PSModuleSettings.Helpers.psm1 |
Adds routing and Git helpers. |
.github/actions/Cleanup-PSModulePrereleases/src/cleanup.ps1 |
Uses normalized PR context. |
.github/actions/Cleanup-PSModulePrereleases/action.yml |
Adds normalized PR input. |
Suppressed comments (3)
.github/actions/Get-PSModuleSettings/src/main.ps1:325
- This condition also selects the PR-files path for a default-branch push that was associated with a merged PR. If one push contains earlier commits plus that merge commit, important-file detection examines only the final PR and can incorrectly skip a release for important changes earlier in the push. Restrict this branch to actual PR events so every push uses the full
before...aftercomparison.
if ($pullRequestContext.Number) {
.github/actions/Get-PSModuleSettings/src/main.ps1:419
- GitHub's compare response exposes at most 300 changed files. A larger default-branch push can therefore hide an important file after the cap and be classified as non-important, silently suppressing its release. Use a complete local diff or fail explicitly when the API cap is reached, as the initial-tree path already does for truncation.
$changedFiles = Invoke-GitHubAPI -ApiEndpoint "/repos/$owner/$repo/compare/$beforeCommitSha...$commitSha" -Method GET |
Select-Object -ExpandProperty Response |
Select-Object -ExpandProperty files |
Select-Object -ExpandProperty filename
.github/actions/Get-PSModuleSettings/src/main.ps1:633
- This now enables
AutoCleanuponly for the closed-PR run. Consequently the stable-push path passesAutoCleanup: falseto the cleanup action even when the user configured it true, so a failed or missed close-event cleanup is never retried after the stable release. Include stable releases in this gate, matching the documented “after a stable default-branch release” behavior.
$shouldAutoCleanup = $routing.ShouldCleanupEvent -and ($settings.Publish.Module.AutoCleanup -eq $true)
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
Addressed the three suppressed default-branch push edge cases in 70fcb5a:
Added routing and compare-limit coverage, plus aligned the scenario matrix. |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
A module version that has never been published to the PowerShell Gallery can now be published. Any first release, and every subsequent new version, previously failed the Publish-Module stage before the upload was attempted. ## Fixed: New module versions publish to the PowerShell Gallery Publishing a version that is not yet on the PowerShell Gallery now succeeds. The stage checks whether the version already exists so an interrupted run can resume, and treats an absent version as the expected result for a new release rather than an error. Before this change the Publish-Module job failed with the following, and no module was ever uploaded: ```text Find-PSResource: Package with name 'MyModule', version '1.3.1' could not be found in repository 'PSGallery'. Error: Process completed with exit code 1. ``` No repository configuration changes are needed. A workflow run that previously failed at this point succeeds on re-run. Resuming an interrupted publication is unchanged: when the version is already on the Gallery, the run skips the upload and continues to GitHub release creation. --- <details> <summary>Technical details</summary> - `.github/actions/Publish-PSModule/src/publish.ps1` — the Gallery existence probe in the `Publish to PSGallery` region ran `Find-PSResource` with `-ErrorAction Stop`. `Microsoft.PowerShell.PSResourceGet` raises `PackageNotFound,Microsoft.PowerShell.PSResourceGet.Cmdlets.FindPSResource` when the requested version does not exist, which `-ErrorAction Stop` turns into a throw, so the probe made a missing version fatal instead of returning `$null`. The probe now keeps `-ErrorAction Stop` and catches only `PackageNotFound`, treating that one error as 'not yet published' and letting the `if ($publishedPackage)` branch decide the outcome. Every other error stays fatal, so a transient Gallery failure cannot be misread as 'version absent' and cause a re-upload of a version that already exists. - The probe was introduced in #512 to make Gallery publication idempotent for the default-branch push release path. That path replaced a `try`/`catch` around `Publish-PSResource`, which is why the regression reached `main` without an existing test catching it. - `.github/actions/Publish-PSModule/tests/Publish-PSModule.Recovery.Tests.ps1` — the harness could not observe whether publication happened, so its assertions were vacuous: `Publish-PSResource` was shimmed to set `$script:publishInvoked`, but `publish.ps1` runs in its own scope via `&`, so the flag never propagated and stayed `$false` regardless. Replaced with a hashtable captured by `GetNewClosure()`, which is shared by reference. A second variant wrote a marker file under `$env:GITHUB_WORKSPACE`; that is process-wide and races between parallel Pester runspaces, so the marker could land in another test file's `TestDrive`. The not-found shim also used `$PSCmdlet.ThrowTerminatingError(...)`, which ignores `-ErrorAction` and therefore threw under both `Stop` and `SilentlyContinue` — unable to distinguish the fix from the defect. It now uses `Write-Error` with the real `PackageNotFound` error ID, matching how the cmdlet actually behaves. Added a case asserting a non-`PackageNotFound` lookup failure stays fatal and does not publish. Each test was verified to fail against the specific defect it guards. - `.github/actions/Release-PSModule/tests/Release-PSModule.WhatIf.Tests.ps1` and `Publish-PSModule.Recovery.Tests.ps1` — shim teardown used `Remove-Item -Path function:global:X`. `Set-Item` accepts that path and creates `X` in the global scope, but `Remove-Item` and `Get-Item` do not resolve it back, and fail silently rather than erroring, so the cleanup was a no-op. The shims survived `AfterAll` and shadowed the real commands for later test files, which is what made `Test-Actions` fail with `A parameter cannot be found that matches parameter name 'Prerelease'` in `Get-NextPrereleaseNumber`. Teardown now removes by name. - Validated end to end in `MariusStorhaug/MariusTestModule` ([PR #63](MariusStorhaug/MariusTestModule#63)) with the caller pointed at this branch. A new version published successfully ([run 33597824748](https://github.com/MariusStorhaug/MariusTestModule/actions/runs/33597824748/job/100145585604)), and re-running the same job with the version present skipped the upload via the resume path ([re-run](https://github.com/MariusStorhaug/MariusTestModule/actions/runs/33597824748/job/100146802704)). Both branches of the probe are confirmed against the live Gallery. - Out of scope, found while reproducing: a `workflow_dispatch` on the default branch resolves no associated pull request, because pull request association in `.github/actions/Get-PSModuleSettings/src/main.ps1` is gated on `$isPush`. A manual recovery run therefore discards the merged pull request's version label and silently resolves a Patch bump. This is a separate defect in version resolution and is recorded in the analysis on #528; it is not addressed here. - Also out of scope: `.github/workflows/Test-Actions.yml` builds a Pester configuration with `Run.Parallel` and `Run.Shuffle`, asserts the options applied, then discards it and creates a fresh `New-PesterConfiguration` for the actual run. Parallel and shuffle are validated but never used, which is why the `GITHUB_WORKSPACE` race above could not surface in CI. The suite now passes both sequentially and under the intended parallel configuration, so enabling it should be safe. | Changed surface | Standards checked | Framework docs checked | Result | | --- | --- | --- | --- | | `.github/actions/Publish-PSModule/src/**` (PowerShell) | Coding standards, error handling | Publish stage contract | Aligned | | `.github/actions/Publish-PSModule/tests/**` (Pester) | Pester test standards | Action test layout | Aligned | | `.github/actions/Release-PSModule/tests/**` (Pester) | Pester test standards | Action test layout | Aligned | </details> <details> <summary>Relevant issues (or links)</summary> - Resolves #528 ### Related work - References #512 </details> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: MariusStorhaug <17722253+MariusStorhaug@users.noreply.github.com> Co-authored-by: Marius Storhaug <Marius.Storhaug@dnb.no> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Process-PSModule now authorizes stable module publication from an important push to the default branch rather than from a merged
pull_requestevent. An associated merged pull request supplies labels and release notes only when its merge commit exactly matches the pushed SHA; direct pushes and default-branch manual dispatches release a Patch version with commit-based notes.Breaking Changes
Caller workflows must add a
pushtrigger for their default branch to receive stable releases. The canonical caller templates now use non-cancelling per-pull-request-or-ref concurrency so pull-request cleanup and the resulting default-branch release remain independent while all release mutations queue safely. The consumer-repository rollout remains tracked in #438.Changed: Stable release lifecycle
AutoPatching; pull-request prereleases retain their configuredAutoPatchingbehavior.pull_request.closedevent can enter cleanup; a label change on an already closed PR runs no build, prerelease, or cleanup path.cancel-in-progress: falseto preserve serialized artifact and tag mutation.Dogfood and documentation
Publish.Site.Skipprevents deployment to the Process-PSModule Pages environment.Scope boundary
Release-GHRepository@v2.0.3, which releases Process-PSModule itself, only supports pull-request event payloads. This PR therefore does not install a push trigger that would succeed without producing that repository release. Push-capable repository releases and moving workflow-consumer tags are tracked separately in PSModule/Release-GHRepository#108.Technical Details
GET /repos/{owner}/{repo}/commits/{sha}/pullsand requires an exact merged commit match on the default branch.Publish.Site.Skipseparates site build from deployment; dogfood callers mark their fixture roots as important, build site artifacts, and skip real Pages publication.Related issues