ModuleForge

My interpretation of how to use SemVer with PowerShell modules

Definitions

Major

A change to a function that is likely to break backwards compatibility and existing scripts

Major Change Examples

Minor

Introduction of a new function that does not significantly alter the result output object or parameters of an existing function

Examples

Patch

No change to parameters or outputs, only code fixes and optimizations.

Patch Examples

prerelease

Test version of any of the above.

Since PSGallery only supports SemVer V1, considerations must be made in how we version our preReleases. Since we cannot use the SemVer V2 Build version with our preRelease Tag As per the Documentation here.

Specifically these points:

As such, care must be taken to ensure that newer preRelease versions are not incorrectly ordered, and that we are adhering to something that is compatible. For example:

1.0.0-prev2 will order more recently than than 1.0.0-prev10, even though from a readability stand-point v2 is much lower than v10.


$versionStrings = @(
    '1.0.0-prev1'
    '1.0.0-prev2'
    '1.0.0-prev3'
    '1.0.0-prev4'
    '1.0.0-prev5'
    '1.0.0-prev6'
    '1.0.0-prev7'
    '1.0.0-prev8'
    '1.0.0-prev9'
    '1.0.0-prev10'
    '1.0.0-prev11'
    '1.0.0-prev12'
)

$versions = $versionStrings.foreach{[semver]::New($_)}
$versions|sort-object

Here is a table that helps demonstrate the results of the above:

version Order Should be
1.0.0-prev1 ✅ 1st 1st
1.0.0-prev10 ❌ 2nd 10th
1.0.0-prev11 ❌ 3rd 11th
1.0.0-prev2 ❌ 4th 2nd
1.0.0-prev3 ❌ 4th 3rd

Special Note on prerelease label casing: There is a small, obscure bug in PSResourceGet (Issue:Status: #1787) that occurs if uppercase is used in prerelease tags. I would prefer to use upper-case pre as I think it looks a little better, but to avoid this bug, I will stick to lower-case labels, and recommend for custom labels that others do the same.

As such, in order to clearly identify correct versions whilst maintaining simplicity and compatibility with SEMVER v1 will be to use the following formatting:

{MAJOR}.{MINOR}.{PATCH}-{preReleaseTag}v{XXX}

Example Version List

Here’s a quick PowerShell snippet to show how this may work in practice

$versionStrings = @(
    '1.0.0-prev001' #The first build
    '1.0.0-prev002' #Tested and fixed some bugs
    '1.0.1' #First actual release after testing
    '1.0.2-prev001' #Optimisation Rework
    '1.0.2' #Second Release
    '1.1.0-prev001' #New function added
    '1.1.0-prev002' #New function bugfixed
    '1.1.0' #Third Release
    '1.1.1-prev001' #Bugfix Pass
    '1.1.1-prev002' #Bugfix Pass 2
    '1.1.1' #Fourth Release
    '1.1.2-prev001' #Optimisation Pass
    '1.1.2' #Fifth Release
    '1.2.0-prev001' #Change to Validators in a function
    '1.2.0' #Sixth Release
    '2.0.0-prev001' #Changes to Return for existing Functions
    '2.0.0-prev002' #Bugfix for previous
    '2.0.0-prev003' #Bugfix for previous
    '2.0.0-prev004' #Optimisation
    '2.0.0-prev005' #More Optimisation
    '2.0.0' #Seventh Release
)
$versions = $versionStrings.foreach{[semver]::New($_)}

#All Versions sorted 
$versions|sort-object

#Current Latest
($versions|sort-object -descending|select -first 1)