Context and request
Observed behavior: since v6, Publish-PSModule derives the git tag from the compiled manifest's ModuleVersion instead of from the resolved FullVersion. ModuleVersion is Major.Minor.Patch by definition — the script even enforces ^\d+\.\d+\.\d+$ — so the configured VersionPrefix is dropped and the release is tagged without it.
.github/actions/Publish-PSModule/src/publish.ps1 (v6.1.15):
$moduleVersion = $manifestData.ModuleVersion
if (-not ($moduleVersion -match '^\d+\.\d+\.\d+$')) { ... }
...
$releaseTag = if ($createPrerelease) { "$moduleVersion-$prerelease" } else { $moduleVersion }
...
$releaseCreateCommand = @('release', 'create', $releaseTag)
The Plan job resolves the prefix correctly and passes it through. From the PSSemVer publish run for PR PSModule/PSSemVer#46:
VersionPrefix : v
GitHub version: [v1.1.9]
New version: [v1.1.10]
"Resolution":{"Version":"1.1.10","Prerelease":"","FullVersion":"v1.1.10","ReleaseType":"Release","CreateRelease":true}
FullVersion is v1.1.10; the tag created is 1.1.10.
Expected behavior: the release tag is the resolved FullVersion, so VersionPrefix: 'v' keeps producing v1.1.10 and a repository's tag history stays consistent.
Reproduction: merge any release-labelled pull request in a module repository pinned to v6 whose settings leave VersionPrefix at the default v, then compare the new tag to the previous one.
Environment: Process-PSModule v6.0.0 through v6.1.15; any module repository using the default VersionPrefix: 'v'.
Regression: yes. v5 produced prefixed tags. Three repositories have already published on v6 and every one of them lost the prefix at the v6 boundary:
| Repository |
Last v5 tag |
First v6 tag |
PSModule/Toml |
v0.0.1 |
0.0.2 |
PSModule/Domeneshop |
v0.0.2 |
1.0.0, 1.0.1 |
PSModule/PSSemVer |
v1.1.9 |
1.1.10 |
This looks like a side effect of #326, which made publish read the version from the manifest read-only. The manifest is the right source for the module version, but it cannot carry the tag prefix.
Workaround: none that preserves history. Setting VersionPrefix: '' makes the repository consistent going forward but abandons every existing v-prefixed tag.
Acceptance criteria:
- With
VersionPrefix: 'v', a stable release is tagged v<Major>.<Minor>.<Patch> and a prerelease is tagged v<Major>.<Minor>.<Patch>-<label>.
- With
VersionPrefix: '', tags stay unprefixed.
AutoCleanup still matches and removes the prerelease tags it created, in both prefixed and unprefixed repositories.
- A regression test covers a prefixed repository, so the prefix cannot be dropped silently again.
Technical decisions
The root cause is bounded to the tag derivation in .github/actions/Publish-PSModule/src/publish.ps1. The manifest check should stay — it is a valid guard that the artifact was stamped — but $releaseTag should come from the Plan job's FullVersion output (or from Version plus the settings VersionPrefix), not from $moduleVersion. The ModuleVersion validation and the 999.0.0 placeholder check remain unchanged.
Two decisions are needed:
- Whether the already-published unprefixed tags are corrected. Retagging
PSSemVer 1.1.10, Toml 0.0.2, and Domeneshop 1.0.0/1.0.1 would restore consistency, but the releases and their attached artifacts are already public, and 1.1.10 is the tag the PowerShell Gallery listing links to. Leaving them and fixing forward is the lower-risk option; either way the choice should be explicit.
- Whether prefix consistency is enforced.
Resolve-PSModuleVersion's Get-LatestGitHubVersion reads tagName and Get-LatestPublishedVersion sorts a prefixed and an unprefixed [PSSemVer] together — CompareTo ignores Prefix, so equal versions sort arbitrarily and the prefix can be lost from the resolved latest version. That is survivable because the prefix is reapplied from settings afterwards, but a repository with mixed tags is worth a warning.
Blast radius grows with #438: 48 of 58 module repositories are still on v5 and will hit this the first time they publish after migrating.
Implementation plan
Add a regression test that publishes from a fixture repository configured with VersionPrefix: 'v' and asserts the created tag, confirm it fails against current main, change $releaseTag to use the resolved full version, re-run the prefixed and unprefixed fixtures plus the AutoCleanup path, then record the decision on the already-published tags.
Context and request
Observed behavior: since v6,
Publish-PSModulederives the git tag from the compiled manifest'sModuleVersioninstead of from the resolvedFullVersion.ModuleVersionisMajor.Minor.Patchby definition — the script even enforces^\d+\.\d+\.\d+$— so the configuredVersionPrefixis dropped and the release is tagged without it..github/actions/Publish-PSModule/src/publish.ps1(v6.1.15):The Plan job resolves the prefix correctly and passes it through. From the
PSSemVerpublish run for PR PSModule/PSSemVer#46:FullVersionisv1.1.10; the tag created is1.1.10.Expected behavior: the release tag is the resolved
FullVersion, soVersionPrefix: 'v'keeps producingv1.1.10and a repository's tag history stays consistent.Reproduction: merge any release-labelled pull request in a module repository pinned to v6 whose settings leave
VersionPrefixat the defaultv, then compare the new tag to the previous one.Environment: Process-PSModule v6.0.0 through v6.1.15; any module repository using the default
VersionPrefix: 'v'.Regression: yes. v5 produced prefixed tags. Three repositories have already published on v6 and every one of them lost the prefix at the v6 boundary:
PSModule/Tomlv0.0.10.0.2PSModule/Domeneshopv0.0.21.0.0,1.0.1PSModule/PSSemVerv1.1.91.1.10This looks like a side effect of #326, which made publish read the version from the manifest read-only. The manifest is the right source for the module version, but it cannot carry the tag prefix.
Workaround: none that preserves history. Setting
VersionPrefix: ''makes the repository consistent going forward but abandons every existingv-prefixed tag.Acceptance criteria:
VersionPrefix: 'v', a stable release is taggedv<Major>.<Minor>.<Patch>and a prerelease is taggedv<Major>.<Minor>.<Patch>-<label>.VersionPrefix: '', tags stay unprefixed.AutoCleanupstill matches and removes the prerelease tags it created, in both prefixed and unprefixed repositories.Technical decisions
The root cause is bounded to the tag derivation in
.github/actions/Publish-PSModule/src/publish.ps1. The manifest check should stay — it is a valid guard that the artifact was stamped — but$releaseTagshould come from the Plan job'sFullVersionoutput (or fromVersionplus the settingsVersionPrefix), not from$moduleVersion. TheModuleVersionvalidation and the999.0.0placeholder check remain unchanged.Two decisions are needed:
PSSemVer 1.1.10,Toml 0.0.2, andDomeneshop 1.0.0/1.0.1would restore consistency, but the releases and their attached artifacts are already public, and1.1.10is the tag the PowerShell Gallery listing links to. Leaving them and fixing forward is the lower-risk option; either way the choice should be explicit.Resolve-PSModuleVersion'sGet-LatestGitHubVersionreadstagNameandGet-LatestPublishedVersionsorts a prefixed and an unprefixed[PSSemVer]together —CompareToignoresPrefix, so equal versions sort arbitrarily and the prefix can be lost from the resolved latest version. That is survivable because the prefix is reapplied from settings afterwards, but a repository with mixed tags is worth a warning.Blast radius grows with #438: 48 of 58 module repositories are still on v5 and will hit this the first time they publish after migrating.
Implementation plan
Add a regression test that publishes from a fixture repository configured with
VersionPrefix: 'v'and asserts the created tag, confirm it fails against currentmain, change$releaseTagto use the resolved full version, re-run the prefixed and unprefixed fixtures plus theAutoCleanuppath, then record the decision on the already-published tags.