Don't pack .NET Standard - #32203
Conversation
There was a problem hiding this comment.
Pull Request Overview
This PR prevents .NET Standard target framework versions from being included in NuGet packages. While .NET Standard targets remain in the codebase for MSBuild task compatibility, they are no longer intended for distribution.
Key Changes
- Adds MSBuild property to exclude .NET Standard TFMs from packaging
732755a to
18b861c
Compare
|
/review -b feature/refactor-copilot-yml |
MauiBot
left a comment
There was a problem hiding this comment.
Expert Review — 1 findings
See inline comments for details.
| <Import Project="Sdk.targets" Sdk="Microsoft.DotNet.Arcade.Sdk" /> | ||
|
|
||
| <PropertyGroup> | ||
| <IsPackable Condition="$(TargetFramework.Contains('netstandard'))">false</IsPackable> |
There was a problem hiding this comment.
[major] Build & MSBuild — This disables packing for every netstandard inner build, including netstandard-only packable tooling projects such as src/Controls/src/Build.Tasks/Controls.Build.Tasks.csproj and src/SingleProject/Resizetizer/src/Resizetizer.csproj. Because those packages only target netstandard2.0, setting IsPackable=false here prevents the packages from being produced at all. Please scope the suppression to multi-target product packages/removing netstandard pack frameworks instead of globally disabling all netstandard pack builds.
This comment has been minimized.
This comment has been minimized.
kubaflo
left a comment
There was a problem hiding this comment.
Could you please check the ai's suggestions?
|
/review -b feature/enhanced-reviewer -p windows |
MauiBot
left a comment
There was a problem hiding this comment.
AI Review Summary
@mattleibow — new AI review results are available based on this last commit:
18b861c.
Don't pack .NET Standard To request a fresh review after new comments or commits, comment/review rerun.
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
Issue: N/A - No linked issue detected
PR: #32203 - Don't pack .NET Standard
Platforms Affected: packaging/build; testing platform windows
Files Changed: 1 implementation, 0 test
Key Findings
- PR changes
Directory.Build.targetsto setIsPackable=falsewheneverTargetFrameworkcontainsnetstandard. - Gate was already skipped by the caller because no tests were detected in this PR; gate verification was not re-run.
- Current fix is too broad:
Directory.Build.targetsis imported after project files, so the new property overrides explicitIsPackable=truein netstandard-only tooling packages. - Netstandard-only packable tooling projects that must continue producing packages include
src/Controls/src/Build.Tasks/Controls.Build.Tasks.csproj,src/SingleProject/Resizetizer/src/Resizetizer.csproj, andsrc/Controls/src/SourceGen/Controls.SourceGen.csproj. - No UI test categories are impacted; this is packaging/MSBuild behavior.
Code Review Summary
Verdict: NEEDS_CHANGES
Confidence: high
Errors: 1 | Warnings: 0 | Suggestions: 0
Key code review findings:
- ❌
Directory.Build.targets:6blanket netstandard pack suppression breaks tooling packages by overriding explicitIsPackable=truein netstandard-only package projects.
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #32203 | Set IsPackable=false when TargetFramework contains netstandard |
Directory.Build.targets |
Original PR fix; code review found it disables required netstandard-only tooling packages |
Code Review — Deep Analysis
Code Review — PR #32203
Independent Assessment
What this changes: Globally sets IsPackable=false whenever TargetFramework contains netstandard.
Inferred motivation: Stop shipping .NET Standard package assets while keeping netstandard builds for tooling/MSBuild tasks.
Reconciliation with PR Narrative
Author claims: .NET Standard was never supported and only remains to help MSBuild tasks.
Agreement/disagreement: The goal matches, but the implementation also disables packaging for required netstandard tooling packages.
Findings
❌ Error — Blanket netstandard pack suppression breaks tooling packages
Directory.Build.targets:6 is imported after project files, so it overrides explicit <IsPackable>true</IsPackable> in netstandard-only package projects such as:
src/Controls/src/Build.Tasks/Controls.Build.Tasks.csprojsrc/SingleProject/Resizetizer/src/Resizetizer.csprojsrc/Controls/src/SourceGen/Controls.SourceGen.csproj
I verified these now evaluate IsPackable=false. These packages carry required buildTransitive assets/task assemblies, so pack output can disappear. CI also shows maui-pr (Pack .NET MAUI Pack Windows) failing.
Devil's Advocate
The one-line fix is attractive and may remove product-library netstandard assets, but it is too broad. A safer fix should target product package framework assets/dependency groups without disabling netstandard-only tooling packages.
Verdict: NEEDS_CHANGES
Confidence: high
Summary: Valid cleanup goal, but current implementation suppresses required tooling packages. Scope the change more narrowly before merging.
Fix — Analysis & Comparison
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| 1 | try-fix | Scope IsPackable=false to multi-target netstandard inner builds |
❌ Fail | Directory.Build.targets |
Preserved tooling package IsPackable=true, but Microsoft.Maui.Core still shipped lib/netstandard2.0 and lib/netstandard2.1 assets. |
| 2 | try-fix | Suppress netstandard build output and dependency groups during product package pack | ✅ Pass | Directory.Build.targets |
Removed Microsoft.Maui.Core netstandard package assets/groups while preserving Controls.Build.Tasks and Resizetizer packages. |
| PR | PR #32203 | Blanket IsPackable=false for any netstandard target |
Directory.Build.targets |
Original PR; code review found it disables netstandard-only tooling packages. |
Cross-Pollination
| Model | Round | New Ideas? | Details |
|---|---|---|---|
| maui-expert-reviewer | 1 | Yes | Suggested scoping IsPackable=false to multi-target netstandard inner builds. Tested as try-fix-1 and failed. |
| maui-expert-reviewer | 2 | Yes | Suggested IncludeBuildOutput=false plus SuppressDependenciesWhenPacking=true for product package netstandard inner builds. Tested as try-fix-2 and passed. |
| maui-expert-reviewer | 3 | No | Only remaining distinct idea was filtering netstandard* out of pack TargetFrameworks, judged riskier and not plausibly better than try-fix-2. |
Exhausted: Yes — two meaningfully different approaches were tested, and expert follow-up found no plausibly better third approach.
Selected Fix: Candidate #2 — It is demonstrably better than the PR's fix because it removes product-package netstandard assets and dependency groups without disabling netstandard-only tooling packages.
Candidate Details
try-fix-1 — Scoped inner-build IsPackable=false
- Result: ❌ Fail
- Validation:
Controls.Build.TasksandResizetizerstill evaluatedIsPackable=true. - Failure:
Microsoft.Maui.Corepackage still containedlib/netstandard2.0/*andlib/netstandard2.1/*entries. - Lesson: Inner-build
IsPackable=falseis not sufficient to remove netstandard assets from NuGet's outer pack graph.
try-fix-2 — Suppress netstandard pack output and dependency groups
- Result: ✅ Pass
- Validation: Packed
Microsoft.Maui.CorewithPacking=trueandBuildForNetStandard=true; the nupkg had nolib/ref/netstandard*entries and no netstandard dependency groups. PackedMicrosoft.Maui.Controls.Build.TasksandMicrosoft.Maui.Resizetizer; both still produced packages. - Risk: Relies on
IncludeBuildOutputandSuppressDependenciesWhenPackingbeing evaluated before NuGet pack collects per-TFM output/dependency metadata. The targeted validation confirms this placement works for representative product and tooling packages.
Report — Final Recommendation
Comparative Report - PR #32203
Candidates
| Candidate | Approach | Test / review result | Rank |
|---|---|---|---|
try-fix-2 |
For product package netstandard inner builds, set IncludeBuildOutput=false and SuppressDependenciesWhenPacking=true while preserving netstandard-only tooling packages. |
Passed targeted Windows package validation: Microsoft.Maui.Core nupkg had no lib/netstandard* or ref/netstandard* assets and no netstandard dependency groups; Controls.Build.Tasks and Resizetizer still packed. |
1 |
pr-plus-reviewer |
Preserve explicit IsPackable=true opt-ins while keeping the PR's netstandard IsPackable=false suppression for other projects. |
Not selected: addresses the expert review's tooling-package regression, but product packages such as Microsoft.Maui.Core also explicitly set IsPackable=true, so this candidate would preserve the unwanted netstandard pack assets. |
2 |
pr |
Set IsPackable=false whenever TargetFramework contains netstandard. |
Gate skipped, but expert review found a blocking regression: required netstandard-only tooling packages become non-packable. | 3 |
try-fix-1 |
Scope IsPackable=false to multi-target netstandard inner builds. |
Failed regression validation: tooling packages remained packable, but Microsoft.Maui.Core still shipped lib/netstandard2.0 and lib/netstandard2.1 assets. Failed candidates rank below candidates without failing regression tests. |
4 |
Winner
Winner: try-fix-2
try-fix-2 is the only candidate with passing targeted package validation and it directly addresses both sides of the problem: product packages stop contributing netstandard assets/dependency groups, while netstandard-only tooling packages remain packable. The raw PR has a confirmed packaging regression, try-fix-1 failed validation, and pr-plus-reviewer is safer than the raw PR but does not fully remove product netstandard package output.
Notes
No gate tests were detected for the PR, so the PR author should add package-focused validation that checks both absence of netstandard assets/dependency groups in product packages and continued pack output for tooling packages.
Future Action — alternative fix proposed (try-fix-2)
Automated review — alternative fix proposed
The expert-reviewer evaluation compared the PR fix against automatically generated candidates and selected try-fix-2 as the strongest fix.
Why: try-fix-2 is the only candidate with passing targeted package validation. It removes product-package netstandard assets and dependency groups while preserving required netstandard-only tooling packages.
Please consider applying the candidate diff below (or use it as guidance). Once you push an update, this workflow will re-trigger and re-evaluate.
Candidate diff (try-fix-2)
diff --git a/Directory.Build.targets b/Directory.Build.targets
index 77feb5312b..a8b39d2c24 100644
--- a/Directory.Build.targets
+++ b/Directory.Build.targets
@@ -1,9 +1,18 @@
<Project>
<Import Project="Sdk.targets" Sdk="Microsoft.DotNet.Arcade.Sdk" />
+ <PropertyGroup Condition="'$(Packing)' == 'true'
+ and '$(BuildForNetStandard)' == 'true'
+ and '$(TargetFrameworks)' != ''
+ and '$(TargetFramework)' != ''
+ and $([System.String]::Copy('$(TargetFramework)').StartsWith('netstandard'))">
+ <IncludeBuildOutput>false</IncludeBuildOutput>
+ <SuppressDependenciesWhenPacking>true</SuppressDependenciesWhenPacking>
+ </PropertyGroup>
+
<ItemGroup>
<!-- Upgrade xunit's transitive NETStandard.Library dependency to avoid .NET Standard 1.x dependencies. -->
<!-- <PackageReference Include="NETStandard.Library"
IsImplicitlyDefined="false"
### Description of Change .NET Standard was never supported, but just remained to help MSBuild tasks. We don't need to actually ship them.
### Description of Change .NET Standard was never supported, but just remained to help MSBuild tasks. We don't need to actually ship them.
The child investigation (PR #36089) binlog-proved the Jun 2026 inflight/current nightly outage: PR #32203's blanket netstandard IsPackable=false in Directory.Build.targets clobbered the workload packs' explicit IsPackable=true, so the no--build 'Pack, Sign' step never ran Build → _GenerateVSWorkloadProps never generated vs-workload.props → MSB4019. Record the specific cause, the fix, the inflight-only scope, and the forward-port warning so the breadcrumb teaches the real failure. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…s MSB4019) (#36089) <!-- Please let the below note in for people that find this PR --> > [!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](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Description of Change Fixes the **nightly official signed build** (`dotnet-maui`, definition 1095, dnceng/internal), which has failed **8 consecutive nights** on `refs/heads/inflight/current`. The Windows `Pack` job → step **"Build Workloads, Sign & Publish"** fails at restore/evaluation: ``` src\Workload\workloads.csproj(30,3): error MSB4019: The imported project "...\artifacts\packages\Release\Shipping\vs-workload.props" was not found. ``` ### Root cause The workload packs — `Microsoft.NET.Sdk.Maui.Manifest` and `Microsoft.Maui.Sdk` — both target **`netstandard2.0`** (via `src/Workload/Shared/Common.targets`) and both **explicitly** set `<IsPackable>true</IsPackable>` because they *are* the shipping workload packages. PR #32203 ("Don't pack .NET Standard") added a blanket rule to `Directory.Build.targets`: ```xml <IsPackable Condition="$(TargetFramework.Contains('netstandard'))">false</IsPackable> ``` `Directory.Build.targets` is auto-imported at the **end** of every project, so this assignment runs *after* the project body and **overrides** the explicit `<IsPackable>true</IsPackable>` on the workload packs. The net effect: the manifest project evaluates to `IsPackable=false`. The chain that breaks from there: 1. With `IsPackable=false`, NuGet's `Pack` target no-ops. 2. The official **"Pack, Sign"** step (`eng/pipelines/arcade/stage-pack.yml`) runs `-restore -pack -sign` **without `-build`**, so the `Build` target never runs for the manifest project. 3. `_GenerateVSWorkloadProps` (in `Microsoft.NET.Sdk.Maui.Manifest.csproj`) is hooked `AfterTargets="Build"`, so it never runs → `vs-workload.props` is never written to `$(ArtifactsShippingPackagesDir)`. 4. The next step (`-build … -projects src/Workload/workloads.csproj`) hits `workloads.csproj` line 30, whose `<Import Project="$(WorkloadMsiGenProps)" />` is unconditional and fails at evaluation → **MSB4019**. The blanket rule is also **over-broad**: it clobbers the explicit opt-in on *every* netstandard-only project, not just the workload packs (see **Scope** below). The workload/MSI leg simply failed loudest because its missing-file import is fatal at evaluation (MSB4019); the others would silently stop shipping. **Why `main` is green:** PR #32203 is on `inflight/current` only — it is *not* an ancestor of `main` or `net10.0` (verified with `git merge-base --is-ancestor`). `main` and `inflight/current` otherwise share identical `global.json` (dotnet `10.0.108`, arcade `25555.106`), identical `src/Workload`, and identical `Microsoft.Build.NoTargets 3.7.0`. The only relevant difference is the #32203 block, which is why this break is specific to `inflight/current`. ### Fix Guard the #32203 rule so it only applies when a project has **not** explicitly opted into packing: ```xml <IsPackable Condition="$(TargetFramework.Contains('netstandard')) and '$(IsPackable)' == ''">false</IsPackable> ``` - Projects that explicitly set `<IsPackable>true</IsPackable>` (the workload packs) are respected and pack again — restoring `vs-workload.props` generation. - Unmarked netstandard projects still default to not-packable, **preserving #32203's intent**. This restores the exact condition (`IsPackable=true` for the manifest project) that the passing `main` build exhibits, where `_GenerateVSWorkloadProps` runs and `vs-workload.props` is produced. ### Scope / blast radius Because #32203's blanket rule was over-broad, this guard restores packability for **6** netstandard-only projects that explicitly opt in — not just the 2 workload packs: | Project | TFM | |---|---| | `Microsoft.NET.Sdk.Maui.Manifest` | `netstandard2.0` | | `Microsoft.Maui.Sdk` | `netstandard2.0` | | `Resizetizer` | `netstandard2.0` | | `Controls.Build.Tasks` | `netstandard2.0` | | `Controls.SourceGen` | `netstandard2.0` | | `Graphics.Text.Markdig` | `netstandard2.0` | All 6 pack on `main` (which never had the #32203 rule), so this is a **`main`-parity restore**, not new shipping behavior. Multi-target libraries (e.g. `Core`, `Controls.Core`) are unaffected: `dotnet pack` evaluates `IsPackable` at the outer level where `TargetFramework=""`, so the netstandard rule never fires for them. ### How validated Root cause confirmed from the actual failing/passing build binlogs (not guesswork): | | failing `inflight/current` build `3006161` | passing `main` build `3006214` | |---|---|---| | `Microsoft.NET.Sdk.Maui.Manifest` `IsPackable` | **`false`** | **`true`** | | `_GenerateVSWorkloadProps` ran? | no (Build never ran) | yes → `vs-workload.props` produced | Verified locally on the `inflight/current` tree with `dotnet msbuild …Manifest.csproj -getProperty:IsPackable`: - **Before** fix: manifest `IsPackable=false` (reproduces the break). - **After** fix: manifest `IsPackable=true`, `Microsoft.Maui.Sdk` `IsPackable=true`. - `Microsoft.Maui.Core` (multi-target) at pack time is unchanged (`IsPackable=true`, `TargetFramework=""`; the netstandard rule only fires for single-TFM netstandard evaluations, so multi-target library packaging is unaffected). - A netstandard project with no explicit opt-in (`Controls.CustomAttributes`) still resolves `IsPackable=false` — #32203's intent preserved. The full signed Windows MSI leg only runs in the official pipeline; this change restores the property state that gates the entire pack → `vs-workload.props` → workloads handoff. **PR CI confirms the fix end-to-end:** on base `inflight/current` the `Pack Windows` leg fails at the root-cause spot; on this PR the same leg is green. The remaining red `maui-pr` legs are pre-existing on `inflight/current` (Windows Helix unit-test flakiness identical on base, and integration legs that were *skipped on base* because Pack was blocked and only run now that the fix unblocked Pack). ### Follow-up note When PR #32203's `Directory.Build.targets` change is forward-ported to `net10.0`/`main`, it must carry this `'$(IsPackable)' == ''` guard, otherwise the same break will reappear on those branches. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
### Description of Change .NET Standard was never supported, but just remained to help MSBuild tasks. We don't need to actually ship them.
…s MSB4019) (#36089) <!-- Please let the below note in for people that find this PR --> > [!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](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Description of Change Fixes the **nightly official signed build** (`dotnet-maui`, definition 1095, dnceng/internal), which has failed **8 consecutive nights** on `refs/heads/inflight/current`. The Windows `Pack` job → step **"Build Workloads, Sign & Publish"** fails at restore/evaluation: ``` src\Workload\workloads.csproj(30,3): error MSB4019: The imported project "...\artifacts\packages\Release\Shipping\vs-workload.props" was not found. ``` ### Root cause The workload packs — `Microsoft.NET.Sdk.Maui.Manifest` and `Microsoft.Maui.Sdk` — both target **`netstandard2.0`** (via `src/Workload/Shared/Common.targets`) and both **explicitly** set `<IsPackable>true</IsPackable>` because they *are* the shipping workload packages. PR #32203 ("Don't pack .NET Standard") added a blanket rule to `Directory.Build.targets`: ```xml <IsPackable Condition="$(TargetFramework.Contains('netstandard'))">false</IsPackable> ``` `Directory.Build.targets` is auto-imported at the **end** of every project, so this assignment runs *after* the project body and **overrides** the explicit `<IsPackable>true</IsPackable>` on the workload packs. The net effect: the manifest project evaluates to `IsPackable=false`. The chain that breaks from there: 1. With `IsPackable=false`, NuGet's `Pack` target no-ops. 2. The official **"Pack, Sign"** step (`eng/pipelines/arcade/stage-pack.yml`) runs `-restore -pack -sign` **without `-build`**, so the `Build` target never runs for the manifest project. 3. `_GenerateVSWorkloadProps` (in `Microsoft.NET.Sdk.Maui.Manifest.csproj`) is hooked `AfterTargets="Build"`, so it never runs → `vs-workload.props` is never written to `$(ArtifactsShippingPackagesDir)`. 4. The next step (`-build … -projects src/Workload/workloads.csproj`) hits `workloads.csproj` line 30, whose `<Import Project="$(WorkloadMsiGenProps)" />` is unconditional and fails at evaluation → **MSB4019**. The blanket rule is also **over-broad**: it clobbers the explicit opt-in on *every* netstandard-only project, not just the workload packs (see **Scope** below). The workload/MSI leg simply failed loudest because its missing-file import is fatal at evaluation (MSB4019); the others would silently stop shipping. **Why `main` is green:** PR #32203 is on `inflight/current` only — it is *not* an ancestor of `main` or `net10.0` (verified with `git merge-base --is-ancestor`). `main` and `inflight/current` otherwise share identical `global.json` (dotnet `10.0.108`, arcade `25555.106`), identical `src/Workload`, and identical `Microsoft.Build.NoTargets 3.7.0`. The only relevant difference is the #32203 block, which is why this break is specific to `inflight/current`. ### Fix Guard the #32203 rule so it only applies when a project has **not** explicitly opted into packing: ```xml <IsPackable Condition="$(TargetFramework.Contains('netstandard')) and '$(IsPackable)' == ''">false</IsPackable> ``` - Projects that explicitly set `<IsPackable>true</IsPackable>` (the workload packs) are respected and pack again — restoring `vs-workload.props` generation. - Unmarked netstandard projects still default to not-packable, **preserving #32203's intent**. This restores the exact condition (`IsPackable=true` for the manifest project) that the passing `main` build exhibits, where `_GenerateVSWorkloadProps` runs and `vs-workload.props` is produced. ### Scope / blast radius Because #32203's blanket rule was over-broad, this guard restores packability for **6** netstandard-only projects that explicitly opt in — not just the 2 workload packs: | Project | TFM | |---|---| | `Microsoft.NET.Sdk.Maui.Manifest` | `netstandard2.0` | | `Microsoft.Maui.Sdk` | `netstandard2.0` | | `Resizetizer` | `netstandard2.0` | | `Controls.Build.Tasks` | `netstandard2.0` | | `Controls.SourceGen` | `netstandard2.0` | | `Graphics.Text.Markdig` | `netstandard2.0` | All 6 pack on `main` (which never had the #32203 rule), so this is a **`main`-parity restore**, not new shipping behavior. Multi-target libraries (e.g. `Core`, `Controls.Core`) are unaffected: `dotnet pack` evaluates `IsPackable` at the outer level where `TargetFramework=""`, so the netstandard rule never fires for them. ### How validated Root cause confirmed from the actual failing/passing build binlogs (not guesswork): | | failing `inflight/current` build `3006161` | passing `main` build `3006214` | |---|---|---| | `Microsoft.NET.Sdk.Maui.Manifest` `IsPackable` | **`false`** | **`true`** | | `_GenerateVSWorkloadProps` ran? | no (Build never ran) | yes → `vs-workload.props` produced | Verified locally on the `inflight/current` tree with `dotnet msbuild …Manifest.csproj -getProperty:IsPackable`: - **Before** fix: manifest `IsPackable=false` (reproduces the break). - **After** fix: manifest `IsPackable=true`, `Microsoft.Maui.Sdk` `IsPackable=true`. - `Microsoft.Maui.Core` (multi-target) at pack time is unchanged (`IsPackable=true`, `TargetFramework=""`; the netstandard rule only fires for single-TFM netstandard evaluations, so multi-target library packaging is unaffected). - A netstandard project with no explicit opt-in (`Controls.CustomAttributes`) still resolves `IsPackable=false` — #32203's intent preserved. The full signed Windows MSI leg only runs in the official pipeline; this change restores the property state that gates the entire pack → `vs-workload.props` → workloads handoff. **PR CI confirms the fix end-to-end:** on base `inflight/current` the `Pack Windows` leg fails at the root-cause spot; on this PR the same leg is green. The remaining red `maui-pr` legs are pre-existing on `inflight/current` (Windows Helix unit-test flakiness identical on base, and integration legs that were *skipped on base* because Pack was blocked and only run now that the fix unblocked Pack). ### Follow-up note When PR #32203's `Directory.Build.targets` change is forward-ported to `net10.0`/`main`, it must carry this `'$(IsPackable)' == ''` guard, otherwise the same break will reappear on those branches. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
### Description of Change .NET Standard was never supported, but just remained to help MSBuild tasks. We don't need to actually ship them.
…s MSB4019) (#36089) <!-- Please let the below note in for people that find this PR --> > [!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](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Description of Change Fixes the **nightly official signed build** (`dotnet-maui`, definition 1095, dnceng/internal), which has failed **8 consecutive nights** on `refs/heads/inflight/current`. The Windows `Pack` job → step **"Build Workloads, Sign & Publish"** fails at restore/evaluation: ``` src\Workload\workloads.csproj(30,3): error MSB4019: The imported project "...\artifacts\packages\Release\Shipping\vs-workload.props" was not found. ``` ### Root cause The workload packs — `Microsoft.NET.Sdk.Maui.Manifest` and `Microsoft.Maui.Sdk` — both target **`netstandard2.0`** (via `src/Workload/Shared/Common.targets`) and both **explicitly** set `<IsPackable>true</IsPackable>` because they *are* the shipping workload packages. PR #32203 ("Don't pack .NET Standard") added a blanket rule to `Directory.Build.targets`: ```xml <IsPackable Condition="$(TargetFramework.Contains('netstandard'))">false</IsPackable> ``` `Directory.Build.targets` is auto-imported at the **end** of every project, so this assignment runs *after* the project body and **overrides** the explicit `<IsPackable>true</IsPackable>` on the workload packs. The net effect: the manifest project evaluates to `IsPackable=false`. The chain that breaks from there: 1. With `IsPackable=false`, NuGet's `Pack` target no-ops. 2. The official **"Pack, Sign"** step (`eng/pipelines/arcade/stage-pack.yml`) runs `-restore -pack -sign` **without `-build`**, so the `Build` target never runs for the manifest project. 3. `_GenerateVSWorkloadProps` (in `Microsoft.NET.Sdk.Maui.Manifest.csproj`) is hooked `AfterTargets="Build"`, so it never runs → `vs-workload.props` is never written to `$(ArtifactsShippingPackagesDir)`. 4. The next step (`-build … -projects src/Workload/workloads.csproj`) hits `workloads.csproj` line 30, whose `<Import Project="$(WorkloadMsiGenProps)" />` is unconditional and fails at evaluation → **MSB4019**. The blanket rule is also **over-broad**: it clobbers the explicit opt-in on *every* netstandard-only project, not just the workload packs (see **Scope** below). The workload/MSI leg simply failed loudest because its missing-file import is fatal at evaluation (MSB4019); the others would silently stop shipping. **Why `main` is green:** PR #32203 is on `inflight/current` only — it is *not* an ancestor of `main` or `net10.0` (verified with `git merge-base --is-ancestor`). `main` and `inflight/current` otherwise share identical `global.json` (dotnet `10.0.108`, arcade `25555.106`), identical `src/Workload`, and identical `Microsoft.Build.NoTargets 3.7.0`. The only relevant difference is the #32203 block, which is why this break is specific to `inflight/current`. ### Fix Guard the #32203 rule so it only applies when a project has **not** explicitly opted into packing: ```xml <IsPackable Condition="$(TargetFramework.Contains('netstandard')) and '$(IsPackable)' == ''">false</IsPackable> ``` - Projects that explicitly set `<IsPackable>true</IsPackable>` (the workload packs) are respected and pack again — restoring `vs-workload.props` generation. - Unmarked netstandard projects still default to not-packable, **preserving #32203's intent**. This restores the exact condition (`IsPackable=true` for the manifest project) that the passing `main` build exhibits, where `_GenerateVSWorkloadProps` runs and `vs-workload.props` is produced. ### Scope / blast radius Because #32203's blanket rule was over-broad, this guard restores packability for **6** netstandard-only projects that explicitly opt in — not just the 2 workload packs: | Project | TFM | |---|---| | `Microsoft.NET.Sdk.Maui.Manifest` | `netstandard2.0` | | `Microsoft.Maui.Sdk` | `netstandard2.0` | | `Resizetizer` | `netstandard2.0` | | `Controls.Build.Tasks` | `netstandard2.0` | | `Controls.SourceGen` | `netstandard2.0` | | `Graphics.Text.Markdig` | `netstandard2.0` | All 6 pack on `main` (which never had the #32203 rule), so this is a **`main`-parity restore**, not new shipping behavior. Multi-target libraries (e.g. `Core`, `Controls.Core`) are unaffected: `dotnet pack` evaluates `IsPackable` at the outer level where `TargetFramework=""`, so the netstandard rule never fires for them. ### How validated Root cause confirmed from the actual failing/passing build binlogs (not guesswork): | | failing `inflight/current` build `3006161` | passing `main` build `3006214` | |---|---|---| | `Microsoft.NET.Sdk.Maui.Manifest` `IsPackable` | **`false`** | **`true`** | | `_GenerateVSWorkloadProps` ran? | no (Build never ran) | yes → `vs-workload.props` produced | Verified locally on the `inflight/current` tree with `dotnet msbuild …Manifest.csproj -getProperty:IsPackable`: - **Before** fix: manifest `IsPackable=false` (reproduces the break). - **After** fix: manifest `IsPackable=true`, `Microsoft.Maui.Sdk` `IsPackable=true`. - `Microsoft.Maui.Core` (multi-target) at pack time is unchanged (`IsPackable=true`, `TargetFramework=""`; the netstandard rule only fires for single-TFM netstandard evaluations, so multi-target library packaging is unaffected). - A netstandard project with no explicit opt-in (`Controls.CustomAttributes`) still resolves `IsPackable=false` — #32203's intent preserved. The full signed Windows MSI leg only runs in the official pipeline; this change restores the property state that gates the entire pack → `vs-workload.props` → workloads handoff. **PR CI confirms the fix end-to-end:** on base `inflight/current` the `Pack Windows` leg fails at the root-cause spot; on this PR the same leg is green. The remaining red `maui-pr` legs are pre-existing on `inflight/current` (Windows Helix unit-test flakiness identical on base, and integration legs that were *skipped on base* because Pack was blocked and only run now that the fix unblocked Pack). ### Follow-up note When PR #32203's `Directory.Build.targets` change is forward-ported to `net10.0`/`main`, it must carry this `'$(IsPackable)' == ''` guard, otherwise the same break will reappear on those branches. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
<!-- Please let the below note in for people that find this PR --> > [!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](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Description Docs/skill-only change. Adds a deterministic breadcrumb so a bare request like **"nightly is broken please fix"** routes an agent (or a human) straight to the right pipeline and the known failure surface, instead of guessing. Today nothing in the repo maps **"nightly" / "inflight feed" / "dogfood feed"** to the official signed build. `copilot-instructions.md` documents only the **PR** pipelines (`maui-pr`, `-devicetests`, `-uitests`), and `azdo-build-investigator` mentioned `ci-official.yml` only tangentially (CFSClean/Gradle). So an agent told the dogfood feed is stale had no way to know the AzDO definition id (1095) or org (`dnceng/internal`) to even query the builds. This matters now because we just shipped the **nightly dogfood feed staleness banner** (#36066) — when that banner turns ❌, the natural next question is *"which pipeline do I go fix?"* and the repo couldn't answer it. ### What changed - **`.github/skills/azdo-build-investigator/SKILL.md`** - Added `nightly` / `inflight feed` / `dogfood feed` / `official build` trigger phrases to the skill `description` (fixes routing). - New **"Nightly / Official Signed Build (inflight dogfood feed)"** section: the pipeline identity (`dotnet-maui`, definition **1095**, `dnceng`/`internal`, defined by `eng/pipelines/ci-official.yml`, cron `05:00 UTC` on `inflight/current`), the AzDO investigation recipe (`azdo_builds` by `definitionId`+branch → `azdo_search_timeline` → `azdo_search_log`), and the recurring **`vs-workload.props` (`MSB4019`)** failure in the `Pack Windows` → "Build Workloads, Sign & Publish" step. Plus a note that the macOS leg can pass while Windows fails, and that the release pipelines are distinct. - Added a matching row to the failure-pattern table. - **`.github/skills/release-readiness/SKILL.md`** - Cross-linked the ❌ staleness banner to the investigator section, so the banner's existing "check the nightly pipeline" hint has a documented target. ### Grounding Every fact was confirmed against the live failing run — definition `1095` / `dnceng-internal`, the `ci-official.yml` schedule, `stage-pack.yml:150` ("Build Workloads, Sign & Publish"), and the `MSB4019: vs-workload.props was not found` signature on `inflight/current` (a multi-day streak as of this writing). No product/runtime code is touched. ### Risk Documentation only. No code paths, no tests affected. `ci-official.yml` excludes `.github/**`, and `maui-pr` skips `.github/**`-only PRs by design. ### Update — confirmed root cause folded in A companion investigation (fix PR #36089, base `inflight/current`) binlog-proved the actual cause of the current outage, now documented in the breadcrumb: - The workload packs (`Microsoft.NET.Sdk.Maui.Manifest`, `Microsoft.Maui.Sdk`) target netstandard but ship, so they set `<IsPackable>true</IsPackable>` explicitly. - PR #32203's blanket `<IsPackable Condition="$(TargetFramework.Contains('netstandard'))">false</IsPackable>` in `Directory.Build.targets` (auto-imported last) overrode that → `IsPackable=false`. - The "Pack, Sign" step runs `-pack` **without** `-build`, so `Build` never ran → `_GenerateVSWorkloadProps` (`AfterTargets="Build"`) never wrote `vs-workload.props` → the line-30 import threw `MSB4019`. - Regression is **`inflight/current`-only** (the #32203 commit isn't on `main`/`net10.0` yet) — forward-port must carry the `and '$(IsPackable)' == ''` guard or the break reappears. The breadcrumb now teaches the real failure mechanism, not just the symptom, and links the fix. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
### Description of Change .NET Standard was never supported, but just remained to help MSBuild tasks. We don't need to actually ship them.
…s MSB4019) (#36089) <!-- Please let the below note in for people that find this PR --> > [!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](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Description of Change Fixes the **nightly official signed build** (`dotnet-maui`, definition 1095, dnceng/internal), which has failed **8 consecutive nights** on `refs/heads/inflight/current`. The Windows `Pack` job → step **"Build Workloads, Sign & Publish"** fails at restore/evaluation: ``` src\Workload\workloads.csproj(30,3): error MSB4019: The imported project "...\artifacts\packages\Release\Shipping\vs-workload.props" was not found. ``` ### Root cause The workload packs — `Microsoft.NET.Sdk.Maui.Manifest` and `Microsoft.Maui.Sdk` — both target **`netstandard2.0`** (via `src/Workload/Shared/Common.targets`) and both **explicitly** set `<IsPackable>true</IsPackable>` because they *are* the shipping workload packages. PR #32203 ("Don't pack .NET Standard") added a blanket rule to `Directory.Build.targets`: ```xml <IsPackable Condition="$(TargetFramework.Contains('netstandard'))">false</IsPackable> ``` `Directory.Build.targets` is auto-imported at the **end** of every project, so this assignment runs *after* the project body and **overrides** the explicit `<IsPackable>true</IsPackable>` on the workload packs. The net effect: the manifest project evaluates to `IsPackable=false`. The chain that breaks from there: 1. With `IsPackable=false`, NuGet's `Pack` target no-ops. 2. The official **"Pack, Sign"** step (`eng/pipelines/arcade/stage-pack.yml`) runs `-restore -pack -sign` **without `-build`**, so the `Build` target never runs for the manifest project. 3. `_GenerateVSWorkloadProps` (in `Microsoft.NET.Sdk.Maui.Manifest.csproj`) is hooked `AfterTargets="Build"`, so it never runs → `vs-workload.props` is never written to `$(ArtifactsShippingPackagesDir)`. 4. The next step (`-build … -projects src/Workload/workloads.csproj`) hits `workloads.csproj` line 30, whose `<Import Project="$(WorkloadMsiGenProps)" />` is unconditional and fails at evaluation → **MSB4019**. The blanket rule is also **over-broad**: it clobbers the explicit opt-in on *every* netstandard-only project, not just the workload packs (see **Scope** below). The workload/MSI leg simply failed loudest because its missing-file import is fatal at evaluation (MSB4019); the others would silently stop shipping. **Why `main` is green:** PR #32203 is on `inflight/current` only — it is *not* an ancestor of `main` or `net10.0` (verified with `git merge-base --is-ancestor`). `main` and `inflight/current` otherwise share identical `global.json` (dotnet `10.0.108`, arcade `25555.106`), identical `src/Workload`, and identical `Microsoft.Build.NoTargets 3.7.0`. The only relevant difference is the #32203 block, which is why this break is specific to `inflight/current`. ### Fix Guard the #32203 rule so it only applies when a project has **not** explicitly opted into packing: ```xml <IsPackable Condition="$(TargetFramework.Contains('netstandard')) and '$(IsPackable)' == ''">false</IsPackable> ``` - Projects that explicitly set `<IsPackable>true</IsPackable>` (the workload packs) are respected and pack again — restoring `vs-workload.props` generation. - Unmarked netstandard projects still default to not-packable, **preserving #32203's intent**. This restores the exact condition (`IsPackable=true` for the manifest project) that the passing `main` build exhibits, where `_GenerateVSWorkloadProps` runs and `vs-workload.props` is produced. ### Scope / blast radius Because #32203's blanket rule was over-broad, this guard restores packability for **6** netstandard-only projects that explicitly opt in — not just the 2 workload packs: | Project | TFM | |---|---| | `Microsoft.NET.Sdk.Maui.Manifest` | `netstandard2.0` | | `Microsoft.Maui.Sdk` | `netstandard2.0` | | `Resizetizer` | `netstandard2.0` | | `Controls.Build.Tasks` | `netstandard2.0` | | `Controls.SourceGen` | `netstandard2.0` | | `Graphics.Text.Markdig` | `netstandard2.0` | All 6 pack on `main` (which never had the #32203 rule), so this is a **`main`-parity restore**, not new shipping behavior. Multi-target libraries (e.g. `Core`, `Controls.Core`) are unaffected: `dotnet pack` evaluates `IsPackable` at the outer level where `TargetFramework=""`, so the netstandard rule never fires for them. ### How validated Root cause confirmed from the actual failing/passing build binlogs (not guesswork): | | failing `inflight/current` build `3006161` | passing `main` build `3006214` | |---|---|---| | `Microsoft.NET.Sdk.Maui.Manifest` `IsPackable` | **`false`** | **`true`** | | `_GenerateVSWorkloadProps` ran? | no (Build never ran) | yes → `vs-workload.props` produced | Verified locally on the `inflight/current` tree with `dotnet msbuild …Manifest.csproj -getProperty:IsPackable`: - **Before** fix: manifest `IsPackable=false` (reproduces the break). - **After** fix: manifest `IsPackable=true`, `Microsoft.Maui.Sdk` `IsPackable=true`. - `Microsoft.Maui.Core` (multi-target) at pack time is unchanged (`IsPackable=true`, `TargetFramework=""`; the netstandard rule only fires for single-TFM netstandard evaluations, so multi-target library packaging is unaffected). - A netstandard project with no explicit opt-in (`Controls.CustomAttributes`) still resolves `IsPackable=false` — #32203's intent preserved. The full signed Windows MSI leg only runs in the official pipeline; this change restores the property state that gates the entire pack → `vs-workload.props` → workloads handoff. **PR CI confirms the fix end-to-end:** on base `inflight/current` the `Pack Windows` leg fails at the root-cause spot; on this PR the same leg is green. The remaining red `maui-pr` legs are pre-existing on `inflight/current` (Windows Helix unit-test flakiness identical on base, and integration legs that were *skipped on base* because Pack was blocked and only run now that the fix unblocked Pack). ### Follow-up note When PR #32203's `Directory.Build.targets` change is forward-ported to `net10.0`/`main`, it must carry this `'$(IsPackable)' == ''` guard, otherwise the same break will reappear on those branches. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
### Description of Change .NET Standard was never supported, but just remained to help MSBuild tasks. We don't need to actually ship them.
…s MSB4019) (#36089) <!-- Please let the below note in for people that find this PR --> > [!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](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Description of Change Fixes the **nightly official signed build** (`dotnet-maui`, definition 1095, dnceng/internal), which has failed **8 consecutive nights** on `refs/heads/inflight/current`. The Windows `Pack` job → step **"Build Workloads, Sign & Publish"** fails at restore/evaluation: ``` src\Workload\workloads.csproj(30,3): error MSB4019: The imported project "...\artifacts\packages\Release\Shipping\vs-workload.props" was not found. ``` ### Root cause The workload packs — `Microsoft.NET.Sdk.Maui.Manifest` and `Microsoft.Maui.Sdk` — both target **`netstandard2.0`** (via `src/Workload/Shared/Common.targets`) and both **explicitly** set `<IsPackable>true</IsPackable>` because they *are* the shipping workload packages. PR #32203 ("Don't pack .NET Standard") added a blanket rule to `Directory.Build.targets`: ```xml <IsPackable Condition="$(TargetFramework.Contains('netstandard'))">false</IsPackable> ``` `Directory.Build.targets` is auto-imported at the **end** of every project, so this assignment runs *after* the project body and **overrides** the explicit `<IsPackable>true</IsPackable>` on the workload packs. The net effect: the manifest project evaluates to `IsPackable=false`. The chain that breaks from there: 1. With `IsPackable=false`, NuGet's `Pack` target no-ops. 2. The official **"Pack, Sign"** step (`eng/pipelines/arcade/stage-pack.yml`) runs `-restore -pack -sign` **without `-build`**, so the `Build` target never runs for the manifest project. 3. `_GenerateVSWorkloadProps` (in `Microsoft.NET.Sdk.Maui.Manifest.csproj`) is hooked `AfterTargets="Build"`, so it never runs → `vs-workload.props` is never written to `$(ArtifactsShippingPackagesDir)`. 4. The next step (`-build … -projects src/Workload/workloads.csproj`) hits `workloads.csproj` line 30, whose `<Import Project="$(WorkloadMsiGenProps)" />` is unconditional and fails at evaluation → **MSB4019**. The blanket rule is also **over-broad**: it clobbers the explicit opt-in on *every* netstandard-only project, not just the workload packs (see **Scope** below). The workload/MSI leg simply failed loudest because its missing-file import is fatal at evaluation (MSB4019); the others would silently stop shipping. **Why `main` is green:** PR #32203 is on `inflight/current` only — it is *not* an ancestor of `main` or `net10.0` (verified with `git merge-base --is-ancestor`). `main` and `inflight/current` otherwise share identical `global.json` (dotnet `10.0.108`, arcade `25555.106`), identical `src/Workload`, and identical `Microsoft.Build.NoTargets 3.7.0`. The only relevant difference is the #32203 block, which is why this break is specific to `inflight/current`. ### Fix Guard the #32203 rule so it only applies when a project has **not** explicitly opted into packing: ```xml <IsPackable Condition="$(TargetFramework.Contains('netstandard')) and '$(IsPackable)' == ''">false</IsPackable> ``` - Projects that explicitly set `<IsPackable>true</IsPackable>` (the workload packs) are respected and pack again — restoring `vs-workload.props` generation. - Unmarked netstandard projects still default to not-packable, **preserving #32203's intent**. This restores the exact condition (`IsPackable=true` for the manifest project) that the passing `main` build exhibits, where `_GenerateVSWorkloadProps` runs and `vs-workload.props` is produced. ### Scope / blast radius Because #32203's blanket rule was over-broad, this guard restores packability for **6** netstandard-only projects that explicitly opt in — not just the 2 workload packs: | Project | TFM | |---|---| | `Microsoft.NET.Sdk.Maui.Manifest` | `netstandard2.0` | | `Microsoft.Maui.Sdk` | `netstandard2.0` | | `Resizetizer` | `netstandard2.0` | | `Controls.Build.Tasks` | `netstandard2.0` | | `Controls.SourceGen` | `netstandard2.0` | | `Graphics.Text.Markdig` | `netstandard2.0` | All 6 pack on `main` (which never had the #32203 rule), so this is a **`main`-parity restore**, not new shipping behavior. Multi-target libraries (e.g. `Core`, `Controls.Core`) are unaffected: `dotnet pack` evaluates `IsPackable` at the outer level where `TargetFramework=""`, so the netstandard rule never fires for them. ### How validated Root cause confirmed from the actual failing/passing build binlogs (not guesswork): | | failing `inflight/current` build `3006161` | passing `main` build `3006214` | |---|---|---| | `Microsoft.NET.Sdk.Maui.Manifest` `IsPackable` | **`false`** | **`true`** | | `_GenerateVSWorkloadProps` ran? | no (Build never ran) | yes → `vs-workload.props` produced | Verified locally on the `inflight/current` tree with `dotnet msbuild …Manifest.csproj -getProperty:IsPackable`: - **Before** fix: manifest `IsPackable=false` (reproduces the break). - **After** fix: manifest `IsPackable=true`, `Microsoft.Maui.Sdk` `IsPackable=true`. - `Microsoft.Maui.Core` (multi-target) at pack time is unchanged (`IsPackable=true`, `TargetFramework=""`; the netstandard rule only fires for single-TFM netstandard evaluations, so multi-target library packaging is unaffected). - A netstandard project with no explicit opt-in (`Controls.CustomAttributes`) still resolves `IsPackable=false` — #32203's intent preserved. The full signed Windows MSI leg only runs in the official pipeline; this change restores the property state that gates the entire pack → `vs-workload.props` → workloads handoff. **PR CI confirms the fix end-to-end:** on base `inflight/current` the `Pack Windows` leg fails at the root-cause spot; on this PR the same leg is green. The remaining red `maui-pr` legs are pre-existing on `inflight/current` (Windows Helix unit-test flakiness identical on base, and integration legs that were *skipped on base* because Pack was blocked and only run now that the fix unblocked Pack). ### Follow-up note When PR #32203's `Directory.Build.targets` change is forward-ported to `net10.0`/`main`, it must carry this `'$(IsPackable)' == ''` guard, otherwise the same break will reappear on those branches. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
### Description of Change .NET Standard was never supported, but just remained to help MSBuild tasks. We don't need to actually ship them.
…s MSB4019) (#36089) <!-- Please let the below note in for people that find this PR --> > [!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](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Description of Change Fixes the **nightly official signed build** (`dotnet-maui`, definition 1095, dnceng/internal), which has failed **8 consecutive nights** on `refs/heads/inflight/current`. The Windows `Pack` job → step **"Build Workloads, Sign & Publish"** fails at restore/evaluation: ``` src\Workload\workloads.csproj(30,3): error MSB4019: The imported project "...\artifacts\packages\Release\Shipping\vs-workload.props" was not found. ``` ### Root cause The workload packs — `Microsoft.NET.Sdk.Maui.Manifest` and `Microsoft.Maui.Sdk` — both target **`netstandard2.0`** (via `src/Workload/Shared/Common.targets`) and both **explicitly** set `<IsPackable>true</IsPackable>` because they *are* the shipping workload packages. PR #32203 ("Don't pack .NET Standard") added a blanket rule to `Directory.Build.targets`: ```xml <IsPackable Condition="$(TargetFramework.Contains('netstandard'))">false</IsPackable> ``` `Directory.Build.targets` is auto-imported at the **end** of every project, so this assignment runs *after* the project body and **overrides** the explicit `<IsPackable>true</IsPackable>` on the workload packs. The net effect: the manifest project evaluates to `IsPackable=false`. The chain that breaks from there: 1. With `IsPackable=false`, NuGet's `Pack` target no-ops. 2. The official **"Pack, Sign"** step (`eng/pipelines/arcade/stage-pack.yml`) runs `-restore -pack -sign` **without `-build`**, so the `Build` target never runs for the manifest project. 3. `_GenerateVSWorkloadProps` (in `Microsoft.NET.Sdk.Maui.Manifest.csproj`) is hooked `AfterTargets="Build"`, so it never runs → `vs-workload.props` is never written to `$(ArtifactsShippingPackagesDir)`. 4. The next step (`-build … -projects src/Workload/workloads.csproj`) hits `workloads.csproj` line 30, whose `<Import Project="$(WorkloadMsiGenProps)" />` is unconditional and fails at evaluation → **MSB4019**. The blanket rule is also **over-broad**: it clobbers the explicit opt-in on *every* netstandard-only project, not just the workload packs (see **Scope** below). The workload/MSI leg simply failed loudest because its missing-file import is fatal at evaluation (MSB4019); the others would silently stop shipping. **Why `main` is green:** PR #32203 is on `inflight/current` only — it is *not* an ancestor of `main` or `net10.0` (verified with `git merge-base --is-ancestor`). `main` and `inflight/current` otherwise share identical `global.json` (dotnet `10.0.108`, arcade `25555.106`), identical `src/Workload`, and identical `Microsoft.Build.NoTargets 3.7.0`. The only relevant difference is the #32203 block, which is why this break is specific to `inflight/current`. ### Fix Guard the #32203 rule so it only applies when a project has **not** explicitly opted into packing: ```xml <IsPackable Condition="$(TargetFramework.Contains('netstandard')) and '$(IsPackable)' == ''">false</IsPackable> ``` - Projects that explicitly set `<IsPackable>true</IsPackable>` (the workload packs) are respected and pack again — restoring `vs-workload.props` generation. - Unmarked netstandard projects still default to not-packable, **preserving #32203's intent**. This restores the exact condition (`IsPackable=true` for the manifest project) that the passing `main` build exhibits, where `_GenerateVSWorkloadProps` runs and `vs-workload.props` is produced. ### Scope / blast radius Because #32203's blanket rule was over-broad, this guard restores packability for **6** netstandard-only projects that explicitly opt in — not just the 2 workload packs: | Project | TFM | |---|---| | `Microsoft.NET.Sdk.Maui.Manifest` | `netstandard2.0` | | `Microsoft.Maui.Sdk` | `netstandard2.0` | | `Resizetizer` | `netstandard2.0` | | `Controls.Build.Tasks` | `netstandard2.0` | | `Controls.SourceGen` | `netstandard2.0` | | `Graphics.Text.Markdig` | `netstandard2.0` | All 6 pack on `main` (which never had the #32203 rule), so this is a **`main`-parity restore**, not new shipping behavior. Multi-target libraries (e.g. `Core`, `Controls.Core`) are unaffected: `dotnet pack` evaluates `IsPackable` at the outer level where `TargetFramework=""`, so the netstandard rule never fires for them. ### How validated Root cause confirmed from the actual failing/passing build binlogs (not guesswork): | | failing `inflight/current` build `3006161` | passing `main` build `3006214` | |---|---|---| | `Microsoft.NET.Sdk.Maui.Manifest` `IsPackable` | **`false`** | **`true`** | | `_GenerateVSWorkloadProps` ran? | no (Build never ran) | yes → `vs-workload.props` produced | Verified locally on the `inflight/current` tree with `dotnet msbuild …Manifest.csproj -getProperty:IsPackable`: - **Before** fix: manifest `IsPackable=false` (reproduces the break). - **After** fix: manifest `IsPackable=true`, `Microsoft.Maui.Sdk` `IsPackable=true`. - `Microsoft.Maui.Core` (multi-target) at pack time is unchanged (`IsPackable=true`, `TargetFramework=""`; the netstandard rule only fires for single-TFM netstandard evaluations, so multi-target library packaging is unaffected). - A netstandard project with no explicit opt-in (`Controls.CustomAttributes`) still resolves `IsPackable=false` — #32203's intent preserved. The full signed Windows MSI leg only runs in the official pipeline; this change restores the property state that gates the entire pack → `vs-workload.props` → workloads handoff. **PR CI confirms the fix end-to-end:** on base `inflight/current` the `Pack Windows` leg fails at the root-cause spot; on this PR the same leg is green. The remaining red `maui-pr` legs are pre-existing on `inflight/current` (Windows Helix unit-test flakiness identical on base, and integration legs that were *skipped on base* because Pack was blocked and only run now that the fix unblocked Pack). ### Follow-up note When PR #32203's `Directory.Build.targets` change is forward-ported to `net10.0`/`main`, it must carry this `'$(IsPackable)' == ''` guard, otherwise the same break will reappear on those branches. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
### Description of Change .NET Standard was never supported, but just remained to help MSBuild tasks. We don't need to actually ship them.
…s MSB4019) (#36089) <!-- Please let the below note in for people that find this PR --> > [!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](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Description of Change Fixes the **nightly official signed build** (`dotnet-maui`, definition 1095, dnceng/internal), which has failed **8 consecutive nights** on `refs/heads/inflight/current`. The Windows `Pack` job → step **"Build Workloads, Sign & Publish"** fails at restore/evaluation: ``` src\Workload\workloads.csproj(30,3): error MSB4019: The imported project "...\artifacts\packages\Release\Shipping\vs-workload.props" was not found. ``` ### Root cause The workload packs — `Microsoft.NET.Sdk.Maui.Manifest` and `Microsoft.Maui.Sdk` — both target **`netstandard2.0`** (via `src/Workload/Shared/Common.targets`) and both **explicitly** set `<IsPackable>true</IsPackable>` because they *are* the shipping workload packages. PR #32203 ("Don't pack .NET Standard") added a blanket rule to `Directory.Build.targets`: ```xml <IsPackable Condition="$(TargetFramework.Contains('netstandard'))">false</IsPackable> ``` `Directory.Build.targets` is auto-imported at the **end** of every project, so this assignment runs *after* the project body and **overrides** the explicit `<IsPackable>true</IsPackable>` on the workload packs. The net effect: the manifest project evaluates to `IsPackable=false`. The chain that breaks from there: 1. With `IsPackable=false`, NuGet's `Pack` target no-ops. 2. The official **"Pack, Sign"** step (`eng/pipelines/arcade/stage-pack.yml`) runs `-restore -pack -sign` **without `-build`**, so the `Build` target never runs for the manifest project. 3. `_GenerateVSWorkloadProps` (in `Microsoft.NET.Sdk.Maui.Manifest.csproj`) is hooked `AfterTargets="Build"`, so it never runs → `vs-workload.props` is never written to `$(ArtifactsShippingPackagesDir)`. 4. The next step (`-build … -projects src/Workload/workloads.csproj`) hits `workloads.csproj` line 30, whose `<Import Project="$(WorkloadMsiGenProps)" />` is unconditional and fails at evaluation → **MSB4019**. The blanket rule is also **over-broad**: it clobbers the explicit opt-in on *every* netstandard-only project, not just the workload packs (see **Scope** below). The workload/MSI leg simply failed loudest because its missing-file import is fatal at evaluation (MSB4019); the others would silently stop shipping. **Why `main` is green:** PR #32203 is on `inflight/current` only — it is *not* an ancestor of `main` or `net10.0` (verified with `git merge-base --is-ancestor`). `main` and `inflight/current` otherwise share identical `global.json` (dotnet `10.0.108`, arcade `25555.106`), identical `src/Workload`, and identical `Microsoft.Build.NoTargets 3.7.0`. The only relevant difference is the #32203 block, which is why this break is specific to `inflight/current`. ### Fix Guard the #32203 rule so it only applies when a project has **not** explicitly opted into packing: ```xml <IsPackable Condition="$(TargetFramework.Contains('netstandard')) and '$(IsPackable)' == ''">false</IsPackable> ``` - Projects that explicitly set `<IsPackable>true</IsPackable>` (the workload packs) are respected and pack again — restoring `vs-workload.props` generation. - Unmarked netstandard projects still default to not-packable, **preserving #32203's intent**. This restores the exact condition (`IsPackable=true` for the manifest project) that the passing `main` build exhibits, where `_GenerateVSWorkloadProps` runs and `vs-workload.props` is produced. ### Scope / blast radius Because #32203's blanket rule was over-broad, this guard restores packability for **6** netstandard-only projects that explicitly opt in — not just the 2 workload packs: | Project | TFM | |---|---| | `Microsoft.NET.Sdk.Maui.Manifest` | `netstandard2.0` | | `Microsoft.Maui.Sdk` | `netstandard2.0` | | `Resizetizer` | `netstandard2.0` | | `Controls.Build.Tasks` | `netstandard2.0` | | `Controls.SourceGen` | `netstandard2.0` | | `Graphics.Text.Markdig` | `netstandard2.0` | All 6 pack on `main` (which never had the #32203 rule), so this is a **`main`-parity restore**, not new shipping behavior. Multi-target libraries (e.g. `Core`, `Controls.Core`) are unaffected: `dotnet pack` evaluates `IsPackable` at the outer level where `TargetFramework=""`, so the netstandard rule never fires for them. ### How validated Root cause confirmed from the actual failing/passing build binlogs (not guesswork): | | failing `inflight/current` build `3006161` | passing `main` build `3006214` | |---|---|---| | `Microsoft.NET.Sdk.Maui.Manifest` `IsPackable` | **`false`** | **`true`** | | `_GenerateVSWorkloadProps` ran? | no (Build never ran) | yes → `vs-workload.props` produced | Verified locally on the `inflight/current` tree with `dotnet msbuild …Manifest.csproj -getProperty:IsPackable`: - **Before** fix: manifest `IsPackable=false` (reproduces the break). - **After** fix: manifest `IsPackable=true`, `Microsoft.Maui.Sdk` `IsPackable=true`. - `Microsoft.Maui.Core` (multi-target) at pack time is unchanged (`IsPackable=true`, `TargetFramework=""`; the netstandard rule only fires for single-TFM netstandard evaluations, so multi-target library packaging is unaffected). - A netstandard project with no explicit opt-in (`Controls.CustomAttributes`) still resolves `IsPackable=false` — #32203's intent preserved. The full signed Windows MSI leg only runs in the official pipeline; this change restores the property state that gates the entire pack → `vs-workload.props` → workloads handoff. **PR CI confirms the fix end-to-end:** on base `inflight/current` the `Pack Windows` leg fails at the root-cause spot; on this PR the same leg is green. The remaining red `maui-pr` legs are pre-existing on `inflight/current` (Windows Helix unit-test flakiness identical on base, and integration legs that were *skipped on base* because Pack was blocked and only run now that the fix unblocked Pack). ### Follow-up note When PR #32203's `Directory.Build.targets` change is forward-ported to `net10.0`/`main`, it must carry this `'$(IsPackable)' == ''` guard, otherwise the same break will reappear on those branches. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
### Description of Change .NET Standard was never supported, but just remained to help MSBuild tasks. We don't need to actually ship them.
…s MSB4019) (#36089) <!-- Please let the below note in for people that find this PR --> > [!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](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Description of Change Fixes the **nightly official signed build** (`dotnet-maui`, definition 1095, dnceng/internal), which has failed **8 consecutive nights** on `refs/heads/inflight/current`. The Windows `Pack` job → step **"Build Workloads, Sign & Publish"** fails at restore/evaluation: ``` src\Workload\workloads.csproj(30,3): error MSB4019: The imported project "...\artifacts\packages\Release\Shipping\vs-workload.props" was not found. ``` ### Root cause The workload packs — `Microsoft.NET.Sdk.Maui.Manifest` and `Microsoft.Maui.Sdk` — both target **`netstandard2.0`** (via `src/Workload/Shared/Common.targets`) and both **explicitly** set `<IsPackable>true</IsPackable>` because they *are* the shipping workload packages. PR #32203 ("Don't pack .NET Standard") added a blanket rule to `Directory.Build.targets`: ```xml <IsPackable Condition="$(TargetFramework.Contains('netstandard'))">false</IsPackable> ``` `Directory.Build.targets` is auto-imported at the **end** of every project, so this assignment runs *after* the project body and **overrides** the explicit `<IsPackable>true</IsPackable>` on the workload packs. The net effect: the manifest project evaluates to `IsPackable=false`. The chain that breaks from there: 1. With `IsPackable=false`, NuGet's `Pack` target no-ops. 2. The official **"Pack, Sign"** step (`eng/pipelines/arcade/stage-pack.yml`) runs `-restore -pack -sign` **without `-build`**, so the `Build` target never runs for the manifest project. 3. `_GenerateVSWorkloadProps` (in `Microsoft.NET.Sdk.Maui.Manifest.csproj`) is hooked `AfterTargets="Build"`, so it never runs → `vs-workload.props` is never written to `$(ArtifactsShippingPackagesDir)`. 4. The next step (`-build … -projects src/Workload/workloads.csproj`) hits `workloads.csproj` line 30, whose `<Import Project="$(WorkloadMsiGenProps)" />` is unconditional and fails at evaluation → **MSB4019**. The blanket rule is also **over-broad**: it clobbers the explicit opt-in on *every* netstandard-only project, not just the workload packs (see **Scope** below). The workload/MSI leg simply failed loudest because its missing-file import is fatal at evaluation (MSB4019); the others would silently stop shipping. **Why `main` is green:** PR #32203 is on `inflight/current` only — it is *not* an ancestor of `main` or `net10.0` (verified with `git merge-base --is-ancestor`). `main` and `inflight/current` otherwise share identical `global.json` (dotnet `10.0.108`, arcade `25555.106`), identical `src/Workload`, and identical `Microsoft.Build.NoTargets 3.7.0`. The only relevant difference is the #32203 block, which is why this break is specific to `inflight/current`. ### Fix Guard the #32203 rule so it only applies when a project has **not** explicitly opted into packing: ```xml <IsPackable Condition="$(TargetFramework.Contains('netstandard')) and '$(IsPackable)' == ''">false</IsPackable> ``` - Projects that explicitly set `<IsPackable>true</IsPackable>` (the workload packs) are respected and pack again — restoring `vs-workload.props` generation. - Unmarked netstandard projects still default to not-packable, **preserving #32203's intent**. This restores the exact condition (`IsPackable=true` for the manifest project) that the passing `main` build exhibits, where `_GenerateVSWorkloadProps` runs and `vs-workload.props` is produced. ### Scope / blast radius Because #32203's blanket rule was over-broad, this guard restores packability for **6** netstandard-only projects that explicitly opt in — not just the 2 workload packs: | Project | TFM | |---|---| | `Microsoft.NET.Sdk.Maui.Manifest` | `netstandard2.0` | | `Microsoft.Maui.Sdk` | `netstandard2.0` | | `Resizetizer` | `netstandard2.0` | | `Controls.Build.Tasks` | `netstandard2.0` | | `Controls.SourceGen` | `netstandard2.0` | | `Graphics.Text.Markdig` | `netstandard2.0` | All 6 pack on `main` (which never had the #32203 rule), so this is a **`main`-parity restore**, not new shipping behavior. Multi-target libraries (e.g. `Core`, `Controls.Core`) are unaffected: `dotnet pack` evaluates `IsPackable` at the outer level where `TargetFramework=""`, so the netstandard rule never fires for them. ### How validated Root cause confirmed from the actual failing/passing build binlogs (not guesswork): | | failing `inflight/current` build `3006161` | passing `main` build `3006214` | |---|---|---| | `Microsoft.NET.Sdk.Maui.Manifest` `IsPackable` | **`false`** | **`true`** | | `_GenerateVSWorkloadProps` ran? | no (Build never ran) | yes → `vs-workload.props` produced | Verified locally on the `inflight/current` tree with `dotnet msbuild …Manifest.csproj -getProperty:IsPackable`: - **Before** fix: manifest `IsPackable=false` (reproduces the break). - **After** fix: manifest `IsPackable=true`, `Microsoft.Maui.Sdk` `IsPackable=true`. - `Microsoft.Maui.Core` (multi-target) at pack time is unchanged (`IsPackable=true`, `TargetFramework=""`; the netstandard rule only fires for single-TFM netstandard evaluations, so multi-target library packaging is unaffected). - A netstandard project with no explicit opt-in (`Controls.CustomAttributes`) still resolves `IsPackable=false` — #32203's intent preserved. The full signed Windows MSI leg only runs in the official pipeline; this change restores the property state that gates the entire pack → `vs-workload.props` → workloads handoff. **PR CI confirms the fix end-to-end:** on base `inflight/current` the `Pack Windows` leg fails at the root-cause spot; on this PR the same leg is green. The remaining red `maui-pr` legs are pre-existing on `inflight/current` (Windows Helix unit-test flakiness identical on base, and integration legs that were *skipped on base* because Pack was blocked and only run now that the fix unblocked Pack). ### Follow-up note When PR #32203's `Directory.Build.targets` change is forward-ported to `net10.0`/`main`, it must carry this `'$(IsPackable)' == ''` guard, otherwise the same break will reappear on those branches. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Description of Change
.NET Standard was never supported, but just remained to help MSBuild tasks.
We don't need to actually ship them.