chore(deps): bump check-jsonschema from 0.37.3 to 0.37.4 in the pip-minor-patch group #11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # PowerShell CI Workflow | |
| # | |
| # Purpose: Run PSScriptAnalyzer linting and Pester tests for PowerShell scripts | |
| # Runs on: push and pull_request events | |
| # | |
| # Jobs: | |
| # - powershell-lint: Runs PSScriptAnalyzer on all .ps1 files (skips if no files found) | |
| # - test: Runs Pester tests on Windows, macOS, and Linux (skips if no *.Tests.ps1 files found) | |
| # - module-build: Stages and uploads the validated IntuneComplianceReport module artifact | |
| # | |
| # Configuration: | |
| # - Linting: .github/linting/PSScriptAnalyzerSettings.psd1 | |
| # - Analyzer gate mode: PSSCRIPTANALYZER_GATE_MODE | |
| # - strict: fail Error, Warning, and unknown-severity findings | |
| # - first-adoption: fail Error and unknown-severity findings, but | |
| # annotate Warning and Information findings as temporary debt | |
| # - Testing: Pester configuration is inline in the workflow steps below | |
| # This workflow intentionally does not use path filters so branch rulesets can | |
| # depend on a stable check name. | |
| name: PowerShell CI | |
| on: | |
| push: | |
| branches: ["**"] | |
| pull_request: | |
| branches: ["**"] | |
| permissions: | |
| contents: read | |
| jobs: | |
| powershell-lint: | |
| name: Lint (PSScriptAnalyzer) | |
| runs-on: ubuntu-latest | |
| env: | |
| # Keep strict as the template default. Existing repositories with | |
| # warning debt may temporarily opt into first-adoption and should record | |
| # that debt before tightening this value back to strict. | |
| PSSCRIPTANALYZER_GATE_MODE: strict | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v7 | |
| - name: Find PowerShell files | |
| id: find-ps1 | |
| run: | | |
| # Find all .ps1 files in the repository | |
| ps1_files=$(find . -name "*.ps1" -type f 2>/dev/null | grep -v "node_modules" || true) | |
| if [ -z "$ps1_files" ]; then | |
| echo "No PowerShell files found in repository" | |
| echo "found=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "Found PowerShell files:" | |
| echo "$ps1_files" | |
| echo "found=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Install PSScriptAnalyzer | |
| if: steps.find-ps1.outputs.found == 'true' | |
| shell: pwsh | |
| run: | | |
| # PSGallery installs intermittently fail with transient errors (for | |
| # example, "No match was found for the specified search criteria"). | |
| # Retry with exponential backoff so a single flaky response does not | |
| # fail the whole job. | |
| if (-not (Get-Module -ListAvailable -Name PSScriptAnalyzer)) { | |
| $maxAttempts = 5 | |
| $delaySeconds = 5 | |
| for ($attempt = 1; $attempt -le $maxAttempts; $attempt++) { | |
| try { | |
| Install-Module -Name PSScriptAnalyzer -Force -Scope CurrentUser -ErrorAction Stop | |
| break | |
| } catch { | |
| if ($attempt -eq $maxAttempts) { | |
| Write-Error "Install-Module PSScriptAnalyzer failed after $maxAttempts attempt(s): $($_.Exception.Message)" | |
| throw | |
| } | |
| Write-Warning "Install-Module PSScriptAnalyzer attempt $attempt of $maxAttempts failed: $($_.Exception.Message). Retrying in $delaySeconds second(s)..." | |
| Start-Sleep -Seconds $delaySeconds | |
| $delaySeconds = $delaySeconds * 2 | |
| } | |
| } | |
| } | |
| Import-Module PSScriptAnalyzer | |
| - name: Run PSScriptAnalyzer | |
| if: steps.find-ps1.outputs.found == 'true' | |
| shell: pwsh | |
| run: | | |
| $settingsPath = Join-Path -Path $env:GITHUB_WORKSPACE -ChildPath ".github/linting/PSScriptAnalyzerSettings.psd1" | |
| $gateHelperPath = Join-Path -Path $env:GITHUB_WORKSPACE -ChildPath "src/tools/Resolve-PSScriptAnalyzerGate.ps1" | |
| . $gateHelperPath | |
| $ps1Files = Get-ChildItem -LiteralPath $env:GITHUB_WORKSPACE -Filter "*.ps1" -Recurse -File | | |
| Where-Object { $_.FullName -notmatch "node_modules" } | |
| $analyzerFindings = [System.Collections.Generic.List[object]]::new() | |
| foreach ($file in $ps1Files) { | |
| Write-Output "Analyzing: $($file.FullName)" | |
| $analyzerFindings.AddRange(@( | |
| Invoke-ScriptAnalyzer -Path $file.FullName -Settings $settingsPath | |
| )) | |
| } | |
| $gateResult = Resolve-PSScriptAnalyzerGate ` | |
| -Mode $env:PSSCRIPTANALYZER_GATE_MODE ` | |
| -AnalyzerFinding $analyzerFindings | |
| foreach ($annotationCommand in $gateResult.AnnotationCommands) { | |
| Write-Output $annotationCommand | |
| } | |
| Write-Output "" | |
| foreach ($summaryLine in $gateResult.SummaryLines) { | |
| Write-Output $summaryLine | |
| } | |
| if ($gateResult.IssueReadyMarkdown.Count -gt 0) { | |
| Write-Output "" | |
| Write-Output "Issue-ready PSScriptAnalyzer cleanup text:" | |
| foreach ($issueLine in $gateResult.IssueReadyMarkdown) { | |
| Write-Output $issueLine | |
| } | |
| } | |
| if ($gateResult.ShouldFail) { | |
| Write-Output "::error::PSScriptAnalyzer gate failed. See annotations and summary above." | |
| exit 1 | |
| } | |
| Write-Output "PowerShell lint gate passed." | |
| - name: Skip - No PowerShell files | |
| if: steps.find-ps1.outputs.found != 'true' | |
| run: echo "Skipping PSScriptAnalyzer - no PowerShell files found in repository" | |
| # Pester Test Job | |
| # | |
| # Purpose: Run Pester 5.x tests across multiple operating systems | |
| # | |
| # Customization: | |
| # - To change test location, update PESTER_TEST_ROOT in the test job env | |
| # - To change output format, update $config.TestResult.OutputFormat | |
| # - To add test filters, use $config.Filter.* properties | |
| # | |
| # Requirements: | |
| # - Pester test files must use *.Tests.ps1 naming convention | |
| # - Product tests should be placed in tests/PowerShell/ | |
| test: | |
| name: PowerShell Tests (Pester) | |
| runs-on: ${{ matrix.os }} | |
| env: | |
| PESTER_TEST_ROOT: tests/ | |
| strategy: | |
| matrix: | |
| os: [ubuntu-latest, windows-latest, macos-latest] | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v7 | |
| # Keep discovery scoped to PESTER_TEST_ROOT; the canonical rule lives in | |
| # `.github/instructions/powershell.instructions.md` under "Running Pester Tests". | |
| - name: Find Pester test files | |
| id: find-tests | |
| shell: pwsh | |
| run: | | |
| $testRoot = $env:PESTER_TEST_ROOT | |
| if (Test-Path -LiteralPath $testRoot) { | |
| $testFiles = Get-ChildItem -LiteralPath $testRoot -Filter "*.Tests.ps1" -Recurse -File | | |
| Where-Object { $_.FullName -notmatch "node_modules" } | |
| } else { | |
| $testFiles = @() | |
| } | |
| if ($testFiles.Count -eq 0) { | |
| Write-Host "No Pester test files found" | |
| "found=false" | Out-File -FilePath $env:GITHUB_OUTPUT -Append | |
| } else { | |
| Write-Host "Found $($testFiles.Count) Pester test file(s):" | |
| $testFiles | ForEach-Object { Write-Host " - $($_.FullName)" } | |
| "found=true" | Out-File -FilePath $env:GITHUB_OUTPUT -Append | |
| } | |
| - name: Install Pester | |
| if: steps.find-tests.outputs.found == 'true' | |
| shell: pwsh | |
| run: | | |
| # PSGallery installs intermittently fail with transient errors (for | |
| # example, "No match was found for the specified search criteria and | |
| # module name 'Pester'"). Retry with exponential backoff so a single | |
| # flaky response does not fail the whole job. | |
| $maxAttempts = 5 | |
| $delaySeconds = 5 | |
| for ($attempt = 1; $attempt -le $maxAttempts; $attempt++) { | |
| try { | |
| Install-Module -Name Pester -MinimumVersion 5.0 -Force -Scope CurrentUser -ErrorAction Stop | |
| break | |
| } catch { | |
| if ($attempt -eq $maxAttempts) { | |
| Write-Error "Install-Module Pester failed after $maxAttempts attempt(s): $($_.Exception.Message)" | |
| throw | |
| } | |
| Write-Warning "Install-Module Pester attempt $attempt of $maxAttempts failed: $($_.Exception.Message). Retrying in $delaySeconds second(s)..." | |
| Start-Sleep -Seconds $delaySeconds | |
| $delaySeconds = $delaySeconds * 2 | |
| } | |
| } | |
| Import-Module Pester | |
| Write-Host "Pester version: $((Get-Module Pester).Version)" | |
| - name: Run Pester tests | |
| if: steps.find-tests.outputs.found == 'true' | |
| shell: pwsh | |
| run: | | |
| $config = New-PesterConfiguration | |
| # Run tests from the configured test root (includes subdirectories) | |
| $config.Run.Path = $env:PESTER_TEST_ROOT | |
| # Exit with non-zero code if tests fail | |
| $config.Run.Exit = $true | |
| # Enable test result output | |
| $config.TestResult.Enabled = $true | |
| $config.TestResult.OutputFormat = "NUnitXml" | |
| $config.TestResult.OutputPath = "testResults.xml" | |
| # Show detailed output | |
| $config.Output.Verbosity = "Detailed" | |
| Invoke-Pester -Configuration $config | |
| - name: Skip - No Pester tests | |
| if: steps.find-tests.outputs.found != 'true' | |
| run: echo "Skipping Pester tests - no *.Tests.ps1 files found in the configured test root" | |
| module-build: | |
| name: Build Module Artifact | |
| runs-on: ubuntu-latest | |
| needs: [powershell-lint, test] | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v7 | |
| - name: Build staged module artifact | |
| shell: pwsh | |
| run: | | |
| $objBuild = ./scripts/Invoke-IntuneComplianceReportModuleBuild.ps1 ` | |
| -OutputRootPath artifacts/module ` | |
| -Clean | |
| $objBuild | Format-List | |
| - name: Upload staged module artifact | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: IntuneComplianceReport-module | |
| path: artifacts/module/IntuneComplianceReport | |
| if-no-files-found: error | |
| retention-days: 14 |