Skip to content

Commit 095bde1

Browse files
Merge branch 'main' into coverage-missed-paths-upstream
2 parents 00cd9d1 + 169c576 commit 095bde1

13 files changed

Lines changed: 930 additions & 40 deletions

File tree

.github/actions/Build-PSModule/src/helpers/Build/Build-PSModuleManifest.ps1

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,8 @@
260260
Write-Host "Processing required module [$requiredModuleName]"
261261
$requiredVersion = $group.Group.RequiredVersion | ForEach-Object { [Version]$_ } | Sort-Object -Unique
262262
$minimumVersion = $group.Group.Version | ForEach-Object { [Version]$_ } | Sort-Object -Unique | Select-Object -Last 1
263-
$maximumVersion = $group.Group.MaximumVersion | ForEach-Object { [Version]$_ } | Sort-Object -Unique | Select-Object -First 1
263+
$maximumVersion = $group.Group.MaximumVersion | Sort-Object -Unique | Select-Object -First 1
264+
$maximumVersionBound = if ($maximumVersion -and ($maximumVersion -notmatch '[*]')) { [Version]$maximumVersion } else { $null }
264265
Write-Host "RequiredVersion: [$($requiredVersion -join ', ')]"
265266
Write-Host "ModuleVersion: [$minimumVersion]"
266267
Write-Host "MaximumVersion: [$maximumVersion]"
@@ -274,17 +275,17 @@
274275
}
275276

276277
if (-not $maximumVersion) {
277-
$maximumVersion = [Version]'9999.9999.9999'
278+
$maximumVersionBound = [Version]'9999.9999.9999'
278279
}
279280

280281
if ($requiredVersion -and ($minimumVersion -gt $requiredVersion)) {
281282
throw 'ModuleVersion is higher than RequiredVersion.'
282283
}
283284

