Skip to content

fix(Get-AdoUserEntitlement): Correct error handling #121

fix(Get-AdoUserEntitlement): Correct error handling

fix(Get-AdoUserEntitlement): Correct error handling #121

Workflow file for this run

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