Skip to content

Default-branch recovery retains the merged pull request's release intent - #531

Draft
Marius Storhaug (MariusStorhaug) wants to merge 6 commits into
mainfrom
fix-dispatch-version-label
Draft

Marius Storhaug (MariusStorhaug) wants to merge 6 commits into
mainfrom
fix-dispatch-version-label

Conversation

@MariusStorhaug

@MariusStorhaug Marius Storhaug (MariusStorhaug) commented Sep 2, 2026 •

Copy link
Copy Markdown
Member

Default-branch recovery retains the merged pull request's configured bump or skip label instead of silently treating its commit as a direct patch release. No caller configuration or invocation edit is required beyond selecting this compatible release; dispatch can recover a merge only while it remains the default branch's tip.

Fixed: Recovery retains the intended release without cleaning another branch

A default-branch push and a recovery dispatch use the same exact merge-SHA association. A matching merged PR supplies its labels and release metadata, including configured skip intent. A legitimate direct release remains supported. Unmatched merged associations stop an important release-capable push or a dispatch; a documentation-only push that cannot publish is not rejected for that association. Lookup failures propagate instead of being interpreted as an empty result.

For recovery, rerun the original workflow's failed jobs to retain its SHA, resolved outputs, and successful build artifacts. A new dispatch uses the current default-branch tip, not an arbitrary older SHA. If the branch has advanced, rerun the original workflow rather than dispatching the newer tip or selecting an old tag; a tag dispatch does not satisfy default-branch recovery. No new recovery-SHA input is introduced.

Prerelease cleanup uses the exact unsanitized GitHub release target branch recorded by Release-PSModule. It no longer guesses ownership from a substring in the tag. Overlapping branches, sanitized-name collisions, numeric branch/counter collisions, stable releases, and the current published tag are retained unless the existing branch-based cleanup contract establishes eligibility. Normal framework callers need no cleanup setting or payload edit. A custom producer that targets prereleases at an immutable SHA rather than the PR branch does not establish eligibility through this branch-based interface; those records are retained, not guessed from tag spelling. WhatIf remains non-mutating.

Replacing AutoPatching with DefaultBump and changing label defaults belongs to the separately scoped #524. Its breaking adoption actions do not apply to this patch.

Technical details

The immutable candidate is 38ff9ff788002cfa442173b78588bead728353a1, compared with current main 64ffb1d87f86bd5d487891fdb140b78385a00531. It preserves both original commits, reconciles the current base through ordinary commits, and includes the tightly coupled cleanup correction found during review. No released source, tag, Gallery version, label history, or ruleset is changed.

Get-PSModuleSettings detects important push files before resolving release-bearing association. Actual-controller tests prove the compare endpoint runs before commit-to-PR lookup, a documentation-only unmatched association succeeds without publication, and the same important push fails. Ten composed push/dispatch cases retain major, minor, patch, direct, and skip intent through the real association and decision helpers.

Cleanup reads every GitHub release page and selects only exact target_commitish matches. The existing producer's --target <PR head branch> interface is verified in Release-PSModule/src/release.ps1; tag text is not treated as ownership evidence. Three controller regressions reproduce the old cross-branch deletions before the fix and pass with the exact-target selector. The newly covered review defects produce four failing cases before correction. Restoring the original push-only gate separately produces nine failing regressions.

Local evidence: 93 focused tests and the full 108-test action suite pass; shuffled parallel containers are exercised. PowerShell analysis is clean and the Zensical documentation build reports no issues. Logging uses the full GitHub cmdlet, and Pester contexts are module-qualified to avoid dependency-dependent alias diagnostics rather than relying on unmatched suppressions. Validation uses synthetic fixtures and local command replacements; it does not publish or delete real releases.

Compatibility evidence: caller inputs, settings mappings, secrets, permissions, runtimes, and direct-release policy are unchanged. No external integration template is changed. The repository's default and with-manifest fixture workflows retain their existing interfaces; current-head hosted fixture checks and the new explicit Copilot review round remain review evidence, not a claim that unmerged source is delivered.

Changed surface Standards checked Framework docs checked Result
Settings helper and controller event ordering PowerShell, Functions, Error Handling, Testing Plan, important-change detection, recovery routing Fixed in this PR
Cleanup helper/controller and its README PowerShell, GitHub Actions, Error Handling, Testing Existing branch-target publication and retained-tag contract Fixed in this PR
Association, controller, and composed decision tests Pester, Testing, Natural Language Action test layout and module-version resolution Aligned
Recovery and scenario guidance Markdown, Natural Language Existing caller contract and publication routing Fixed in this PR

All five findings from the first explicit Copilot round are addressed: tip-only recovery guidance, exact cleanup target, important-change gating, skip coverage, and public dispatch documentation. The complete summary was read; it contained no additional suppressed findings. A new round and current-head hosted checks are required before readiness. Main's live rules expose no required_status_checks rule, so enforcement is a genuine remaining gate, not something this documentation fixes.

Scoped issue convergence: #530 is delivered here. #529 is related recovery context, not an additional closing claim. Intended order is this patch first, then #524 after refreshing and validating its composed settings changes. Existing artifact-isolation and later authoring/skills work remain separately owned.

