Skip to content

Migrate Common.GenerateSourceLinkFile to multithreaded task model#1733

Open
jankratochvilcz wants to merge 6 commits into
dotnet:mainfrom
jankratochvilcz:mt/generate-sourcelinkfile
Open

Migrate Common.GenerateSourceLinkFile to multithreaded task model#1733
jankratochvilcz wants to merge 6 commits into
dotnet:mainfrom
jankratochvilcz:mt/generate-sourcelinkfile

Conversation

@jankratochvilcz

Copy link
Copy Markdown
Contributor

Summary

Migrates Microsoft.SourceLink.Common.GenerateSourceLinkFile to the MSBuild multithreaded task model for dotnet/msbuild#14093.

Details

  • Adds [MSBuildMultiThreadableTask] and implements IMultiThreadableTask with TaskEnvironment.Fallback so direct unit-test construction keeps existing semantics.
  • Resolves OutputFile via TaskEnvironment.GetAbsolutePath before all File.Exists, File.Delete, File.ReadAllText, and File.WriteAllText calls, so relative paths are based on the project directory instead of process CWD.
  • Preserves Sin 1 behavior by keeping the [Output] SourceLink value as the original OutputFile string, not the absolute path.
  • Preserves Sin 2 behavior by continuing to log the original OutputFile value and sanitizing exception messages that include the absolutized path back to the original path.
  • Keeps the prior empty-content/null-or-empty OutputFile no-existing-file behavior before absolutization; non-empty content still fails through the existing catch path.

Tests

  • ./build.sh --restore --build --verbosity minimal
  • ./.dotnet/dotnet test src/SourceLink.Common.UnitTests/Microsoft.SourceLink.Common.UnitTests.csproj -f net11.0 --no-restore
  • Added WriteSourceLinkFileResolvesRelativeOutputFileAgainstProjectDirectory, a decoy-CWD test that verifies a relative output file is written under the TaskEnvironment project directory, not process CWD, while SourceLink remains the original relative value.

Add the MSBuild multithreaded task marker and IMultiThreadableTask implementation with a TaskEnvironment fallback for direct unit-test construction.

Resolve OutputFile through TaskEnvironment once for file operations while preserving the original OutputFile value for the SourceLink output and log messages. Sanitize exception messages that may contain the absolutized path back to the original path, and preserve the empty-output/null-or-empty OutputFile no-file behavior before absolutization.

Add a decoy-CWD test that proves a relative OutputFile is resolved against the project directory while SourceLink remains the original relative value.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jankratochvilcz jankratochvilcz requested a review from tmat as a code owner June 30, 2026 13:39
@jankratochvilcz

Copy link
Copy Markdown
Contributor Author

Automated MT review (MT-migration reviewer + expert code review): both approved, no blocking/actionable findings. Verified: Sin 1 (SourceLink output keeps the original relative path on both the up-to-date and write branches), Sin 2 (all log/error messages use the original OutputFile; catch-block sanitizes the exception message back to the original path), Sin 3/6 (full {content}×{OutputFile} truth table matches pre-migration behavior; the added content==null && IsNullOrEmpty(OutputFile) guard avoids GetAbsolutePath("") while preserving the original outcome), nullable AbsolutePath? handling, and a parallel-safe decoy-CWD test that fails if the migration is reverted. No changes required.

@jankratochvilcz jankratochvilcz marked this pull request as draft June 30, 2026 16:25
jankratochvilcz and others added 2 commits July 3, 2026 12:09
The empty-OutputFile/null-content guard only calls string.IsNullOrEmpty and
Log.LogMessage and returns before outputPath is assigned, so none of it can
throw. Move it above the try so the try scopes exactly the code that can throw
(GetAbsolutePath + file I/O). No behavior change.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jankratochvilcz jankratochvilcz marked this pull request as ready for review July 3, 2026 10:12
Log.LogWarning(Resources.SourceControlInformationIsNotAvailableGeneratedSourceLinkEmpty);
}

if (content == null && string.IsNullOrEmpty(OutputFile))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd make it a requirement on OutputFile to be an absolute path. The value of this parameter is controlled by our target and set from _SourceLinkFilePath defined here:

<_SourceLinkFilePath>$(IntermediateOutputPath)$(MSBuildProjectName).sourcelink.json</_SourceLinkFilePath>

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.

@tmat I changed the implementation, please check it out

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.

@tmat Are you confident on this one? We have failing tests that suggest that currently absolute paths are not always being passed 👀

image

Address review feedback: rather than resolving OutputFile against the
task's working directory via TaskEnvironment.GetAbsolutePath, require it
to already be a fully qualified path. OutputFile is set by the SourceLink
targets from _SourceLinkFilePath, so it is always fully qualified in
practice, and file access must not depend on the shared process current
directory under the multithreaded task model.

- Make the MT migration attribute-only: drop IMultiThreadableTask and the
  TaskEnvironment property; keep [MSBuildMultiThreadableTask]. OutputFile is
  the only filesystem path the task touches, so rejecting a non-fully-qualified
  value makes the task MT-safe.
- Reject a non-fully-qualified OutputFile via PathUtilities.IsPathFullyQualified.
- Replace the relative-path resolution test with one asserting rejection.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
jankratochvilcz and others added 2 commits July 9, 2026 10:57
GenerateSourceLinkFile now requires OutputFile to be fully qualified. The
targets set OutputFile from _SourceLinkFilePath, which was relative because
IntermediateOutputPath is relative. Normalize it against the project directory
so all source link tasks operate on absolute paths, and update integration
tests to expect the absolute $(SourceLink) value.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants