Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,77 @@ function Resolve-WorkflowEventRouting {
}
}

function Resolve-PSModulePublishSetting {
<#
.SYNOPSIS
Resolves module publication settings and their defaults.

.DESCRIPTION
Applies Process-PSModule defaults while preserving every consumer-provided
publication and release-label mapping. Rejects the removed AutoPatching
setting and invalid DefaultBump values with migration guidance.

.OUTPUTS
System.Management.Automation.PSCustomObject

.EXAMPLE
Resolve-PSModulePublishSetting -PublishModule $settings.Publish.Module
#>
[CmdletBinding()]
[OutputType([PSCustomObject])]
param(
[Parameter()]
[AllowNull()]
[object] $PublishModule
)

$propertyNames = if ($null -eq $PublishModule) {
@()
} elseif ($PublishModule -is [System.Collections.IDictionary]) {
@($PublishModule.Keys)
} else {
@($PublishModule.PSObject.Properties.Name)
}

if ($propertyNames -contains 'AutoPatching') {
throw (
'Publish.Module.AutoPatching was removed in Process-PSModule v9. ' +
'Replace it with Publish.Module.DefaultBump set to patch, minor, or major.'
)
}

$hasDefaultBump = $propertyNames -contains 'DefaultBump'
$defaultBump = if ($hasDefaultBump) {
[string]$PublishModule.DefaultBump
} else {
'patch'
}
$validDefaultBumps = @('patch', 'minor', 'major')
if ($validDefaultBumps -cnotcontains $defaultBump) {
throw (
"Invalid Publish.Module.DefaultBump: [$defaultBump]. " +
"Valid values are: $($validDefaultBumps -join ', ')."
)
}

[pscustomobject]@{
Skip = $PublishModule.Skip ?? $false
AutoCleanup = $PublishModule.AutoCleanup ?? $true
DefaultBump = $defaultBump
IncrementalPrerelease = $PublishModule.IncrementalPrerelease ?? $true
DatePrereleaseFormat = $PublishModule.DatePrereleaseFormat ?? ''
VersionPrefix = $PublishModule.VersionPrefix ?? 'v'
MajorLabels = $PublishModule.MajorLabels ?? 'release:major'
MinorLabels = $PublishModule.MinorLabels ?? 'release:minor'
PatchLabels = $PublishModule.PatchLabels ?? 'release:patch'
IgnoreLabels = $PublishModule.IgnoreLabels ?? 'release:skip'
PrereleaseLabels = $PublishModule.PrereleaseLabels ?? 'release:pre-release'
UsePRTitleAsReleaseName = $PublishModule.UsePRTitleAsReleaseName ?? $false
UsePRBodyAsReleaseNotes = $PublishModule.UsePRBodyAsReleaseNotes ?? $true
UsePRTitleAsNotesHeading = $PublishModule.UsePRTitleAsNotesHeading ?? $true
}
}

function Select-PullRequestForPush {
<#
.SYNOPSIS
Expand Down
27 changes: 19 additions & 8 deletions .github/actions/Get-PSModuleSettings/src/Settings.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,15 @@
"type": "boolean",
"description": "When enabled (default: true), automatically cleans up old prerelease tags when merging to main or when a PR is abandoned"
},
"AutoPatching": {
"type": "boolean",
"description": "Automatically apply patches"
"DefaultBump": {
"type": "string",
"enum": [
"patch",
"minor",
"major"
],
"description": "Version bump used when no configured bump label is present",
"default": "patch"
},
"IncrementalPrerelease": {
"type": "boolean",
Expand All @@ -156,23 +162,28 @@
},
"MajorLabels": {
"type": "string",
"description": "Comma-separated labels that trigger major version bump"
"description": "Comma-separated labels that trigger major version bump",
"default": "release:major"
},
"MinorLabels": {
"type": "string",
"description": "Comma-separated labels that trigger minor version bump"
"description": "Comma-separated labels that trigger minor version bump",
"default": "release:minor"
},
"PatchLabels": {
"type": "string",
"description": "Comma-separated labels that trigger patch version bump"
"description": "Comma-separated labels that trigger patch version bump",
"default": "release:patch"
},
"IgnoreLabels": {
"type": "string",
"description": "Comma-separated labels that prevent release"
"description": "Comma-separated labels that prevent release",
"default": "release:skip"
},
"PrereleaseLabels": {
"type": "string",
"description": "Comma-separated labels that trigger a prerelease"
"description": "Comma-separated labels that trigger a prerelease",
"default": "release:pre-release"
},
"UsePRTitleAsReleaseName": {
"type": "boolean",
Expand Down
21 changes: 5 additions & 16 deletions .github/actions/Get-PSModuleSettings/src/main.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ if (![string]::IsNullOrEmpty($settingsPath) -and (Test-Path -Path $settingsPath)
}

LogGroup 'Validate settings against schema' {
# Validate release settings first so removed or invalid values get a
# migration-focused error instead of only a generic schema failure.
$null = Resolve-PSModulePublishSetting -PublishModule $settings.Publish.Module

$schemaPath = Join-Path $PSScriptRoot 'Settings.schema.json'
if (Test-Path -Path $schemaPath) {
Write-Host 'Validating settings against schema...'
Expand Down Expand Up @@ -187,22 +191,7 @@ $settings = [pscustomobject]@{
}
}
Publish = [pscustomobject]@{
Module = [pscustomobject]@{
Skip = $settings.Publish.Module.Skip ?? $false
AutoCleanup = $settings.Publish.Module.AutoCleanup ?? $true
AutoPatching = $settings.Publish.Module.AutoPatching ?? $true
IncrementalPrerelease = $settings.Publish.Module.IncrementalPrerelease ?? $true
DatePrereleaseFormat = $settings.Publish.Module.DatePrereleaseFormat ?? ''
VersionPrefix = $settings.Publish.Module.VersionPrefix ?? 'v'
MajorLabels = $settings.Publish.Module.MajorLabels ?? 'major, breaking'
MinorLabels = $settings.Publish.Module.MinorLabels ?? 'minor, feature'
PatchLabels = $settings.Publish.Module.PatchLabels ?? 'patch, fix'
IgnoreLabels = $settings.Publish.Module.IgnoreLabels ?? 'NoRelease'
PrereleaseLabels = $settings.Publish.Module.PrereleaseLabels ?? 'prerelease'
UsePRTitleAsReleaseName = $settings.Publish.Module.UsePRTitleAsReleaseName ?? $false
UsePRBodyAsReleaseNotes = $settings.Publish.Module.UsePRBodyAsReleaseNotes ?? $true
UsePRTitleAsNotesHeading = $settings.Publish.Module.UsePRTitleAsNotesHeading ?? $true
}
Module = Resolve-PSModulePublishSetting -PublishModule $settings.Publish.Module
Site = [pscustomobject]@{
Skip = $settings.Publish.Site.Skip ?? $false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,73 @@ Describe 'Resolve-WorkflowEventRouting' {
}
}

Describe 'Resolve-PSModulePublishSetting' {
It 'uses the canonical release-label defaults' {
$result = Resolve-PSModulePublishSetting -PublishModule $null

$result.DefaultBump | Should -BeExactly 'patch'
$result.MajorLabels | Should -BeExactly 'release:major'
$result.MinorLabels | Should -BeExactly 'release:minor'
$result.PatchLabels | Should -BeExactly 'release:patch'
$result.PrereleaseLabels | Should -BeExactly 'release:pre-release'
$result.IgnoreLabels | Should -BeExactly 'release:skip'
}

It 'preserves consumer-controlled release settings' {
$publishModule = [pscustomobject]@{
DefaultBump = 'minor'
MajorLabels = 'custom:major'
MinorLabels = 'custom:minor'
PatchLabels = 'custom:patch'
PrereleaseLabels = 'custom:pre-release'
IgnoreLabels = 'custom:skip'
}

$result = Resolve-PSModulePublishSetting -PublishModule $publishModule

$result.DefaultBump | Should -BeExactly 'minor'
$result.MajorLabels | Should -BeExactly 'custom:major'
$result.MinorLabels | Should -BeExactly 'custom:minor'
$result.PatchLabels | Should -BeExactly 'custom:patch'
$result.PrereleaseLabels | Should -BeExactly 'custom:pre-release'
$result.IgnoreLabels | Should -BeExactly 'custom:skip'
}

It 'declares the same canonical defaults in the settings schema' {
$schemaPath = Join-Path -Path $PSScriptRoot -ChildPath '../src/Settings.schema.json'
$schema = Get-Content -Path $schemaPath -Raw | ConvertFrom-Json
$moduleProperties = $schema.properties.Publish.properties.Module.properties

$moduleProperties.DefaultBump.default | Should -BeExactly 'patch'
$moduleProperties.DefaultBump.enum | Should -Be @('patch', 'minor', 'major')
$moduleProperties.PSObject.Properties.Name | Should -Not -Contain 'AutoPatching'
$moduleProperties.MajorLabels.default | Should -BeExactly 'release:major'
$moduleProperties.MinorLabels.default | Should -BeExactly 'release:minor'
$moduleProperties.PatchLabels.default | Should -BeExactly 'release:patch'
$moduleProperties.PrereleaseLabels.default | Should -BeExactly 'release:pre-release'
$moduleProperties.IgnoreLabels.default | Should -BeExactly 'release:skip'
}

It 'rejects the invalid DefaultBump value <DefaultBump>' -ForEach @(
@{ DefaultBump = $null }
@{ DefaultBump = '' }
@{ DefaultBump = 'Patch' }
@{ DefaultBump = 'none' }
) {
$publishModule = [pscustomobject]@{ DefaultBump = $DefaultBump }

{ Resolve-PSModulePublishSetting -PublishModule $publishModule } |
Should -Throw '*Valid values are: patch, minor, major*'
}

It 'rejects AutoPatching with migration guidance' {
$publishModule = [pscustomobject]@{ AutoPatching = $true }

{ Resolve-PSModulePublishSetting -PublishModule $publishModule } |
Should -Throw '*AutoPatching was removed*Replace it with Publish.Module.DefaultBump*'
}
}

Describe 'Select-PullRequestForPush' {
It 'selects the merged PR whose merge commit matches the pushed commit' {
$pullRequests = @(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,37 @@
($Value -split ',') | ForEach-Object { $_.Trim() } | Where-Object { $_ }
}

function Resolve-DefaultBump {
<#
.SYNOPSIS
Validates and returns the configured default version bump.

.OUTPUTS
System.String

.EXAMPLE
Resolve-DefaultBump -DefaultBump 'patch'
#>
[CmdletBinding()]
[OutputType([string])]
param(
# The default bump name.
[Parameter(Mandatory)]
[AllowEmptyString()]
[string] $DefaultBump
)

$validDefaultBumps = @('patch', 'minor', 'major')
if ($validDefaultBumps -cnotcontains $DefaultBump) {
throw (
"Invalid Publish.Module.DefaultBump: [$DefaultBump]. " +
"Valid values are: $($validDefaultBumps -join ', ')."
)
}

$DefaultBump
}

function Read-ActionInput {
<#
.SYNOPSIS
Expand Down Expand Up @@ -66,7 +97,7 @@ function Get-PublishConfiguration {
Parses the settings JSON into a publish configuration object.

.DESCRIPTION
Extracts publish module settings including auto-patching flags, version prefix,
Extracts publish module settings including the default bump, version prefix,
release type, and label classification arrays.

.OUTPUTS
Expand All @@ -89,9 +120,10 @@ function Get-PublishConfiguration {
LogGroup 'Resolve configuration' {
$settings = $SettingsJson | ConvertFrom-Json
$publishModule = $settings.Publish.Module
$defaultBump = Resolve-DefaultBump -DefaultBump ([string]$publishModule.DefaultBump)

$config = [PSCustomObject]@{
AutoPatching = [bool]$publishModule.AutoPatching
DefaultBump = $defaultBump
IncrementalPrerelease = [bool]$publishModule.IncrementalPrerelease
DatePrereleaseFormat = [string]$publishModule.DatePrereleaseFormat
VersionPrefix = [string]$publishModule.VersionPrefix
Expand All @@ -104,7 +136,7 @@ function Get-PublishConfiguration {

Write-Host '-------------------------------------------------'
Write-Host ([PSCustomObject]@{
AutoPatching = $config.AutoPatching
DefaultBump = $config.DefaultBump
IncrementalPrerelease = $config.IncrementalPrerelease
DatePrereleaseFormat = $config.DatePrereleaseFormat
VersionPrefix = $config.VersionPrefix
Expand All @@ -129,7 +161,7 @@ function Get-GitHubPullRequest {
The settings action resolves the pull request associated with a default-branch push
before this action runs. When no pull request exists, a direct push or manual
dispatch on the default branch still receives release context so it resolves the
default patch bump.
configured default bump.

.OUTPUTS
PSCustomObject with pull-request metadata, or a default-branch direct-release
Expand Down Expand Up @@ -164,7 +196,7 @@ function Get-GitHubPullRequest {
}

if ($context.IsPushToDefaultBranch -or $context.IsManualDispatchToDefaultBranch) {
Write-Host 'Using direct default-branch release context with the default patch bump.'
Write-Host 'Using direct default-branch release context with the configured default bump.'
return [PSCustomObject]@{
Number = $null
HeadRef = $context.DefaultBranch
Expand Down Expand Up @@ -238,6 +270,7 @@ function Resolve-ReleaseDecision {
$prereleaseName = $PullRequest.HeadRef -replace '[^a-zA-Z0-9]'
$labels = $PullRequest.Labels
$releaseType = $Configuration.ReleaseType
$defaultBump = Resolve-DefaultBump -DefaultBump ([string]$Configuration.DefaultBump)

$validReleaseTypes = @('Release', 'Prerelease', 'None')
if ([string]::IsNullOrWhiteSpace($releaseType)) {
Expand Down Expand Up @@ -285,20 +318,16 @@ function Resolve-ReleaseDecision {

$majorRelease = $majorLabels.Count -eq 1
$minorRelease = $minorLabels.Count -eq 1
$isDirectStableRelease = $createRelease -and $PullRequest.IsDirectRelease
$patchRelease = $patchLabels.Count -eq 1 -or (
-not $majorRelease -and
-not $minorRelease -and
($Configuration.AutoPatching -or $isDirectStableRelease)
)
$hasVersionBump = $majorRelease -or $minorRelease -or $patchRelease
$patchRelease = $patchLabels.Count -eq 1

if (-not $hasVersionBump) {
Write-Host 'No version bump label and AutoPatching disabled; previewing a patch version without publishing.'
$patchRelease = $true
$hasVersionBump = $true
$shouldPublish = $false
if (-not $majorRelease -and -not $minorRelease -and -not $patchRelease) {
switch -CaseSensitive ($defaultBump) {
'major' { $majorRelease = $true }
'minor' { $minorRelease = $true }
'patch' { $patchRelease = $true }
}
}
$hasVersionBump = $majorRelease -or $minorRelease -or $patchRelease

if ($ignoreRelease) {
$createRelease = $false
Expand All @@ -316,6 +345,7 @@ function Resolve-ReleaseDecision {
ShouldPublish = $shouldPublish
CreateRelease = $createRelease
CreatePrerelease = $createPrerelease
DefaultBump = $defaultBump
Major = $majorRelease
Minor = $minorRelease
Patch = $patchRelease
Expand Down
Loading
Loading