The Process-PSModule workflow is moving to a Plan → Build → Test → Publish pipeline where version calculation happens before build (see #326). The resolved version is stamped into the module manifest at build time so the tested artifact is identical to the published artifact ("test what you ship").
Request
What happens
When Resolve-PSModuleVersion runs and ShouldPublish resolves to false — because ReleaseType is None, ignore labels match, or no version bump label is present — main.ps1 skips version calculation entirely and emits empty strings for Version, Prerelease, and FullVersion.
This is visible in Workflow-Test runs where the Plan job completes with no version, and downstream Build-Module has nothing to stamp on the manifest.
# main.ps1 — version is only calculated when ShouldPublish is true
$newVersion = $null
if ($decision.ShouldPublish) {
# ... resolve version ...
$newVersion = Get-NextModuleVersion @params
}
Write-ActionOutput -Decision $decision -NewVersion $newVersion
# ↑ emits empty strings when $newVersion is $null
What is expected
The action should always emit a usable version — even when no release will be created. A development prerelease version (for example 0.0.1-mybranch001) is acceptable for non-publishable runs. The publish decision (CreateRelease output) remains the authoritative signal for whether downstream jobs should publish.
This aligns with the CI/CD principle that every build produces a versioned, immutable artifact. Tools like GitVersion, Semantic Release, and setuptools-scm all follow this pattern — every build gets a version; the publish gate is separate.
Acceptance criteria
- The
Version and FullVersion outputs are never empty when the action completes successfully
- When
ShouldPublish is true: behavior is unchanged (proper next version based on labels and latest published version)
- When
ShouldPublish is false: a development prerelease version is emitted using the latest published version as base and the branch name as prerelease identifier
- The
CreateRelease output remains false when no publish should occur — downstream consumers use this to skip publishing
- Workflow-Test runs in Process-PSModule receive a version and build a properly stamped artifact
Technical decisions
Always-version strategy: When ShouldPublish is false, still query the latest published version and produce a prerelease version from it. The prerelease tag uses the sanitized branch name (existing PrereleaseName logic in Helpers.psm1) so development builds are identifiable. This reuses the existing infrastructure in Get-GitHubRelease, Get-LatestPSGalleryVersion, and Get-LatestPublishedVersion — no new external queries needed.
Bump type for non-publishable builds: Use patch bump. A non-publishable build is transient and will never land in a registry, so the exact bump type is irrelevant — what matters is that the version is valid and unique. Patch is the smallest, safest increment.
Incremental prerelease for non-publishable: Apply the same IncrementalPrerelease / DatePrereleaseFormat logic that already exists for prerelease builds. This ensures uniqueness across repeated runs on the same branch.
No new outputs: The existing output schema (Version, Prerelease, FullVersion, ReleaseType, CreateRelease) is sufficient. ReleaseType remains None and CreateRelease remains false — callers already gate on these values.
Backward compatibility: Callers that only act when CreateRelease is true are unaffected. Callers that consume Version unconditionally (like the Plan job in Process-PSModule) now get a valid value in all scenarios.
Best practice alignment: The "Plan early, build once, test the real thing" pattern is standard across modern CI/CD:
- GitVersion always produces a version from git topology — every branch, every commit.
- Semantic Release calculates version before build and feeds it into the build toolchain.
- setuptools-scm derives a version from the latest tag + commit distance — dev builds get versions like
1.2.3.dev4.
- The general principle: version calculation and publish decision are orthogonal concerns. The former always happens; the latter is gated on policy.
Implementation plan
Tests
Validation
The Process-PSModule workflow is moving to a Plan → Build → Test → Publish pipeline where version calculation happens before build (see #326). The resolved version is stamped into the module manifest at build time so the tested artifact is identical to the published artifact ("test what you ship").
Request
What happens
When
Resolve-PSModuleVersionruns andShouldPublishresolves tofalse— becauseReleaseTypeisNone, ignore labels match, or no version bump label is present —main.ps1skips version calculation entirely and emits empty strings forVersion,Prerelease, andFullVersion.This is visible in Workflow-Test runs where the Plan job completes with no version, and downstream
Build-Modulehas nothing to stamp on the manifest.What is expected
The action should always emit a usable version — even when no release will be created. A development prerelease version (for example
0.0.1-mybranch001) is acceptable for non-publishable runs. The publish decision (CreateReleaseoutput) remains the authoritative signal for whether downstream jobs should publish.This aligns with the CI/CD principle that every build produces a versioned, immutable artifact. Tools like GitVersion, Semantic Release, and setuptools-scm all follow this pattern — every build gets a version; the publish gate is separate.
Acceptance criteria
VersionandFullVersionoutputs are never empty when the action completes successfullyShouldPublishistrue: behavior is unchanged (proper next version based on labels and latest published version)ShouldPublishisfalse: a development prerelease version is emitted using the latest published version as base and the branch name as prerelease identifierCreateReleaseoutput remainsfalsewhen no publish should occur — downstream consumers use this to skip publishingTechnical decisions
Always-version strategy: When
ShouldPublishisfalse, still query the latest published version and produce a prerelease version from it. The prerelease tag uses the sanitized branch name (existingPrereleaseNamelogic inHelpers.psm1) so development builds are identifiable. This reuses the existing infrastructure inGet-GitHubRelease,Get-LatestPSGalleryVersion, andGet-LatestPublishedVersion— no new external queries needed.Bump type for non-publishable builds: Use patch bump. A non-publishable build is transient and will never land in a registry, so the exact bump type is irrelevant — what matters is that the version is valid and unique. Patch is the smallest, safest increment.
Incremental prerelease for non-publishable: Apply the same
IncrementalPrerelease/DatePrereleaseFormatlogic that already exists for prerelease builds. This ensures uniqueness across repeated runs on the same branch.No new outputs: The existing output schema (
Version,Prerelease,FullVersion,ReleaseType,CreateRelease) is sufficient.ReleaseTyperemainsNoneandCreateReleaseremainsfalse— callers already gate on these values.Backward compatibility: Callers that only act when
CreateReleaseistrueare unaffected. Callers that consumeVersionunconditionally (like the Plan job in Process-PSModule) now get a valid value in all scenarios.Best practice alignment: The "Plan early, build once, test the real thing" pattern is standard across modern CI/CD:
1.2.3.dev4.Implementation plan
Core changes (in
Resolve-PSModuleVersion)main.ps1to always resolve the latest published version and compute a next version, regardless ofShouldPublishShouldPublishisfalse, force prerelease-like behavior: apply patch bump and append the branch-based prerelease tagWrite-ActionOutputalways receives a non-null$NewVersionTests
ReleaseType = None→ version is still emitted,CreateRelease = falseCreateRelease = falseAutoPatching = false→ version is still emitted,CreateRelease = falseShouldPublish = truecontinue to pass unchangedValidation