Enlighten RAR task#13319
Conversation
There was a problem hiding this comment.
Pull request overview
This PR advances “RAR task enlightening” by routing path resolution and environment access through TaskEnvironment (including in the out-of-proc RAR node), and by upgrading several RAR inputs from strings to AbsolutePath to ensure stable, project-relative-to-absolute resolution in multithreaded builds.
Changes:
- RAR and related resolvers now use
TaskEnvironmentfor absolute path conversion and environment variable access. - Out-of-proc RAR node now hydrates a multithreaded
TaskEnvironmentusing the client project directory. - Introduces a new ChangeWave (18.6) and updates task/unit test code to provide
TaskEnvironment.
Reviewed changes
Copilot reviewed 51 out of 51 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Tasks/SystemState.cs | Uses TaskEnvironment for state file path handling during precomputed cache load. |
| src/Tasks/StateFileBase.cs | Clarifies expectation that state file path is absolute. |
| src/Tasks/RedistList.cs | Moves redist list paths to AbsolutePath and enables TaskEnvironment-based absolutization. |
| src/Tasks/InstalledSDKResolver.cs | Caches absolute SDK root paths for resolver probing. |
| src/Tasks/GetReferenceAssemblyPaths.cs | Marks task as multi-threadable and passes TaskEnvironment into GAC resolution. |
| src/Tasks/AssemblyDependency/Resolver.cs | Adds TaskEnvironment to resolver base for consistent path/env usage. |
| src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs | Converts several inputs to AbsolutePath, adds MT task interface, and updates RAR execution to pass TaskEnvironment through the pipeline. |
| src/Tasks/AssemblyDependency/ReferenceTable.cs | Propagates TaskEnvironment into resolution pipeline and normalizes resolved paths. |
| src/Tasks/AssemblyDependency/Reference.cs | Adds IsFrameworkFile overload for AbsolutePath[] framework paths. |
| src/Tasks/AssemblyDependency/RawFilenameResolver.cs | Resolves raw filename candidate via TaskEnvironment. |
| src/Tasks/AssemblyDependency/Node/RarNodeExecuteRequest.cs | Captures project directory for out-of-proc node TaskEnvironment creation. |
| src/Tasks/AssemblyDependency/Node/OutOfProcRarNodeEndpoint.cs | Creates a multithreaded TaskEnvironment per request using the client project directory. |
| src/Tasks/AssemblyDependency/HintPathResolver.cs | Resolves hint path using TaskEnvironment and canonicalizes. |
| src/Tasks/AssemblyDependency/GlobalAssemblyCache.cs | Switches env-var access to TaskEnvironment and threads it through GetLocation APIs. |
| src/Tasks/AssemblyDependency/GacResolver.cs | Threads TaskEnvironment into GAC resolver construction. |
| src/Tasks/AssemblyDependency/FrameworkPathResolver.cs | Threads TaskEnvironment into framework path resolver construction. |
| src/Tasks/AssemblyDependency/DirectoryResolver.cs | Caches absolute search path via TaskEnvironment. |
| src/Tasks/AssemblyDependency/CandidateAssemblyFilesResolver.cs | Threads TaskEnvironment into candidate assembly files resolver construction. |
| src/Tasks/AssemblyDependency/AssemblyResolution.cs | Threads TaskEnvironment through resolver compilation APIs. |
| src/Tasks/AssemblyDependency/AssemblyFoldersResolver.cs | Threads TaskEnvironment into AssemblyFolders resolver. |
| src/Tasks/AssemblyDependency/AssemblyFoldersFromConfig/AssemblyFoldersFromConfigResolver.cs | Uses TaskEnvironment for cache escape-hatch env var access and passes it into cache. |
| src/Tasks/AssemblyDependency/AssemblyFoldersFromConfig/AssemblyFoldersFromConfigCache.cs | Uses TaskEnvironment for cache escape-hatch env var access. |
| src/Tasks/AssemblyDependency/AssemblyFoldersExResolver.cs | Uses TaskEnvironment for cache escape-hatch env var access and passes it into cache. |
| src/Tasks.UnitTests/RARPrecomputedCache_Tests.cs | Updates RAR tests to provide TaskEnvironment. |
| src/Tasks.UnitTests/HintPathResolver_Tests.cs | Updates resolver test to provide TaskEnvironment. |
| src/Tasks.UnitTests/GetReferencePaths_Tests.cs | Updates task test to provide TaskEnvironment. |
| src/Tasks.UnitTests/AssemblyDependency/WinMDTests.cs | Updates RAR tests to provide TaskEnvironment. |
| src/Tasks.UnitTests/AssemblyDependency/VerifyTargetFrameworkHigherThanRedist.cs | Updates RAR tests to provide TaskEnvironment. |
| src/Tasks.UnitTests/AssemblyDependency/VerifyTargetFrameworkAttribute.cs | Updates RAR tests to provide TaskEnvironment. |
| src/Tasks.UnitTests/AssemblyDependency/VerifyIgnoreVersionForFrameworkReference.cs | Updates RAR tests to provide TaskEnvironment. |
| src/Tasks.UnitTests/AssemblyDependency/SuggestedRedirects.cs | Updates RAR tests to provide TaskEnvironment. |
| src/Tasks.UnitTests/AssemblyDependency/StronglyNamedDependencyAutoUnify.cs | Updates RAR tests to provide TaskEnvironment. |
| src/Tasks.UnitTests/AssemblyDependency/StronglyNamedDependencyAppConfig.cs | Updates RAR tests to provide TaskEnvironment. |
| src/Tasks.UnitTests/AssemblyDependency/StronglyNamedDependency.cs | Updates RAR tests to provide TaskEnvironment. |
| src/Tasks.UnitTests/AssemblyDependency/SpecificVersionPrimary.cs | Updates RAR tests to provide TaskEnvironment. |
| src/Tasks.UnitTests/AssemblyDependency/ResolveAssemblyReferenceTestFixture.cs | Updates helper to pass TaskEnvironment into GAC resolution. |
| src/Tasks.UnitTests/AssemblyDependency/Perf.cs | Updates perf tests to provide TaskEnvironment. |
| src/Tasks.UnitTests/AssemblyDependency/NonSpecificVersionStrictPrimary.cs | Updates RAR tests to provide TaskEnvironment. |
| src/Tasks.UnitTests/AssemblyDependency/Node/RarNodeExecuteRequest_Tests.cs | Updates node request tests to provide TaskEnvironment. |
| src/Tasks.UnitTests/AssemblyDependency/Node/OutOfProcRarNode_Tests.cs | Updates node tests to provide TaskEnvironment. |
| src/Tasks.UnitTests/AssemblyDependency/Miscellaneous.cs | Updates RAR tests to provide TaskEnvironment. |
| src/Tasks.UnitTests/AssemblyDependency/InstalledSDKResolverFixture.cs | Updates resolver fixture to provide TaskEnvironment. |
| src/Tasks.UnitTests/AssemblyDependency/GlobalAssemblyCacheTests.cs | Updates cache tests to pass TaskEnvironment. |
| src/Tasks.UnitTests/AssemblyDependency/FilePrimary.cs | Updates RAR tests to provide TaskEnvironment. |
| src/Tasks.UnitTests/AssemblyDependency/AssemblyFoldersFromConfig_Tests.cs | Updates tests to provide TaskEnvironment. |
| src/Framework/MultiThreadedTaskEnvironmentDriver.cs | Moves driver into Framework layer and updates env-var comparer dependency. |
| src/Framework/MultiProcessTaskEnvironmentDriver.cs | Moves driver into Framework layer and routes env-var ops through Framework utilities. |
| src/Framework/FrameworkCommunicationsUtilities.cs | Adds Framework-local env-var utilities needed by moved drivers. |
| src/Framework/ChangeWaves.cs | Adds new wave 18.6 and includes it in AllWaves. |
| src/Build/Microsoft.Build.csproj | Removes compilation of drivers from Build project (now in Framework). |
| src/Build/BackEnd/Components/RequestBuilder/RequestBuilder.cs | Updates comment to reflect new Framework env-var utilities usage. |
Comments suppressed due to low confidence (1)
src/Tasks/AssemblyDependency/ReferenceTable.cs:496
- When
assemblyFileNameis relative,reference.FullPathis made absolute viaTaskEnvironment, but the subsequent_fileExists,_directoryExists,_getAssemblyName, andResolvedSearchPathlogic still uses the original (potentially relative)assemblyFileName. In multithreaded/out-of-proc scenarios this can probe the wrong directory and fail to resolve assemblies. Use the resolved absolute path (e.g.,reference.FullPath) consistently for file system checks and assembly name probing.
…on as it is expensive and would be done in ReferenceTable centrally.
|
/review |
|
❌ Expert Code Review (command) failed. Please review the logs for details. Review complete — the expert-reviewer sub-agent posted 6 inline comments and 1 summary COMMENT review on PR #13319. No additional action needed from the orchestrator. |
There was a problem hiding this comment.
Expert Review — PR #13319: RAR Path Handling Enlightenment (Part 2)
Summary
This PR continues the enlightenment of RAR (ResolveAssemblyReference) for the TaskEnvironment API. Key changes include: defensive ?? [] null-coalescing for array property setters, removal of redundant _taskEnvironment field in AssemblyFoldersExResolver, removal of .GetCanonicalForm() from individual resolvers (centralizing canonicalization in ReferenceTable), a new AbsolutePath overload for StateFileBase.SerializeCache, path absolutization in AssemblyFoldersFromConfig, ChangeWave 18_6 tests for empty AppConfigFile, and an InstalledSDKResolver comparer fix.
Severity Legend
- 🔴 BLOCKING — Must be fixed before merge
- 🟠 MAJOR — Should be fixed; significant quality/correctness concern
- 🟡 MINOR — Nice to fix; low-risk style or completeness issue
- 🔵 ADVISORY — Informational, no action required
Issues Found
| # | Severity | Dimension | File | Finding |
|---|---|---|---|---|
| 1 | 🟠 | Null Safety | AssemblyFoldersFromConfigCache.cs:49-51 |
GetAbsolutePath called before null/empty filter — could throw for edge-case empty DirectoryPath after env-var expansion |
| 2 | 🟠 | Null Safety | AssemblyFoldersFromConfigResolver.cs:185 |
Same issue — no guard before GetAbsolutePath on config directory paths |
| 3 | 🟡 | Code Duplication | StateFileBase.cs:78-108 |
AbsolutePath overload is near-copy of string overload (acceptable per migration plan) |
| 4 | 🟡 | C# Modernization | Miscellaneous.cs:1189,1215 |
new ITaskItem[] { ... } → [...] collection expressions |
| 5 | 🟡 | Test Resilience | Miscellaneous.cs:1223 |
ResetStateForTests() skipped if assertion throws |
| 6 | 🔵 | Good Fix | InstalledSDKResolver.cs:36 |
Comparer propagation fix — prevents key-mismatch bugs |
Verification Notes
✅ Canonicalization removal is correct: Confirmed that ReferenceTable.cs:1368 canonicalizes all resolved paths centrally before storing them in _externallyResolvedImmutableFiles. Removing .GetCanonicalForm() from individual resolvers avoids redundant Path.GetFullPath calls.
✅ ChangeWave 18_6 is the correct wave version: Verified in ChangeWaves.cs. Wave18_6 is defined and properly gated.
✅ FullFrameworkFolders null-conditional removal is correct: VerifyThrowArgumentNull at line 961 guarantees value is non-null, making value?.Select(...) → value.Select(...) safe.
✅ ?? [] defensive null handling is a good improvement: Prevents null assignment to array fields that are initialized as [], maintaining the non-null invariant.
✅ _stateFile type change is sound: _stateFile is AbsolutePath (not Lazy<AbsolutePath>), so calling SerializeCache(_stateFile, Log) directly (dropping .Value) correctly matches the new AbsolutePath overload.
Verdict
No blocking issues. Two MAJOR defensive-coding concerns around GetAbsolutePath being called without null/empty guards on config-derived paths. Recommend adding guards to prevent ArgumentException from propagating in edge cases.
Note
🔒 Integrity filter blocked 2 items
The following items were blocked because they don't meet the GitHub integrity level.
- #13319
pull_request_read: has lower integrity than agent requires. The agent cannot read data with integrity below "approved". - #13319
pull_request_read: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
To allow these resources, lower min-integrity in your GitHub frontmatter:
tools:
github:
min-integrity: approved # merged | approved | unapproved | noneGenerated by Expert Code Review (command) for issue #13319 · ● 13.9M
…s with a try-cacth fallback. Those paths should be already absolute and in a canoniocal form.
|
/review |
|
✅ Expert Code Review (command) completed successfully! |
There was a problem hiding this comment.
RAR Multi-Threaded Task Migration Review
Overall this is a solid migration. The architecture of propagating TaskEnvironment through the resolver hierarchy, gating behavioral changes behind Wave 18.6, and adding connection pooling for out-of-proc RAR is well-designed. A few findings:
🔴 IMPORTANT (2 findings)
-
Broken connections returned to pool (
OutOfProcRarClient.csline 199): IfWritePacket/ReadPacketthrows (broken pipe), thefinallyblock returns the brokenpipeClientto the pool. Next caller may dequeue it, see staleIsConnected == true, and fail. Fix: Only return to pool on success; dispose on failure. -
Unguarded
GetCanonicalForm()calls (ReferenceTable.cslines 481, 1370):GetCanonicalForm()callsPath.GetFullPath()which can throwArgumentExceptionon .NET Framework for invalid path characters. The PR introducesTryGetCanonicalForm()as a resilient alternative but doesn't use it consistently. These call sites lack protection, unlikeMakeCanonicalPathin RAR (line 1170) which correctly usesTryGetCanonicalForm(Log).
🟡 MINOR (3 findings)
-
LINQ in property getters (RAR lines 298, 407, 435, 947):
.Select(path => path.OriginalValue).ToArray()allocates on every property access. Acceptable for setters (called once), but getters are called during serialization. -
AppConfigFilesetter null handling (RAR line 699-713): The three-way branch (non-empty / empty / null) is correct but subtle — a comment would help maintainability. -
Broad exception catch in
TryGetCanonicalForm(TaskEnvironmentExtensions.csline 30): Not blocking; the fallback is safe.
✅ Verified correct
- TaskEnvironment excluded from serialization is correctly handled —
OutOfProcRarNodeEndpointcreates its ownTaskEnvironmentwithMultiThreadedTaskEnvironmentDriver(line 103-105). - ChangeWave 18.6 guards are consistently applied for behavioral changes.
Resolverbase class correctly propagatestaskEnvironmentto all subclasses.- Double-checked locking in
Dispose()is correct (volatile + lock). StateFileBasestring overloads withignoreRootedCheck: trueare appropriate for backward compat.
Note
🔒 Integrity filter blocked 2 items
The following items were blocked because they don't meet the GitHub integrity level.
- #13319
pull_request_read: has lower integrity than agent requires. The agent cannot read data with integrity below "approved". - #13319
pull_request_read: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
To allow these resources, lower min-integrity in your GitHub frontmatter:
tools:
github:
min-integrity: approved # merged | approved | unapproved | noneGenerated by Expert Code Review (command) for issue #13319 · ● 12.1M
| public string AppConfigFile | ||
| { | ||
| get { return _appConfigFile; } | ||
| set { _appConfigFile = value; } | ||
| get => _appConfigFile.OriginalValue; | ||
| set | ||
| { | ||
| if (!string.IsNullOrEmpty(value)) | ||
| { | ||
| _appConfigFile = MakeAbsolutePath(value); | ||
| } | ||
| else if (value == string.Empty && !ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave18_6)) | ||
| { | ||
| _appConfigValueIsEmptyString = true; |
There was a problem hiding this comment.
MINOR — null value silently falls through both branches
When value is null:
string.IsNullOrEmpty(null)→true→ first branch skippedvalue == string.Empty→false→ second branch skipped- Neither
_appConfigFilenor_appConfigValueIsEmptyStringis set
This appears intentional (null = "not set"), and the backward compat shim at line 2506 only fires for _appConfigValueIsEmptyString, which correctly only triggers for the empty-string case.
A brief comment documenting the null-falls-through behavior would be helpful for future maintainers, since this three-way branching (non-empty / empty / null) is subtle.
| if (ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave18_6)) | ||
| { | ||
| resolvedPath = FileUtilities.FixFilePath(_taskEnvironment.GetAbsolutePath(resolvedPath).GetCanonicalForm()).Value; |
There was a problem hiding this comment.
IMPORTANT — Unhandled exception from GetCanonicalForm() in the Wave 18.6 path
Same concern as NameAssemblyFileReference line 481: GetCanonicalForm() can throw ArgumentException on .NET Framework for invalid path characters, but there's no try-catch around this specific code path.
The try at line 1340 only catches BadImageFormatException.
Consider using TryGetCanonicalForm() here too:
resolvedPath = FileUtilities.FixFilePath(_taskEnvironment.GetAbsolutePath(resolvedPath).TryGetCanonicalForm()).Value;This is especially important because resolvedPath comes from resolvers which may return paths with unusual characters (e.g., from registry-based AssemblyFoldersEx entries).
| } | ||
| finally | ||
| { | ||
| // Return the pipe client to the pool | ||
| if (pipeClient != null) | ||
| { | ||
| ErrorUtilities.ThrowInternalError($"Received unexpected packet type {packet.Type}"); | ||
| ReleaseConnection(pipeClient); |
There was a problem hiding this comment.
IMPORTANT — Broken connection returned to pool on exception
If WritePacket (line 152) or ReadPacket (lines 154/186) throws (e.g., IOException from a broken pipe, deserialization error), the finally block returns the broken pipeClient to the pool via ReleaseConnection.
The next caller that dequeues this client may see IsConnected == true (the property can be stale — the pipe stream hasn't been explicitly disconnected), attempt to write/read on a corrupted stream, and get another exception. This creates a cascading failure pattern.
Suggested fix: Track success and only return to pool on success. On failure, dispose the client:
bool success = false;
try
{
pipeClient = AcquireConnection();
// ... existing logic ...
success = true;
return response.Success;
}
finally
{
if (pipeClient != null)
{
if (success)
ReleaseConnection(pipeClient);
else
pipeClient.Dispose();
}
}This also handles the minor sub-case where ConnectToServer returns false — currently the never-connected client is pooled (harmless but wasteful).
| { | ||
| return absolutePath.GetCanonicalForm(); | ||
| } | ||
| catch (Exception e) |
There was a problem hiding this comment.
MINOR — Broad exception catch
Catching Exception is very broad. Consider narrowing to the specific exceptions Path.GetFullPath() can throw: ArgumentException, NotSupportedException, PathTooLongException, SecurityException.
That said, the XML doc comment explains the rationale well, and the fallback (returning the original path) is safe. The logging at MessageImportance.Low is appropriate for this resilience pattern. Not blocking.
| if (!Path.IsPathRooted(assemblyFileName)) | ||
| { | ||
| reference.FullPath = Path.GetFullPath(assemblyFileName); | ||
| reference.FullPath = _taskEnvironment.GetAbsolutePath(assemblyFileName).GetCanonicalForm(); |
There was a problem hiding this comment.
IMPORTANT — Missing TryGetCanonicalForm error handling (unlike other call sites)
This call to GetCanonicalForm() (which calls Path.GetFullPath()) is unguarded and can throw ArgumentException on .NET Framework for paths with illegal characters (e.g., |, <, >).
In contrast, ResolveAssemblyReference.MakeCanonicalPath (line 1170) uses TryGetCanonicalForm(Log) which catches exceptions and falls back gracefully. Here, an exception would propagate up uncaught (the try block at line 488 only catches BadImageFormatException and UnauthorizedAccessException).
Consider using TryGetCanonicalForm() here for consistency and resilience:
reference.FullPath = _taskEnvironment.GetAbsolutePath(assemblyFileName).TryGetCanonicalForm();Note: The old code Path.GetFullPath(assemblyFileName) had the same throw risk, so this isn't a regression per se — but since the PR introduces TryGetCanonicalForm as a resilient alternative, it should be used consistently.
| /// </summary> | ||
| private AbsolutePath[] MakeAbsolutePaths(string[] paths) | ||
| { | ||
| return paths?.Select(path => MakeAbsolutePath(path)).ToArray() ?? []; |
There was a problem hiding this comment.
MINOR — LINQ allocation on potentially large arrays
MakeAbsolutePaths uses .Select().ToArray(). While the setter is called once per task execution, CandidateAssemblyFiles can contain hundreds of items in large projects, and similar LINQ patterns appear in:
- Property getters like
CandidateAssemblyFiles(line 407):.Select(path => path.OriginalValue).ToArray() MakeCanonicalPaths(line 1180)TargetFrameworkDirectories,LatestTargetFrameworkDirectories,FullFrameworkFoldersgetters
For setters (called once), this is acceptable. For getters that allocate a new array on every access, consider caching the string[] result or using a simple loop instead of LINQ.
Not blocking, but worth noting since RAR runs for every project and these getters may be called during serialization (out-of-proc path).
|
Hello, I poked and proded at the PR, making use of the whole shebang I gathered while trying to migrate sdk tasks. I also noticed a drop in my ability to properly review this manually, which is concerning and vexing. That being said - here is a group of tests that pin what the review considers breaking points: Repro: Deterministic tests coverage, each pins a behavior worth considering. I'm not saying all of these need to be addressed. But it would be nice to consider how much of an issue they are NEW3 _appConfigValueIsEmptyString silently dropped across the OOP wire NEW4 StateFile / AppConfigFile no longer absolutized at the wire boundary NEW8 RawFilenameResolver guards only NEW10 MultiThreadedTaskEnvironmentDriver accepts unvalidated ProjectDirectory C5/N3 AppConfigFile setter has stale state on re-assignment to "": |
…13319 Adds a paired `_Control` test next to each `_Breakage` test where a multi-process / single-threaded equivalent of the scenario exists. Each Control test is expected to PASS on the PR head, demonstrating that the breakage is specific to the new multi-threaded / out-of-proc path and not present in the original `-multiprocess` paradigm. Also adds the concurrency regression suite (PRBreakageConcurrency_Tests): NEW-1 publication race, C1 broken-pipe pool poisoning (10s hard timeout), NEW-2 client read deadlock on server exception, and NEW-6 GetInstance TOCTOU leak. Findings without a meaningful MP equivalent (NEW-8, NEW-10, C1, NEW-2) have an inline note explaining why no Control test exists. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Secondary findings - nondeterministic test breakages https://github.com/dotnet/msbuild/tree/pr-13319-regression-tests-concurrency Comments per concurrency test (PRBreakageConcurrency_Tests) NEW1_StringsInitialize_HasPublicationRace NEW1_StringsInitialize_SingleThreaded_Control C1_FailedExecute_DoesNotReturnBrokenPipeToPool NEW2_OopNodeException_LeavesClientReadBlocked NEW6_GetInstance_TOCTOU_LeaksUnregisteredClients NEW6_GetInstance_SingleThreaded_Control |
JanProvaznik
left a comment
There was a problem hiding this comment.
review point 1 before I get to the juicy stuff:
pls remove everywhere t.TaskEnvironment = TaskEnvironmentHelper.CreateForTest(); which will make the PR also optically smaller
| if (resolvedPath != null) | ||
| { | ||
| resolvedPath = FileUtilities.FixFilePath(_taskEnvironment.GetAbsolutePath(resolvedPath).GetCanonicalForm()).Value; | ||
| if (ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave18_6)) |
There was a problem hiding this comment.
wave 18.7/8 depends on when we merge...
| { | ||
| AllowOutOfProcNode = true, | ||
| BuildEngine = engine, | ||
| TaskEnvironment = TaskEnvironmentHelper.CreateForTest(), |
There was a problem hiding this comment.
obsolete, remove - is implicit in task what is fallback
| ResolveAssemblyReference clientRar = new() | ||
| { | ||
| BuildEngine = new MockEngine(), | ||
| TaskEnvironment = TaskEnvironmentHelper.CreateForTest(), |
There was a problem hiding this comment.
obsolete remove (search for all occurrences in your changed files)
| ResolveAssemblyReference t = new ResolveAssemblyReference(); | ||
|
|
||
| t.BuildEngine = new MockEngine(_output); | ||
| t.TaskEnvironment = TaskEnvironmentHelper.CreateForTest(); |
There was a problem hiding this comment.
are there any tests for the -mt path?
Fixes #12483
Context
RAR task enlightening. De-facto the only inputs that I saw unenlightened in the logs were
StateFile,AppConfigFileandCandidateAssemblyFiles. However multiple other inputs, likeTargetFrameworkDirectoriesorHintPathof assemblies are not guaranteed to be the full path. I added additional logic that ensures that the full path is used for them too.Changes Made
StateFileandAppConfigFile)Breaking changes under a ChangeWave:
AppConfigFileresulted before in failure while now it is skipped (as if it was null before)StateFile.ItemSpecis used for the path instead ofStateFile.ToString()which could be otherwise defined in a customITaskItemCommits overview:
Testing (in progress)
Checklist: