Skip to content

🪲 [Fix]: New module versions publish to the PowerShell Gallery - #529

Merged
Marius Storhaug (MariusStorhaug) merged 6 commits into
mainfrom
copilot/fix-publish-module-error
Sep 2, 2026
Merged

🪲 [Fix]: New module versions publish to the PowerShell Gallery#529
Marius Storhaug (MariusStorhaug) merged 6 commits into
mainfrom
copilot/fix-publish-module-error

Conversation

Copilot AI commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

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:

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.


Technical details
  • .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 🌟 [Major]: Publish stable releases from default-branch pushes #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) 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.
  • 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 🪲[Bug]: Publish Module is failing #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
Relevant issues (or links)

Related work

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
@MariusStorhaug Marius Storhaug (MariusStorhaug) changed the title Allow publishing new PSGallery versions 🪲 [Fix]: New module versions publish to the PowerShell Gallery Sep 1, 2026
@MariusStorhaug
Marius Storhaug (MariusStorhaug) marked this pull request as ready for review September 1, 2026 20:38
Marius Storhaug and others added 3 commits September 1, 2026 22:45
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 AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 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.

Comment thread .github/actions/Publish-PSModule/tests/Publish-PSModule.Recovery.Tests.ps1 Outdated
Comment thread .github/actions/Release-PSModule/tests/Release-PSModule.WhatIf.Tests.ps1 Outdated
Comment thread .github/actions/Publish-PSModule/src/publish.ps1
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>
@MariusStorhaug
Marius Storhaug (MariusStorhaug) merged commit 68696b6 into main Sep 2, 2026
59 checks passed
@MariusStorhaug
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Fix release:patch Publish a patch release.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🪲[Bug]: Publish Module is failing

3 participants