diff --git a/src/StaticWebAssetsSdk/Targets/Microsoft.NET.Sdk.StaticWebAssets.Publish.targets b/src/StaticWebAssetsSdk/Targets/Microsoft.NET.Sdk.StaticWebAssets.Publish.targets
index f5d5181b2ebb..0b392f857100 100644
--- a/src/StaticWebAssetsSdk/Targets/Microsoft.NET.Sdk.StaticWebAssets.Publish.targets
+++ b/src/StaticWebAssetsSdk/Targets/Microsoft.NET.Sdk.StaticWebAssets.Publish.targets
@@ -200,6 +200,7 @@ Copyright (c) .NET Foundation. All rights reserved.
<_PublishStaticWebAssetsCopyAlways Include="@(_PublishStaticWebAssetsTargetPath)" Condition="'%(CopyToPublishDirectory)' == 'Always'" />
<_PublishStaticWebAssetsPreserveNewest Include="@(_PublishStaticWebAssetsTargetPath)" Condition="'%(CopyToPublishDirectory)' == 'PreserveNewest'" />
+ <_PublishStaticWebAssetsIfDifferent Include="@(_PublishStaticWebAssetsTargetPath)" Condition="'%(CopyToPublishDirectory)' == 'IfDifferent'" />
@@ -207,7 +208,8 @@ Copyright (c) .NET Foundation. All rights reserved.
+ AfterTargets="_SplitPublishStaticWebAssetsByCopyOptions"
+ Condition=" '@(_PublishStaticWebAssetsPreserveNewest)' != '' ">
+ AfterTargets="_SplitPublishStaticWebAssetsByCopyOptions"
+ Condition=" '@(_PublishStaticWebAssetsCopyAlways)' != '' ">
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/StaticWebAssetsSdk/Targets/Microsoft.NET.Sdk.StaticWebAssets.targets b/src/StaticWebAssetsSdk/Targets/Microsoft.NET.Sdk.StaticWebAssets.targets
index 0fb3afa2fbc2..c3e5fad9ab49 100644
--- a/src/StaticWebAssetsSdk/Targets/Microsoft.NET.Sdk.StaticWebAssets.targets
+++ b/src/StaticWebAssetsSdk/Targets/Microsoft.NET.Sdk.StaticWebAssets.targets
@@ -498,6 +498,7 @@ Copyright (c) .NET Foundation. All rights reserved.
<_BuildStaticWebAssetsCopyAlways Include="@(_BuildStaticWebAssetsTargetPath)" Condition="'%(CopyToOutputDirectory)' == 'Always'" />
<_BuildStaticWebAssetsPreserveNewest Include="@(_BuildStaticWebAssetsTargetPath)" Condition="'%(CopyToOutputDirectory)' == 'PreserveNewest'" />
+ <_BuildStaticWebAssetsIfDifferent Include="@(_BuildStaticWebAssetsTargetPath)" Condition="'%(CopyToOutputDirectory)' == 'IfDifferent'" />
@@ -537,8 +538,29 @@ Copyright (c) .NET Foundation. All rights reserved.
+
+
+
+
+
+
+
+
+
+
+
-
+
<_UpToDateCheckStaticWebAssetCandidate Include="@(StaticWebAsset)" Condition="'%(SourceType)' == 'Discovered'" />
diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Publish.targets b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Publish.targets
index 728f17b43132..e38b16fe46b3 100644
--- a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Publish.targets
+++ b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Publish.targets
@@ -268,6 +268,7 @@ Copyright (c) .NET Foundation. All rights reserved.
DependsOnTargets="_IncrementalCleanPublishDirectory;
_CopyResolvedFilesToPublishPreserveNewest;
_CopyResolvedFilesToPublishAlways;
+ _CopyResolvedFilesToPublishIfDifferent;
_HandleFileConflictsForPublish" />
+
+
+
+
+
+
+
+
+
@@ -431,7 +459,7 @@ Copyright (c) .NET Foundation. All rights reserved.
============================================================
_ComputeResolvedFilesToPublishTypes
- Splits ResolvedFileToPublish items into 'PreserveNewest' and 'Always' buckets.
+ Splits ResolvedFileToPublish items into 'PreserveNewest', 'Always' and 'IfDifferent' buckets.
Then further splits those into 'Unbundled' buckets based on the single file setting.
============================================================
-->
@@ -443,6 +471,9 @@ Copyright (c) .NET Foundation. All rights reserved.
<_ResolvedFileToPublishAlways Include="@(ResolvedFileToPublish)"
Condition="'%(ResolvedFileToPublish.CopyToPublishDirectory)'=='Always'" />
+
+ <_ResolvedFileToPublishIfDifferent Include="@(ResolvedFileToPublish)"
+ Condition="'%(ResolvedFileToPublish.CopyToPublishDirectory)'=='IfDifferent'" />
@@ -456,6 +487,11 @@ Copyright (c) .NET Foundation. All rights reserved.
Include="@(_ResolvedFileToPublishAlways)"
Condition="'$(PublishSingleFile)' != 'true' or
'%(_ResolvedFileToPublishAlways.ExcludeFromSingleFile)'=='true'" />
+
+ <_ResolvedUnbundledFileToPublishIfDifferent
+ Include="@(_ResolvedFileToPublishIfDifferent)"
+ Condition="'$(PublishSingleFile)' != 'true' or
+ '%(_ResolvedFileToPublishIfDifferent.ExcludeFromSingleFile)'=='true'" />
@@ -784,10 +820,40 @@ Copyright (c) .NET Foundation. All rights reserved.
PreserveNewest
True
+
+
+ %(_SourceItemsToCopyToPublishDirectoryIfDifferent.TargetPath)
+ IfDifferent
+ True
+
+
+
+
+ <_ContentWithPublishMetadata Include="@(Content)"
+ Condition="'%(Content.CopyToPublishDirectory)' != '' and '%(Content.CopyToPublishDirectory)' != 'Never' and '%(Content.CopyToOutputDirectory)' == ''">
+
+ %(Content.TargetPath)
+ %(Content.Link)
+ $([MSBuild]::MakeRelative(%(Content.DefiningProjectDirectory), %(Content.FullPath)))
+ $([MSBuild]::MakeRelative($(MSBuildProjectDirectory), %(Content.FullPath)))
+
+
+
+
+
@@ -860,6 +930,9 @@ Copyright (c) .NET Foundation. All rights reserved.
<_SourceItemsToCopyToPublishDirectory KeepMetadata="$(_GCTPDIKeepMetadata)"
Include="@(ContentWithTargetPath->'%(FullPath)')"
Condition="'%(ContentWithTargetPath.CopyToPublishDirectory)'=='PreserveNewest'"/>
+ <_SourceItemsToCopyToPublishDirectoryIfDifferent KeepMetadata="$(_GCTPDIKeepMetadata)"
+ Include="@(ContentWithTargetPath->'%(FullPath)')"
+ Condition="'%(ContentWithTargetPath.CopyToPublishDirectory)'=='IfDifferent'"/>
@@ -869,11 +942,14 @@ Copyright (c) .NET Foundation. All rights reserved.
<_SourceItemsToCopyToPublishDirectory KeepMetadata="$(_GCTPDIKeepMetadata)"
Include="@(EmbeddedResource->'%(FullPath)')"
Condition="'%(EmbeddedResource.CopyToPublishDirectory)'=='PreserveNewest'"/>
+ <_SourceItemsToCopyToPublishDirectoryIfDifferent KeepMetadata="$(_GCTPDIKeepMetadata)"
+ Include="@(EmbeddedResource->'%(FullPath)')"
+ Condition="'%(EmbeddedResource.CopyToPublishDirectory)'=='IfDifferent'"/>
<_CompileItemsToPublish Include="@(Compile->'%(FullPath)')"
- Condition="'%(Compile.CopyToPublishDirectory)'=='Always' or '%(Compile.CopyToPublishDirectory)'=='PreserveNewest'"/>
+ Condition="'%(Compile.CopyToPublishDirectory)'=='Always' or '%(Compile.CopyToPublishDirectory)'=='PreserveNewest' or '%(Compile.CopyToPublishDirectory)'=='IfDifferent'"/>
@@ -887,6 +963,9 @@ Copyright (c) .NET Foundation. All rights reserved.
<_SourceItemsToCopyToPublishDirectory KeepMetadata="$(_GCTPDIKeepMetadata)"
Include="@(_CompileItemsToPublishWithTargetPath)"
Condition="'%(_CompileItemsToPublishWithTargetPath.CopyToPublishDirectory)'=='PreserveNewest'"/>
+ <_SourceItemsToCopyToPublishDirectoryIfDifferent KeepMetadata="$(_GCTPDIKeepMetadata)"
+ Include="@(_CompileItemsToPublishWithTargetPath)"
+ Condition="'%(_CompileItemsToPublishWithTargetPath.CopyToPublishDirectory)'=='IfDifferent'"/>
@@ -896,12 +975,16 @@ Copyright (c) .NET Foundation. All rights reserved.
<_SourceItemsToCopyToPublishDirectory KeepMetadata="$(_GCTPDIKeepMetadata)"
Include="@(_NoneWithTargetPath->'%(FullPath)')"
Condition="'%(_NoneWithTargetPath.CopyToPublishDirectory)'=='PreserveNewest'"/>
+ <_SourceItemsToCopyToPublishDirectoryIfDifferent KeepMetadata="$(_GCTPDIKeepMetadata)"
+ Include="@(_NoneWithTargetPath->'%(FullPath)')"
+ Condition="'%(_NoneWithTargetPath.CopyToPublishDirectory)'=='IfDifferent'"/>
<_SourceItemsToCopyToPublishDirectoryAlways Remove="$(AppHostIntermediatePath)" />
<_SourceItemsToCopyToPublishDirectory Remove="$(AppHostIntermediatePath)" />
+ <_SourceItemsToCopyToPublishDirectoryIfDifferent Remove="$(AppHostIntermediatePath)" />
<_SourceItemsToCopyToPublishDirectoryAlways Include="$(SingleFileHostIntermediatePath)" CopyToOutputDirectory="Always" TargetPath="$(AssemblyName)$(_NativeExecutableExtension)" />
@@ -911,13 +994,14 @@ Copyright (c) .NET Foundation. All rights reserved.
<_SourceItemsToCopyToPublishDirectoryAlways Remove="$(AppHostIntermediatePath)" />
<_SourceItemsToCopyToPublishDirectory Remove="$(AppHostIntermediatePath)" />
+ <_SourceItemsToCopyToPublishDirectoryIfDifferent Remove="$(AppHostIntermediatePath)" />
<_SourceItemsToCopyToPublishDirectoryAlways Include="$(AppHostForPublishIntermediatePath)" CopyToOutputDirectory="Always" TargetPath="$(AssemblyName)$(_NativeExecutableExtension)" />
-
+
@@ -927,7 +1011,7 @@ Copyright (c) .NET Foundation. All rights reserved.
DefaultCopyToPublishDirectoryMetadata
If CopyToPublishDirectory isn't set on these items, the value should be taken from CopyToOutputDirectory.
- This way, projects can just set "CopyToOutputDirectory = Always/PreserveNewest" and by default the item will be copied
+ This way, projects can just set "CopyToOutputDirectory = Always/PreserveNewest/IfDifferent" and by default the item will be copied
to both the build output and publish directories.
============================================================
-->
@@ -942,6 +1026,9 @@ Copyright (c) .NET Foundation. All rights reserved.
PreserveNewest
+
+ IfDifferent
+
Always
@@ -949,6 +1036,9 @@ Copyright (c) .NET Foundation. All rights reserved.
PreserveNewest
+
+ IfDifferent
+
Always
@@ -956,6 +1046,9 @@ Copyright (c) .NET Foundation. All rights reserved.
PreserveNewest
+
+ IfDifferent
+
<_NoneWithTargetPath Condition="'%(_NoneWithTargetPath.CopyToOutputDirectory)'=='Always' and '%(_NoneWithTargetPath.CopyToPublishDirectory)' == ''">
Always
@@ -963,6 +1056,9 @@ Copyright (c) .NET Foundation. All rights reserved.
<_NoneWithTargetPath Condition="'%(_NoneWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest' and '%(_NoneWithTargetPath.CopyToPublishDirectory)' == ''">
PreserveNewest
+ <_NoneWithTargetPath Condition="'%(_NoneWithTargetPath.CopyToOutputDirectory)'=='IfDifferent' and '%(_NoneWithTargetPath.CopyToPublishDirectory)' == ''">
+ IfDifferent
+
diff --git a/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishWithIfDifferent.cs b/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishWithIfDifferent.cs
new file mode 100644
index 000000000000..9ebb72c1b982
--- /dev/null
+++ b/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishWithIfDifferent.cs
@@ -0,0 +1,385 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#nullable disable
+
+namespace Microsoft.NET.Publish.Tests
+{
+ public class GivenThatWeWantToPublishWithIfDifferent : SdkTest
+ {
+ public GivenThatWeWantToPublishWithIfDifferent(ITestOutputHelper log) : base(log)
+ {
+ }
+
+ [Fact]
+ public void It_publishes_content_files_with_IfDifferent_metadata()
+ {
+ var testProject = new TestProject()
+ {
+ Name = "PublishWithIfDifferent",
+ TargetFrameworks = ToolsetInfo.CurrentTargetFramework,
+ IsExe = true
+ };
+
+ // Add Program.cs to fix compilation
+ testProject.SourceFiles["Program.cs"] = @"using System;
+class Program { static void Main() => Console.WriteLine(""Hello""); }";
+
+ // Add content files with different CopyToPublishDirectory metadata values
+ testProject.SourceFiles["data1.txt"] = "Data file 1 content";
+ testProject.SourceFiles["data2.txt"] = "Data file 2 content";
+ testProject.SourceFiles["data3.txt"] = "Data file 3 content";
+
+ var testAsset = _testAssetsManager.CreateTestProject(testProject);
+
+ // Update the project file to set CopyToPublishDirectory metadata
+ var projectFile = Path.Combine(testAsset.Path, testProject.Name, $"{testProject.Name}.csproj");
+ var projectContent = File.ReadAllText(projectFile);
+ projectContent = projectContent.Replace("", @"
+
+
+
+
+
+");
+ File.WriteAllText(projectFile, projectContent);
+
+ var publishCommand = new PublishCommand(testAsset);
+ var publishResult = publishCommand.Execute();
+
+ publishResult.Should().Pass();
+
+ var publishDirectory = publishCommand.GetOutputDirectory(testProject.TargetFrameworks);
+
+ // Verify all content files are published
+ publishDirectory.Should().HaveFile("data1.txt");
+ publishDirectory.Should().HaveFile("data2.txt");
+ publishDirectory.Should().HaveFile("data3.txt");
+
+ // Verify file contents
+ File.ReadAllText(Path.Combine(publishDirectory.FullName, "data1.txt")).Should().Be("Data file 1 content");
+ File.ReadAllText(Path.Combine(publishDirectory.FullName, "data2.txt")).Should().Be("Data file 2 content");
+ File.ReadAllText(Path.Combine(publishDirectory.FullName, "data3.txt")).Should().Be("Data file 3 content");
+ }
+
+ [Fact]
+ public void It_skips_unchanged_files_with_IfDifferent_on_republish()
+ {
+ var testProject = new TestProject()
+ {
+ Name = "PublishIfDifferentSkipUnchanged",
+ TargetFrameworks = ToolsetInfo.CurrentTargetFramework,
+ IsExe = true
+ };
+
+ // Add Program.cs to fix compilation
+ testProject.SourceFiles["Program.cs"] = @"using System;
+class Program { static void Main() => Console.WriteLine(""Hello""); }";
+
+ testProject.SourceFiles["unchangedData.txt"] = "Original content";
+ testProject.SourceFiles["changedData.txt"] = "Original content";
+
+ var testAsset = _testAssetsManager.CreateTestProject(testProject);
+
+ var projectFile = Path.Combine(testAsset.Path, testProject.Name, $"{testProject.Name}.csproj");
+ var projectContent = File.ReadAllText(projectFile);
+ projectContent = projectContent.Replace("", @"
+
+
+
+
+");
+ File.WriteAllText(projectFile, projectContent);
+
+ // First publish
+ var publishCommand = new PublishCommand(testAsset);
+ publishCommand.Execute().Should().Pass();
+
+ var publishDirectory = publishCommand.GetOutputDirectory(testProject.TargetFrameworks);
+
+ // Record timestamps after first publish
+ var unchangedFileInfo = new FileInfo(Path.Combine(publishDirectory.FullName, "unchangedData.txt"));
+ var changedFileInfo = new FileInfo(Path.Combine(publishDirectory.FullName, "changedData.txt"));
+
+ unchangedFileInfo.Exists.Should().BeTrue();
+ changedFileInfo.Exists.Should().BeTrue();
+
+ var unchangedOriginalTime = unchangedFileInfo.LastWriteTimeUtc;
+ var changedOriginalTime = changedFileInfo.LastWriteTimeUtc;
+
+ // Wait to ensure timestamp difference would be detectable
+ System.Threading.Thread.Sleep(1000);
+
+ // Modify only one source file
+ var changedSourcePath = Path.Combine(testAsset.Path, testProject.Name, "changedData.txt");
+ File.WriteAllText(changedSourcePath, "Modified content");
+
+ // Second publish
+ publishCommand.Execute().Should().Pass();
+
+ // Refresh file info
+ unchangedFileInfo.Refresh();
+ changedFileInfo.Refresh();
+
+ // The unchanged file should have the same timestamp (wasn't copied)
+ unchangedFileInfo.LastWriteTimeUtc.Should().Be(unchangedOriginalTime);
+
+ // The changed file should have a new timestamp (was copied)
+ changedFileInfo.LastWriteTimeUtc.Should().BeAfter(changedOriginalTime);
+
+ // Verify content
+ File.ReadAllText(Path.Combine(publishDirectory.FullName, "unchangedData.txt")).Should().Be("Original content");
+ File.ReadAllText(Path.Combine(publishDirectory.FullName, "changedData.txt")).Should().Be("Modified content");
+ }
+
+ [Fact]
+ public void It_handles_None_items_with_IfDifferent_metadata()
+ {
+ var testProject = new TestProject()
+ {
+ Name = "PublishNoneWithIfDifferent",
+ TargetFrameworks = ToolsetInfo.CurrentTargetFramework,
+ IsExe = true
+ };
+
+ testProject.SourceFiles["Program.cs"] = "class Program { static void Main() { } }";
+ testProject.SourceFiles["config.json"] = "{ \"setting\": \"value\" }";
+
+ var testAsset = _testAssetsManager.CreateTestProject(testProject);
+
+ var projectFile = Path.Combine(testAsset.Path, testProject.Name, $"{testProject.Name}.csproj");
+ var projectContent = File.ReadAllText(projectFile);
+ projectContent = projectContent.Replace("", @"
+
+
+ Never
+
+
+");
+ File.WriteAllText(projectFile, projectContent);
+
+ var publishCommand = new PublishCommand(testAsset);
+ publishCommand.Execute().Should().Pass();
+
+ var publishDirectory = publishCommand.GetOutputDirectory(testProject.TargetFrameworks);
+
+ // Verify the None item with IfDifferent is published
+ publishDirectory.Should().HaveFile("config.json");
+ File.ReadAllText(Path.Combine(publishDirectory.FullName, "config.json")).Should().Be("{ \"setting\": \"value\" }");
+ }
+
+ [Fact]
+ public void It_handles_Compile_items_with_IfDifferent_metadata()
+ {
+ var testProject = new TestProject()
+ {
+ Name = "PublishCompileWithIfDifferent",
+ TargetFrameworks = ToolsetInfo.CurrentTargetFramework,
+ IsExe = true
+ };
+
+ testProject.SourceFiles["Program.cs"] = "class Program { static void Main() { } }";
+ testProject.SourceFiles["SourceFile.cs"] = @"
+namespace PublishCompileWithIfDifferent
+{
+ public class SourceClass { }
+}";
+
+ var testAsset = _testAssetsManager.CreateTestProject(testProject);
+
+ var projectFile = Path.Combine(testAsset.Path, testProject.Name, $"{testProject.Name}.csproj");
+ var projectContent = File.ReadAllText(projectFile);
+ projectContent = projectContent.Replace("", @"
+
+
+
+");
+ File.WriteAllText(projectFile, projectContent);
+
+ var publishCommand = new PublishCommand(testAsset);
+ publishCommand.Execute().Should().Pass();
+
+ var publishDirectory = publishCommand.GetOutputDirectory(testProject.TargetFrameworks);
+
+ // Verify the Compile item with IfDifferent is published
+ publishDirectory.Should().HaveFile("SourceFile.cs");
+ }
+
+ [Fact]
+ public void It_copies_IfDifferent_files_correctly_with_referenced_projects()
+ {
+ var referencedProject = new TestProject()
+ {
+ Name = "ReferencedProject",
+ TargetFrameworks = ToolsetInfo.CurrentTargetFramework,
+ };
+
+ referencedProject.SourceFiles["shared.txt"] = "Shared content from library";
+
+ var mainProject = new TestProject()
+ {
+ Name = "MainProject",
+ TargetFrameworks = ToolsetInfo.CurrentTargetFramework,
+ IsExe = true,
+ ReferencedProjects = { referencedProject }
+ };
+
+ // Add Program.cs to fix compilation
+ mainProject.SourceFiles["Program.cs"] = @"using System;
+class Program { static void Main() => Console.WriteLine(""Hello""); }";
+
+ mainProject.SourceFiles["main.txt"] = "Main project content";
+
+ var testAsset = _testAssetsManager.CreateTestProject(mainProject);
+
+ // Configure the referenced project to include the file with IfDifferent
+ var referencedProjectFile = Path.Combine(testAsset.Path, referencedProject.Name, $"{referencedProject.Name}.csproj");
+ var referencedProjectContent = File.ReadAllText(referencedProjectFile);
+ referencedProjectContent = referencedProjectContent.Replace("", @"
+
+
+
+");
+ File.WriteAllText(referencedProjectFile, referencedProjectContent);
+
+ // Configure the main project
+ var mainProjectFile = Path.Combine(testAsset.Path, mainProject.Name, $"{mainProject.Name}.csproj");
+ var mainProjectContent = File.ReadAllText(mainProjectFile);
+ mainProjectContent = mainProjectContent.Replace("", @"
+
+
+
+");
+ File.WriteAllText(mainProjectFile, mainProjectContent);
+
+ var publishCommand = new PublishCommand(testAsset);
+ publishCommand.Execute().Should().Pass();
+
+ var publishDirectory = publishCommand.GetOutputDirectory(mainProject.TargetFrameworks);
+
+ // Verify files from both projects are published
+ publishDirectory.Should().HaveFile("main.txt");
+ publishDirectory.Should().HaveFile("shared.txt");
+
+ File.ReadAllText(Path.Combine(publishDirectory.FullName, "main.txt")).Should().Be("Main project content");
+ File.ReadAllText(Path.Combine(publishDirectory.FullName, "shared.txt")).Should().Be("Shared content from library");
+ }
+
+ [Fact]
+ public void It_handles_mixed_CopyToPublishDirectory_metadata_values()
+ {
+ var testProject = new TestProject()
+ {
+ Name = "MixedCopyMetadata",
+ TargetFrameworks = ToolsetInfo.CurrentTargetFramework,
+ IsExe = true
+ };
+
+ testProject.SourceFiles["Program.cs"] = "class Program { static void Main() { } }";
+ testProject.SourceFiles["always.txt"] = "Always copy";
+ testProject.SourceFiles["preserveNewest.txt"] = "PreserveNewest copy";
+ testProject.SourceFiles["ifDifferent.txt"] = "IfDifferent copy";
+ testProject.SourceFiles["doNotCopy.txt"] = "Do not copy";
+
+ var testAsset = _testAssetsManager.CreateTestProject(testProject);
+
+ var projectFile = Path.Combine(testAsset.Path, testProject.Name, $"{testProject.Name}.csproj");
+ var projectContent = File.ReadAllText(projectFile);
+ projectContent = projectContent.Replace("", @"
+
+
+
+
+
+
+");
+ File.WriteAllText(projectFile, projectContent);
+
+ var publishCommand = new PublishCommand(testAsset);
+ publishCommand.Execute().Should().Pass();
+
+ var publishDirectory = publishCommand.GetOutputDirectory(testProject.TargetFrameworks);
+
+ // Verify the correct files are published
+ publishDirectory.Should().HaveFile("always.txt");
+ publishDirectory.Should().HaveFile("preserveNewest.txt");
+ publishDirectory.Should().HaveFile("ifDifferent.txt");
+ publishDirectory.Should().NotHaveFile("doNotCopy.txt");
+ }
+
+ [Fact]
+ public void It_publishes_IfDifferent_files_with_TargetPath()
+ {
+ var testProject = new TestProject()
+ {
+ Name = "IfDifferentWithTargetPath",
+ TargetFrameworks = ToolsetInfo.CurrentTargetFramework,
+ IsExe = true
+ };
+
+ testProject.SourceFiles["Program.cs"] = "class Program { static void Main() { } }";
+ testProject.SourceFiles[Path.Combine("source", "data.txt")] = "Data in subfolder";
+
+ var testAsset = _testAssetsManager.CreateTestProject(testProject);
+
+ var projectFile = Path.Combine(testAsset.Path, testProject.Name, $"{testProject.Name}.csproj");
+ var projectContent = File.ReadAllText(projectFile);
+ projectContent = projectContent.Replace("", $@"
+
+
+ {Path.Combine("output", "data.txt")}
+
+
+");
+ File.WriteAllText(projectFile, projectContent);
+
+ var publishCommand = new PublishCommand(testAsset);
+ publishCommand.Execute().Should().Pass();
+
+ var publishDirectory = publishCommand.GetOutputDirectory(testProject.TargetFrameworks);
+
+ // Verify the file is published to the target path
+ var targetFile = Path.Combine(publishDirectory.FullName, "output", "data.txt");
+ File.Exists(targetFile).Should().BeTrue();
+ File.ReadAllText(targetFile).Should().Be("Data in subfolder");
+ }
+
+ [Fact]
+ public void It_handles_IfDifferent_with_self_contained_publish()
+ {
+ var testProject = new TestProject()
+ {
+ Name = "IfDifferentSelfContained",
+ TargetFrameworks = ToolsetInfo.CurrentTargetFramework,
+ IsExe = true,
+ RuntimeIdentifier = EnvironmentInfo.GetCompatibleRid(ToolsetInfo.CurrentTargetFramework)
+ };
+
+ testProject.AdditionalProperties["SelfContained"] = "true";
+ testProject.SourceFiles["Program.cs"] = "class Program { static void Main() { } }";
+ testProject.SourceFiles["appdata.txt"] = "Application data";
+
+ var testAsset = _testAssetsManager.CreateTestProject(testProject);
+
+ var projectFile = Path.Combine(testAsset.Path, testProject.Name, $"{testProject.Name}.csproj");
+ var projectContent = File.ReadAllText(projectFile);
+ projectContent = projectContent.Replace("", @"
+
+
+
+");
+ File.WriteAllText(projectFile, projectContent);
+
+ var publishCommand = new PublishCommand(testAsset);
+ publishCommand.Execute().Should().Pass();
+
+ var publishDirectory = publishCommand.GetOutputDirectory(
+ testProject.TargetFrameworks,
+ runtimeIdentifier: testProject.RuntimeIdentifier);
+
+ // Verify the content file is published
+ publishDirectory.Should().HaveFile("appdata.txt");
+ File.ReadAllText(Path.Combine(publishDirectory.FullName, "appdata.txt")).Should().Be("Application data");
+ }
+ }
+}