284-
if ($minimumVersion -gt $maximumVersion) {
285+
if ($maximumVersionBound -and ($minimumVersion -gt $maximumVersionBound)) {
285286
throw 'ModuleVersion is higher than MaximumVersion.'
286287
}
287-
if ($requiredVersion -and ($requiredVersion -gt $maximumVersion)) {
288+
if ($requiredVersion -and $maximumVersionBound -and ($requiredVersion -gt $maximumVersionBound)) {
288289
throw 'RequiredVersion is higher than MaximumVersion.'
289290
}
290291

@@ -294,15 +295,15 @@
294295
ModuleName = $requiredModuleName
295296
RequiredVersion = $requiredVersion
296297
}
297-
} elseif (($minimumVersion -ne [Version]'0.0.0') -or ($maximumVersion -ne [Version]'9999.9999.9999')) {
298+
} elseif (($minimumVersion -ne [Version]'0.0.0') -or ($maximumVersionBound -ne [Version]'9999.9999.9999')) {
298299
Write-Host '[RequiredModules] - ModuleVersion/MaximumVersion'
299300
$uniqueModule = @{
300301
ModuleName = $requiredModuleName
301302
}
302303
if ($minimumVersion -ne [Version]'0.0.0') {
303304
$uniqueModule['ModuleVersion'] = $minimumVersion
304305
}
305-
if ($maximumVersion -ne [Version]'9999.9999.9999') {
306+
if ($maximumVersionBound -ne [Version]'9999.9999.9999') {
306307
$uniqueModule['MaximumVersion'] = $maximumVersion
307308
}
308309
} else {

.github/actions/Install-PSModule/src/PSModule/PSModule.psm1

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,18 +87,40 @@ function Convert-VersionSpec {
8787
[string] $RequiredVersion
8888
)
8989

90+
$maximumVersionIsWildcard = $MaximumVersion -and ($MaximumVersion -match '[*]')
91+
if ($maximumVersionIsWildcard) {
92+
$versionParts = @($MaximumVersion -split '\.')
93+
$wildcardIndex = [Array]::IndexOf($versionParts, '*')
94+
if ($wildcardIndex -lt 0) {
95+
throw "MaximumVersion '$MaximumVersion' contains an unsupported wildcard pattern."
96+
}
97+
98+
if ($wildcardIndex -eq 0) {
99+
throw "MaximumVersion '$MaximumVersion' contains an unsupported wildcard pattern."
100+
}
101+
102+
$upperBoundParts = @(0, 0, 0)
103+
for ($i = 0; $i -lt $wildcardIndex; $i++) {
104+
$upperBoundParts[$i] = [int]$versionParts[$i]
105+
}
106+
$upperBoundParts[$wildcardIndex - 1]++
107+
$MaximumVersion = $upperBoundParts -join '.'
108+
}
109+
90110
if ($RequiredVersion) {
91111
# Use exact match in bracket notation.
92112
return "[$RequiredVersion]"
93113
} elseif ($MinimumVersion -and $MaximumVersion) {
94-
# Both bounds provided; both are inclusive.
95-
return "[$MinimumVersion,$MaximumVersion]"
114+
# Wildcard maximum versions are translated to an exclusive upper bound.
115+
$upperBound = $maximumVersionIsWildcard ? ')' : ']'
116+
return "[$MinimumVersion,$MaximumVersion$upperBound"
96117
} elseif ($MinimumVersion) {
97118
# Only a minimum is provided. Use a minimum-inclusive range.
98119
return "[$MinimumVersion, ]"
99120
} elseif ($MaximumVersion) {
100-
# Only a maximum is provided; lower bound open.
101-
return "(, $MaximumVersion]"
121+
# Only a maximum is provided; lower bound open. Wildcards are exclusive upper bounds.
122+
$upperBound = $maximumVersionIsWildcard ? ')' : ']'
123+
return "(, $MaximumVersion$upperBound"
102124
} else {
103125
return $null
104126
}

.github/actions/Publish-PSModule/action.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ inputs:
3737
description: Name of the uploaded artifact to download. Must match the name used in the upstream upload-artifact step.
3838
required: false
3939
default: module
40+
VersionPrefix:
41+
description: |
42+
Prefix put in front of the version in the git tag of the GitHub release, for example 'v'.
43+
Comes from Settings.Publish.Module.VersionPrefix, which the Plan job resolves. The compiled manifest carries the module version as
44+
Major.Minor.Patch and cannot carry the prefix, so it is supplied here. An empty value tags the release without a prefix.
45+
required: false
46+
default: ''
4047

4148
runs:
4249
using: composite
@@ -65,4 +72,5 @@ runs:
6572
PSMODULE_PUBLISH_PSMODULE_INPUT_UsePRBodyAsReleaseNotes: ${{ inputs.UsePRBodyAsReleaseNotes }}
6673
PSMODULE_PUBLISH_PSMODULE_INPUT_UsePRTitleAsReleaseName: ${{ inputs.UsePRTitleAsReleaseName }}
6774
PSMODULE_PUBLISH_PSMODULE_INPUT_UsePRTitleAsNotesHeading: ${{ inputs.UsePRTitleAsNotesHeading }}
75+
PSMODULE_PUBLISH_PSMODULE_INPUT_VersionPrefix: ${{ inputs.VersionPrefix }}
6876
run: ${{ github.action_path }}/src/publish.ps1
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
function Get-ModuleVersionString {
2+
<#
3+
.SYNOPSIS
4+
Builds the SemVer version string that identifies the module itself.
5+
6+
.DESCRIPTION
7+
Composes the module version and, when there is one, the prerelease label. This is the string the
8+
PowerShell Gallery and the module manifest understand: `Major.Minor.Patch` optionally followed by
9+
`-<prerelease>`. It never carries the repository's version prefix, because neither the manifest's
10+
`ModuleVersion` nor a Gallery package version accepts one.
11+
12+
.OUTPUTS
13+
String with the module version.
14+
15+
.EXAMPLE
16+
Get-ModuleVersionString -ModuleVersion '1.1.10'
17+
18+
Returns '1.1.10'.
19+
20+
.EXAMPLE
21+
Get-ModuleVersionString -ModuleVersion '1.1.10' -Prerelease 'mybranch001'
22+
23+
Returns '1.1.10-mybranch001'.
24+
#>
25+
[CmdletBinding()]
26+
[OutputType([string])]
27+
param(
28+
# The module version from the compiled manifest, in Major.Minor.Patch format.
29+
[Parameter(Mandatory)]
30+
[ValidateNotNullOrEmpty()]
31+
[string] $ModuleVersion,
32+
33+
# The prerelease label from the compiled manifest. Empty for a stable release.
34+
[Parameter()]
35+
[AllowEmptyString()]
36+
[AllowNull()]
37+
[string] $Prerelease
38+
)
39+
40+
if ([string]::IsNullOrWhiteSpace($Prerelease)) {
41+
return $ModuleVersion
42+
}
43+
44+
"$ModuleVersion-$($Prerelease.Trim())"
45+
}
46+
47+
function Get-ReleaseTag {
48+
<#
49+
.SYNOPSIS
50+
Builds the git tag used for the GitHub release.
51+
52+
.DESCRIPTION
53+
Prefixes the module's SemVer version string with the configured version prefix. The version comes
54+
from the compiled manifest, which is the artifact that is published, so the tag always names the
55+
exact bytes that were tested and pushed to the PowerShell Gallery. The manifest's ModuleVersion is
56+
Major.Minor.Patch by definition and cannot carry the prefix, so the prefix is supplied from the
57+
resolved settings (Publish.Module.VersionPrefix) instead.
58+
59+
The prefix belongs to the GitHub release tag and to nothing else. PowerShell manifests and Gallery
60+
package versions only accept plain SemVer, so callers that need the module's own version use
61+
Get-ModuleVersionString. Deriving both from the same composition keeps the prefix as the only
62+
difference between them.
63+
64+
.OUTPUTS
65+
String with the release tag.
66+
67+
.EXAMPLE
68+
Get-ReleaseTag -VersionPrefix 'v' -ModuleVersion '1.1.10'
69+
70+
Returns 'v1.1.10'.
71+
72+
.EXAMPLE
73+
Get-ReleaseTag -VersionPrefix 'v' -ModuleVersion '1.1.10' -Prerelease 'mybranch001'
74+
75+
Returns 'v1.1.10-mybranch001'.
76+
77+
.EXAMPLE
78+
Get-ReleaseTag -VersionPrefix '' -ModuleVersion '1.1.10'
79+
80+
Returns '1.1.10'.
81+
#>
82+
[CmdletBinding()]
83+
[OutputType([string])]
84+
param(
85+
# The module version from the compiled manifest, in Major.Minor.Patch format.
86+
[Parameter(Mandatory)]
87+
[ValidateNotNullOrEmpty()]
88+
[string] $ModuleVersion,
89+
90+
# The prefix put in front of the version, for example 'v'. Empty for an unprefixed repository.
91+
[Parameter()]
92+
[AllowEmptyString()]
93+
[AllowNull()]
94+
[string] $VersionPrefix,
95+
96+
# The prerelease label from the compiled manifest. Empty for a stable release.
97+
[Parameter()]
98+
[AllowEmptyString()]
99+
[AllowNull()]
100+
[string] $Prerelease
101+
)
102+
103+
"$($VersionPrefix.Trim())$(Get-ModuleVersionString -ModuleVersion $ModuleVersion -Prerelease $Prerelease)"
104+
}

.github/actions/Publish-PSModule/src/publish.ps1

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ param()
2828
$PSStyle.OutputRendering = 'Ansi'
2929

3030
Import-Module -Name 'PSModule' -Force
31+
Import-Module -Name "$PSScriptRoot/Publish-PSModule.Helpers.psm1" -Force
3132

3233
#region Load inputs
3334
LogGroup 'Load inputs' {
@@ -58,10 +59,14 @@ LogGroup 'Load inputs' {
5859
$usePRBodyAsReleaseNotes = $env:PSMODULE_PUBLISH_PSMODULE_INPUT_UsePRBodyAsReleaseNotes -eq 'true'
5960
$usePRTitleAsReleaseName = $env:PSMODULE_PUBLISH_PSMODULE_INPUT_UsePRTitleAsReleaseName -eq 'true'
6061
$usePRTitleAsNotesHeading = $env:PSMODULE_PUBLISH_PSMODULE_INPUT_UsePRTitleAsNotesHeading -eq 'true'
62+
# The prefix the repository tags releases with, resolved by the Plan job from
63+
# Settings.Publish.Module.VersionPrefix. Empty means the repository tags without a prefix.
64+
$versionPrefix = $env:PSMODULE_PUBLISH_PSMODULE_INPUT_VersionPrefix
6165

62-
Write-Host "Module name: [$name]"
63-
Write-Host "Module path: [$modulePath]"
64-
Write-Host "WhatIf: [$whatIf]"
66+
Write-Host "Module name: [$name]"
67+
Write-Host "Module path: [$modulePath]"
68+
Write-Host "Version prefix: [$versionPrefix]"
69+
Write-Host "WhatIf: [$whatIf]"
6570
}
6671
#endregion Load inputs
6772

@@ -129,12 +134,18 @@ LogGroup 'Resolve version from manifest' {
129134
$createPrerelease = $true
130135
}
131136

132-
$releaseTag = if ($createPrerelease) { "$moduleVersion-$prerelease" } else { $moduleVersion }
137+
# The PowerShell Gallery and the module manifest only accept plain SemVer, so the configured
138+
# VersionPrefix is applied to the GitHub release tag and to nothing else. Both strings are derived
139+
# from the same composition here, so the prefix is the only difference between them.
140+
$publishPSVersion = Get-ModuleVersionString -ModuleVersion $moduleVersion -Prerelease $prerelease
141+
$releaseTag = Get-ReleaseTag -VersionPrefix $versionPrefix -ModuleVersion $moduleVersion -Prerelease $prerelease
133142

134143
[PSCustomObject]@{
135144
ModuleVersion = $moduleVersion
145+
VersionPrefix = $versionPrefix
136146
Prerelease = $prerelease
137147
CreatePrerelease = $createPrerelease
148+
GalleryVersion = $publishPSVersion
138149
ReleaseTag = $releaseTag
139150
PRNumber = $prNumber
140151
PRHeadRef = $prHeadRef
@@ -154,7 +165,6 @@ LogGroup 'Install module dependencies' {
154165
#region Publish to PSGallery
155166
LogGroup 'Publish to PSGallery' {
156167
$releaseType = if ($createPrerelease) { 'New prerelease' } else { 'New release' }
157-
$publishPSVersion = if ($createPrerelease) { "$moduleVersion-$prerelease" } else { $moduleVersion }
158168
$psGalleryReleaseLink = "https://www.powershellgallery.com/packages/$name/$publishPSVersion"
159169

160170
Write-Host 'Publish module to PowerShell Gallery using API key from environment.'
@@ -280,4 +290,4 @@ LogGroup 'Create GitHub release' {
280290
}
281291
#endregion Create GitHub release
282292

283-
Write-Host "Publishing complete. Version: [$releaseTag]"
293+
Write-Host "Publishing complete. PowerShell Gallery version: [$publishPSVersion]. GitHub release tag: [$releaseTag]."

0 commit comments

Comments
 (0)