lib/rules/releases/release_should_be_published/release_should_be_published.Tests.ps1
|
############################################################################# # Tests for Rule: release_should_be_published ############################################################################# BeforeAll { . "$PSScriptRoot/../../../StateModel.ps1" . "$PSScriptRoot/../../../ValidationRules.ps1" . "$PSScriptRoot/../../../RemediationActions.ps1" . "$PSScriptRoot/release_should_be_published.ps1" } Describe "release_should_be_published" { Context "Condition - AppliesWhen check-release-immutability" { It "should return results when check-release-immutability is 'error'" { $state = [RepositoryState]::new() $releaseData = [PSCustomObject]@{ tag_name = "v1.0.0" id = 123 draft = $true prerelease = $false html_url = "https://github.com/repo/releases/tag/v1.0.0" target_commitish = "abc123" immutable = $false } $state.Releases = @([ReleaseInfo]::new($releaseData)) $state.IgnoreVersions = @() $config = @{ 'check-release-immutability' = 'error' } $result = & $Rule_ReleaseShouldBePublished.Condition $state $config $result.Count | Should -Be 1 } It "should return results when check-release-immutability is 'warning'" { $state = [RepositoryState]::new() $releaseData = [PSCustomObject]@{ tag_name = "v1.0.0" id = 123 draft = $true prerelease = $false html_url = "https://github.com/repo/releases/tag/v1.0.0" target_commitish = "abc123" immutable = $false } $state.Releases = @([ReleaseInfo]::new($releaseData)) $state.IgnoreVersions = @() $config = @{ 'check-release-immutability' = 'warning' } $result = & $Rule_ReleaseShouldBePublished.Condition $state $config $result.Count | Should -Be 1 } It "should return empty when both check-release-immutability and check-releases are 'none'" { $state = [RepositoryState]::new() $releaseData = [PSCustomObject]@{ tag_name = "v1.0.0" id = 123 draft = $true prerelease = $false html_url = "https://github.com/repo/releases/tag/v1.0.0" target_commitish = "abc123" immutable = $false } $state.Releases = @([ReleaseInfo]::new($releaseData)) $state.IgnoreVersions = @() $config = @{ 'check-release-immutability' = 'none' 'check-releases' = 'none' } $result = & $Rule_ReleaseShouldBePublished.Condition $state $config $result.Count | Should -Be 0 } It "should return results when check-releases is 'error' even if check-release-immutability is 'none'" { $state = [RepositoryState]::new() $releaseData = [PSCustomObject]@{ tag_name = "v1.0.0" id = 123 draft = $true prerelease = $false html_url = "https://github.com/repo/releases/tag/v1.0.0" target_commitish = "abc123" immutable = $false } $state.Releases = @([ReleaseInfo]::new($releaseData)) $state.IgnoreVersions = @() $config = @{ 'check-release-immutability' = 'none' 'check-releases' = 'error' } $result = & $Rule_ReleaseShouldBePublished.Condition $state $config $result.Count | Should -Be 1 } } Context "Condition - Finding draft releases" { It "should return draft release for patch version" { $state = [RepositoryState]::new() $releaseData = [PSCustomObject]@{ tag_name = "v1.0.0" id = 123 draft = $true prerelease = $false html_url = "https://github.com/repo/releases/tag/v1.0.0" target_commitish = "abc123" immutable = $false } $state.Releases = @([ReleaseInfo]::new($releaseData)) $state.IgnoreVersions = @() $config = @{ 'check-release-immutability' = 'error' } $result = & $Rule_ReleaseShouldBePublished.Condition $state $config $result.Count | Should -Be 1 $result[0].TagName | Should -Be "v1.0.0" } It "should not return published release" { $state = [RepositoryState]::new() $releaseData = [PSCustomObject]@{ tag_name = "v1.0.0" id = 123 draft = $false prerelease = $false html_url = "https://github.com/repo/releases/tag/v1.0.0" target_commitish = "abc123" immutable = $false } $state.Releases = @([ReleaseInfo]::new($releaseData)) $state.IgnoreVersions = @() $config = @{ 'check-release-immutability' = 'error' } $result = & $Rule_ReleaseShouldBePublished.Condition $state $config $result.Count | Should -Be 0 } It "should skip ignored versions" { $state = [RepositoryState]::new() $releaseData = [PSCustomObject]@{ tag_name = "v1.0.0" id = 123 draft = $true prerelease = $false html_url = "https://github.com/repo/releases/tag/v1.0.0" target_commitish = "abc123" immutable = $false } $ignored = [ReleaseInfo]::new($releaseData) $ignored.IsIgnored = $true $state.Releases = @($ignored) $state.IgnoreVersions = @("v1.0.0") $config = @{ 'check-release-immutability' = 'error' } $result = & $Rule_ReleaseShouldBePublished.Condition $state $config $result.Count | Should -Be 0 } It "should not return draft release for floating version (major)" { $state = [RepositoryState]::new() $releaseData = [PSCustomObject]@{ tag_name = "v1" id = 123 draft = $true prerelease = $false html_url = "https://github.com/repo/releases/tag/v1" target_commitish = "abc123" immutable = $false } $state.Releases = @([ReleaseInfo]::new($releaseData)) $state.IgnoreVersions = @() $config = @{ 'check-release-immutability' = 'error' } $result = & $Rule_ReleaseShouldBePublished.Condition $state $config $result.Count | Should -Be 0 } It "should not return draft release for floating version (minor)" { $state = [RepositoryState]::new() $releaseData = [PSCustomObject]@{ tag_name = "v1.0" id = 123 draft = $true prerelease = $false html_url = "https://github.com/repo/releases/tag/v1.0" target_commitish = "abc123" immutable = $false } $state.Releases = @([ReleaseInfo]::new($releaseData)) $state.IgnoreVersions = @() $config = @{ 'check-release-immutability' = 'error' } $result = & $Rule_ReleaseShouldBePublished.Condition $state $config $result.Count | Should -Be 0 } It "should return only the primary draft release when duplicates exist for same tag" { # Scenario: Multiple draft releases exist for the same tag (can happen via API) # The duplicate_release rule handles deleting duplicates, so this rule # should only return the one that will be kept (lowest ID) $state = [RepositoryState]::new() # Create 3 duplicate draft releases for v1.0.0 (like in the user's repo) $release1 = [ReleaseInfo]::new( [PSCustomObject]@{ tag_name = "v1.0.0" id = 101 draft = $true prerelease = $false html_url = "url1" target_commitish = "abc123" immutable = $false }) $release2 = [ReleaseInfo]::new([PSCustomObject]@{ tag_name = "v1.0.0" id = 102 draft = $true prerelease = $false html_url = "url2" target_commitish = "abc123" immutable = $false }) $release3 = [ReleaseInfo]::new([PSCustomObject]@{ tag_name = "v1.0.0" id = 103 draft = $true prerelease = $false html_url = "url3" target_commitish = "abc123" immutable = $false }) $state.Releases = @($release1, $release2, $release3) $state.IgnoreVersions = @() $config = @{ 'check-releases' = 'error' } $result = & $Rule_ReleaseShouldBePublished.Condition $state $config # Should return only the primary draft (id 101, lowest ID) - duplicates are handled by duplicate_release rule $result.Count | Should -Be 1 $result[0].Id | Should -Be 101 $result[0].TagName | Should -Be "v1.0.0" } It "should return one draft per version when duplicates exist across different versions" { # Scenario: Multiple draft releases for multiple versions # The duplicate_release rule handles deleting duplicates per tag $state = [RepositoryState]::new() # 2 drafts for v1.0.0, 1 draft for v2.0.0 $state.Releases = @( [ReleaseInfo]::new([PSCustomObject]@{ tag_name = "v1.0.0" id = 101 draft = $true prerelease = $false html_url = "url1" target_commitish = "abc" immutable = $false }), [ReleaseInfo]::new([PSCustomObject]@{ tag_name = "v1.0.0" id = 102 draft = $true prerelease = $false html_url = "url2" target_commitish = "abc" immutable = $false }), [ReleaseInfo]::new([PSCustomObject]@{ tag_name = "v2.0.0" id = 201 draft = $true prerelease = $false html_url = "url3" target_commitish = "def" immutable = $false }) ) $state.IgnoreVersions = @() $config = @{ 'check-releases' = 'error' } $result = & $Rule_ReleaseShouldBePublished.Condition $state $config # Should return 2 drafts: one for v1.0.0 (id 101) and one for v2.0.0 (id 201) $result.Count | Should -Be 2 ($result | Where-Object { $_.TagName -eq "v1.0.0" }).Count | Should -Be 1 ($result | Where-Object { $_.TagName -eq "v1.0.0" }).Id | Should -Be 101 ($result | Where-Object { $_.TagName -eq "v2.0.0" }).Count | Should -Be 1 } It "should not return draft when published release already exists for same tag" { # Scenario: A published release exists, and a draft duplicate also exists # The draft will be deleted by duplicate_release rule, so this rule should not include it $state = [RepositoryState]::new() $published = [ReleaseInfo]::new([PSCustomObject]@{ tag_name = "v1.0.0" id = 100 draft = $false prerelease = $false html_url = "url1" target_commitish = "abc123" immutable = $true }) $draft = [ReleaseInfo]::new([PSCustomObject]@{ tag_name = "v1.0.0" id = 200 draft = $true prerelease = $false html_url = "url2" target_commitish = "abc123" immutable = $false }) $state.Releases = @($published, $draft) $state.IgnoreVersions = @() $config = @{ 'check-releases' = 'error' } $result = & $Rule_ReleaseShouldBePublished.Condition $state $config # Draft should be excluded since published release exists (draft will be deleted by duplicate_release) $result.Count | Should -Be 0 } } Context "CreateIssue" { It "should create issue with error severity" { $releaseData = [PSCustomObject]@{ tag_name = "v1.0.0" id = 123 draft = $true prerelease = $false html_url = "https://github.com/repo/releases/tag/v1.0.0" target_commitish = "abc123" immutable = $false } $releaseInfo = [ReleaseInfo]::new($releaseData) $state = [RepositoryState]::new() $config = @{ 'check-release-immutability' = 'error' } $issue = & $Rule_ReleaseShouldBePublished.CreateIssue $releaseInfo $state $config $issue.Type | Should -Be "draft_release" $issue.Severity | Should -Be "error" $issue.Message | Should -BeLike "*v1.0.0*" $issue.RemediationAction | Should -Not -BeNullOrEmpty $issue.RemediationAction.GetType().Name | Should -Be "PublishReleaseAction" } It "should create issue with warning severity when both are warning" { $releaseData = [PSCustomObject]@{ tag_name = "v1.0.0" id = 123 draft = $true prerelease = $false html_url = "https://github.com/repo/releases/tag/v1.0.0" target_commitish = "abc123" immutable = $false } $releaseInfo = [ReleaseInfo]::new($releaseData) $state = [RepositoryState]::new() $config = @{ 'check-release-immutability' = 'warning' 'check-releases' = 'warning' } $issue = & $Rule_ReleaseShouldBePublished.CreateIssue $releaseInfo $state $config $issue.Severity | Should -Be "warning" } It "should create issue with error severity when one is error and one is warning (most severe wins)" { $releaseData = [PSCustomObject]@{ tag_name = "v1.0.0" id = 123 draft = $true prerelease = $false html_url = "https://github.com/repo/releases/tag/v1.0.0" target_commitish = "abc123" immutable = $false } $releaseInfo = [ReleaseInfo]::new($releaseData) $state = [RepositoryState]::new() # Test: check-releases=error, check-release-immutability=warning → error $config = @{ 'check-release-immutability' = 'warning' 'check-releases' = 'error' } $issue = & $Rule_ReleaseShouldBePublished.CreateIssue $releaseInfo $state $config $issue.Severity | Should -Be "error" # Test: check-releases=warning, check-release-immutability=error → error $config = @{ 'check-release-immutability' = 'error' 'check-releases' = 'warning' } $issue = & $Rule_ReleaseShouldBePublished.CreateIssue $releaseInfo $state $config $issue.Severity | Should -Be "error" } It "should configure PublishReleaseAction with release ID" { $releaseData = [PSCustomObject]@{ tag_name = "v1.0.0" id = 456 draft = $true prerelease = $false html_url = "https://github.com/repo/releases/tag/v1.0.0" target_commitish = "abc123" immutable = $false } $releaseInfo = [ReleaseInfo]::new($releaseData) $state = [RepositoryState]::new() $config = @{ 'check-release-immutability' = 'error' } $issue = & $Rule_ReleaseShouldBePublished.CreateIssue $releaseInfo $state $config $issue.RemediationAction.ReleaseId | Should -Be 456 $issue.RemediationAction.TagName | Should -Be "v1.0.0" } } Context "CreateIssue - MakeLatest integration with Test-ShouldBeLatestRelease" { It "should set MakeLatest=false when higher version release exists" { $state = [RepositoryState]::new() # v2.0.0 already exists and is latest $existingRelease = [PSCustomObject]@{ tag_name = "v2.0.0" id = 200 draft = $false prerelease = $false html_url = "https://github.com/repo/releases/tag/v2.0.0" target_commitish = "def456" immutable = $false } $latestRelease = [ReleaseInfo]::new($existingRelease) $latestRelease.IsLatest = $true $state.Releases = @($latestRelease) # Publishing draft for v1.0.0 (lower version) $draftRelease = [PSCustomObject]@{ tag_name = "v1.0.0" id = 100 draft = $true prerelease = $false html_url = "https://github.com/repo/releases/tag/v1.0.0" target_commitish = "abc123" immutable = $false } $releaseInfo = [ReleaseInfo]::new($draftRelease) $config = @{ 'check-releases' = 'error' } $issue = & $Rule_ReleaseShouldBePublished.CreateIssue $releaseInfo $state $config # MakeLatest should be false to prevent overwriting v2.0.0 as latest $issue.RemediationAction.MakeLatest | Should -Be $false } It "should NOT set MakeLatest (let GitHub decide) when publishing highest version" { $state = [RepositoryState]::new() # v1.0.0 already exists $existingRelease = [PSCustomObject]@{ tag_name = "v1.0.0" id = 100 draft = $false prerelease = $false html_url = "https://github.com/repo/releases/tag/v1.0.0" target_commitish = "abc123" immutable = $false } $latestRelease = [ReleaseInfo]::new($existingRelease) $latestRelease.IsLatest = $true $state.Releases = @($latestRelease) # Publishing draft for v2.0.0 (higher version - should become latest) $draftRelease = [PSCustomObject]@{ tag_name = "v2.0.0" id = 200 draft = $true prerelease = $false html_url = "https://github.com/repo/releases/tag/v2.0.0" target_commitish = "def456" immutable = $false } $releaseInfo = [ReleaseInfo]::new($draftRelease) $config = @{ 'check-releases' = 'error' } $issue = & $Rule_ReleaseShouldBePublished.CreateIssue $releaseInfo $state $config # MakeLatest should be null (not explicitly set) to let GitHub make it latest $issue.RemediationAction.MakeLatest | Should -BeNullOrEmpty } It "should NOT set MakeLatest when no other releases exist (first publish)" { $state = [RepositoryState]::new() # Only the draft release exists $draftRelease = [PSCustomObject]@{ tag_name = "v1.0.0" id = 100 draft = $true prerelease = $false html_url = "https://github.com/repo/releases/tag/v1.0.0" target_commitish = "abc123" immutable = $false } $releaseInfo = [ReleaseInfo]::new($draftRelease) $state.Releases = @($releaseInfo) $config = @{ 'check-releases' = 'error' } $issue = & $Rule_ReleaseShouldBePublished.CreateIssue $releaseInfo $state $config # MakeLatest should be null to let GitHub make it latest $issue.RemediationAction.MakeLatest | Should -BeNullOrEmpty } It "should set MakeLatest=false when publishing prerelease" { $state = [RepositoryState]::new() # v1.0.0 exists and is latest $existingRelease = [PSCustomObject]@{ tag_name = "v1.0.0" id = 100 draft = $false prerelease = $false html_url = "https://github.com/repo/releases/tag/v1.0.0" target_commitish = "abc123" immutable = $false } $latestRelease = [ReleaseInfo]::new($existingRelease) $latestRelease.IsLatest = $true $state.Releases = @($latestRelease) # Publishing draft for v2.0.0 that's marked as prerelease $draftRelease = [PSCustomObject]@{ tag_name = "v2.0.0" id = 200 draft = $true prerelease = $true # This is a prerelease! html_url = "https://github.com/repo/releases/tag/v2.0.0" target_commitish = "def456" immutable = $false } $releaseInfo = [ReleaseInfo]::new($draftRelease) $config = @{ 'check-releases' = 'error' } $issue = & $Rule_ReleaseShouldBePublished.CreateIssue $releaseInfo $state $config # MakeLatest should be false - prereleases should NOT become latest $issue.RemediationAction.MakeLatest | Should -Be $false } It "should set MakeLatest=false when publishing backport release" { $state = [RepositoryState]::new() # v2.5.0 is the current latest $existingRelease = [PSCustomObject]@{ tag_name = "v2.5.0" id = 250 draft = $false prerelease = $false html_url = "https://github.com/repo/releases/tag/v2.5.0" target_commitish = "sha250" immutable = $false } $latestRelease = [ReleaseInfo]::new($existingRelease) $latestRelease.IsLatest = $true $state.Releases = @($latestRelease) # Publishing backport draft for v1.5.1 $draftRelease = [PSCustomObject]@{ tag_name = "v1.5.1" id = 151 draft = $true prerelease = $false html_url = "https://github.com/repo/releases/tag/v1.5.1" target_commitish = "backport123" immutable = $false } $releaseInfo = [ReleaseInfo]::new($draftRelease) $config = @{ 'check-releases' = 'error' } $issue = & $Rule_ReleaseShouldBePublished.CreateIssue $releaseInfo $state $config # MakeLatest should be false to prevent overwriting v2.5.0 $issue.RemediationAction.MakeLatest | Should -Be $false } It "should NOT set MakeLatest when only prereleases exist at higher versions" { $state = [RepositoryState]::new() # v2.0.0 exists but is a prerelease (so v1.0.0 should become latest) $existingRelease = [PSCustomObject]@{ tag_name = "v2.0.0" id = 200 draft = $false prerelease = $true # This is a prerelease html_url = "https://github.com/repo/releases/tag/v2.0.0" target_commitish = "def456" immutable = $false } $state.Releases = @([ReleaseInfo]::new($existingRelease)) # Publishing draft for v1.0.0 (lower version but should be latest since v2.0.0 is prerelease) $draftRelease = [PSCustomObject]@{ tag_name = "v1.0.0" id = 100 draft = $true prerelease = $false # Not a prerelease html_url = "https://github.com/repo/releases/tag/v1.0.0" target_commitish = "abc123" immutable = $false } $releaseInfo = [ReleaseInfo]::new($draftRelease) $config = @{ 'check-releases' = 'error' } $issue = & $Rule_ReleaseShouldBePublished.CreateIssue $releaseInfo $state $config # MakeLatest should be null - v1.0.0 IS the highest non-prerelease $issue.RemediationAction.MakeLatest | Should -BeNullOrEmpty } It "should handle multiple existing releases correctly" { $state = [RepositoryState]::new() # Multiple releases exist: v1.0.0, v1.5.0, v2.0.0 $releases = @() foreach ($v in @("v1.0.0", "v1.5.0", "v2.0.0")) { $release = [PSCustomObject]@{ tag_name = $v id = [int]($v -replace '\D', '') draft = $false prerelease = $false html_url = "https://github.com/repo/releases/tag/$v" target_commitish = "sha$v" immutable = $false } $ri = [ReleaseInfo]::new($release) $ri.IsLatest = ($v -eq "v2.0.0") $releases += $ri } $state.Releases = $releases # Publishing draft for v1.2.0 (between v1.0.0 and v1.5.0 - NOT highest) $draftRelease = [PSCustomObject]@{ tag_name = "v1.2.0" id = 120 draft = $true prerelease = $false html_url = "https://github.com/repo/releases/tag/v1.2.0" target_commitish = "sha120" immutable = $false } $releaseInfo = [ReleaseInfo]::new($draftRelease) $config = @{ 'check-releases' = 'error' } $issue = & $Rule_ReleaseShouldBePublished.CreateIssue $releaseInfo $state $config # Should be false - v2.0.0 is still highest $issue.RemediationAction.MakeLatest | Should -Be $false } } } |