Repository navigation
[ci] Enable non-workload NuGet releases - #37658
Conversation
Generalize the Darc-based official release pipeline to publish shipping NuGet packages for allowlisted non-workload repositories while preserving inferred MAUI workload behavior. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2933e733-3bed-4524-ae14-f7ad1c7959e6
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 37658Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 37658" |
|
Azure Pipelines: Successfully started running 1 pipeline(s). There may be pipelines that require an authorized user to comment /azp run to run. |
|
I will need to manually test this and bring it out of draft. I also need to merge this first: |
Avoid strict-mode failures when non-workload releases use the default skip values for all workload-only filters. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2933e733-3bed-4524-ae14-f7ad1c7959e6
Align non-workload releases with workload releases by removing packages that reached NuGet.org after preparation and before the publish task. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2933e733-3bed-4524-ae14-f7ad1c7959e6
Permit the pre-publish recheck to process package files removed during preparation, while still failing when a missing file is not available on NuGet.org. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2933e733-3bed-4524-ae14-f7ad1c7959e6
Apply the existing include and exclude package filters to non-workload NuGet release sets while continuing to reject workload-only recovery inputs. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2933e733-3bed-4524-ae14-f7ad1c7959e6
Resolve the requested commit to exactly one matching BAR build and use its returned ID for gathering without imposing an Android-libraries channel requirement. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2933e733-3bed-4524-ae14-f7ad1c7959e6
Allow Darc to continue when previously released assets are no longer downloadable, then require every missing selected identity to exist on NuGet.org while preserving fail-fast workload gathering. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2933e733-3bed-4524-ae14-f7ad1c7959e6
This comment has been minimized.
This comment has been minimized.
MauiBot
left a comment
There was a problem hiding this comment.
Expert Review — 4 findings
See inline comments for details.
MauiBot
left a comment
There was a problem hiding this comment.
AI Review Summary
@jonathanpeppers — new AI review results are available based on commit
adec5b8.
🗂️ Review Sessions — click to expand
🚦 Gate — Test Before & After Fix
Gate Result: ⚠️ SKIPPED
No tests were detected in this PR.
Recommendation: Add tests to verify the fix using the write-tests-agent.
📋 Pre-Flight — Context & Validation
PR #37658 Pre-Flight
Context
- Title:
[ci] Enable non-workload NuGet releases - State: Open draft
- Base / head:
main(f578901012885b2845763e1587f7c230b25b0e8e) /jonathanpeppers-release-android-libraries(adec5b8d7230acaf8996a0961915a5f2fdc97f7a) - Local review commit:
ec075411c8531566cbfd0155af8a7f2ed5e322ba, a squash of the PR ontoabdfbef0e91622ef4b1cceb4897c236f7452f428 - Scope: 7 files, +462/-93. The PR generalizes the Darc-based official release pipeline to publish shipping NuGet packages from allowlisted non-workload repositories, initially
dotnet/android-libraries, while retaining the workload path fordotnet/android,dotnet/macios, anddotnet/maui. - Linked issue: None. The author notes that a real pipeline dry run is still required and depends on
dotnet/android-libraries#1530. - Gate: Previously completed and skipped because no tests were detected. It must not be rerun and
gate/content.mdmust not be changed.
Existing PR approach
The PR infers workload mode from the requested owner/repository, validates an allowlist, resolves exactly one BAR build by repository and commit, and gathers shipping NuGet assets by the returned BAR ID. Workload packages retain the existing release path. Non-workload packages are selected against BAR asset identities, filtered against NuGet.org, staged with an audit artifact, approved manually, published through 1ES.PublishNuget@1, and verified afterward. The publish stage is factored into a new eng/pipelines/common/non-workload-publish.yml template.
An earlier hard-coded .NET 10 channel name/ID approach was removed after review. Alternatives must not reintroduce repository-specific channel IDs and must remain distinct from the current “single BAR build + separate non-workload publish template” design.
Changed files
.github/workflows/powershell-script-tests.ymldocs/ReleaseProcess.mdeng/pipelines/ci-official-release.Tests.ps1eng/pipelines/ci-official-release.ymleng/pipelines/common/non-workload-publish.yml(new)eng/scripts/nuget_release_packages.Tests.ps1eng/scripts/nuget_release_packages.ps1
The working tree already contains harness/trusted-script overlays, including modifications to the two nuget_release_packages files. These pre-existing changes must not be manually reverted or overwritten. Each try-fix invocation must rely exclusively on EstablishBrokenBaseline.ps1 and its baseline allow-list.
Focused verification
The PR adds/updates two focused Pester suites. Use only these suites; do not run the repository-wide PowerShell test directory or any full test suite:
pwsh -NoProfile -Command '$ErrorActionPreference = "Stop"; Import-Module Pester -RequiredVersion 5.9.0; $config = New-PesterConfiguration; $config.Run.Path = @("eng/pipelines/ci-official-release.Tests.ps1", "eng/scripts/nuget_release_packages.Tests.ps1"); $config.Run.PassThru = $true; $config.Output.Verbosity = "Detailed"; $result = Invoke-Pester -Configuration $config; if ($result.FailedCount -gt 0 -or $result.TotalCount -lt 1) { throw "Focused Pester validation failed." }'No additional mandatory regression tests were supplied. The target platform is Windows.
Try-fix constraints
Each attempt may perform one implementation/test pass and at most one focused correction/retest. It must perform the try-fix skill's inline expert self-review, capture all required artifacts, and restore only with:
pwsh .github/scripts/EstablishBrokenBaseline.ps1 -RestoreThe PR adds eng/pipelines/common/non-workload-publish.yml. If .github/.baseline-state.json reports this or any other path in NewFiles, the try-fix skill requires the attempt to be recorded as Blocked before editing because the restore mechanism cannot safely restore added production files.
🔬 Code Review — Deep Analysis
Expert Code Review - PR #37658
Initial Verdict: NEEDS_CHANGES
Confidence: low for overall merge safety because this changes shared production-release infrastructure and the trusted Gate was skipped; confidence is high in the blocking BAR-resolution finding.
Independent Assessment
What this changes: The submitted PR generalizes the official Darc-based release pipeline so allowlisted non-workload repositories can publish one audited set of shipping NuGet packages, while retaining separate workload pack/manifest publication. It resolves a repository and commit to BAR, gathers shipping assets, validates identities, filters packages already on NuGet.org, publishes through 1ES.PublishNuget@1, and verifies availability.
Inferred motivation: dotnet/android-libraries needs a controlled release path without pretending its packages are a MAUI workload or weakening the existing service-connection and approval boundaries.
Approach assessment: The non-workload path is generally coherent and fail-closed. Its allowlist, immutable pipeline artifact, script hash checks, manifest-to-directory validation, repeat availability filtering, and missing-file/HTTP-404 guard preserve the intended release set. However, changing the shared workload lookup from selecting one returned BAR build to rejecting every multi-match result introduces a blocking operational regression.
Prior Review Reconciliation
| Prior feedback | Status | Evidence |
|---|---|---|
| The initial repository-specific channel ID/name was too specific. | Addressed | The submitted diff removes the fixed channel policy and resolves the requested repository and commit dynamically. |
| The repository allowlist is intentional. | Confirmed | The runtime input is normalized and checked against four explicit GitHub repository URLs before Darc runs. |
No prior error-severity finding remains to reconcile.
CI and Gate
- Public head
adec5b8d7230acaf8996a0961915a5f2fdc97f7areported 32 successful checks, one skipped check, and no failing checks when reviewed. - The trusted Gate result supplied to this phase is
SKIPPED - no tests detected in this PR; it must not be treated as approval evidence. - The submitted focused Pester tests cover the helper's missing-file behavior, but they do not exercise a real Azure DevOps release expansion or BAR query.
Findings
Error - exact-one BAR lookup regresses workload release recovery
eng/pipelines/ci-official-release.yml:239 now rejects a repository/commit query unless Darc returns exactly one BAR build. This is shared by the established workload path. Re-queued official builds can register more than one BAR build for the same source commit, so a retry can now stop before preparation with no operator-selectable build ID. Preserve deterministic selection without making an otherwise valid workload release impossible, preferably with an explicit BAR build override rather than silently choosing an arbitrary match.
Warning - missing BAR GitHub metadata produces an opaque runtime failure
eng/pipelines/ci-official-release.yml:242 calls GetLeftPart on the cast gitHubRepository value without first checking it. An AzDO-only BAR record can therefore fail with a null-method error rather than a diagnostic naming the BAR build and expected repository. Add an explicit null/empty guard while retaining fail-closed behavior.
Suggestion - synthesized identities assume BAR versions are NuGet-normalized
eng/pipelines/ci-official-release.yml:368-369 uses the raw BAR version as both normalizedVersion and part of fileName when a package was not downloaded. A non-canonical but equivalent NuGet version can make the flat-container availability probe and package filters diverge from the downloaded-package path. Normalize the BAR version before synthesizing the identity, or establish and test the BAR contract that guarantees it is already normalized.
Suggestion - HasPackages is calculated but does not suppress a no-op approval
eng/pipelines/common/non-workload-publish.yml:23 binds HasPackages but never consumes it. A fully published release still waits at ManualValidation@0 before doing no publish work. Either gate the approval/stage with this output or remove the misleading unused variable.
Failure-Mode Probing
- A non-workload gather that misses an unpublished package fails: the manifest retains the selected BAR identity and
FilterExistingthrows when both the file is absent and NuGet.org returns 404. - A package published between preparation and approval is removed by the second filter and is not sent to
1ES.PublishNuget@1. - A corrupt or unexpected gathered package fails identity/archive validation or the manifest-directory consistency check.
- A workload manifest in the non-workload path is rejected before artifact publication.
- Two BAR builds for one workload repository/commit fail unconditionally at the new exact-one guard, which is the blocking regression.
External Output Contract
| Consumer token/pattern | Producer location | Producer emission condition | Consumer assumption | Ordinary negative case | Downstream effect |
|---|---|---|---|---|---|
| Darc JSON result count | darc get-build --output-format json |
Emits every build matching repository and commit | More than one match is invalid | A legitimate official rebuild registers a second BAR build for the same commit | Preparation aborts and no workload release can be selected |
| Darc process exit code | darc gather-drop --continue-on-error |
Nonzero when one or more gather operations fail | Non-workload misses may be tolerated only if every selected missing identity is already public | A partial gather has ordinary missing assets | The manifest plus NuGet.org probes either account for every missing identity or fail closed |
| HTTP 200/404 | NuGet.org flat-container HEAD |
200 for an indexed normalized ID/version, 404 when unavailable | 200 means safe to omit; 404 requires a staged file | A package was published after preparation | The second filter removes it and the publish task avoids a conflict |
Verdict
NEEDS_CHANGES. The new non-workload design is careful overall, but the exact-one lookup changes the established workload release path and can strand a routine release retry. The null diagnostic should be fixed in the same resolution block; version normalization and no-op approval handling are worthwhile hardening opportunities.
🛠️ Try-Fix — Analysis & Comparison
Try-Fix Candidate 1 — PR #37658
Result: Blocked (no implementation, no test)
Attempt artifacts: CustomAgentLogsTmp/PRState/37658/PRAgent/try-fix/attempt-1
Approach (designed, not implemented)
Asset-first, single-path publish driven by a declarative release manifest.
eng/scripts/nuget_release_packages.ps1would emit a declarative release manifest — repo, BAR build id(s), per-package identity/version, shipping classification, NuGet.org presence — produced from a darc asset-level query over the build drop, instead of returning a single resolved build that downstream YAML re-interprets. The asset set, not the build, becomes the unit of resolution.- Repository eligibility becomes data, not control flow: the allowlist and per-repo release semantics (
workloadvspackagesOnly) live in pipelineparameters/variable-group data consumed byci-official-release.yml. Addingdotnet/android-libraries(or the next repo) is a manifest edit, not a new code branch. No repository-specific channel id/name policy is reintroduced — there are no channel constants at all. ci-official-release.ymlkeeps exactly one publish stage that iterates manifest rows. Workload rows additionally run the existing workload-insertion steps; package rows skip them.eng/pipelines/common/non-workload-publish.ymlis unnecessary because staging audit artifact, manual approval,1ES.PublishNuget@1publish, and post-publish verification are shared.
Exact BAR repository/commit resolution, auditable staging, manual approval, NuGet publishing, and post-publish verification are all preserved; the workload release path is untouched in substance.
Prior approach avoided
- The PR's current design: infer workload mode from requested owner/repo, validate an allowlist, resolve exactly one BAR build by repository + commit, gather shipping assets by that BAR id, then hand off non-workload releases to a dedicated
non-workload-publish.ymltemplate. Failure mechanism: duplication of the release contract. Publish semantics now exist in two places selected by a boolean computed deep in script logic, so future divergence between the two paths (a missing audit artifact, a skipped verification step) is invisible to the focused Pester suites, which can only assert YAML/script shape rather than cross-path agreement. - The earlier, already-removed design: hard-coded
.NET 10channel name/ID policy. Failure mechanism: release-cycle-specific policy embedded in repository code, which goes stale each band and requires a code change per release. Explicitly not reintroduced.
Mechanism-level difference
The PR resolves a build and then decides which pipeline path to take — divergence risk is created at the instant the workload boolean is computed, and it propagates into a second template. In the candidate approach, resolution yields a list of classified assets, and the boolean never selects a code path; it only gates whether the extra workload-insertion steps run inside the single publish stage. Because there is exactly one staging → approval → publish → verify implementation, a non-workload release structurally cannot miss a step the workload path has. That is a different root-cause hypothesis (the risk is contract duplication, not resolution granularity), not merely a different file location.
Files changed
None. The attempt was blocked before any edit.
Captured diff
Empty (fix.diff is 0 bytes; reviewer-findings.diff is 0 bytes). No tracked or untracked file was created, modified, or deleted by this attempt. All ~57 pre-existing dirty harness/trusted-script files were preserved untouched.
Test result
No test executed. The permitted focused command
pwsh -NoProfile -Command '... Invoke-Pester -Configuration $config ...' over
eng/pipelines/ci-official-release.Tests.ps1 and eng/scripts/nuget_release_packages.Tests.ps1 was intentionally not run: with no implementation applied it would have measured the unmodified harness-overlay state, producing a meaningless result. test-output.log records this reason verbatim.
Failure / block analysis
Step 2 (Establish Baseline) failed. pwsh .github/scripts/EstablishBrokenBaseline.ps1 exited 1 with:
ERROR: DIRTY WORKING DIRECTORY - Cannot establish baseline
...
EstablishBrokenBaseline.ps1 failed: Working directory is not clean. Clean up before establishing baseline.
It listed ~57 pre-existing modified files under .github/scripts, .github/skills, and eng/scripts — including both eng/scripts/nuget_release_packages.ps1 and eng/scripts/nuget_release_packages.Tests.ps1, i.e. two of the seven target files. As a result .github/.baseline-state.json was never created (Test-Path → False), so there is no RevertedFiles allow-list.
The try-fix baseline-file boundary rule permits editing only files in RevertedFiles and mandates reporting Blocked before editing when the state file is absent, because nothing could be safely restored afterward. The block is unresolvable from inside the attempt: the pre-existing dirty files must be preserved, and every cleanup mechanism that would satisfy the script's guard (git checkout/restore/reset/clean/stash, Remove-Item) is prohibited. The pre-flight brief separately anticipated a Blocked outcome via NewFiles containing the PR's added eng/pipelines/common/non-workload-publish.yml; that check was never reached because the dirty-tree guard fired first.
Result
Blocked — recorded in result.txt.
Self-review finding count
0 findings (reviewer-findings.json = []). The inline expert self-review was performed against .github/agents/maui-expert-reviewer.md (Overarching Principles + always-active dimensions: Logic and Correctness, Regression Prevention, Complexity Reduction). With an empty diff there is no changed code to violate any rule, so [] is the correct and honest output. No maui-expert-reviewer sub-agent was launched.
Restoration outcome
Ran the exact mandated command and waited for completion:
pwsh .github/scripts/EstablishBrokenBaseline.ps1 -Restore
→ No baseline state found. Nothing to restore.
→ Message: No baseline state found / Restored: False
Restored False is the expected and accepted result for this verified no-state Blocked path: baseline state was never created and no attempt edits were made. The worktree is byte-identical to its pre-attempt state; all pre-existing dirty/untracked harness inputs remain in place. No git history-altering or filesystem-deletion command was used at any point.
Try-Fix Candidate 2 — PR #37658
Result: Blocked (no implementation, no test)
Attempt artifacts: CustomAgentLogsTmp/PRState/37658/PRAgent/try-fix/attempt-2
Approach (designed, not implemented)
Approval-bound content-addressed release capsule. For an allowlisted non-workload repository, preparation would resolve the exact BAR build by normalized repository plus commit, select shipping NuGet assets, and seal the packages with BAR provenance and per-file SHA-256 hashes into one immutable capsule. Manual approval would review that capsule's audit. The production release job would independently repeat the Darc repository/commit lookup, require the same BAR ID, verify every package hash, extract into a fresh directory, publish via 1ES.PublishNuget@1, and verify every approved identity/version on NuGet.org. Existing workload stages remain unchanged. The non-workload capsule job would be inline in ci-official-release.yml, not a separate template and not part of a unified workload/package stage.
Prior approaches avoided
- Current PR: one BAR resolution during preparation followed by a dedicated
non-workload-publish.ymlpath. Its handoff authenticates the helper script but does not cryptographically bind every approved package byte plus BAR provenance to the production job. - Candidate 1: an asset-first declarative repository manifest driving one unified publish stage. It was blocked before editing; this candidate does not use a repository manifest or unify workload and non-workload publication.
- Removed historical design: repository-specific
.NET 10channel names/IDs. This candidate uses no channel names or IDs.
Mechanism-level difference
The root-cause hypothesis is an approval-to-publish time-of-check/time-of-use gap, rather than the PR's release-path split or candidate 1's contract-duplication concern. Approval is bound to content hashes and BAR provenance. A second independent Darc lookup proves that repository/commit still maps to the approved BAR ID, while package hashes prove that the exact reviewed bytes enter 1ES.PublishNuget@1. This adds an independently checked provenance boundary without merely relocating checks, without a separate publish template, and without merging both release types into one stage.
Files changed
None. Baseline establishment failed before editing, so no production target was modified.
Full captured diff
The captured fix.diff is empty (0 bytes).
Exact test result and output summary
No test executed. test-output.log records:
BLOCKED BEFORE IMPLEMENTATION OR TESTING. The mandatory baseline command failed because approximately 57 pre-existing harness/trusted-script files are modified.
.github/.baseline-state.jsonwas not created, so noRevertedFilesmodification allow-list exists. Per the try-fix baseline boundary, no production file could be edited safely. Running the focused Pester command without an implementation would test the pre-existing overlay rather than candidate 2 and was therefore not permitted or meaningful. No test command was executed.
The sole permitted focused Pester command was not invoked, so there is no Pester pass/fail count.
Failure / block analysis
pwsh .github/scripts/EstablishBrokenBaseline.ps1 exited 1 after rejecting approximately 57 pre-existing modified harness/trusted-script files, including eng/scripts/nuget_release_packages.ps1 and eng/scripts/nuget_release_packages.Tests.ps1. .github/.baseline-state.json did not exist afterward. With no RevertedFiles allow-list, the skill required a Blocked result before editing. The pre-existing modifications could not be cleaned because they must be preserved and manual git/filesystem cleanup is prohibited.
Result
Blocked — recorded in result.txt.
Self-review finding count
0 findings. The mandatory inline expert self-review applied all overarching principles and the always-active Logic and Correctness, Regression Prevention, and Complexity Reduction dimensions. Since candidate 2 produced no code diff, reviewer-findings.json correctly contains []. No reviewer or child agent was launched.
Restoration outcome
The exact required command ran and completed:
pwsh .github/scripts/EstablishBrokenBaseline.ps1 -Restore
No baseline state found. Nothing to restore.
Message: No baseline state found
Restored: False
Restored False is accepted for this verified no-state path: baseline state was never created and no attempt production edits occurred. All pre-existing dirty and untracked inputs remain untouched.
🏁 Report — Final Recommendation
⚠️ Final Recommendation: REQUEST CHANGES
Winning candidate: pr-plus-reviewer
The submitted PR has a sound non-workload release design, but its exact-one BAR lookup also changes the established workload path: a repository/commit with multiple BAR builds cannot be released. pr-plus-reviewer retains strict default resolution while adding an explicit positive barBuildId disambiguator that must match the same repository/commit query. It also adds a clear invalid/missing gitHubRepository diagnostic and uses the existing HasPackages output to skip a production stage and manual approval when preparation proves there is nothing to publish.
Candidate ranking
| Rank | Candidate | Implementation | Required validation | Assessment |
|---|---|---|---|---|
| 1 | pr-plus-reviewer |
Complete consolidated patch | Passed: 25/25 focused Pester tests | Best balance of release safety, backward compatibility, operator recovery, and limited scope. |
| 2 | pr |
Complete submitted fix | Public CI was green; trusted Gate was skipped | Strong fail-closed package handling, but the shared exact-one lookup can strand ordinary workload release retries and repository metadata failures are opaque. |
| 3 | try-fix-2 |
Blocked; design only | Not run | The content-addressed capsule could strengthen provenance, but it produced no diff or empirical evidence and duplicates resolution in preparation and publication. |
| 4 | try-fix-1 |
Blocked; design only | Not run | The unified declarative-manifest redesign is substantially broader than the problem, produced no diff, and replaces mature workload stages without validation. |
No candidate failed a regression test. The two try-fix-* candidates were blocked before implementation and testing, so neither can outrank an implemented candidate whose required regression suite passed.
Expert findings applied
- Blocking BAR ambiguity: Added optional
barBuildIdinput. The default still requires exactly one result; an override is parsed as a positive integer and must uniquely match the builds returned for the requested repository and commit. This avoids silently selecting an unrelated build. - Repository metadata diagnostics: Replaced the null-sensitive URI chain with
Uri.TryCreateand a BAR-ID-specific fail-closed error. - No-op manual approval: Gated
publish_non_workloadonprepareRelease.HasPackages, so an already-complete release does not wait for approval or request production publication. - Submitted helper behavior retained: Restored the PR's missing-file logic and its two tests over the trusted baseline overlay: missing packages are accepted only when NuGet.org returns 200 and rejected when it returns 404.
The reviewer suggestion to normalize synthesized BAR versions was not added because this pass did not establish that BAR package asset versions can be non-normalized or identify an existing NuGet normalization API available in the release PowerShell host. The risk remains documented rather than adding an unproven custom SemVer implementation.
Validation and residual uncertainty
The exact required Windows command ran once from D:\a\_temp\pr-37658-pr-plus-reviewer and passed all 25 focused tests with zero failures or skips. git diff --check cf9e410bc389a32f9a302e1bda6f165d0ea448c2 also passed before validation.
This remains production-release infrastructure. The focused suite verifies PowerShell behavior and YAML shape, but it does not expand the pipeline in Azure DevOps, query a live multi-build BAR result, exercise the protected NuGet service connection, or perform the documented dry run. The trusted Gate was skipped because it detected no tests, so these gaps must remain explicit.
Required change
Port the BAR-disambiguation, repository-validation, stage-gating, tests, and documentation hunks from CustomAgentLogsTmp/PRState/37658/PRAgent/pr-plus-reviewer/reviewer.patch, then complete the documented internal YAML-preview and dry-run checks before a production release. The helper-script hunks in that patch only reconstruct behavior already present in the submitted PR over the trusted validation overlay and should not be applied a second time. Because the winning behavior is not present in the submitted PR HEAD, the recommendation is REQUEST CHANGES.
🧭 Next Steps — reviewer changes required
The reviewer-enhanced candidate identified changes that are not yet in the submitted PR.
Why: pr-plus-reviewer preserves the submitted non-workload release flow while adding deterministic BAR-build disambiguation, clear repository metadata validation, and no-op approval suppression. It is the only alternative with an implementation, and all 25 required focused Pester tests passed.
Address the actionable findings in this review before merging.
Use the first BAR build returned for repository and commit releases across workload and non-workload paths, and remove the unused non-workload package output. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2933e733-3bed-4524-ae14-f7ad1c7959e6
Prevent AzureCLI@2 from failing non-workload preparation after a tolerated partial gather and successful package reconciliation. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2933e733-3bed-4524-ae14-f7ad1c7959e6
|
Azure Pipelines: Successfully started running 1 pipeline(s). There may be pipelines that require an authorized user to comment /azp run to run. |
There was a problem hiding this comment.
🟡 Changes recommended
The updated release documentation still describes the preparation gather as “fail-fast” even though non-workload releases now use a continue-on-error gather path, which could mislead release operators.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR generalizes the existing official release pipeline so it can publish shipping NuGet packages from an allowlisted non-workload repository (initially dotnet/android-libraries), while keeping the existing MAUI/workload release flow intact.
Changes:
- Extends
eng/pipelines/ci-official-release.ymlto support a non-workload prepare + publish path (including audit artifact creation and package filtering). - Updates
nuget_release_packages.ps1(and adds tests) to tolerate packages that are already on NuGet.org even if their.nupkgfile is no longer present locally. - Adds a dedicated non-workload publish template, updates Pester tests, and refreshes the documented release process.
File summaries
| File | Description |
|---|---|
| eng/scripts/nuget_release_packages.Tests.ps1 | Adds Pester coverage for the new “already published but file missing” and “unpublished + missing file” behaviors. |
| eng/scripts/nuget_release_packages.ps1 | Adjusts FilterExisting to not require a local .nupkg when NuGet reports the package is already published. |
| eng/pipelines/common/non-workload-publish.yml | Introduces a non-workload publish stage with manual approval, pre-push filtering, push, and verification. |
| eng/pipelines/ci-official-release.yml | Adds inferred workload vs non-workload branching, allowlisting, non-workload audit emission, and wires in the new publish template. |
| eng/pipelines/ci-official-release.Tests.ps1 | Expands pipeline Pester assertions to cover inference, audit, non-workload template wiring, and gather behavior. |
| docs/ReleaseProcess.md | Documents non-workload releases, audit artifact behavior, and updated parameter semantics. |
| .github/workflows/powershell-script-tests.yml | Adds the new YAML template to the PowerShell regression-test path filters. |
Review details
- Files reviewed: 7/7 changed files
- Comments generated: 1
- Review effort level: Lite
There was a problem hiding this comment.
🟡 Changes recommended
The tests do not explicitly protect the new repository allowlist entry, and the release documentation incorrectly describes non-workload gathering as fail-fast.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (1)
docs/ReleaseProcess.md:71
- This description contradicts the non-workload behavior documented above and implemented with
--continue-on-error: only workload gathering is fail-fast, while non-workload gathering can return failure and then validates every missing selected identity against NuGet.org. Please distinguish those paths so operators do not expect all gather failures to stop preparation immediately.
The preparation stage resolves the BAR build once and runs one fail-fast `darc gather-drop`, filtered to BAR NuGet package assets. Symbol and other path-based blob assets are not NuGet.org release inputs and are not downloaded. The stage rejects a failed or incomplete package gather. Workload releases apply the include and exclude filters and require non-empty pack and manifest sets; non-workload releases use the single package set described above.
- Files reviewed: 7/7 changed files
- Comments generated: 1
- Review effort level: Balanced
Clarify non-workload gather reconciliation and pin every allowed repository in the pipeline regression tests. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2933e733-3bed-4524-ae14-f7ad1c7959e6
There was a problem hiding this comment.
🟡 Changes recommended
The approval instructions and release documentation inaccurately describe the staged package list and missing-package identity handling.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 7/7 changed files
- Comments generated: 2
- Review effort level: Balanced
Document BAR-derived identities for unavailable artifacts and explain that the approval audit is an upper bound after the final NuGet.org check. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2933e733-3bed-4524-ae14-f7ad1c7959e6
Multi-model review summaryVerdict: NEEDS_CHANGES (comment-only) · Confidence: Low Independent passes used GPT-5.6 Terra for MAUI dimensions, GPT-5.6 Luna for the release state machine, and GPT-5.5 for producer/consumer contracts. Candidates were then challenged across tracks. One finding survived cross-pollination:
Prior feedback: all existing inline threads are resolved. The earlier exact-one-BAR-build bug was fixed, and the finding above is distinct from the resolved synthetic-version fallback discussion. CI: the PR-specific release and NuGet Pester tests pass. The red PowerShell Script Tests run is caused by 13 unrelated The title and description match the implementation and include the required testing note. No other high-confidence findings remain. I did not submit an approval or request-changes review event. |
|
Follow-up on the surviving finding above: after tracing the producer implementation, I don't believe a code change is needed. Arcade's I replied with this evidence and resolved the inline thread. |
Note
Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!
Description of Change
Generalizes the existing Darc-based official release pipeline so it can publish shipping NuGet packages from allowlisted non-workload repositories, initially
dotnet/android-libraries, while preserving the existing MAUI workload-release path.dotnet/android,dotnet/macios, anddotnet/maui.NuGetReleaseAuditartifact before manual approval.1ES.PublishNuget@1task andnuget.org (dotnetframework)service connection, then verifies every expected package on NuGet.org.pushPackages: false.Dry-run inputs
Queue
dotnet-maui-releaseagainst this PR branch after it appears in the internaldotnet-mauimirror. The run performs BAR resolution, gathering, package validation/filtering, and audit artifact publication without promotion or NuGet publishing.External setup
Before enabling a real push, release owners must verify that the existing
nuget.org (dotnetframework)service connection owns every package ID in the audit artifact and has sufficient scope/quota. Android-libraries BAR builds contain per-build deltas rather than the union of channel assets, so each pending BAR build must be released in commit order.Validation
dotnet/android-librariesNuGet.org release run: BAR resolution, gathering, filtering, audit publication, package push, and NuGet.org verification all succeeded.partiallySucceededonly because 1ES production branch/source validation reported non-blocking errors for running the test from this PR branch instead of an approved production branch.Issues Fixed
N/A