Skip to content

Resolve-PSModuleVersion: Always emit a version regardless of publish decision #348

@MariusStorhaug

Description

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

Core changes (in Resolve-PSModuleVersion)

  • Refactor main.ps1 to always resolve the latest published version and compute a next version, regardless of ShouldPublish
  • When ShouldPublish is false, force prerelease-like behavior: apply patch bump and append the branch-based prerelease tag
  • Ensure Write-ActionOutput always receives a non-null $NewVersion

Tests

  • Add test case: ReleaseType = None → version is still emitted, CreateRelease = false
  • Add test case: ignore label present → version is still emitted, CreateRelease = false
  • Add test case: no version bump label and AutoPatching = false → version is still emitted, CreateRelease = false
  • Existing tests for ShouldPublish = true continue to pass unchanged

Validation

  • Run against Process-PSModule Workflow-Test and confirm the Plan job emits a version that Build-Module stamps into the manifest

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No fields configured for Task.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions