Skip to content

🪲 [Fix]: Manual dispatch on the default branch discards the merged pull request's version label #530

Description

A workflow_dispatch run on the default branch resolves no associated pull request, so the merged pull request's version label is discarded and the version silently falls back to a Patch bump. Recovering a failed release by manual dispatch therefore publishes the wrong version, and PowerShell Gallery versions cannot be reclaimed once taken.

Impact

Manual dispatch on the default branch is the documented recovery route when a release run fails or is cancelled. In that exact scenario, the label that determines the version bump is ignored:

  • A merged pull request labelled minor should release 1.4.0 from 1.3.0.
  • A manual dispatch resolves no pull request, finds no version label, and applies AutoPatching.
  • The run publishes 1.3.1.

1.3.1 then permanently occupies the Gallery. The intended 1.4.0 can still be released afterwards, but the incorrect version cannot be removed, and consumers who installed in between receive a release that was never intended to exist.

This is silent. The run succeeds, and the only signal is a log line stating a patch bump was assumed.

Reproduction

Observed in PSModule/PSWEE while diagnosing #528:

Correct version 1.4.0
Version attempted 1.3.1
  1. PSWEE PR 🚀 [Feature]: Enter the Matrix #12, labelled Minor, merged as f8c59e6. Latest GitHub release and Gallery version were both 1.3.0.
  2. The push run for f8c59e6 (run 33551501626) was cancelled one second after starting, because that caller still used cancel-in-progress: true with a github.ref-only concurrency key.
  3. Recovery was attempted as a workflow_dispatch on main. The Plan job logged "Using direct default-branch release context with the default patch bump" and resolved 1.3.1.

The cancelled push is a separate caller-configuration problem. This issue is only about step 3: once a recovery dispatch happens, the version resolves incorrectly.

Cause

.github/actions/Get-PSModuleSettings/src/main.ps1 gates pull request association on $isPush:

$isPush = $eventName -eq 'push'
$isManualDispatch = $eventName -eq 'workflow_dispatch'
$commitSha = if ($isPush) { $eventData.After ?? $env:GITHUB_SHA } else { $env:GITHUB_SHA }

if ($isPush -and $commitSha) {
    # /repos/{owner}/{repo}/commits/{sha}/pulls -> Select-PullRequestForPush
}

$commitSha is populated for a manual dispatch (from GITHUB_SHA), and $isManualDispatchToDefaultBranch is computed on the line above, so the event is already recognised. Only the lookup is skipped.

With $pullRequest left null, Resolve-ReleaseDecision sees no labels. $majorRelease and $minorRelease are both false, so the $patchRelease fallback applies via AutoPatching or $isDirectStableRelease, and the run resolves a patch bump.

Expected behaviour

A workflow_dispatch on the default branch should resolve the pull request associated with the dispatched commit and honour its version label, exactly as the equivalent push does. The same Select-PullRequestForPush selection logic applies — the commit is a merge commit on the default branch in both cases.

If no pull request can be resolved, the run should fail loudly rather than silently assuming Patch. Publishing a wrong version to the Gallery is unrecoverable, so an explicit failure is strictly better than a silent downgrade.

Suggested approach

Widen the gate to cover a manual dispatch targeting the default branch, so the same association and selection path runs:

if (($isPush -or $isManualDispatchToDefaultBranch) -and $commitSha) {

Then decide the no-pull-request case deliberately. For a manual dispatch on the default branch, resolving no pull request most likely means the commit was pushed directly, so the existing direct-release path is legitimate. The distinction worth encoding is "no pull request exists" (proceed) versus "a pull request exists but was not consulted" (the current defect).

Validation plan

MariusStorhaug/MariusTestModule will be used as the consuming repository, following the approach that validated #528 and #529:

  1. Reproduce the defect on the test module against the current v8, showing a labelled merged pull request whose label is discarded by a manual dispatch.
  2. Capture the resolved-version evidence from the Plan job.
  3. Fix in Process-PSModule with unit coverage in Get-PSModuleSettings and Resolve-PSModuleVersion tests.
  4. Retarget the test module's caller at the fix branch and confirm the label is honoured.
  5. Revert the caller to @v8 once the fix ships in a tag.

Note that step 1 must avoid publishing an incorrect stable version to the Gallery, since that cannot be undone. The reproduction will use the prerelease label or WhatIf so the wrong resolved version is observable without being published.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions