Skip to content

Migrate StaticWebAssetsGeneratePackagePropsFile to IMultiThreadableTask#54617

Open
jankratochvilcz wants to merge 3 commits into
dotnet:mainfrom
jankratochvilcz:migrate-swa-generate-package-props
Open

Migrate StaticWebAssetsGeneratePackagePropsFile to IMultiThreadableTask#54617
jankratochvilcz wants to merge 3 commits into
dotnet:mainfrom
jankratochvilcz:migrate-swa-generate-package-props

Conversation

@jankratochvilcz
Copy link
Copy Markdown
Contributor

Context

MSBuild's multi-threaded task execution model does not guarantee that the process current directory matches the project directory. Tasks that touch the filesystem need to resolve paths through the injected TaskEnvironment.

Changes

  • Mark StaticWebAssetsGeneratePackagePropsFile as an MSBuild multi-threadable task.
  • Implement IMultiThreadableTask and resolve BuildTargetPath via TaskEnvironment before file IO.
  • Add a regression test that changes the process CWD and verifies a relative output path is written under the task environment project directory.

Safety

The existing fallback behavior is preserved through TaskEnvironment.Fallback, so legacy absolute paths continue to work. The task has no output path items that need OriginalValue preservation.

Testing

  • ./.dotnet/dotnet build src/StaticWebAssetsSdk/Tasks/Microsoft.NET.Sdk.StaticWebAssets.Tasks.csproj
  • ./.dotnet/dotnet build test/Microsoft.NET.Sdk.StaticWebAssets.Tests/Microsoft.NET.Sdk.StaticWebAssets.Tests.csproj
  • ./.dotnet/dotnet exec artifacts/bin/Microsoft.NET.Sdk.StaticWebAssets.Tests/Debug/net11.0/Microsoft.NET.Sdk.StaticWebAssets.Tests.dll -method "StaticWebAssetsGeneratePackagePropsFile" -noLogo -noAutoReporters

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 5, 2026 14:16
@github-actions github-actions Bot added the Area-AspNetCore RazorSDK, BlazorWebAssemblySDK, StaticWebAssetsSDK label Jun 5, 2026
@dotnet-policy-service
Copy link
Copy Markdown
Contributor

Thanks for your PR, @jankratochvilcz.
To learn about the PR process and branching schedule of this repo, please take a look at the SDK PR Guide.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the Static Web Assets SDK task StaticWebAssetsGeneratePackagePropsFile to be safe under MSBuild’s multi-threaded task execution model by resolving filesystem paths via TaskEnvironment rather than relying on the process current directory.

Changes:

  • Mark StaticWebAssetsGeneratePackagePropsFile as multi-threadable ([MSBuildMultiThreadableTask], IMultiThreadableTask).
  • Resolve BuildTargetPath using TaskEnvironment.GetAbsolutePath(...) before performing file IO.
  • Add a regression test that changes the process CWD and verifies the props file is still written under the task-environment project directory.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
src/StaticWebAssetsSdk/Tasks/StaticWebAssetsGeneratePackagePropsFile.cs Makes the task MSBuild-multithreadable and ensures file output uses TaskEnvironment-resolved paths.
test/Microsoft.NET.Sdk.StaticWebAssets.Tests/StaticWebAssets/StaticWebAssetsGeneratePackagePropsFileMultiThreadingTest.cs Adds a regression test to validate correct output location when process CWD differs from the project directory.

Comment thread src/StaticWebAssetsSdk/Tasks/StaticWebAssetsGeneratePackagePropsFile.cs Outdated
jankratochvilcz and others added 2 commits June 5, 2026 16:33
- Fix awkward log message grammar (Copilot comment 3363270444)
- Remove redundant test [Collection]/[CollectionDefinition] now that
  parallelization is disabled assembly-wide via
  LegacyStaticWebAssetsV1IntegrationTest.cs (Copilot comments 3363270493, 3363270509)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Avoid leaking the resolved absolute path into log output ("sin" of
MT migrations — preserve original caller shape for user-visible
strings; only use the resolved absolute path for file I/O).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

@jankratochvilcz jankratochvilcz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Self-review notes on intentional path-handling decisions (this PR was authored by an autonomous agent — reviewer, please push back if any of this sounds off).

AbsolutePath buildTargetPath = TaskEnvironment.GetAbsolutePath(BuildTargetPath);

var document = new XDocument(new XDeclaration("1.0", "utf-8", "yes"));
var elements = (AdditionalImports ?? []).Select(e => e.ItemSpec).Prepend(PropsFileImport)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Intentionally NOT routed through TaskEnvironment.GetAbsolutePath.

PropsFileImport and each AdditionalImports.ItemSpec end up here verbatim as the value of <Import Project="..."/> in the generated .props file (line 35 below). That generated .props file is packed into a NuGet (e.g., build/<PackageId>.props) and consumed on a different machine. MSBuild resolves the Project attribute at consume time, relative to the directory of the importing file — so the value must stay package-relative.

Example. A consumer authors <PackageReference Include="Contoso.AspNetCore.StaticWebAssets" />. NuGet drops build/Contoso.AspNetCore.StaticWebAssets.props which contains:

<Import Project="Microsoft.AspNetCore.StaticWebAssets.props" />

That resolves to <nuget-cache>/contoso.aspnetcore.staticwebassets/<ver>/build/Microsoft.AspNetCore.StaticWebAssets.props on the consumer's machine. If we absolutized at pack time it would become e.g. /Users/jan/src/.../Microsoft.AspNetCore.StaticWebAssets.props and break every consumer.

The only path with a real CWD-vs-project-dir dependency in this task is BuildTargetPath (the write target), which is correctly routed through TaskEnvironment.GetAbsolutePath above. Imports are pure pass-through string content of the generated file.

Reviewer: if this reasoning is wrong (e.g., a call site does pass relative imports that need resolution at task time, not at consume time), please flag — this PR was authored by an autonomous agent and I'd like a human pair of eyes on this decision specifically.

{
Log.LogMessage(MessageImportance.Low, $"Creating file '{BuildTargetPath}' does not exist.");
File.WriteAllBytes(BuildTargetPath, data);
Log.LogMessage(MessageImportance.Low, $"Creating file '{BuildTargetPath}' because it does not exist.");
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Intentionally logs the caller-shape BuildTargetPath, not the resolved buildTargetPath.

The local buildTargetPath is always an absolute path (the output of TaskEnvironment.GetAbsolutePath). Logging it would leak machine-specific paths into customer-visible diagnostics and change historical log output for any caller that passed a relative path. File.Exists/File.WriteAllBytes below correctly use the resolved absolute path; only the user-visible string keeps the original shape — same pattern recent migrations (#54444) use via AbsolutePath.OriginalValue for output metadata.

Reviewer: if there's a stronger convention here (e.g., always log the absolute path because that's what hits disk), let me know. Autonomous-agent-authored PR — please challenge if this looks wrong.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-AspNetCore RazorSDK, BlazorWebAssemblySDK, StaticWebAssetsSDK

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants