diff --git a/.github/actions/Resolve-PSModuleVersion/src/Resolve-PSModuleVersion.Helpers.psm1 b/.github/actions/Resolve-PSModuleVersion/src/Resolve-PSModuleVersion.Helpers.psm1 index d4f2f450..cd48d4dc 100644 --- a/.github/actions/Resolve-PSModuleVersion/src/Resolve-PSModuleVersion.Helpers.psm1 +++ b/.github/actions/Resolve-PSModuleVersion/src/Resolve-PSModuleVersion.Helpers.psm1 @@ -277,16 +277,52 @@ function Resolve-ReleaseDecision { } } +function ConvertFrom-GitHubReleaseJson { + <# + .SYNOPSIS + Converts the JSON output of 'gh release list' into a flat array of release objects. + + .DESCRIPTION + Normalizes the release listing so a repository with no releases, or a command that + produced no output at all, yields an empty array instead of $null. + + .OUTPUTS + Array of release objects. Empty when there are no releases. + + .EXAMPLE + $releases = ConvertFrom-GitHubReleaseJson -Json '[{"tagName":"v1.0.0"}]' + #> + [CmdletBinding()] + [OutputType([object[]], [array])] + param( + # The raw JSON returned by 'gh release list'. Empty or null when the command produced no output. + [Parameter()] + [AllowNull()] + [AllowEmptyString()] + [string] $Json + ) + + if ([string]::IsNullOrWhiteSpace($Json)) { + return @() + } + + @($Json | ConvertFrom-Json) +} + function Get-GitHubRelease { <# .SYNOPSIS Retrieves all releases from the current GitHub repository. + .DESCRIPTION + Lists the releases of the current repository. A repository that has no releases yet + produces no output, so callers normalize the result with @() before using it. + .OUTPUTS - Array of release objects. + Array of release objects. Nothing when the repository has no releases. .EXAMPLE - $releases = Get-GitHubRelease + $releases = @(Get-GitHubRelease) #> [CmdletBinding()] [OutputType([array])] @@ -298,9 +334,10 @@ function Get-GitHubRelease { Write-Error 'Failed to list releases for the repo.' exit $LASTEXITCODE } - $releases = $releasesJson | ConvertFrom-Json + $releases = ConvertFrom-GitHubReleaseJson -Json $releasesJson Write-Host '-------------------------------------------------' + Write-Host "Found [$($releases.Count)] releases." Write-Host ($releases | Select-Object -Property name, isPrerelease, isLatest, publishedAt | Format-Table | Out-String) Write-Host '-------------------------------------------------' @@ -314,6 +351,11 @@ function Get-LatestGitHubVersion { .SYNOPSIS Extracts the latest stable version from a GitHub releases list. + .DESCRIPTION + Returns the version of the release marked as latest. A repository that has no releases + yet - or that has releases but none marked as latest - resolves to '0.0.0' so a brand-new + module can still be versioned before its first release exists. + .OUTPUTS PSSemVer representing the latest GitHub release version. @@ -325,9 +367,11 @@ function Get-LatestGitHubVersion { [CmdletBinding()] [OutputType([object])] param( - # The GitHub releases array to search. - [Parameter(Mandatory)] - [array] $Releases + # The GitHub releases array to search. Empty or null when the repository has no releases. + [Parameter()] + [AllowNull()] + [AllowEmptyCollection()] + [array] $Releases = @() ) LogGroup 'Get latest version - GitHub' { @@ -409,6 +453,11 @@ function Get-LatestPublishedVersion { .SYNOPSIS Returns the highest version between GitHub and the PowerShell Gallery. + .DESCRIPTION + Compares the two known published versions and returns the highest one. A missing + (null) version is treated as '0.0.0', so a module that has never been released to + GitHub or published to the PowerShell Gallery resolves to a '0.0.0' baseline. + .OUTPUTS PSSemVer representing the highest known published version. @@ -420,19 +469,27 @@ function Get-LatestPublishedVersion { [CmdletBinding()] [OutputType([object])] param( - # The latest version found in GitHub releases. - [Parameter(Mandatory)] + # The latest version found in GitHub releases. Null when the repository has no releases. + [Parameter()] + [AllowNull()] [object] $GitHubVersion, - # The latest version found in the PowerShell Gallery. - [Parameter(Mandatory)] + # The latest version found in the PowerShell Gallery. Null when the module is unpublished. + [Parameter()] + [AllowNull()] [object] $PSGalleryVersion ) LogGroup 'Latest version' { - $latestVersion = New-PSSemVer -Version ( - $PSGalleryVersion, $GitHubVersion | Sort-Object -Descending | Select-Object -First 1 - ) + $candidates = @($PSGalleryVersion, $GitHubVersion) | + Where-Object { $null -ne $_ -and -not [string]::IsNullOrWhiteSpace([string]$_) } + + $latestVersion = if ($candidates.Count -gt 0) { + New-PSSemVer -Version ($candidates | Sort-Object -Descending | Select-Object -First 1) + } else { + Write-Warning "No published version found in GitHub or the PowerShell Gallery. Using '0.0.0'." + New-PSSemVer -Version '0.0.0' + } Write-Host "Latest version: [$($latestVersion.ToString())]" $latestVersion } @@ -472,9 +529,11 @@ function Get-NextPrereleaseNumber { [ValidateNotNullOrEmpty()] [string] $PrereleaseName, - # The GitHub releases list. - [Parameter(Mandatory)] - [array] $Releases + # The GitHub releases list. Empty or null when the repository has no releases. + [Parameter()] + [AllowNull()] + [AllowEmptyCollection()] + [array] $Releases = @() ) $params = @{ @@ -532,8 +591,9 @@ function Get-NextModuleVersion { [CmdletBinding()] [OutputType([object])] param( - # The current latest published version. - [Parameter(Mandatory)] + # The current latest published version. Null resolves to a '0.0.0' baseline. + [Parameter()] + [AllowNull()] [object] $LatestVersion, # The release decision object. @@ -550,12 +610,21 @@ function Get-NextModuleVersion { [string] $ModuleName, # The GitHub releases list, used for incremental prerelease calculation. - [Parameter(Mandatory)] - [array] $Releases + # Empty or null when the repository has no releases. + [Parameter()] + [AllowNull()] + [AllowEmptyCollection()] + [array] $Releases = @() ) LogGroup 'Calculate new version' { - $newVersion = New-PSSemVer -Version $LatestVersion + $baseVersion = if ($null -eq $LatestVersion -or [string]::IsNullOrWhiteSpace([string]$LatestVersion)) { + Write-Warning "No latest version was resolved. Using '0.0.0' as the baseline." + '0.0.0' + } else { + $LatestVersion + } + $newVersion = New-PSSemVer -Version $baseVersion $newVersion.Prefix = $Configuration.VersionPrefix if ($Decision.MajorRelease) { diff --git a/.github/actions/Resolve-PSModuleVersion/src/main.ps1 b/.github/actions/Resolve-PSModuleVersion/src/main.ps1 index da6d70e6..9d143fba 100644 --- a/.github/actions/Resolve-PSModuleVersion/src/main.ps1 +++ b/.github/actions/Resolve-PSModuleVersion/src/main.ps1 @@ -28,7 +28,7 @@ $decision = if ($null -eq $pullRequest) { Resolve-ReleaseDecision -Configuration $config -PullRequest $pullRequest } -$releases = Get-GitHubRelease +$releases = @(Get-GitHubRelease) $ghVersion = Get-LatestGitHubVersion -Releases $releases $psGalleryVersion = Get-LatestPSGalleryVersion -ModuleName $actionInput.Name $latestVersion = Get-LatestPublishedVersion -GitHubVersion $ghVersion -PSGalleryVersion $psGalleryVersion diff --git a/.github/actions/Resolve-PSModuleVersion/tests/Resolve-PSModuleVersion.Helpers.Tests.ps1 b/.github/actions/Resolve-PSModuleVersion/tests/Resolve-PSModuleVersion.Helpers.Tests.ps1 new file mode 100644 index 00000000..5c212c9a --- /dev/null +++ b/.github/actions/Resolve-PSModuleVersion/tests/Resolve-PSModuleVersion.Helpers.Tests.ps1 @@ -0,0 +1,454 @@ +[Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSUseDeclaredVarsMoreThanAssignments', '', + Justification = 'Variables are assigned in BeforeAll and used inside It blocks.' +)] +[CmdletBinding()] +param() + +BeforeAll { + Import-Module -Name 'PSModule' -Force + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '../src/Resolve-PSModuleVersion.Helpers.psm1') -Force + + function Get-TestConfiguration { + <# + .SYNOPSIS + Builds a publish configuration object equivalent to what Get-PublishConfiguration returns. + #> + [CmdletBinding()] + [OutputType([PSCustomObject])] + param( + # Whether an unlabeled pull request is treated as a patch. + [Parameter()] + [bool] $AutoPatching = $true, + + # Whether prereleases get an incrementing number suffix. + [Parameter()] + [bool] $IncrementalPrerelease, + + # The date format appended to the prerelease tag. + [Parameter()] + [string] $DatePrereleaseFormat = '', + + # The prefix put in front of the version, for example 'v'. + [Parameter()] + [string] $VersionPrefix = 'v', + + # The release type resolved from the pull request labels. + [Parameter()] + [string] $ReleaseType = 'Release' + ) + + [PSCustomObject]@{ + AutoPatching = $AutoPatching + IncrementalPrerelease = $IncrementalPrerelease + DatePrereleaseFormat = $DatePrereleaseFormat + VersionPrefix = $VersionPrefix + ReleaseType = $ReleaseType + IgnoreLabels = @('NoRelease') + MajorLabels = @('major') + MinorLabels = @('minor') + PatchLabels = @('patch') + } + } + + function Get-TestDecision { + <# + .SYNOPSIS + Builds a release decision object equivalent to what Resolve-ReleaseDecision returns. + #> + [CmdletBinding()] + [OutputType([PSCustomObject])] + param( + # The version bump to apply - Major, Minor, Patch, or None. + [Parameter()] + [ValidateSet('Major', 'Minor', 'Patch', 'None')] + [string] $Bump = 'Patch', + + # Whether a prerelease tag is added to the resolved version. + [Parameter()] + [bool] $CreatePrerelease, + + # The sanitized prerelease name derived from the branch name. + [Parameter()] + [string] $PrereleaseName = '', + + # Whether the run publishes the resolved version. + [Parameter()] + [bool] $ShouldPublish = $true + ) + + [PSCustomObject]@{ + ShouldPublish = $ShouldPublish + CreateRelease = $ShouldPublish -and -not $CreatePrerelease + CreatePrerelease = $CreatePrerelease + MajorRelease = $Bump -eq 'Major' + MinorRelease = $Bump -eq 'Minor' + PatchRelease = $Bump -eq 'Patch' + HasVersionBump = $Bump -ne 'None' + PrereleaseName = $PrereleaseName + } + } +} + +Describe 'Resolve-PSModuleVersion' { + Describe 'ConvertFrom-GitHubReleaseJson' { + Context 'ConvertFrom-GitHubReleaseJson - repository without releases' { + It 'ConvertFrom-GitHubReleaseJson - returns an empty array for an empty JSON array' { + $result = ConvertFrom-GitHubReleaseJson -Json '[]' + @($result).Count | Should -Be 0 + } + + It 'ConvertFrom-GitHubReleaseJson - returns an empty array when the command produced no output' { + $result = ConvertFrom-GitHubReleaseJson -Json '' + @($result).Count | Should -Be 0 + } + + It 'ConvertFrom-GitHubReleaseJson - returns an empty array for null input' { + $result = ConvertFrom-GitHubReleaseJson -Json $null + @($result).Count | Should -Be 0 + } + } + + Context 'ConvertFrom-GitHubReleaseJson - releases present' { + It 'ConvertFrom-GitHubReleaseJson - returns a flat array of release objects' { + $json = '[{"tagName":"v1.2.3","isLatest":true},{"tagName":"v1.2.2","isLatest":false}]' + $result = @(ConvertFrom-GitHubReleaseJson -Json $json) + $result.Count | Should -Be 2 + $result[0].tagName | Should -Be 'v1.2.3' + } + + It 'ConvertFrom-GitHubReleaseJson - returns a single release without nesting it in an inner array' { + $result = @(ConvertFrom-GitHubReleaseJson -Json '[{"tagName":"v0.0.1","isLatest":true}]') + $result.Count | Should -Be 1 + $result[0].tagName | Should -Be 'v0.0.1' + } + + It 'ConvertFrom-GitHubReleaseJson - output binds to the Releases parameter without nesting' { + $json = '[{"tagName":"v1.2.3","isLatest":true},{"tagName":"v1.2.2","isLatest":false}]' + $releases = @(ConvertFrom-GitHubReleaseJson -Json $json) + $result = Get-LatestGitHubVersion -Releases $releases + $result.ToString() | Should -Be 'v1.2.3' + } + + It 'ConvertFrom-GitHubReleaseJson - survives the log group wrapper without nesting' { + $json = '[{"tagName":"v1.2.3","isLatest":true},{"tagName":"v1.2.2","isLatest":false}]' + $releases = @(LogGroup 'Get releases - GitHub' { ConvertFrom-GitHubReleaseJson -Json $json }) + $releases.Count | Should -Be 2 + $releases[0].tagName | Should -Be 'v1.2.3' + } + } + } + + Describe 'Get-LatestGitHubVersion' { + Context 'Get-LatestGitHubVersion - repository without releases' { + It 'Get-LatestGitHubVersion - returns 0.0.0 when the releases list is null' { + $result = Get-LatestGitHubVersion -Releases $null + $result.ToString() | Should -Be '0.0.0' + } + + It 'Get-LatestGitHubVersion - returns 0.0.0 when the releases list is an empty array' { + $result = Get-LatestGitHubVersion -Releases @() + $result.ToString() | Should -Be '0.0.0' + } + + It 'Get-LatestGitHubVersion - returns 0.0.0 when no releases list is passed at all' { + $result = Get-LatestGitHubVersion + $result.ToString() | Should -Be '0.0.0' + } + + It 'Get-LatestGitHubVersion - does not fail parameter binding on a null releases list' { + { Get-LatestGitHubVersion -Releases $null } | Should -Not -Throw + } + } + + Context 'Get-LatestGitHubVersion - releases present but none marked as latest' { + It 'Get-LatestGitHubVersion - returns 0.0.0 when no release is marked as latest' { + $releases = @( + [PSCustomObject]@{ tagName = 'v1.2.3'; isLatest = $false; isPrerelease = $false } + [PSCustomObject]@{ tagName = 'v1.2.2'; isLatest = $false; isPrerelease = $false } + ) + $result = Get-LatestGitHubVersion -Releases $releases + $result.ToString() | Should -Be '0.0.0' + } + + It 'Get-LatestGitHubVersion - returns 0.0.0 when the repository only has prereleases' { + $releases = @( + [PSCustomObject]@{ tagName = 'v0.0.1-mybranch001'; isLatest = $false; isPrerelease = $true } + ) + $result = Get-LatestGitHubVersion -Releases $releases + $result.ToString() | Should -Be '0.0.0' + } + } + + Context 'Get-LatestGitHubVersion - releases present' { + It 'Get-LatestGitHubVersion - returns the version of the release marked as latest' { + $releases = @( + [PSCustomObject]@{ tagName = 'v1.2.2'; isLatest = $false; isPrerelease = $false } + [PSCustomObject]@{ tagName = 'v1.2.3'; isLatest = $true; isPrerelease = $false } + [PSCustomObject]@{ tagName = 'v1.3.0-mybranch001'; isLatest = $false; isPrerelease = $true } + ) + $result = Get-LatestGitHubVersion -Releases $releases + $result.Major | Should -Be 1 + $result.Minor | Should -Be 2 + $result.Patch | Should -Be 3 + } + + It 'Get-LatestGitHubVersion - returns the version when the repository has a single release' { + $releases = @( + [PSCustomObject]@{ tagName = 'v0.0.1'; isLatest = $true; isPrerelease = $false } + ) + $result = Get-LatestGitHubVersion -Releases $releases + $result.Patch | Should -Be 1 + } + } + } + + Describe 'Get-LatestPublishedVersion' { + Context 'Get-LatestPublishedVersion - brand-new module' { + It 'Get-LatestPublishedVersion - returns 0.0.0 when neither source has a version' { + $result = Get-LatestPublishedVersion -GitHubVersion $null -PSGalleryVersion $null + $result.ToString() | Should -Be '0.0.0' + } + + It 'Get-LatestPublishedVersion - returns 0.0.0 when both sources report the 0.0.0 baseline' { + $params = @{ + GitHubVersion = New-PSSemVer -Version '0.0.0' + PSGalleryVersion = New-PSSemVer -Version '0.0.0' + } + $result = Get-LatestPublishedVersion @params + $result.ToString() | Should -Be '0.0.0' + } + + It 'Get-LatestPublishedVersion - returns 0.0.0 when no versions are passed at all' { + $result = Get-LatestPublishedVersion + $result.ToString() | Should -Be '0.0.0' + } + } + + Context 'Get-LatestPublishedVersion - one source has a version' { + It 'Get-LatestPublishedVersion - returns the GitHub version when the gallery has none' { + $result = Get-LatestPublishedVersion -GitHubVersion (New-PSSemVer -Version '1.2.3') -PSGalleryVersion $null + $result.ToString() | Should -Be '1.2.3' + } + + It 'Get-LatestPublishedVersion - returns the gallery version when GitHub has none' { + $result = Get-LatestPublishedVersion -GitHubVersion $null -PSGalleryVersion (New-PSSemVer -Version '2.0.0') + $result.ToString() | Should -Be '2.0.0' + } + } + + Context 'Get-LatestPublishedVersion - both sources have a version' { + It 'Get-LatestPublishedVersion - returns the highest of the two versions' { + $params = @{ + GitHubVersion = New-PSSemVer -Version '1.4.2' + PSGalleryVersion = New-PSSemVer -Version '1.5.0' + } + $result = Get-LatestPublishedVersion @params + $result.ToString() | Should -Be '1.5.0' + } + } + } + + Describe 'Get-NextPrereleaseNumber' { + Context 'Get-NextPrereleaseNumber - repository without releases' { + It 'Get-NextPrereleaseNumber - returns 001 when the releases list is null' { + $params = @{ + ModuleName = 'PSModuleNonExistentModuleForTesting' + BaseVersion = '0.0.1' + PrereleaseName = 'mybranch' + Releases = $null + } + Get-NextPrereleaseNumber @params | Should -Be '001' + } + + It 'Get-NextPrereleaseNumber - returns 001 when the releases list is an empty array' { + $params = @{ + ModuleName = 'PSModuleNonExistentModuleForTesting' + BaseVersion = '0.0.1' + PrereleaseName = 'mybranch' + Releases = @() + } + Get-NextPrereleaseNumber @params | Should -Be '001' + } + + It 'Get-NextPrereleaseNumber - returns 001 when no releases list is passed at all' { + $params = @{ + ModuleName = 'PSModuleNonExistentModuleForTesting' + BaseVersion = '0.0.1' + PrereleaseName = 'mybranch' + } + Get-NextPrereleaseNumber @params | Should -Be '001' + } + } + + Context 'Get-NextPrereleaseNumber - matching prereleases exist on GitHub' { + It 'Get-NextPrereleaseNumber - returns the number after the highest matching GitHub prerelease' { + $params = @{ + ModuleName = 'PSModuleNonExistentModuleForTesting' + BaseVersion = '1.2.3' + PrereleaseName = 'mybranch' + Releases = @( + [PSCustomObject]@{ tagName = 'v1.2.3-mybranch001'; isLatest = $false; isPrerelease = $true } + [PSCustomObject]@{ tagName = 'v1.2.3-mybranch005'; isLatest = $false; isPrerelease = $true } + ) + } + Get-NextPrereleaseNumber @params | Should -Be '006' + } + } + } + + Describe 'Get-NextModuleVersion' { + Context 'Get-NextModuleVersion - brand-new module without releases' { + It 'Get-NextModuleVersion - resolves the first patch release to 0.0.1' { + $params = @{ + LatestVersion = New-PSSemVer -Version '0.0.0' + Decision = Get-TestDecision -Bump 'Patch' + Configuration = Get-TestConfiguration + ModuleName = 'MyBrandNewModule' + Releases = @() + } + $result = Get-NextModuleVersion @params + $result.ToString() | Should -Be 'v0.0.1' + } + + It 'Get-NextModuleVersion - resolves the first minor release to 0.1.0' { + $params = @{ + LatestVersion = New-PSSemVer -Version '0.0.0' + Decision = Get-TestDecision -Bump 'Minor' + Configuration = Get-TestConfiguration + ModuleName = 'MyBrandNewModule' + Releases = @() + } + $result = Get-NextModuleVersion @params + $result.ToString() | Should -Be 'v0.1.0' + } + + It 'Get-NextModuleVersion - resolves the first major release to 1.0.0' { + $params = @{ + LatestVersion = New-PSSemVer -Version '0.0.0' + Decision = Get-TestDecision -Bump 'Major' + Configuration = Get-TestConfiguration + ModuleName = 'MyBrandNewModule' + Releases = @() + } + $result = Get-NextModuleVersion @params + $result.ToString() | Should -Be 'v1.0.0' + } + + It 'Get-NextModuleVersion - resolves a version when the releases list is null' { + $params = @{ + LatestVersion = New-PSSemVer -Version '0.0.0' + Decision = Get-TestDecision -Bump 'Patch' + Configuration = Get-TestConfiguration + ModuleName = 'MyBrandNewModule' + Releases = $null + } + $result = Get-NextModuleVersion @params + $result.ToString() | Should -Be 'v0.0.1' + } + + It 'Get-NextModuleVersion - resolves a version when no releases list is passed at all' { + $params = @{ + LatestVersion = New-PSSemVer -Version '0.0.0' + Decision = Get-TestDecision -Bump 'Patch' + Configuration = Get-TestConfiguration + ModuleName = 'MyBrandNewModule' + } + $result = Get-NextModuleVersion @params + $result.ToString() | Should -Be 'v0.0.1' + } + + It 'Get-NextModuleVersion - falls back to the 0.0.0 baseline when no latest version was resolved' { + $params = @{ + LatestVersion = $null + Decision = Get-TestDecision -Bump 'Patch' + Configuration = Get-TestConfiguration + ModuleName = 'MyBrandNewModule' + Releases = @() + } + $result = Get-NextModuleVersion @params + $result.ToString() | Should -Be 'v0.0.1' + } + + It 'Get-NextModuleVersion - resolves the first prerelease from an empty releases list' { + $params = @{ + LatestVersion = New-PSSemVer -Version '0.0.0' + Decision = Get-TestDecision -Bump 'Patch' -CreatePrerelease $true -PrereleaseName 'mybranch' + Configuration = Get-TestConfiguration -ReleaseType 'Prerelease' + ModuleName = 'MyBrandNewModule' + Releases = @() + } + $result = Get-NextModuleVersion @params + $result.ToString() | Should -Be 'v0.0.1-mybranch' + } + } + + Context 'Get-NextModuleVersion - existing module with releases' { + It 'Get-NextModuleVersion - bumps the patch version of the latest release' { + $params = @{ + LatestVersion = New-PSSemVer -Version '1.2.3' + Decision = Get-TestDecision -Bump 'Patch' + Configuration = Get-TestConfiguration + ModuleName = 'MyModule' + Releases = @( + [PSCustomObject]@{ tagName = 'v1.2.3'; isLatest = $true; isPrerelease = $false } + ) + } + $result = Get-NextModuleVersion @params + $result.ToString() | Should -Be 'v1.2.4' + } + } + } + + Describe 'Resolve-PSModuleVersion' { + Context 'Resolve-PSModuleVersion - brand-new module with no GitHub release and no gallery version' { + It 'Resolve-PSModuleVersion - resolves the full chain to the first patch version' { + $githubVersion = Get-LatestGitHubVersion -Releases @() + $latestVersion = Get-LatestPublishedVersion -GitHubVersion $githubVersion -PSGalleryVersion $null + $params = @{ + LatestVersion = $latestVersion + Decision = Get-TestDecision -Bump 'Patch' + Configuration = Get-TestConfiguration + ModuleName = 'MyBrandNewModule' + Releases = @() + } + $result = Get-NextModuleVersion @params + + $latestVersion.ToString() | Should -Be '0.0.0' + $result.ToString() | Should -Be 'v0.0.1' + } + + It 'Resolve-PSModuleVersion - resolves the full chain to the first minor version' { + $githubVersion = Get-LatestGitHubVersion -Releases $null + $psGalleryVersion = New-PSSemVer -Version '0.0.0' + $latestVersion = Get-LatestPublishedVersion -GitHubVersion $githubVersion -PSGalleryVersion $psGalleryVersion + $params = @{ + LatestVersion = $latestVersion + Decision = Get-TestDecision -Bump 'Minor' + Configuration = Get-TestConfiguration + ModuleName = 'MyBrandNewModule' + Releases = $null + } + $result = Get-NextModuleVersion @params + + $result.ToString() | Should -Be 'v0.1.0' + } + + It 'Resolve-PSModuleVersion - resolves the full chain to the first major version' { + $githubVersion = Get-LatestGitHubVersion -Releases @() + $psGalleryVersion = New-PSSemVer -Version '0.0.0' + $latestVersion = Get-LatestPublishedVersion -GitHubVersion $githubVersion -PSGalleryVersion $psGalleryVersion + $params = @{ + LatestVersion = $latestVersion + Decision = Get-TestDecision -Bump 'Major' + Configuration = Get-TestConfiguration + ModuleName = 'MyBrandNewModule' + Releases = @() + } + $result = Get-NextModuleVersion @params + + $result.ToString() | Should -Be 'v1.0.0' + } + } + } +} diff --git a/.github/workflows/Test-Actions.yml b/.github/workflows/Test-Actions.yml new file mode 100644 index 00000000..1960cf35 --- /dev/null +++ b/.github/workflows/Test-Actions.yml @@ -0,0 +1,54 @@ +name: Test-Actions + +run-name: "Test-Actions - [${{ github.event.pull_request.title }} #${{ github.event.pull_request.number }}] by @${{ github.actor }}" + +on: + workflow_dispatch: + pull_request: + paths: + - '.github/actions/**' + - '.github/workflows/Test-Actions.yml' + schedule: + - cron: '0 0 * * *' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + TestActions: + name: Test actions + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + + - name: Install-PSModule + uses: ./.github/actions/Install-PSModule + + - name: Install test dependencies + shell: pwsh + run: | + Install-PSResource -Name Pester -Version '[5.7.1,6.0.0)' -Repository PSGallery -TrustRepository + Install-PSResource -Name PSSemVer -Repository PSGallery -TrustRepository + + - name: Run action unit tests + shell: pwsh + run: | + $testPaths = Get-ChildItem -Path '.github/actions' -Directory | + ForEach-Object { Join-Path -Path $_.FullName -ChildPath 'tests' } | + Where-Object { Test-Path -Path $_ } + if (-not $testPaths) { + throw 'No action test folders were found under .github/actions.' + } + + $configuration = New-PesterConfiguration + $configuration.Run.Path = $testPaths + $configuration.Run.Throw = $true + $configuration.Output.Verbosity = 'Detailed' + Invoke-Pester -Configuration $configuration