Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 26, 2026

Context

Mirrors PR #12914 which migrated Copy, Delete, MakeDir, RemoveDir, and Touch tasks to use the thread-safe task API. Path.GetFullPath() uses process-global CWD state which is unsafe when tasks run in parallel. TaskEnvironment.GetAbsolutePath() provides thread-safe path resolution via the task's execution context.

Changes Made

src/Tasks/Move.cs:

  • Add [MSBuildMultiThreadableTask] attribute and IMultiThreadableTask interface
  • Add TaskEnvironment property
  • Change MoveFileWithLogging and MakeWriteableIfReadOnly to accept AbsolutePath instead of string
  • Resolve paths via TaskEnvironment.GetAbsolutePath() in Execute(), with calls placed inside the try block using nullable AbsolutePath? to preserve original error handling behavior (log error and continue with other inputs)
  • Use sourceFile?.OriginalValue ?? sourceSpec for LockCheck.GetLockedFileMessage call to safely handle null sourceFile in catch block

src/Tasks.UnitTests/Move_Tests.cs:

  • Add TaskEnvironmentHelper.CreateForTest() to all 20 Move task instantiations

Testing

All 18 applicable Move tests pass. 5 tests skipped (Windows/.NET Framework only).

Notes

Pattern matches existing implementations in Copy.cs, Delete.cs, MakeDir.cs, RemoveDir.cs, Touch.cs. The GetAbsolutePath calls are placed inside the try block (similar to Delete.cs) to ensure that any ArgumentException from null/empty paths is caught and logged, allowing the task to continue processing remaining files. The null-coalescing pattern for LockCheck.GetLockedFileMessage is consistent with the approach used in Delete.cs and MakeDir.cs.

Original prompt

Look at what happened in this Pull request with the tasks: #12914

Do the same for the "Move" task, preserve correctness, performance and validate tests pass


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@dotnet-policy-service
Copy link
Contributor

Hello @@copilot, I noticed that you’re changing an .swr file or any file under src/Package/MSBuild.VSSetup.. Please make sure to validate this change by an experimental VS insertion. This is accomplished by pushing to an exp/* branch, which requires write permissions to this repo.

Copilot AI changed the title [WIP] Refactor move task to preserve correctness and performance Implement IMultiThreadableTask for Move task Jan 26, 2026
Copilot AI requested a review from JanProvaznik January 26, 2026 10:03
@JanProvaznik JanProvaznik marked this pull request as ready for review January 26, 2026 10:07
Copy link
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 pull request implements the IMultiThreadableTask interface for the Move task, enabling thread-safe execution in parallel build scenarios by replacing process-global Path.GetFullPath() calls with thread-safe TaskEnvironment.GetAbsolutePath(). This mirrors the changes made in PR #12914 for Copy, Delete, MakeDir, RemoveDir, and Touch tasks.

Changes:

  • Modified Move task to implement IMultiThreadableTask and use TaskEnvironment for thread-safe path resolution
  • Updated Move task tests to initialize TaskEnvironment for test execution
  • Maintained backward compatibility by using OriginalValue for logging user-visible paths

Reviewed changes

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

File Description
src/Tasks/Move.cs Added IMultiThreadableTask interface, TaskEnvironment property, and converted MoveFileWithLogging and MakeWriteableIfReadOnly to accept AbsolutePath instead of string
src/Tasks.UnitTests/Move_Tests.cs Added TaskEnvironment initialization to 20 Move task instantiations in test methods

string sourceSpec = SourceFiles[i].ItemSpec;
string destinationSpec = DestinationFiles[i].ItemSpec;

AbsolutePath sourceFile = TaskEnvironment.GetAbsolutePath(sourceSpec);
Copy link
Member

Choose a reason for hiding this comment

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

@copilot this can throw when sourceSpec is null or empty. This introduces a behavioral change: before the chnages the task would log error and continue with other inputs, while now it will throw and not process other inputs.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 8b4620b. Moved the GetAbsolutePath calls inside the try block (using nullable AbsolutePath? variables initialized to null) so that any ArgumentException from null/empty paths is caught and logged, allowing processing to continue with other inputs - matching the original behavior and the pattern used in Delete.cs.

Copy link
Member

Choose a reason for hiding this comment

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

thanks for catching that, lgtm

Copy link
Member

Choose a reason for hiding this comment

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

not sure if you're able to approve now that you copilot commited though :D

Copy link
Member

Choose a reason for hiding this comment

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

it is not a full fix yet, there is a possible null value in catch block in logging.

Copy link
Member

Choose a reason for hiding this comment

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

as for approval, let's see :)

Copilot AI requested a review from AR-May January 28, 2026 13:33

AbsolutePath sourceFile = TaskEnvironment.GetAbsolutePath(sourceSpec);
AbsolutePath destinationFile = TaskEnvironment.GetAbsolutePath(destinationSpec);
AbsolutePath? sourceFile = null;
Copy link
Member

Choose a reason for hiding this comment

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

@copilot in the catch block there is line
string lockedFileMessage = LockCheck.GetLockedFileMessage(sourceFile);
in which sourceFile may be null while before it could not.
Account for the possibility of throwing on TaskEnvironment.GetAbsolutePath and having null value for the sourceFile in the catch block.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 81911cb. Changed line 182 to use sourceFile?.Value ?? sourceSpec so that when sourceFile is null (if GetAbsolutePath throws), we fall back to the original sourceSpec string for the lock check message.

Copy link
Member

Choose a reason for hiding this comment

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

that's overengineering, if it's null it will eat that behavior inside and that's OK, because there is no locked file message for nonexistsnt files 😕

Copy link
Member

@AR-May AR-May Jan 29, 2026

Choose a reason for hiding this comment

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

you sure it does not throw on null? then I guess it is an overkill

Copilot AI requested a review from AR-May January 29, 2026 15:18
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.

3 participants