2222
2323env :
2424 DOTNET_VERSION : " 10.0.103"
25+ BASELINE_BRANCH : " next"
2526
2627permissions :
2728 contents : read
@@ -68,39 +69,45 @@ jobs:
6869
6970 - name : Restore benchmark project
7071 if : steps.run_gate.outputs.should_run == 'true'
71- run : dotnet restore src/FastCloner.Benchmark.CI/FastCloner.Benchmark.CI.csproj
72+ working-directory : src
73+ run : dotnet restore FastCloner.Benchmark.CI/FastCloner.Benchmark.CI.csproj
7274
7375 - name : Run deep clone benchmarks
7476 if : steps.run_gate.outputs.should_run == 'true'
77+ working-directory : src
7578 shell : pwsh
7679 run : >
77- dotnet run -c Release --project src/ FastCloner.Benchmark.CI/FastCloner.Benchmark.CI.csproj -- --filter *DeepCloneBenchmarks*
80+ dotnet run -c Release --project FastCloner.Benchmark.CI/FastCloner.Benchmark.CI.csproj -- --filter *DeepCloneBenchmarks*
7881
7982 - name : Resolve benchmark CSV path
8083 if : steps.run_gate.outputs.should_run == 'true'
8184 shell : pwsh
8285 run : |
83- $csv = Get-ChildItem -Path "BenchmarkDotNet.Artifacts/results" -Filter "*DeepCloneBenchmarks-report.csv" -Recurse |
86+ $csv = Get-ChildItem -Path "src/ BenchmarkDotNet.Artifacts/results" -Filter "*DeepCloneBenchmarks-report.csv" -Recurse |
8487 Sort-Object LastWriteTime -Descending |
8588 Select-Object -First 1
8689 if (-not $csv) {
8790 throw "Could not find BenchmarkDotNet CSV output for DeepCloneBenchmarks."
8891 }
8992
9093 "BENCHMARK_CSV=$($csv.FullName)" | Out-File -FilePath $env:GITHUB_ENV -Append
91- "RESULT_DIR=benchmark-results/${{ matrix.os }}" | Out-File -FilePath $env:GITHUB_ENV -Append
94+ "RESULT_DIR=$($env:GITHUB_WORKSPACE)/src/ benchmark-results/${{ matrix.os }}" | Out-File -FilePath $env:GITHUB_ENV -Append
9295
93- - name : Download latest baseline from next
96+ - name : Download latest baseline artifact
9497 if : steps.run_gate.outputs.should_run == 'true' && github.event_name == 'pull_request'
98+ id : baseline_lookup
9599 shell : pwsh
96100 env :
97101 GH_TOKEN : ${{ github.token }}
98102 run : |
99103 $repo = "${{ github.repository }}"
100104 $workflowFile = "benchmark.yml"
101105 $artifactName = "deepclone-baseline-${{ matrix.os }}"
106+ $baselineBranch = "${{ env.BASELINE_BRANCH }}"
107+
108+ "baseline_branch=$baselineBranch" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
102109
103- $runsResponse = gh api "repos/$repo/actions/workflows/$workflowFile/runs?branch=next &event=push&status=success&per_page=50"
110+ $runsResponse = gh api "repos/$repo/actions/workflows/$workflowFile/runs?branch=$baselineBranch &event=push&status=success&per_page=50"
104111 $runs = ($runsResponse | ConvertFrom-Json).workflow_runs
105112 $baselineRunId = $null
106113
@@ -121,7 +128,9 @@ jobs:
121128 }
122129
123130 if (-not $baselineRunId) {
124- Write-Host "No baseline artifact found for '$artifactName'."
131+ Write-Host "No baseline artifact found for '$artifactName' on branch '$baselineBranch'. Falling back to slow-path baseline generation."
132+ "baseline_found=false" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
133+ "baseline_needs_slow_path=true" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
125134 exit 0
126135 }
127136
@@ -132,20 +141,68 @@ jobs:
132141 if ($baselineJson) {
133142 "BASELINE_JSON=$($baselineJson.FullName)" | Out-File -FilePath $env:GITHUB_ENV -Append
134143 Write-Host "Using baseline: $($baselineJson.FullName)"
144+ "baseline_found=true" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
145+ "baseline_needs_slow_path=false" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
135146 } else {
136- Write-Host "Downloaded baseline artifact but current-normalized.json was not found."
147+ Write-Host "Downloaded baseline artifact but current-normalized.json was not found. Falling back to slow-path baseline generation."
148+ "baseline_found=false" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
149+ "baseline_needs_slow_path=true" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
150+ }
151+
152+ - name : Clone baseline branch for slow-path comparison
153+ if : steps.run_gate.outputs.should_run == 'true' && github.event_name == 'pull_request' && steps.baseline_lookup.outputs.baseline_needs_slow_path == 'true'
154+ shell : pwsh
155+ run : |
156+ $repo = "${{ github.repository }}"
157+ $baselineBranch = "${{ steps.baseline_lookup.outputs.baseline_branch }}"
158+
159+ if (Test-Path baseline-repo) {
160+ Remove-Item -Recurse -Force baseline-repo
161+ }
162+
163+ git clone --depth 1 --branch $baselineBranch "https://github.com/$repo.git" baseline-repo
164+
165+ - name : Restore slow-path baseline benchmark project
166+ if : steps.run_gate.outputs.should_run == 'true' && github.event_name == 'pull_request' && steps.baseline_lookup.outputs.baseline_needs_slow_path == 'true'
167+ working-directory : baseline-repo/src
168+ run : dotnet restore FastCloner.Benchmark.CI/FastCloner.Benchmark.CI.csproj
169+
170+ - name : Run slow-path baseline benchmarks
171+ if : steps.run_gate.outputs.should_run == 'true' && github.event_name == 'pull_request' && steps.baseline_lookup.outputs.baseline_needs_slow_path == 'true'
172+ working-directory : baseline-repo/src
173+ shell : pwsh
174+ run : >
175+ dotnet run -c Release --project FastCloner.Benchmark.CI/FastCloner.Benchmark.CI.csproj -- --filter *DeepCloneBenchmarks*
176+
177+ - name : Generate slow-path baseline normalized report
178+ if : steps.run_gate.outputs.should_run == 'true' && github.event_name == 'pull_request' && steps.baseline_lookup.outputs.baseline_needs_slow_path == 'true'
179+ working-directory : baseline-repo/src
180+ shell : pwsh
181+ run : |
182+ $csv = Get-ChildItem -Path "BenchmarkDotNet.Artifacts/results" -Filter "*DeepCloneBenchmarks-report.csv" -Recurse |
183+ Sort-Object LastWriteTime -Descending |
184+ Select-Object -First 1
185+ if (-not $csv) {
186+ throw "Could not find BenchmarkDotNet CSV output for slow-path baseline benchmarks."
137187 }
138188
189+ dotnet run -c Release --project FastCloner.Benchmark.CI/FastCloner.Benchmark.CI.csproj -- --report --csv $csv.FullName --normalized-json benchmark-results/current-normalized.json
190+
191+ $baselineJson = Resolve-Path "benchmark-results/current-normalized.json"
192+ "BASELINE_JSON=$($baselineJson.Path)" | Out-File -FilePath $env:GITHUB_ENV -Append
193+ Write-Host "Generated slow-path baseline: $($baselineJson.Path)"
194+
139195 - name : Generate normalized report and diff
140196 if : steps.run_gate.outputs.should_run == 'true'
197+ working-directory : src
141198 shell : pwsh
142199 run : |
143200 New-Item -ItemType Directory -Force -Path $env:RESULT_DIR | Out-Null
144201
145202 $args = @(
146203 "run",
147204 "-c", "Release",
148- "--project", "src/ FastCloner.Benchmark.CI/FastCloner.Benchmark.CI.csproj",
205+ "--project", "FastCloner.Benchmark.CI/FastCloner.Benchmark.CI.csproj",
149206 "--",
150207 "--report",
151208 "--csv", $env:BENCHMARK_CSV,
@@ -177,8 +234,8 @@ jobs:
177234 with :
178235 name : deepclone-results-${{ matrix.os }}
179236 path : |
180- benchmark-results/${{ matrix.os }}/**
181- BenchmarkDotNet.Artifacts/results/*DeepCloneBenchmarks*
237+ src/ benchmark-results/${{ matrix.os }}/**
238+ src/ BenchmarkDotNet.Artifacts/results/*DeepCloneBenchmarks*
182239 if-no-files-found : warn
183240 retention-days : 30
184241
@@ -187,7 +244,7 @@ jobs:
187244 uses : actions/upload-artifact@v4
188245 with :
189246 name : deepclone-baseline-${{ matrix.os }}
190- path : benchmark-results/${{ matrix.os }}/current-normalized.json
247+ path : src/ benchmark-results/${{ matrix.os }}/current-normalized.json
191248 if-no-files-found : error
192249 retention-days : 30
193250
@@ -198,15 +255,42 @@ jobs:
198255 GH_TOKEN : ${{ github.token }}
199256 run : |
200257 $commentPath = "$env:RESULT_DIR/pr-comment.md"
201- if (-not (Test-Path $commentPath)) {
202- throw "PR comment report not found: $commentPath"
203- }
204-
205258 $marker = "<!-- deepclone-benchmark-report -->"
206- $body = $marker + "`n" + (Get-Content $commentPath -Raw)
207259 $repo = "${{ github.repository }}"
208260 $prNumber = "${{ github.event.pull_request.number }}"
209261
262+ if (Test-Path $commentPath) {
263+ $body = $marker + "`n" + (Get-Content $commentPath -Raw)
264+ } else {
265+ $summaryPath = "$env:RESULT_DIR/summary.md"
266+ $currentReportPath = "$env:RESULT_DIR/current-report.md"
267+
268+ $fallback = @(
269+ '## Deep Clone Benchmarks'
270+ ''
271+ '- OS: `${{ matrix.os }}`'
272+ '- Detailed PR benchmark report was not generated for this run.'
273+ )
274+
275+ if (Test-Path $summaryPath) {
276+ $fallback += ""
277+ $fallback += "### Summary"
278+ $fallback += ""
279+ $fallback += (Get-Content $summaryPath -Raw)
280+ } elseif (Test-Path $currentReportPath) {
281+ $fallback += ""
282+ $fallback += "### Current FastCloner vs DeepCloner"
283+ $fallback += ""
284+ $fallback += (Get-Content $currentReportPath -Raw)
285+ } else {
286+ $fallback += ""
287+ $fallback += "Benchmark artifacts should still be attached to this workflow run."
288+ }
289+
290+ $body = $marker + "`n" + ($fallback -join "`n")
291+ Write-Host "PR comment report not found at $commentPath. Posting fallback benchmark comment instead."
292+ }
293+
210294 $comments = gh api "repos/$repo/issues/$prNumber/comments?per_page=100" | ConvertFrom-Json
211295 $existing = $comments | Where-Object { $_.body -like "*$marker*" } | Select-Object -First 1
212296
0 commit comments