Skip to content

Commit 5072205

Browse files
Refactor and enhance Pester tests batch (#9762)
1 parent 072e653 commit 5072205

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+4937
-3019
lines changed

.aitools/aitools.psm1

Lines changed: 0 additions & 1999 deletions
This file was deleted.
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
function Get-AppVeyorFailure {
2+
<#
3+
.SYNOPSIS
4+
Retrieves test failure information from AppVeyor builds.
5+
6+
.DESCRIPTION
7+
This function fetches test failure details from AppVeyor builds, either by specifying
8+
pull request numbers or a specific build number. It extracts failed test information
9+
from build artifacts and returns detailed failure data for analysis.
10+
11+
.PARAMETER PullRequest
12+
Array of pull request numbers to process. If not specified and no BuildNumber is provided,
13+
processes all open pull requests with AppVeyor failures.
14+
15+
.PARAMETER BuildNumber
16+
Specific AppVeyor build number to target instead of automatically detecting from PR checks.
17+
When specified, retrieves failures directly from this build number, ignoring PR-based detection.
18+
19+
.NOTES
20+
Tags: Testing, AppVeyor, CI, PullRequest
21+
Author: dbatools team
22+
Requires: AppVeyor API access, gh CLI
23+
24+
.EXAMPLE
25+
PS C:\> Get-AppVeyorFailure
26+
Retrieves test failures from all open pull requests with AppVeyor failures.
27+
28+
.EXAMPLE
29+
PS C:\> Get-AppVeyorFailure -PullRequest 9234
30+
Retrieves test failures from AppVeyor builds associated with PR #9234.
31+
32+
.EXAMPLE
33+
PS C:\> Get-AppVeyorFailure -PullRequest 9234, 9235
34+
Retrieves test failures from AppVeyor builds associated with PRs #9234 and #9235.
35+
36+
.EXAMPLE
37+
PS C:\> Get-AppVeyorFailure -BuildNumber 12345
38+
Retrieves test failures directly from AppVeyor build #12345, bypassing PR detection.
39+
#>
40+
[CmdletBinding()]
41+
param (
42+
[int[]]$PullRequest,
43+
44+
[int]$BuildNumber
45+
)
46+
47+
# If BuildNumber is specified, use it directly instead of looking up PR checks
48+
if ($BuildNumber) {
49+
Write-Progress -Activity "Get-AppVeyorFailure" -Status "Fetching build details for build #$BuildNumber..." -PercentComplete 0
50+
Write-Verbose "Using specified build number: $BuildNumber"
51+
52+
try {
53+
$apiParams = @{
54+
Endpoint = "projects/dataplat/dbatools/builds/$BuildNumber"
55+
}
56+
$build = Invoke-AppVeyorApi @apiParams
57+
58+
if (-not $build -or -not $build.build -or -not $build.build.jobs) {
59+
Write-Verbose "No build data or jobs found for build $BuildNumber"
60+
Write-Progress -Activity "Get-AppVeyorFailure" -Completed
61+
return
62+
}
63+
64+
$failedJobs = $build.build.jobs | Where-Object Status -eq "failed"
65+
66+
if (-not $failedJobs) {
67+
Write-Verbose "No failed jobs found in build $BuildNumber"
68+
Write-Progress -Activity "Get-AppVeyorFailure" -Completed
69+
return
70+
}
71+
72+
$totalJobs = $failedJobs.Count
73+
$currentJob = 0
74+
75+
foreach ($job in $failedJobs) {
76+
$currentJob++
77+
$jobProgress = [math]::Round(($currentJob / $totalJobs) * 100)
78+
Write-Progress -Activity "Getting job failure information" -Status "Processing failed job $currentJob of $totalJobs for build #$BuildNumber" -PercentComplete $jobProgress -CurrentOperation "Job: $($job.name)"
79+
Write-Verbose "Processing failed job: $($job.name) (ID: $($job.jobId))"
80+
(Get-TestArtifact -JobId $job.jobid).Content.Failures
81+
}
82+
} catch {
83+
Write-Verbose "Failed to fetch AppVeyor build details for build ${BuildNumber}: $_"
84+
}
85+
86+
Write-Progress -Activity "Get-AppVeyorFailure" -Completed
87+
return
88+
}
89+
90+
# Original logic for PR-based build detection
91+
if (-not $PullRequest) {
92+
Write-Progress -Activity "Get-AppVeyorFailure" -Status "Fetching open pull requests..." -PercentComplete 0
93+
Write-Verbose "No pull request numbers specified, getting all open PRs..."
94+
$prsJson = gh pr list --state open --json "number,title,headRefName,state,statusCheckRollup"
95+
if (-not $prsJson) {
96+
Write-Progress -Activity "Get-AppVeyorFailure" -Completed
97+
Write-Warning "No open pull requests found"
98+
return
99+
}
100+
$openPRs = $prsJson | ConvertFrom-Json
101+
$PullRequest = $openPRs | ForEach-Object { $_.number }
102+
Write-Verbose "Found $($PullRequest.Count) open PRs: $($PullRequest -join ',')"
103+
}
104+
105+
$totalPRs = $PullRequest.Count
106+
$currentPR = 0
107+
108+
foreach ($prNumber in $PullRequest) {
109+
$currentPR++
110+
$prPercentComplete = [math]::Round(($currentPR / $totalPRs) * 100)
111+
Write-Progress -Activity "Getting PR build information" -Status "Processing PR #$prNumber ($currentPR of $totalPRs)" -PercentComplete $prPercentComplete
112+
Write-Verbose "Fetching AppVeyor build information for PR #$prNumber"
113+
114+
$checksJson = gh pr checks $prNumber --json "name,state,link" 2>$null
115+
if (-not $checksJson) {
116+
Write-Verbose "Could not fetch checks for PR #$prNumber"
117+
continue
118+
}
119+
120+
$checks = $checksJson | ConvertFrom-Json
121+
$appveyorCheck = $checks | Where-Object { $_.name -like "*AppVeyor*" -and $_.state -match "PENDING|FAILURE" }
122+
123+
if (-not $appveyorCheck) {
124+
Write-Verbose "No failing or pending AppVeyor builds found for PR #$prNumber"
125+
continue
126+
}
127+
128+
if ($appveyorCheck.link -match '/project/[^/]+/[^/]+/builds/(\d+)') {
129+
$buildId = $Matches[1]
130+
} else {
131+
Write-Verbose "Could not parse AppVeyor build ID from URL: $($appveyorCheck.link)"
132+
continue
133+
}
134+
135+
try {
136+
Write-Progress -Activity "Getting build details" -Status "Fetching build details for PR #$prNumber" -PercentComplete $prPercentComplete
137+
Write-Verbose "Fetching build details for build ID: $buildId"
138+
139+
$apiParams = @{
140+
Endpoint = "projects/dataplat/dbatools/builds/$buildId"
141+
}
142+
$build = Invoke-AppVeyorApi @apiParams
143+
144+
if (-not $build -or -not $build.build -or -not $build.build.jobs) {
145+
Write-Verbose "No build data or jobs found for build $buildId"
146+
continue
147+
}
148+
149+
$failedJobs = $build.build.jobs | Where-Object Status -eq "failed"
150+
151+
if (-not $failedJobs) {
152+
Write-Verbose "No failed jobs found in build $buildId"
153+
continue
154+
}
155+
156+
$totalJobs = $failedJobs.Count
157+
$currentJob = 0
158+
159+
foreach ($job in $failedJobs) {
160+
$currentJob++
161+
Write-Progress -Activity "Getting job failure information" -Status "Processing failed job $currentJob of $totalJobs for PR #$prNumber" -PercentComplete $prPercentComplete -CurrentOperation "Job: $($job.name)"
162+
Write-Verbose "Processing failed job: $($job.name) (ID: $($job.jobId))"
163+
(Get-TestArtifact -JobId $job.jobid).Content.Failures
164+
}
165+
} catch {
166+
Write-Verbose "Failed to fetch AppVeyor build details for build ${buildId}: $_"
167+
continue
168+
}
169+
}
170+
171+
Write-Progress -Activity "Get-AppVeyorFailure" -Completed
172+
}

.aitools/module/Get-TestArtifact.ps1

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
function Get-TestArtifact {
2+
<#
3+
.SYNOPSIS
4+
Gets test artifacts from an AppVeyor job.
5+
6+
.DESCRIPTION
7+
Retrieves test failure summary artifacts from an AppVeyor job.
8+
9+
.PARAMETER JobId
10+
The AppVeyor job ID to get artifacts from.
11+
12+
.NOTES
13+
Tags: AppVeyor, Testing, Artifacts
14+
Author: dbatools team
15+
Requires: APPVEYOR_API_TOKEN environment variable
16+
#>
17+
[CmdletBinding()]
18+
param(
19+
[Parameter(ValueFromPipeline)]
20+
[string[]]$JobId
21+
)
22+
23+
function Get-JsonFromContent {
24+
param([Parameter(ValueFromPipeline)]$InputObject)
25+
process {
26+
if ($null -eq $InputObject) { return $null }
27+
28+
# AppVeyor often returns PSCustomObject with .Content (string) and .Created
29+
$raw = if ($InputObject -is [string] -or $InputObject -is [byte[]]) {
30+
$InputObject
31+
} elseif ($InputObject.PSObject.Properties.Name -contains 'Content') {
32+
$InputObject.Content
33+
} else {
34+
[string]$InputObject
35+
}
36+
37+
$s = if ($raw -is [byte[]]) { [Text.Encoding]::UTF8.GetString($raw) } else { [string]$raw }
38+
$s = $s.TrimStart([char]0xFEFF) # strip BOM
39+
if ($s -notmatch '^\s*[\{\[]') {
40+
throw "Artifact body is not JSON. Starts with: '$($s.Substring(0,1))'."
41+
}
42+
$s | ConvertFrom-Json -Depth 50
43+
}
44+
}
45+
46+
foreach ($id in $JobId) {
47+
Write-Verbose ("Fetching artifacts for job {0}" -f $id)
48+
$list = Invoke-AppVeyorApi "buildjobs/$id/artifacts"
49+
if (-not $list) { Write-Warning ("No artifacts for job {0}" -f $id); continue }
50+
51+
$targets = $list | Where-Object { $_.fileName -match 'TestFailureSummary.*\.json' }
52+
if (-not $targets) {
53+
continue
54+
}
55+
56+
foreach ($art in $targets) {
57+
$resp = Invoke-AppVeyorApi "buildjobs/$id/artifacts/$($art.fileName)"
58+
59+
$parsed = $null
60+
$rawOut = $null
61+
$created = if ($resp.PSObject.Properties.Name -contains 'Created') { $resp.Created } else { $art.created }
62+
63+
try {
64+
$parsed = $resp | Get-JsonFromContent
65+
} catch {
66+
$rawOut = if ($resp.PSObject.Properties.Name -contains 'Content') { [string]$resp.Content } else { [string]$resp }
67+
Write-Warning ("Failed to parse {0} in job {1}: {2}" -f $art.fileName, $id, $_.Exception.Message)
68+
}
69+
70+
[pscustomobject]@{
71+
JobId = $id
72+
FileName = $art.fileName
73+
Type = $art.type
74+
Size = $art.size
75+
Created = $created
76+
Content = $parsed
77+
Raw = $rawOut
78+
}
79+
}
80+
}
81+
}

0 commit comments

Comments
 (0)