Tests/GitEasy.PublishReadiness.Tests.ps1
|
BeforeAll { $ProjectRoot = Split-Path -Parent $PSScriptRoot $ModulePath = Join-Path $ProjectRoot 'GitEasy.psd1' # Publish-readiness contract. Every It in this file represents one row of # the docs/PSGALLERY-METADATA-PLAYBOOK.md pre-publish checklist. If any of # these fail, do NOT run Publish-Module. Fix the gap first. # # These tests verify metadata SHAPE (values, presence, formats). They do # NOT touch the network. URL reachability is checked by # tools/Publish-GitEasy.ps1 at stage time so that: # - Tests stay deterministic in CI / on air-gapped machines. # - Network checks happen close to the actual publish. } Describe 'GitEasy publish readiness - core manifest fields' { BeforeAll { $script:manifest = Import-PowerShellDataFile -LiteralPath $ModulePath Test-ModuleManifest -Path $ModulePath -ErrorAction Stop | Out-Null } It 'GUID is the canonical GitEasy GUID' { $manifest.GUID | Should -Be '2e113abf-c0e7-4dfb-9cb1-69476d7541f6' } It 'ModuleVersion is three-segment SemVer' { $manifest.ModuleVersion | Should -Match '^\d+\.\d+\.\d+$' } It 'Author is set' { [string]::IsNullOrWhiteSpace($manifest.Author) | Should -Be $false } It 'CompanyName is set' { [string]::IsNullOrWhiteSpace($manifest.CompanyName) | Should -Be $false } It 'Copyright contains a four-digit year' { $manifest.Copyright | Should -Match '20\d\d' } It 'Copyright references the SPDX license id' { $manifest.Copyright | Should -Match 'MPL' } It 'Description is non-empty' { [string]::IsNullOrWhiteSpace($manifest.Description) | Should -Be $false } It 'Description is at most 400 characters (avoid search-card truncation)' { ($manifest.Description.Length -le 400) | Should -Be $true } It 'Description is at least 80 characters (avoid telegraphic blurb)' { ($manifest.Description.Length -ge 80) | Should -Be $true } It 'Description names the audience' { $manifest.Description | Should -Match '(?i)sysadmin|compliance|change manager' } It 'Description names at least one exported command' { $manifest.Description | Should -Match '(Save-Work|Find-CodeChange|Show-History|Set-Token|Test-Login)' } It 'PowerShellVersion is 5.1' { $manifest.PowerShellVersion | Should -Be '5.1' } It 'CompatiblePSEditions includes Desktop' { ($manifest.CompatiblePSEditions -contains 'Desktop') | Should -Be $true } It 'CompatiblePSEditions includes Core' { ($manifest.CompatiblePSEditions -contains 'Core') | Should -Be $true } It 'FormatsToProcess files all exist on disk' { foreach ($f in $manifest.FormatsToProcess) { Test-Path (Join-Path $ProjectRoot $f) | Should -Be $true } } } Describe 'GitEasy publish readiness - exports' { BeforeAll { $script:manifest = Import-PowerShellDataFile -LiteralPath $ModulePath } It 'CmdletsToExport is an empty array, not a wildcard' { ($manifest.CmdletsToExport.Count -eq 0) | Should -Be $true } It 'VariablesToExport is an empty array, not a wildcard' { ($manifest.VariablesToExport.Count -eq 0) | Should -Be $true } It 'AliasesToExport contains the three documented singular-form aliases' { # Plural cmdlet names are a brand choice (see site/who.html#naming); # singular aliases are exported so PowerShell convention-followers # can also type Get-Update / Show-Release / Undo-Change. $expected = @('Get-Update', 'Show-Release', 'Undo-Change') | Sort-Object $actual = @($manifest.AliasesToExport | Sort-Object) ($actual -join '|') | Should -Be ($expected -join '|') } It 'AliasesToExport contains no wildcards' { ($manifest.AliasesToExport -join ',') | Should -Not -Match '\*' } It 'FunctionsToExport contains no wildcards' { ($manifest.FunctionsToExport -join ',') | Should -Not -Match '\*' } It 'FunctionsToExport matches the Public\ directory exactly' { $publicFiles = @(Get-ChildItem -LiteralPath (Join-Path $ProjectRoot 'Public') -Filter '*.ps1' | ForEach-Object { $_.BaseName } | Sort-Object) $exported = @($manifest.FunctionsToExport | Sort-Object) ($publicFiles -join '|') | Should -Be ($exported -join '|') } } Describe 'GitEasy publish readiness - PSData' { BeforeAll { $script:manifest = Import-PowerShellDataFile -LiteralPath $ModulePath $script:psdata = $manifest.PrivateData.PSData } It 'Tags has 10 or more entries' { ($psdata.Tags.Count -ge 10) | Should -Be $true } It 'Tags includes Git' { ($psdata.Tags -contains 'Git') | Should -Be $true } It 'Tags includes PSEdition_Desktop (drives Find-Module -Tag)' { ($psdata.Tags -contains 'PSEdition_Desktop') | Should -Be $true } It 'Tags includes PSEdition_Core (drives Find-Module -Tag)' { ($psdata.Tags -contains 'PSEdition_Core') | Should -Be $true } It 'Tags does not include a generic "PowerShell" tag (every module is PowerShell)' { foreach ($t in $psdata.Tags) { ($t.ToLower() -eq 'powershell') | Should -Be $false } } It 'No tag contains whitespace' { foreach ($t in $psdata.Tags) { $t | Should -Not -Match '\s' } } It 'LicenseUri is HTTPS' { $psdata.LicenseUri | Should -Match '^https://' } It 'LicenseUri points at the in-repo LICENSE file (display matches shipped license)' { $psdata.LicenseUri | Should -Match 'github\.com/greenmtnsun/GitEasy/blob/main/LICENSE' } It 'ProjectUri is HTTPS' { $psdata.ProjectUri | Should -Match '^https://' } It 'ProjectUri is the canonical GitHub repo' { $psdata.ProjectUri | Should -Be 'https://github.com/greenmtnsun/GitEasy' } It 'IconUri is set' { [string]::IsNullOrWhiteSpace($psdata.IconUri) | Should -Be $false } It 'IconUri is on raw.githubusercontent.com (direct image, not a webpage)' { $psdata.IconUri | Should -Match '^https://raw\.githubusercontent\.com/' } It 'IconUri references a .png file' { $psdata.IconUri | Should -Match '\.png$' } It 'ReleaseNotes is inline content, not just a URL stub' { ($psdata.ReleaseNotes.Length -gt 100) | Should -Be $true } It 'ReleaseNotes spans multiple lines (Gallery renders plaintext, line breaks matter)' { $psdata.ReleaseNotes | Should -Match "`n" } It 'ReleaseNotes references the current ModuleVersion' { $psdata.ReleaseNotes | Should -Match ([regex]::Escape($manifest.ModuleVersion)) } It 'Prerelease is unset for a stable release' { $val = $psdata['Prerelease'] ($null -eq $val -or [string]::IsNullOrWhiteSpace($val)) | Should -Be $true } It 'RequireLicenseAcceptance is unset (MPL-2.0 does not need click-through)' { $val = $psdata['RequireLicenseAcceptance'] ($null -eq $val -or $val -eq $false) | Should -Be $true } } Describe 'GitEasy publish readiness - repo files the Gallery surface depends on' { BeforeAll { $script:manifest = Import-PowerShellDataFile -LiteralPath $ModulePath } It 'LICENSE file exists at repo root' { Test-Path (Join-Path $ProjectRoot 'LICENSE') | Should -Be $true } It 'LICENSE file references Mozilla Public License Version 2.0' { $licText = Get-Content -LiteralPath (Join-Path $ProjectRoot 'LICENSE') -Raw $licText | Should -Match 'Mozilla Public License Version 2\.0' } It 'README.md exists at repo root' { Test-Path (Join-Path $ProjectRoot 'README.md') | Should -Be $true } It 'CHANGELOG.md exists at repo root' { Test-Path (Join-Path $ProjectRoot 'CHANGELOG.md') | Should -Be $true } It 'CHANGELOG.md contains an entry for the current ModuleVersion' { $changelog = Get-Content -LiteralPath (Join-Path $ProjectRoot 'CHANGELOG.md') -Raw $changelog | Should -Match ([regex]::Escape($manifest.ModuleVersion)) } } |