From a0ce4f9c6c8305fd3b352ad785547f5108931570 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Jare=C5=A1?= Date: Mon, 20 Jul 2026 12:28:51 +0200 Subject: [PATCH 1/5] Move v4 CI from AppVeyor to GitHub Actions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AppVeyor build for v4 is dead. Replace it with a GitHub Actions workflow that runs the test suite on Windows PowerShell 5.1 and PowerShell 7 (Windows and Ubuntu), using the same invocation AppVeyor used. Remove the AppVeyor, Travis and Azure DevOps configs, the Azure one depended on a self-hosted PS2/PS3 pool that no longer exists. Fix `New-TimeSpan -mi` in TestResults tests, newer PowerShell 7 added -Milliseconds so -mi became ambiguous. 🤖 --- .appveyor.yml | 27 ----------------- .github/workflows/ci.yml | 54 +++++++++++++++++++++++++++++++++ .travis.yml | 24 --------------- Functions/TestResults.Tests.ps1 | 4 +-- azure-pipelines.yml | 46 ---------------------------- 5 files changed, 56 insertions(+), 99 deletions(-) delete mode 100644 .appveyor.yml create mode 100644 .github/workflows/ci.yml delete mode 100644 .travis.yml delete mode 100644 azure-pipelines.yml diff --git a/.appveyor.yml b/.appveyor.yml deleted file mode 100644 index ebc8f80aa..000000000 --- a/.appveyor.yml +++ /dev/null @@ -1,27 +0,0 @@ -environment: - matrix: - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - PSEdition: Core - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - PSEdition: Desktop - - APPVEYOR_BUILD_WORKER_IMAGE: WMF 4 - PSEdition: Desktop - -skip_branch_with_pr: true -build: off - -test_script: - - ps: | - if ( $env:PSEdition -eq 'Desktop' ) { - Set-StrictMode -Version Latest - $global:PesterDebugPreference_ShowFullErrors = $true - Import-Module ./Pester.psd1 - Invoke-Pester -ExcludeTag VersionChecks, StyleRules, Help -EnableExit -OutputFile TestResults.xml -OutputFormat NUnitXml - (New-Object 'System.Net.WebClient').UploadFile("https://ci.appveyor.com/api/testresults/nunit/${env:APPVEYOR_JOB_ID}", (Join-Path $PWD 'TestResults.xml')) } - - pwsh: | - if ( $env:PSEdition -eq 'Core' ) { - Set-StrictMode -Version Latest - $global:PesterDebugPreference_ShowFullErrors = $true - Import-Module ./Pester.psd1 - Invoke-Pester -ExcludeTag VersionChecks, StyleRules, Help -EnableExit -OutputFile TestResults.xml -OutputFormat NUnitXml - (New-Object 'System.Net.WebClient').UploadFile("https://ci.appveyor.com/api/testresults/nunit/${env:APPVEYOR_JOB_ID}", (Join-Path $PWD 'TestResults.xml')) } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..6e9c83c30 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,54 @@ +# CI for the Pester v4 maintenance branch. Replaces the dead AppVeyor setup. +# +# v4 is in security-fix-only maintenance. We test only Windows PowerShell 5.1 +# and PowerShell 7 — nothing else is guaranteed. The goal is to keep the branch +# releasable: green CI here means a security fix can be validated and shipped +# through the manual release process (release.ps1). +name: CI + +on: + push: + branches: ['rel/4.x.x'] + pull_request: + branches: ['rel/4.x.x'] + workflow_dispatch: + +permissions: + contents: read + +jobs: + test: + name: ${{ matrix.name }} + runs-on: ${{ matrix.os }} + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + include: + - { name: 'PS5.1 - Windows', id: ps51-windows, os: windows-latest, shell: powershell } + - { name: 'PS7 - Windows', id: ps7-windows, os: windows-latest, shell: pwsh } + - { name: 'PS7 - Ubuntu', id: ps7-ubuntu, os: ubuntu-latest, shell: pwsh } + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 1 + + # Same test invocation AppVeyor used: import the module from the repo + # root and run the suite, excluding the tags that need extra tooling. + - name: Test Pester + shell: ${{ matrix.shell }} + run: | + $PSVersionTable + Set-StrictMode -Version Latest + $global:PesterDebugPreference_ShowFullErrors = $true + Import-Module ./Pester.psd1 + Invoke-Pester -ExcludeTag VersionChecks, StyleRules, Help -EnableExit -OutputFile TestResults.xml -OutputFormat NUnitXml + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: results-${{ matrix.id }} + retention-days: 7 + if-no-files-found: ignore + path: TestResults.xml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index da81af5de..000000000 --- a/.travis.yml +++ /dev/null @@ -1,24 +0,0 @@ -language: generic - -matrix: - include: - - os: osx - osx_image: xcode9.1 - before_install: - # - brew update - # - brew tap caskroom/cask - - brew cask install powershell - - os: linux - dist: trusty - # VM-based builds turned out to be faster - sudo: required - addons: - apt: - sources: - - sourceline: deb [arch=amd64] https://packages.microsoft.com/ubuntu/14.04/prod trusty main - key_url: https://packages.microsoft.com/keys/microsoft.asc - packages: - - powershell - -script: - - pwsh -c 'Set-StrictMode -Version Latest; $global:PesterDebugPreference_ShowFullErrors = $true ;Import-Module ./Pester.psd1; Invoke-Pester -ExcludeTag VersionChecks, StyleRules, Help -EnableExit' diff --git a/Functions/TestResults.Tests.ps1 b/Functions/TestResults.Tests.ps1 index fc17c2f1d..60ebe00fd 100644 --- a/Functions/TestResults.Tests.ps1 +++ b/Functions/TestResults.Tests.ps1 @@ -198,7 +198,7 @@ InModuleScope Pester { #create state $TestResults = New-PesterState -Path TestDrive:\ $testResults.EnterTestGroup('Describe #1', 'Describe') - $TestResults.AddTestResult("Successful testcase", 'Passed', (New-TimeSpan -mi 1)) + $TestResults.AddTestResult("Successful testcase", 'Passed', (New-TimeSpan -Minutes 1)) $testResults.LeaveTestGroup('Describe #1', 'Describe') $testResults.EnterTestGroup('Describe #2', 'Describe') $TestResults.AddTestResult("Failed testcase", 'Failed', (New-TimeSpan -Seconds 2)) @@ -352,7 +352,7 @@ InModuleScope Pester { #create state $TestResults = New-PesterState -Path TestDrive:\ $testResults.EnterTestGroup('Describe #1', 'Describe') - $TestResults.AddTestResult("Successful testcase", 'Passed', (New-TimeSpan -mi 1)) + $TestResults.AddTestResult("Successful testcase", 'Passed', (New-TimeSpan -Minutes 1)) $testResults.LeaveTestGroup('Describe #1', 'Describe') $testResults.EnterTestGroup('Describe #2', 'Describe') $TestResults.AddTestResult("Failed testcase", 'Failed', (New-TimeSpan -Seconds 2)) diff --git a/azure-pipelines.yml b/azure-pipelines.yml deleted file mode 100644 index ea9d5531d..000000000 --- a/azure-pipelines.yml +++ /dev/null @@ -1,46 +0,0 @@ -trigger: - - rel/4.x.x -pr: - - rel/4.x.x - -resources: - - repo: self - clean: true - fetchDepth: 1 - -jobs: - - job: ps2 - displayName: PowerShell 2 - continueOnError: false - pool: - name: Default - demands: - - ps2 - workspace: - clean: all - timeoutInMinutes: 5 - steps: - - script: | - rem build in 32-bit version of PowerShell 2 because the 64-bit version - rem was butchered and replaced with PowerShell 6 to be able to run the - rem Azure Pipelines agent on Server 2008 R2 with only PowerShell 2 - C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe -c "$errorActionPreference = 'stop'; $global:PesterDebugPreference_ShowFullErrors = $true ; try {$PSVersionTable; Set-StrictMode -Version Latest; Import-Module .\Pester.psd1; Invoke-Pester -ExcludeTag VersionChecks, StyleRules, Help -EnableExit} catch { Write-Error $_; exit 9999 }" - exit %errorlevel% - - - job: ps3 - displayName: PowerShell 3 - continueOnError: false - pool: - name: Default - demands: - - ps3 - workspace: - clean: all - timeoutInMinutes: 5 - steps: - - powershell: | - $global:PesterDebugPreference_ShowFullErrors = $true - $errorActionPreference = 'stop' - Set-StrictMode -Version Latest - Import-Module .\Pester.psd1 - Invoke-Pester -ExcludeTag VersionChecks, StyleRules, Help -EnableExit From 20e799754e3f91170bc34b0916965a0a067bb48f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Jare=C5=A1?= Date: Mon, 20 Jul 2026 12:31:39 +0200 Subject: [PATCH 2/5] Fix workflow, shell cannot take a matrix expression MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 --- .github/workflows/ci.yml | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6e9c83c30..00de00a6d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,9 +25,9 @@ jobs: fail-fast: false matrix: include: - - { name: 'PS5.1 - Windows', id: ps51-windows, os: windows-latest, shell: powershell } - - { name: 'PS7 - Windows', id: ps7-windows, os: windows-latest, shell: pwsh } - - { name: 'PS7 - Ubuntu', id: ps7-ubuntu, os: ubuntu-latest, shell: pwsh } + - { name: 'PS5.1 - Windows', id: ps51-windows, os: windows-latest, psexe: powershell } + - { name: 'PS7 - Windows', id: ps7-windows, os: windows-latest, psexe: pwsh } + - { name: 'PS7 - Ubuntu', id: ps7-ubuntu, os: ubuntu-latest, psexe: pwsh } steps: - uses: actions/checkout@v6 with: @@ -35,14 +35,15 @@ jobs: # Same test invocation AppVeyor used: import the module from the repo # root and run the suite, excluding the tags that need extra tooling. + # `shell:` cannot take a matrix expression, so run from a fixed pwsh and + # launch the leg's interpreter: pwsh for PS7, powershell (Windows + # PowerShell 5.1) for the 5.1 leg. exit $LASTEXITCODE so a failure in + # the launched process still fails the job. - name: Test Pester - shell: ${{ matrix.shell }} + shell: pwsh run: | - $PSVersionTable - Set-StrictMode -Version Latest - $global:PesterDebugPreference_ShowFullErrors = $true - Import-Module ./Pester.psd1 - Invoke-Pester -ExcludeTag VersionChecks, StyleRules, Help -EnableExit -OutputFile TestResults.xml -OutputFormat NUnitXml + & ${{ matrix.psexe }} -NoProfile -Command '$PSVersionTable; Set-StrictMode -Version Latest; $global:PesterDebugPreference_ShowFullErrors = $true; Import-Module ./Pester.psd1; Invoke-Pester -ExcludeTag VersionChecks, StyleRules, Help -EnableExit -OutputFile TestResults.xml -OutputFormat NUnitXml' + exit $LASTEXITCODE - name: Upload test results if: always() From 5fa20abd7362445f9ff7e71cee42abbd75bb9ae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Jare=C5=A1?= Date: Mon, 20 Jul 2026 12:35:44 +0200 Subject: [PATCH 3/5] Expand TEMP short path in TestDrive tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GitHub Actions runners set TEMP to the 8.3 short form (C:\Users\RUNNER~1\...), but TestDrive paths resolve to the long form, so the -like comparisons against $env:TEMP never match. Expand TEMP to the long path via Scripting.FileSystemObject. 🤖 --- Functions/TestDrive.Tests.ps1 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Functions/TestDrive.Tests.ps1 b/Functions/TestDrive.Tests.ps1 index 28b6edac7..f5f4ee656 100644 --- a/Functions/TestDrive.Tests.ps1 +++ b/Functions/TestDrive.Tests.ps1 @@ -1,7 +1,10 @@ Set-StrictMode -Version Latest if ($PSVersionTable.PSVersion.Major -lt 6 -or $IsWindows) { - $tempPath = $env:TEMP + # GitHub Actions runners set TEMP to the 8.3 short form (C:\Users\RUNNER~1\...), + # but TestDrive paths resolve to the long form, expand TEMP so the -like + # comparisons below work + $tempPath = (New-Object -ComObject Scripting.FileSystemObject).GetFolder($env:TEMP).Path } elseif ($IsMacOS) { $tempPath = '/private/tmp' From b1e3341503824e33812894e5d6f6f6e18eab5911 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Jare=C5=A1?= Date: Mon, 20 Jul 2026 12:38:47 +0200 Subject: [PATCH 4/5] TEMP diagnostics for TestDrive path mismatch on CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 --- Functions/TestDrive.Tests.ps1 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Functions/TestDrive.Tests.ps1 b/Functions/TestDrive.Tests.ps1 index f5f4ee656..a0c8f43cb 100644 --- a/Functions/TestDrive.Tests.ps1 +++ b/Functions/TestDrive.Tests.ps1 @@ -16,6 +16,13 @@ else { Describe "Setup" { It "returns a location that is in a temp area" { $testDrivePath = (Get-Item $TestDrive).FullName + # TEMP diagnostic, remove before merge + Write-Host "DIAG tempPath = '$tempPath'" + Write-Host "DIAG testDrivePath = '$testDrivePath'" + Write-Host "DIAG env:TEMP = '$env:TEMP'" + Write-Host "DIAG env:TMP = '$env:TMP'" + Write-Host "DIAG GetTempPath = '$([System.IO.Path]::GetTempPath())'" + Write-Host "DIAG TestDrive var = '$TestDrive'" $testDrivePath -like "$tempPath*" | Should -Be $true } From 5990eaab06b6baaf4be826de507161995160794c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Jare=C5=A1?= Date: Mon, 20 Jul 2026 13:54:09 +0200 Subject: [PATCH 5/5] Use GetTempPath instead of env:TEMP in TestDrive tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GitHub Actions runners set TEMP to the 8.3 short form (C:\Users\RUNNER~1\...), but TestDrive is created via GetTempPath which returns the long form, so the -like comparisons never match. Compare against GetTempPath, the same API TestDrive uses. 🤖 --- Functions/TestDrive.Tests.ps1 | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/Functions/TestDrive.Tests.ps1 b/Functions/TestDrive.Tests.ps1 index a0c8f43cb..a505fc8a0 100644 --- a/Functions/TestDrive.Tests.ps1 +++ b/Functions/TestDrive.Tests.ps1 @@ -1,10 +1,11 @@ Set-StrictMode -Version Latest if ($PSVersionTable.PSVersion.Major -lt 6 -or $IsWindows) { - # GitHub Actions runners set TEMP to the 8.3 short form (C:\Users\RUNNER~1\...), - # but TestDrive paths resolve to the long form, expand TEMP so the -like - # comparisons below work - $tempPath = (New-Object -ComObject Scripting.FileSystemObject).GetFolder($env:TEMP).Path + # don't use $env:TEMP directly, GitHub Actions runners set it to the 8.3 + # short form (C:\Users\RUNNER~1\...) but TestDrive is created via + # GetTempPath which returns the long form, so the -like comparisons below + # would never match + $tempPath = [System.IO.Path]::GetTempPath() } elseif ($IsMacOS) { $tempPath = '/private/tmp' @@ -16,13 +17,6 @@ else { Describe "Setup" { It "returns a location that is in a temp area" { $testDrivePath = (Get-Item $TestDrive).FullName - # TEMP diagnostic, remove before merge - Write-Host "DIAG tempPath = '$tempPath'" - Write-Host "DIAG testDrivePath = '$testDrivePath'" - Write-Host "DIAG env:TEMP = '$env:TEMP'" - Write-Host "DIAG env:TMP = '$env:TMP'" - Write-Host "DIAG GetTempPath = '$([System.IO.Path]::GetTempPath())'" - Write-Host "DIAG TestDrive var = '$TestDrive'" $testDrivePath -like "$tempPath*" | Should -Be $true }