Related references
Release decisions
  • Release: Yes - the versioned framework's supported recovery and cleanup behavior is corrected for module-maintainer integrations.
  • Version bump: Patch - a compatible fix, with explicit release:patch intent. The currently released native self-release reader is still Release-GHRepository v2.0.3 and reads the unchanged legacy Patch/Fix mappings; those agree on patch while the owned-label caller follow-up is pending.
  • Mode: Stable - this PR targets the framework's default-branch native release route. Final version/base coordinates, tag, source, and consumer-change baseline are resolved by the release process at publication.
  • Labels: release:patch. Existing non-owned compatibility labels are retained; no label cleanup is performed. The draft is not ready while current-head review/checks or required release-decision enforcement remain open.

Marius Storhaug and others added 2 commits September 2, 2026 11:08
A workflow_dispatch on the default branch is the documented recovery route for
a failed or cancelled release run. Pull request association was gated on
$isPush, so a dispatch resolved no pull request, saw no version label, and
silently applied the AutoPatching patch fallback.

Widen the gate to cover a manual dispatch on the default branch, so the same
association and selection path runs for the same merge commit.

Also fail loudly when a merged default-branch pull request is associated with
the commit but does not match it, instead of falling back to a patch bump. A
wrong version published to the PowerShell Gallery cannot be reclaimed.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Extract the gate, selection, and no-pull-request decision from main.ps1 into
Resolve-ReleasePullRequest, with the GitHub lookup injected as a script block.
The composed logic that produced the wrong version is now covered directly
rather than re-implemented in a test.

Add Get-DiscardedReleasePullRequest so a merged default-branch pull request that
does not match the released commit fails the run instead of silently applying a
patch bump. Open pull requests and non-default-branch merges are ignored, so a
direct push and a feature-branch push are unaffected.

Each new test was verified to fail against the specific defect it guards.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@MariusStorhaug Marius Storhaug (MariusStorhaug) changed the title 🪲 [Fix]: Manual dispatch on the default branch honours the merged pull request's version label 🪲 [Fix]: Manual dispatch on the default branch honors the merged pull request's version label Oct 31, 2026

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.

🟡 Changes recommended

Dispatch recovery can resolve the wrong commit and delete another PR’s prereleases, while documentation-only pushes can fail unnecessarily.

5 open issues
What changed in this PR

This PR addresses #530 by making default-branch manual dispatches resolve the merged pull request associated with the dispatched commit, preserving its version-label intent in the release pipeline.

Changes:

  • Shares commit-to-PR resolution between pushes and default-branch dispatches.
  • Rejects unmatched merged-PR associations while preserving legitimate direct releases and propagating lookup failures.
  • Adds association regressions and composed version-resolution tests without changing public workflow inputs or versioning defaults.
File Description
.github/​actions/​Resolve-PSModuleVersion/​tests/​Resolve-PSModuleVersion.Helpers.Tests.ps1 Adds dispatch-context and composed version-resolution tests.
.github/​actions/​Get-PSModuleSettings/​tests/​Get-PSModuleSettings.Helpers.Tests.ps1 Covers association selection, rejection, direct releases, and lookup failures.
.github/​actions/​Get-PSModuleSettings/​src/​main.ps1 Wires event context and the association API into the shared resolver.
.github/​actions/​Get-PSModuleSettings/​src/​Get-PSModuleSettings.Helpers.psm1 Adds release-PR resolution and unmatched-association safeguards.

Review effort: Balanced

@MariusStorhaug Marius Storhaug (MariusStorhaug) added the release:patch Publish a patch release. label Oct 31, 2026
@MariusStorhaug Marius Storhaug (MariusStorhaug) changed the title 🪲 [Fix]: Manual dispatch on the default branch honors the merged pull request's version label Default-branch recovery retains the merged pull request's release intent Oct 31, 2026
@github-actions

Copy link
Copy Markdown

Super-linter summary

Language Validation result
CHECKOV Pass ✅
CSS Pass ✅
CSS_PRETTIER Pass ✅
GITHUB_ACTIONS Pass ✅
GITHUB_ACTIONS_ZIZMOR Pass ✅
GITLEAKS Pass ✅
GIT_MERGE_CONFLICT_MARKERS Pass ✅
HTML Pass ✅
JAVASCRIPT_ES Pass ✅
JAVASCRIPT_PRETTIER Pass ✅
MARKDOWN Pass ✅
NATURAL_LANGUAGE Pass ✅
POWERSHELL Pass ✅
PRE_COMMIT Pass ✅
SPELL_CODESPELL Pass ✅
TRIVY Pass ✅
YAML Pass ✅

All files and directories linted successfully

For more information, see the GitHub Actions workflow run

Powered by Super-linter

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.

Comment on lines +53 to +54
if ($candidate.targetCommitish -ceq $HeadRef) {
$candidate
Write-Host 'Non-PR event - treating as having important changes'
}

# Dispatch resolves the current default-branch tip. Rerun the original workflow for an older merge.
$response.Response
}
}
$resolution = Resolve-ReleasePullRequest @resolveParams
'The following merged pull request(s) are associated with it but none matches the commit ' +
"being released: $($discarded -join '; '). " +
'Refusing to fall back to a patch bump, because a wrong version published to the ' +
'PowerShell Gallery cannot be reclaimed. Rerun the original workflow for the intended merge commit. ' +

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Fix Patch release:patch Publish a patch release.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

2 participants