🪲 [Fix]: New module versions publish to the PowerShell Gallery - #529
Merged
Marius Storhaug (MariusStorhaug) merged 6 commits intoSep 2, 2026
Merged
Conversation
Copilot started work on behalf of
Marius Storhaug (MariusStorhaug)
September 1, 2026 20:02
View session
Co-authored-by: MariusStorhaug <17722253+MariusStorhaug@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Fix publish module failing when version not found
Allow publishing new PSGallery versions
Sep 1, 2026
Marius Storhaug (MariusStorhaug)
marked this pull request as ready for review
September 1, 2026 20:38
Marius Storhaug (MariusStorhaug)
requested a review
from a team
as a code owner
September 1, 2026 20:38
Remove-Item does not accept a 'global:' scope qualifier in a provider path, so the AfterAll cleanup silently failed and left the Find-PSResource, Publish-PSResource, Resolve-PSModuleDependency, gh, and git shims in the global scope. Later test files then resolved the shims instead of the real commands, which failed Get-NextPrereleaseNumber with 'A parameter cannot be found that matches parameter name Prerelease'. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Addresses review feedback on #528: -ErrorAction SilentlyContinue swallowed every Find-PSResource failure, not just 'version not found'. During a Gallery outage the probe returned null, publish was attempted anyway, and an already-published version failed the upload with a conflict - losing the resume behaviour the probe exists to provide. The probe now runs with -ErrorAction Stop and only treats the PackageNotFound error ID as 'not yet published'. Any other error stays fatal. Also fixed the test harness, which could not observe whether publish ran: - The $script:publishInvoked flag was never set, because the publish script runs in its own scope. Both existing assertions were vacuous. Replaced with a hashtable captured by GetNewClosure(), shared by reference. - The marker-file variant depended on $env:GITHUB_WORKSPACE, which is process-wide and races between parallel Pester runspaces. - The not-found shim used ThrowTerminatingError, which ignores -ErrorAction and so could not distinguish the fix from the bug. It now uses Write-Error with the real PackageNotFound error ID. Added a case asserting a non-PackageNotFound lookup failure stays fatal and does not publish. Verified each test fails against the defect it guards. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot started reviewing on behalf of
Marius Storhaug (MariusStorhaug)
September 2, 2026 06:26
View session
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
The implementation and tests correctly cover the regression, with only non-blocking documentation inconsistencies remaining.
Pull request overview
Fixes new-version publication by handling the Gallery’s expected PackageNotFound error without suppressing other failures.
Changes:
- Selectively catches missing-package errors.
- Tests missing, existing, and transient-error scenarios.
- Updates test-shim cleanup.
File summaries
| File | Description |
|---|---|
Release-PSModule.WhatIf.Tests.ps1 |
Adjusts shim cleanup. |
Publish-PSModule.Recovery.Tests.ps1 |
Expands publication recovery coverage. |
publish.ps1 |
Allows unpublished versions to proceed to upload. |
Review details
- Files reviewed: 3/3 changed files
- Comments generated: 3
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Copilot review flagged the comments as factually wrong, and it was half right. Set-Item does accept 'function:global:X' - it creates X in the global scope. The real problem is asymmetry: Remove-Item and Get-Item do not resolve that same path back to the function, and fail silently instead of erroring, so the teardown was a no-op. Verified no 'global:' path form removes the function (function:global:X, Function:global:X, Function:\global:X all leave it in place), so removing by name is required. Behaviour is unchanged; only the explanation is corrected. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Marius Storhaug (MariusStorhaug)
deleted the
copilot/fix-publish-module-error
branch
September 2, 2026 07:18
Marius Storhaug (MariusStorhaug)
pushed a commit
to MariusStorhaug/MariusTestModule
that referenced
this pull request
Sep 2, 2026
PSModule/Process-PSModule#529 merged and shipped in v8.0.4, so the publish fix is available from the v8 tag. The temporary branch pin is no longer needed, and the branch it referenced has been deleted. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Marius Storhaug (MariusStorhaug)
added a commit
to MariusStorhaug/MariusTestModule
that referenced
this pull request
Sep 2, 2026
… (#63) Validates the publish fix in [PSModule/Process-PSModule#529](PSModule/Process-PSModule#529) end to end, against a real publication. ## Why This repository reproduced the defect in [PSModule/Process-PSModule#528](PSModule/Process-PSModule#528): merging #62 to `main` failed at Publish-Module before any upload was attempted. **Failing run:** [33596331743](https://github.com/MariusStorhaug/MariusTestModule/actions/runs/33596331743) → [Publish-Module job](https://github.com/MariusStorhaug/MariusTestModule/actions/runs/33596331743/job/100141121893) ```text | Package with name 'MariusTestModule', version '0.4.13' could not be | found in repository 'PSGallery'. ##[error]Process completed with exit code 1. ``` The existence probe in `publish.ps1` treated an absent version as fatal, so every first-time publication of a new version failed. ## What this changes | File | Change | | --- | --- | | `.github/workflows/Process-PSModule.yml` | caller ref `@v8` → `@copilot/fix-publish-module-error` | | `src/functions/public/DateAndTime/Get-CurrentDateTime.ps1` | documentation only — clarifies culture behaviour of the format presets | The source change exists only to give the pipeline something to release. It is comment-only: no executable code is touched. Pointing the caller's `uses:` ref at the branch is sufficient, because the reusable workflow checks out its own actions at the resolved workflow commit rather than a floating tag: ```yaml - name: Checkout Process-PSModule uses: actions/checkout@... with: repository: ${{ job.workflow_repository }} ref: ${{ job.workflow_sha }} path: _wf ``` So `_wf/.github/actions/Publish-PSModule/src/publish.ps1` resolves to the fixed file, with no vendoring or pinning workarounds. ## Success criteria | Stage | Expected | | --- | --- | | Plan | resolves the next version | | Publish-Module (this PR) | prerelease publishes to the Gallery | | Publish-Module (on merge) | stable version publishes, **no `PackageNotFound` failure** | | GitHub release | created for the new version | The decisive signal is the merge publication: the probe must report "not found" without failing the job, then hand off to `Publish-PSResource`. The starting point is clean — the failed run left the Gallery at `0.4.12` with no `0.4.13` release — so this is a direct before/after on the same version that previously failed. ## Do not merge as-is⚠️ The caller ref points at a **branch**, not a release tag. Once #529 merges and a `v8` tag includes it, this must be reverted to `@v8`. Merging this ref permanently would pin the module to a feature branch. --------- Co-authored-by: Marius Storhaug <Marius.Storhaug@dnb.no> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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:
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.
Technical details
.github/actions/Publish-PSModule/src/publish.ps1— the Gallery existence probe in thePublish to PSGalleryregion ranFind-PSResourcewith-ErrorAction Stop.Microsoft.PowerShell.PSResourceGetraisesPackageNotFound,Microsoft.PowerShell.PSResourceGet.Cmdlets.FindPSResourcewhen the requested version does not exist, which-ErrorAction Stopturns into a throw, so the probe made a missing version fatal instead of returning$null. The probe now keeps-ErrorAction Stopand catches onlyPackageNotFound, treating that one error as 'not yet published' and letting theif ($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.try/catcharoundPublish-PSResource, which is why the regression reachedmainwithout 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-PSResourcewas shimmed to set$script:publishInvoked, butpublish.ps1runs in its own scope via&, so the flag never propagated and stayed$falseregardless. Replaced with a hashtable captured byGetNewClosure(), 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'sTestDrive. The not-found shim also used$PSCmdlet.ThrowTerminatingError(...), which ignores-ErrorActionand therefore threw under bothStopandSilentlyContinue— unable to distinguish the fix from the defect. It now usesWrite-Errorwith the realPackageNotFounderror ID, matching how the cmdlet actually behaves. Added a case asserting a non-PackageNotFoundlookup 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.ps1andPublish-PSModule.Recovery.Tests.ps1— shim teardown usedRemove-Item -Path function:global:X.Set-Itemaccepts that path and createsXin the global scope, butRemove-ItemandGet-Itemdo not resolve it back, and fail silently rather than erroring, so the cleanup was a no-op. The shims survivedAfterAlland shadowed the real commands for later test files, which is what madeTest-Actionsfail withA parameter cannot be found that matches parameter name 'Prerelease'inGet-NextPrereleaseNumber. Teardown now removes by name.MariusStorhaug/MariusTestModule(PR #63) with the caller pointed at this branch. A new version published successfully (run 33597824748), and re-running the same job with the version present skipped the upload via the resume path (re-run). Both branches of the probe are confirmed against the live Gallery.workflow_dispatchon the default branch resolves no associated pull request, because pull request association in.github/actions/Get-PSModuleSettings/src/main.ps1is 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 🪲[Bug]: Publish Module is failing #528; it is not addressed here..github/workflows/Test-Actions.ymlbuilds a Pester configuration withRun.ParallelandRun.Shuffle, asserts the options applied, then discards it and creates a freshNew-PesterConfigurationfor the actual run. Parallel and shuffle are validated but never used, which is why theGITHUB_WORKSPACErace above could not surface in CI. The suite now passes both sequentially and under the intended parallel configuration, so enabling it should be safe..github/actions/Publish-PSModule/src/**(PowerShell).github/actions/Publish-PSModule/tests/**(Pester).github/actions/Release-PSModule/tests/**(Pester)Relevant issues (or links)
Related work