fix(Get-AdoUserEntitlement): Correct error handling #121
Workflow file for this run
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
| name: Code Analysis and Testing | |
| on: | |
| pull_request: | |
| branches: ['main'] | |
| workflow_dispatch: | |
| jobs: | |
| test: | |
| name: Run Pester Tests | |
| runs-on: ubuntu-latest | |
| outputs: | |
| has_src_changes: ${{ steps.src-changes.outputs.HAS_SRC_CHANGES }} | |
| test_total: ${{ steps.export-metrics.outputs.test_total }} | |
| test_passed: ${{ steps.export-metrics.outputs.test_passed }} | |
| test_failed: ${{ steps.export-metrics.outputs.test_failed }} | |
| analyzer_total: ${{ steps.export-metrics.outputs.analyzer_total }} | |
| analyzer_errors: ${{ steps.export-metrics.outputs.analyzer_errors }} | |
| analyzer_warnings: ${{ steps.export-metrics.outputs.analyzer_warnings }} | |
| coverage_percent: ${{ steps.export-metrics.outputs.coverage_percent }} | |
| steps: | |
| - name: Always run - Workflow initialized | |
| shell: pwsh | |
| run: | | |
| Write-Host "Workflow initialized successfully" -ForegroundColor Green | |
| Write-Host "Event: $env:GITHUB_EVENT_NAME" | |
| Write-Host "Branch: $env:GITHUB_REF_NAME" | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Check for src changes | |
| id: src-changes | |
| shell: pwsh | |
| run: | | |
| if ($env:GITHUB_EVENT_NAME -eq 'pull_request') { | |
| $baseSha = "${{ github.event.pull_request.base.sha }}" | |
| $headSha = "${{ github.event.pull_request.head.sha }}" | |
| $changedFiles = git diff --name-only $baseSha $headSha | |
| } elseif ($env:GITHUB_EVENT_NAME -eq 'push') { | |
| $changedFiles = git diff --name-only ${{ github.event.before }} ${{ github.sha }} | |
| } else { | |
| # For workflow_dispatch or other events, assume src changes | |
| "HAS_SRC_CHANGES=true" | Out-File -FilePath $env:GITHUB_OUTPUT -Append | |
| Write-Host "Manual trigger detected, running all steps" | |
| exit 0 | |
| } | |
| Write-Host "Changed files:" | |
| $changedFiles | ForEach-Object { Write-Host " $_" } | |
| $srcChanged = $changedFiles | Where-Object { $_ -like 'src/**' -and $_ -notlike 'src/Azure.DevOps.PSModule/Tests/**' } | |
| if ($srcChanged) { | |
| "HAS_SRC_CHANGES=true" | Out-File -FilePath $env:GITHUB_OUTPUT -Append | |
| Write-Host "Source files changed - running all steps" -ForegroundColor Cyan | |
| } else { | |
| "HAS_SRC_CHANGES=false" | Out-File -FilePath $env:GITHUB_OUTPUT -Append | |
| Write-Host "No source files changed - skipping analysis and tests" -ForegroundColor Yellow | |
| } | |
| - name: Setup PowerShell | |
| if: steps.src-changes.outputs.HAS_SRC_CHANGES == 'true' | |
| shell: pwsh | |
| run: | | |
| Write-Host "PowerShell Version: $($PSVersionTable.PSVersion)" | |
| Write-Host "OS: $($PSVersionTable.OS)" | |
| - name: Verify required modules | |
| if: steps.src-changes.outputs.HAS_SRC_CHANGES == 'true' | |
| shell: pwsh | |
| run: | | |
| Write-Host "Installing required module dependencies..." | |
| Install-Module -Name Az.Accounts -Force -SkipPublisherCheck -Scope CurrentUser | |
| Write-Host "Az.Accounts installed successfully" | |
| Write-Host "PowerShell Modules Available:" | |
| Get-Module -Name Pester -ListAvailable | Select-Object Name, Version | |
| Get-Module -Name PSScriptAnalyzer -ListAvailable | Select-Object Name, Version | |
| Get-Module -Name Az.Accounts -ListAvailable | Select-Object Name, Version | |
| - name: Run PSScriptAnalyzer | |
| if: steps.src-changes.outputs.HAS_SRC_CHANGES == 'true' | |
| continue-on-error: true | |
| shell: pwsh | |
| run: | | |
| Write-Host "Running PSScriptAnalyzer..." -ForegroundColor Cyan | |
| $sourcePath = Join-Path $env:GITHUB_WORKSPACE "src" | |
| $settingsPath = Join-Path $env:GITHUB_WORKSPACE "src/PSScriptAnalyzerSettings.psd1" | |
| # Exclude unit test files (*.Tests.ps1) but include test helper files | |
| $filesToAnalyze = Get-ChildItem -Path $sourcePath -Recurse -Include '*.ps1', '*.psm1', '*.psd1' | | |
| Where-Object { $_.Name -notlike '*.Tests.ps1' } | |
| $results = $filesToAnalyze | Invoke-ScriptAnalyzer -Settings $settingsPath | |
| if ($results) { | |
| $errors = ($results | Where-Object Severity -eq 'Error').Count | |
| $warnings = ($results | Where-Object Severity -eq 'Warning').Count | |
| Write-Host "Analysis Results:" -ForegroundColor Yellow | |
| Write-Host " Total Issues: $($results.Count)" | |
| Write-Host " Errors: $errors" | |
| Write-Host " Warnings: $warnings" | |
| $results | Format-Table -AutoSize | |
| # Store analysis results for badge generation | |
| "ANALYZER_TOTAL=$($filesToAnalyze.Count)" | Out-File -FilePath $env:GITHUB_ENV -Append | |
| "ANALYZER_ERRORS=$errors" | Out-File -FilePath $env:GITHUB_ENV -Append | |
| "ANALYZER_WARNINGS=$warnings" | Out-File -FilePath $env:GITHUB_ENV -Append | |
| if ($errors -gt 0) { | |
| Write-Error "PSScriptAnalyzer found $errors error(s). Build failed." | |
| # exit 1 | |
| } | |
| } else { | |
| Write-Host "No issues found!" -ForegroundColor Green | |
| "ANALYZER_TOTAL=$($filesToAnalyze.Count)" | Out-File -FilePath $env:GITHUB_ENV -Append | |
| "ANALYZER_ERRORS=0" | Out-File -FilePath $env:GITHUB_ENV -Append | |
| "ANALYZER_WARNINGS=0" | Out-File -FilePath $env:GITHUB_ENV -Append | |
| } | |
| - name: Run Pester Tests | |
| if: steps.src-changes.outputs.HAS_SRC_CHANGES == 'true' | |
| continue-on-error: true | |
| shell: pwsh | |
| run: | | |
| Write-Host "Running Pester Tests..." -ForegroundColor Cyan | |
| # Add the module to PSModulePath so tests can import it | |
| $modulePath = Join-Path $env:GITHUB_WORKSPACE "src" | |
| $env:PSModulePath = "$modulePath$([System.IO.Path]::PathSeparator)$env:PSModulePath" | |
| Write-Host "Module path added to PSModulePath: $modulePath" | |
| $codePath = Join-Path $env:GITHUB_WORKSPACE "src\Azure.DevOps.PSModule" | |
| $testsPath = Join-Path $env:GITHUB_WORKSPACE "src\Azure.DevOps.PSModule\Tests" | |
| $config = New-PesterConfiguration | |
| $config.Run.Path = $testsPath | |
| $config.Run.Exit = $false | |
| $config.Run.PassThru = $true | |
| $config.TestResult.Enabled = $true | |
| $config.TestResult.OutputPath = 'testResults.xml' | |
| $config.CodeCoverage.Enabled = $true | |
| $config.CodeCoverage.Path = @( | |
| (Join-Path $codePath "Public\**\*.ps1"), | |
| (Join-Path $codePath "Private\**\*.ps1"), | |
| (Join-Path $codePath "*.psm1") | |
| ) | |
| $config.CodeCoverage.OutputFormat = 'JaCoCo' | |
| $config.CodeCoverage.OutputPath = 'coverage.xml' | |
| $config.Output.Verbosity = 'Detailed' | |
| $result = Invoke-Pester -Configuration $config | |
| # Extract test counts | |
| $totalTests = $result.TotalCount | |
| $passedTests = $result.PassedCount | |
| $failedTests = $result.FailedCount | |
| # Extract code coverage metrics | |
| $coverage = $result.CodeCoverage | |
| $coveragePercent = '{0:F0}' -f $coverage.CoveragePercent | |
| Write-Host "Code Coverage: $coveragePercent%" -ForegroundColor Cyan | |
| # Store test results for badge generation | |
| "TEST_TOTAL=$totalTests" | Out-File -FilePath $env:GITHUB_ENV -Append | |
| "TEST_PASSED=$passedTests" | Out-File -FilePath $env:GITHUB_ENV -Append | |
| "TEST_FAILED=$failedTests" | Out-File -FilePath $env:GITHUB_ENV -Append | |
| "COVERAGE_PERCENT=$coveragePercent" | Out-File -FilePath $env:GITHUB_ENV -Append | |
| if ($failedTests -gt 0) { | |
| Write-Error "Pester tests found $failedTests error(s). Build failed." | |
| # exit 1 | |
| } | |
| Write-Host "All tests passed! Total: $totalTests, Passed: $passedTests" -ForegroundColor Green | |
| - name: Generate badge data | |
| if: steps.src-changes.outputs.HAS_SRC_CHANGES == 'true' | |
| shell: pwsh | |
| run: | | |
| Write-Host "Generating badge data..." -ForegroundColor Cyan | |
| # Cast environment variables to integers | |
| $testTotal = [int]$env:TEST_TOTAL | |
| $testPassed = [int]$env:TEST_PASSED | |
| $testFailed = [int]$env:TEST_FAILED | |
| $analyzerTotal = [int]$env:ANALYZER_TOTAL | |
| $analyzerErrors = [int]$env:ANALYZER_ERRORS | |
| $analyzerWarnings = [int]$env:ANALYZER_WARNINGS | |
| # Test badge | |
| $testColor = if ($testFailed -eq 0) { 'brightgreen' } else { 'red' } | |
| $testMessage = if ($testFailed -eq 0) { "$testPassed passing" } else { "$testFailed / $testTotal failing" } | |
| $testBadge = @{ | |
| schemaVersion = 1 | |
| label = 'code tests' | |
| message = $testMessage | |
| color = $testColor | |
| } | |
| $testBadge | ConvertTo-Json | Out-File -FilePath 'test-badge.json' -Encoding utf8 | |
| # Code analysis badge | |
| $analysisColor = if ($analyzerErrors -eq 0 -and $analyzerWarnings -eq 0) { 'brightgreen' } elseif ($analyzerErrors -eq 0) { 'yellow' } else { 'red' } | |
| $analysisMessage = if ($analyzerErrors -eq 0 -and $analyzerWarnings -eq 0) { "$analyzerTotal total" } elseif ($analyzerErrors -eq 0) { "0 errors, $analyzerWarnings warnings" } else { "$analyzerErrors errors, $analyzerWarnings warnings" } | |
| $analysisBadge = @{ | |
| schemaVersion = 1 | |
| label = 'code analysis' | |
| message = $analysisMessage | |
| color = $analysisColor | |
| } | |
| $analysisBadge | ConvertTo-Json | Out-File -FilePath 'analysis-badge.json' -Encoding utf8 | |
| # Code coverage badge | |
| $coveragePercent = [int]$env:COVERAGE_PERCENT | |
| $coverageColor = if ($coveragePercent -ge 80) { 'brightgreen' } elseif ($coveragePercent -ge 60) { 'green' } elseif ($coveragePercent -ge 40) { 'yellow' } else { 'red' } | |
| $coverageMessage = "$coveragePercent%" | |
| $coverageBadge = @{ | |
| schemaVersion = 1 | |
| label = 'code coverage' | |
| message = $coverageMessage | |
| color = $coverageColor | |
| } | |
| $coverageBadge | ConvertTo-Json | Out-File -FilePath 'coverage-badge.json' -Encoding utf8 | |
| Write-Host "Badge data generated successfully" -ForegroundColor Green | |
| - name: Upload test results | |
| if: steps.src-changes.outputs.HAS_SRC_CHANGES == 'true' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: test-results | |
| path: testResults.xml | |
| - name: Upload coverage results | |
| if: steps.src-changes.outputs.HAS_SRC_CHANGES == 'true' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: coverage-results | |
| path: coverage.xml | |
| - name: Export badge metrics | |
| if: steps.src-changes.outputs.HAS_SRC_CHANGES == 'true' | |
| id: export-metrics | |
| shell: pwsh | |
| run: | | |
| "test_total=$env:TEST_TOTAL" | Out-File -FilePath $env:GITHUB_OUTPUT -Append | |
| "test_passed=$env:TEST_PASSED" | Out-File -FilePath $env:GITHUB_OUTPUT -Append | |
| "test_failed=$env:TEST_FAILED" | Out-File -FilePath $env:GITHUB_OUTPUT -Append | |
| "analyzer_total=$env:ANALYZER_TOTAL" | Out-File -FilePath $env:GITHUB_OUTPUT -Append | |
| "analyzer_errors=$env:ANALYZER_ERRORS" | Out-File -FilePath $env:GITHUB_OUTPUT -Append | |
| "analyzer_warnings=$env:ANALYZER_WARNINGS" | Out-File -FilePath $env:GITHUB_OUTPUT -Append | |
| "coverage_percent=$env:COVERAGE_PERCENT" | Out-File -FilePath $env:GITHUB_OUTPUT -Append | |
| - name: Run final results summary | |
| if: steps.src-changes.outputs.HAS_SRC_CHANGES == 'true' | |
| shell: pwsh | |
| run: | | |
| Write-Host "Running final results summary..." -ForegroundColor Cyan | |
| # Cast environment variables to integers | |
| $analyzerErrors = [int]$env:ANALYZER_ERRORS | |
| $testFailed = [int]$env:TEST_FAILED | |
| if (($analyzerErrors -gt 0) -or ($testFailed -gt 0)) { | |
| Write-Error "One or more checks failed. See workflow steps for details." | |
| exit 1 | |
| } | |
| Write-Host "All checks passed successfully!" -ForegroundColor Green | |
| badges: | |
| name: Publish Badges | |
| runs-on: ubuntu-latest | |
| needs: test | |
| if: >- | |
| ${{ | |
| needs.test.outputs.has_src_changes == 'true' && success() && | |
| (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) | |
| }} | |
| steps: | |
| - name: Verify gist access | |
| shell: pwsh | |
| run: | | |
| $token = "${{ secrets.GIST_TOKEN }}" | |
| $gistId = "${{ secrets.GIST_ID }}" | |
| if ([string]::IsNullOrWhiteSpace($token) -or [string]::IsNullOrWhiteSpace($gistId)) { | |
| Write-Error "Required gist secrets are missing. Ensure both GIST_TOKEN and GIST_ID are defined." | |
| exit 1 | |
| } | |
| $uri = "https://api.github.com/gists/$gistId" | |
| $headers = @{ Authorization = "token $token" } | |
| try { | |
| $response = Invoke-RestMethod -Uri $uri -Headers $headers -ErrorAction Stop | |
| Write-Host "Verified gist '$gistId' - description: $($response.description)" -ForegroundColor Green | |
| } | |
| catch { | |
| Write-Error "Unable to reach gist '$gistId': $($_.Exception.Message)" | |
| throw | |
| } | |
| - name: Create pester tests badge gist | |
| uses: schneegans/dynamic-badges-action@v1.7.0 | |
| with: | |
| auth: ${{ secrets.GIST_TOKEN }} | |
| gistID: ${{ secrets.GIST_ID }} | |
| filename: az-devops-psmodule-test-badge.json | |
| label: code tests | |
| message: ${{ needs.test.outputs.test_failed == '0' && format('{0}', needs.test.outputs.test_passed) || format('{0} failing, {1} passing', needs.test.outputs.test_failed, needs.test.outputs.test_passed) }} | |
| color: ${{ needs.test.outputs.test_failed == '0' && 'brightgreen' || 'red' }} | |
| forceUpdate: true | |
| - name: Create analysis badge gist | |
| uses: schneegans/dynamic-badges-action@v1.7.0 | |
| with: | |
| auth: ${{ secrets.GIST_TOKEN }} | |
| gistID: ${{ secrets.GIST_ID }} | |
| filename: az-devops-psmodule-analysis-badge.json | |
| label: code analysis | |
| message: ${{ needs.test.outputs.analyzer_errors == '0' && needs.test.outputs.analyzer_warnings == '0' && format('{0}', needs.test.outputs.analyzer_total) || needs.test.outputs.analyzer_errors == '0' && format('0 errors, {0} warnings', needs.test.outputs.analyzer_warnings) || format('{0} errors, {1} warnings', needs.test.outputs.analyzer_errors, needs.test.outputs.analyzer_warnings) }} | |
| color: ${{ needs.test.outputs.analyzer_errors == '0' && needs.test.outputs.analyzer_warnings == '0' && 'brightgreen' || needs.test.outputs.analyzer_errors == '0' && 'yellow' || 'red' }} | |
| forceUpdate: true | |
| - name: Create coverage badge gist | |
| uses: schneegans/dynamic-badges-action@v1.7.0 | |
| with: | |
| auth: ${{ secrets.GIST_TOKEN }} | |
| gistID: ${{ secrets.GIST_ID }} | |
| filename: az-devops-psmodule-coverage-badge.json | |
| label: code coverage | |
| message: ${{ format('{0}%', needs.test.outputs.coverage_percent) }} | |
| color: ${{ needs.test.outputs.coverage_percent >= 80 && 'brightgreen' || needs.test.outputs.coverage_percent >= 60 && 'green' || needs.test.outputs.coverage_percent >= 40 && 'yellow' || 'red' }} | |
| forceUpdate: true |