commit
97c847b5f0
|
|
@ -17,6 +17,7 @@ namespace Microsoft.AspNetCore.Razor.Tasks
|
||||||
{
|
{
|
||||||
private const string ContentRoot = "ContentRoot";
|
private const string ContentRoot = "ContentRoot";
|
||||||
private const string BasePath = "BasePath";
|
private const string BasePath = "BasePath";
|
||||||
|
private const string SourceId = "SourceId";
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
public string TargetManifestPath { get; set; }
|
public string TargetManifestPath { get; set; }
|
||||||
|
|
@ -76,13 +77,19 @@ namespace Microsoft.AspNetCore.Razor.Tasks
|
||||||
// so it needs to always be '/'.
|
// so it needs to always be '/'.
|
||||||
var normalizedBasePath = basePath.Replace("\\", "/");
|
var normalizedBasePath = basePath.Replace("\\", "/");
|
||||||
|
|
||||||
|
// contentRoot can have forward and trailing slashes and sometimes consecutive directory
|
||||||
|
// separators. To be more flexible we will normalize the content root so that it contains a
|
||||||
|
// single trailing separator.
|
||||||
|
var normalizedContentRoot = $"{contentRoot.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)}{Path.DirectorySeparatorChar}";
|
||||||
|
|
||||||
// At this point we already know that there are no elements with different base paths and same content roots
|
// At this point we already know that there are no elements with different base paths and same content roots
|
||||||
// or viceversa. Here we simply skip additional items that have the same base path and same content root.
|
// or viceversa. Here we simply skip additional items that have the same base path and same content root.
|
||||||
if (!nodes.Exists(e => e.Attribute(BasePath).Value.Equals(normalizedBasePath, StringComparison.OrdinalIgnoreCase)))
|
if (!nodes.Exists(e => e.Attribute("BasePath").Value.Equals(normalizedBasePath, StringComparison.OrdinalIgnoreCase) &&
|
||||||
|
e.Attribute("Path").Value.Equals(normalizedContentRoot, StringComparison.OrdinalIgnoreCase)))
|
||||||
{
|
{
|
||||||
nodes.Add(new XElement("ContentRoot",
|
nodes.Add(new XElement("ContentRoot",
|
||||||
new XAttribute("BasePath", normalizedBasePath),
|
new XAttribute("BasePath", normalizedBasePath),
|
||||||
new XAttribute("Path", contentRoot)));
|
new XAttribute("Path", normalizedContentRoot)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -102,7 +109,8 @@ namespace Microsoft.AspNetCore.Razor.Tasks
|
||||||
{
|
{
|
||||||
var contentRootDefinition = ContentRootDefinitions[i];
|
var contentRootDefinition = ContentRootDefinitions[i];
|
||||||
if (!EnsureRequiredMetadata(contentRootDefinition, BasePath) ||
|
if (!EnsureRequiredMetadata(contentRootDefinition, BasePath) ||
|
||||||
!EnsureRequiredMetadata(contentRootDefinition, ContentRoot))
|
!EnsureRequiredMetadata(contentRootDefinition, ContentRoot) ||
|
||||||
|
!EnsureRequiredMetadata(contentRootDefinition, SourceId))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -126,23 +134,35 @@ namespace Microsoft.AspNetCore.Razor.Tasks
|
||||||
var contentRootDefinition = ContentRootDefinitions[i];
|
var contentRootDefinition = ContentRootDefinitions[i];
|
||||||
var basePath = contentRootDefinition.GetMetadata(BasePath);
|
var basePath = contentRootDefinition.GetMetadata(BasePath);
|
||||||
var contentRoot = contentRootDefinition.GetMetadata(ContentRoot);
|
var contentRoot = contentRootDefinition.GetMetadata(ContentRoot);
|
||||||
|
var sourceId = contentRootDefinition.GetMetadata(SourceId);
|
||||||
|
|
||||||
if (basePaths.TryGetValue(basePath, out var existingBasePath))
|
if (basePaths.TryGetValue(basePath, out var existingBasePath))
|
||||||
{
|
{
|
||||||
var existingBasePathContentRoot = existingBasePath.GetMetadata(ContentRoot);
|
var existingBasePathContentRoot = existingBasePath.GetMetadata(ContentRoot);
|
||||||
if (!string.Equals(contentRoot, existingBasePathContentRoot, StringComparison.OrdinalIgnoreCase))
|
var existingSourceId = existingBasePath.GetMetadata(SourceId);
|
||||||
|
if (!string.Equals(contentRoot, existingBasePathContentRoot, StringComparison.OrdinalIgnoreCase) &&
|
||||||
|
// We want to check this case to allow for client-side blazor projects to have multiple different content
|
||||||
|
// root sources exposed under the same base path while still requiring unique base paths/content roots across
|
||||||
|
// project/package boundaries.
|
||||||
|
!string.Equals(sourceId, existingSourceId, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
// Case:
|
// Case:
|
||||||
// Item1: /_content/Library, /package/aspnetContent1
|
// Item2: /_content/Library, project:/project/aspnetContent2
|
||||||
// Item2: /_content/Library, /package/aspnetContent2
|
// Item1: /_content/Library, package:/package/aspnetContent1
|
||||||
Log.LogError($"Duplicate base paths '{basePath}' for content root paths '{contentRoot}' and '{existingBasePathContentRoot}'. " +
|
Log.LogError($"Duplicate base paths '{basePath}' for content root paths '{contentRoot}' and '{existingBasePathContentRoot}'. " +
|
||||||
$"('{contentRootDefinition.ItemSpec}', '{existingBasePath.ItemSpec}')");
|
$"('{contentRootDefinition.ItemSpec}', '{existingBasePath.ItemSpec}')");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// It was a duplicate, so we skip it.
|
// It was a duplicate, so we skip it.
|
||||||
// Case:
|
// Case:
|
||||||
// Item1: /_content/Library, /package/aspnetContent
|
// Item1: /_content/Library, project:/project/aspnetContent
|
||||||
// Item2: /_content/Library, /package/aspnetContent
|
// Item2: /_content/Library, project:/project/aspnetContent
|
||||||
|
|
||||||
|
// It was a separate content root exposed from the same project/package, so we skip it.
|
||||||
|
// Case:
|
||||||
|
// Item1: /_content/Library, project:/project/aspnetContent/bin/debug/netstandard2.1/dist
|
||||||
|
// Item2: /_content/Library, project:/project/wwwroot
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using Microsoft.Build.Framework;
|
||||||
|
using Microsoft.Build.Utilities;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Razor.Tasks
|
||||||
|
{
|
||||||
|
public class ValidateStaticWebAssetsUniquePaths : Task
|
||||||
|
{
|
||||||
|
private const string BasePath = "BasePath";
|
||||||
|
private const string RelativePath = "RelativePath";
|
||||||
|
private const string TargetPath = "TargetPath";
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public ITaskItem[] StaticWebAssets { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public ITaskItem[] WebRootFiles { get; set; }
|
||||||
|
|
||||||
|
public override bool Execute()
|
||||||
|
{
|
||||||
|
var assetsByWebRootPaths = new Dictionary<string, ITaskItem>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
for (var i = 0; i < StaticWebAssets.Length; i++)
|
||||||
|
{
|
||||||
|
var contentRootDefinition = StaticWebAssets[i];
|
||||||
|
if (!EnsureRequiredMetadata(contentRootDefinition, BasePath) ||
|
||||||
|
!EnsureRequiredMetadata(contentRootDefinition, RelativePath))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var webRootPath = GetWebRootPath(
|
||||||
|
contentRootDefinition.GetMetadata(BasePath),
|
||||||
|
contentRootDefinition.GetMetadata(RelativePath));
|
||||||
|
|
||||||
|
if (assetsByWebRootPaths.TryGetValue(webRootPath, out var existingWebRootPath))
|
||||||
|
{
|
||||||
|
if (!string.Equals(contentRootDefinition.ItemSpec, existingWebRootPath.ItemSpec, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
Log.LogError($"Conflicting assets with the same path '{webRootPath}' for content root paths '{contentRootDefinition.ItemSpec}' and '{existingWebRootPath.ItemSpec}'.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assetsByWebRootPaths.Add(webRootPath, contentRootDefinition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < WebRootFiles.Length; i++)
|
||||||
|
{
|
||||||
|
var webRootFile = WebRootFiles[i];
|
||||||
|
var relativePath = webRootFile.GetMetadata(TargetPath);
|
||||||
|
var webRootFileWebRootPath = GetWebRootPath("/", relativePath);
|
||||||
|
if (assetsByWebRootPaths.TryGetValue(webRootFileWebRootPath, out var existingAsset))
|
||||||
|
{
|
||||||
|
Log.LogError($"The static web asset '{existingAsset.ItemSpec}' has a conflicting web root path '{webRootFileWebRootPath}' with the project file '{webRootFile.ItemSpec}'.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalizes /base/relative \base\relative\ base\relative and so on to /base/relative
|
||||||
|
private string GetWebRootPath(string basePath, string relativePath) => $"/{Path.Combine(basePath, relativePath.TrimStart('.').TrimStart('/')).Replace("\\", "/").Trim('/')}";
|
||||||
|
|
||||||
|
private bool EnsureRequiredMetadata(ITaskItem item, string metadataName)
|
||||||
|
{
|
||||||
|
var value = item.GetMetadata(metadataName);
|
||||||
|
if (string.IsNullOrEmpty(value))
|
||||||
|
{
|
||||||
|
Log.LogError($"Missing required metadata '{metadataName}' for '{item.ItemSpec}'.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -32,6 +32,11 @@ Copyright (c) .NET Foundation. All rights reserved.
|
||||||
AssemblyFile="$(RazorSdkBuildTasksAssembly)"
|
AssemblyFile="$(RazorSdkBuildTasksAssembly)"
|
||||||
Condition="'$(RazorSdkBuildTasksAssembly)' != ''" />
|
Condition="'$(RazorSdkBuildTasksAssembly)' != ''" />
|
||||||
|
|
||||||
|
<UsingTask
|
||||||
|
TaskName="Microsoft.AspNetCore.Razor.Tasks.ValidateStaticWebAssetsUniquePaths"
|
||||||
|
AssemblyFile="$(RazorSdkBuildTasksAssembly)"
|
||||||
|
Condition="'$(RazorSdkBuildTasksAssembly)' != ''" />
|
||||||
|
|
||||||
<UsingTask
|
<UsingTask
|
||||||
TaskName="Microsoft.AspNetCore.Razor.Tasks.GenerateStaticWebAsssetsPropsFile"
|
TaskName="Microsoft.AspNetCore.Razor.Tasks.GenerateStaticWebAsssetsPropsFile"
|
||||||
AssemblyFile="$(RazorSdkBuildTasksAssembly)"
|
AssemblyFile="$(RazorSdkBuildTasksAssembly)"
|
||||||
|
|
@ -54,23 +59,19 @@ Copyright (c) .NET Foundation. All rights reserved.
|
||||||
$(GetCurrentProjectStaticWebAssetsDependsOn)
|
$(GetCurrentProjectStaticWebAssetsDependsOn)
|
||||||
</GetCurrentProjectStaticWebAssetsDependsOn>
|
</GetCurrentProjectStaticWebAssetsDependsOn>
|
||||||
|
|
||||||
<AssignTargetPathsDependsOn>
|
<GetCopyToOutputDirectoryItemsDependsOn>
|
||||||
|
$(GetCopyToOutputDirectoryItemsDependsOn);
|
||||||
GenerateStaticWebAssetsManifest;
|
GenerateStaticWebAssetsManifest;
|
||||||
$(AssignTargetPathsDependsOn)
|
</GetCopyToOutputDirectoryItemsDependsOn>
|
||||||
</AssignTargetPathsDependsOn>
|
|
||||||
|
|
||||||
<ResolveStaticWebAssetsInputsDependsOn>
|
<ResolveStaticWebAssetsInputsDependsOn>
|
||||||
ResolveCurrentProjectStaticWebAssetsInputs;
|
ResolveCurrentProjectStaticWebAssetsInputs;
|
||||||
$(ResolveStaticWebAssetsInputsDependsOn)
|
|
||||||
</ResolveStaticWebAssetsInputsDependsOn>
|
|
||||||
|
|
||||||
<ResolveStaticWebAssetsInputsDependsOn Condition="$(NoBuild) != 'true'">
|
|
||||||
ResolveReferencedProjectsStaticWebAssets;
|
ResolveReferencedProjectsStaticWebAssets;
|
||||||
$(ResolveStaticWebAssetsInputsDependsOn)
|
$(ResolveStaticWebAssetsInputsDependsOn)
|
||||||
</ResolveStaticWebAssetsInputsDependsOn>
|
</ResolveStaticWebAssetsInputsDependsOn>
|
||||||
|
|
||||||
<ResolveReferencedProjectsStaticWebAssetsDependsOn>
|
<ResolveReferencedProjectsStaticWebAssetsDependsOn>
|
||||||
ResolveReferences;
|
PrepareProjectReferences;
|
||||||
$(ResolveReferencedProjectsStaticWebAssetsDependsOn)
|
$(ResolveReferencedProjectsStaticWebAssetsDependsOn)
|
||||||
</ResolveReferencedProjectsStaticWebAssetsDependsOn>
|
</ResolveReferencedProjectsStaticWebAssetsDependsOn>
|
||||||
|
|
||||||
|
|
@ -145,11 +146,12 @@ Copyright (c) .NET Foundation. All rights reserved.
|
||||||
Condition="'%(SourceType)' != ''">
|
Condition="'%(SourceType)' != ''">
|
||||||
<BasePath>%(StaticWebAsset.BasePath)</BasePath>
|
<BasePath>%(StaticWebAsset.BasePath)</BasePath>
|
||||||
<ContentRoot>%(StaticWebAsset.ContentRoot)</ContentRoot>
|
<ContentRoot>%(StaticWebAsset.ContentRoot)</ContentRoot>
|
||||||
|
<SourceId>%(StaticWebAsset.SourceId)</SourceId>
|
||||||
</_ExternalStaticWebAsset>
|
</_ExternalStaticWebAsset>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<!-- We need a transform here to make sure we hash the metadata -->
|
<!-- We need a transform here to make sure we hash the metadata -->
|
||||||
<Hash ItemsToHash="@(_ExternalStaticWebAsset->'%(Identity)%(BasePath)%(ContentRoot)')">
|
<Hash ItemsToHash="@(_ExternalStaticWebAsset->'%(Identity)%(SourceId)%(BasePath)%(ContentRoot)')">
|
||||||
<Output TaskParameter="HashResult" PropertyName="_StaticWebAssetsCacheHash" />
|
<Output TaskParameter="HashResult" PropertyName="_StaticWebAssetsCacheHash" />
|
||||||
</Hash>
|
</Hash>
|
||||||
|
|
||||||
|
|
@ -181,20 +183,29 @@ Copyright (c) .NET Foundation. All rights reserved.
|
||||||
Outputs="$(_GeneratedStaticWebAssetsDevelopmentManifest)"
|
Outputs="$(_GeneratedStaticWebAssetsDevelopmentManifest)"
|
||||||
DependsOnTargets="$(GenerateStaticWebAssetsManifestDependsOn)">
|
DependsOnTargets="$(GenerateStaticWebAssetsManifestDependsOn)">
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<_WebRootFiles Include="@(ContentWithTargetPath)" Condition="$([System.String]::Copy('%(TargetPath)').Replace('\','/').StartsWith('wwwroot/'))" />
|
||||||
|
<_ReferencedStaticWebAssets Include="@(StaticWebAsset)" Condition="'%(SourceType)' != ''" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ValidateStaticWebAssetsUniquePaths
|
||||||
|
StaticWebAssets="@(_ReferencedStaticWebAssets)"
|
||||||
|
WebRootFiles="@(_WebRootFiles)" />
|
||||||
|
|
||||||
<GenerateStaticWebAssetsManifest
|
<GenerateStaticWebAssetsManifest
|
||||||
ContentRootDefinitions="@(_ExternalStaticWebAsset)"
|
ContentRootDefinitions="@(_ExternalStaticWebAsset)"
|
||||||
TargetManifestPath="$(_GeneratedStaticWebAssetsDevelopmentManifest)" />
|
TargetManifestPath="$(_GeneratedStaticWebAssetsDevelopmentManifest)" />
|
||||||
|
|
||||||
<!-- This is the list of inputs that will be used for generating the manifest used during development. -->
|
<!-- This is the list of inputs that will be used for generating the manifest used during development. -->
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content
|
<ContentWithTargetPath
|
||||||
Include="$(_GeneratedStaticWebAssetsDevelopmentManifest)"
|
Include="$(_GeneratedStaticWebAssetsDevelopmentManifest)"
|
||||||
Condition="'@(_ExternalStaticWebAsset->Count())' != '0'"
|
Condition="'@(_ExternalStaticWebAsset->Count())' != '0'">
|
||||||
Link="$(TargetName).StaticWebAssets.xml">
|
|
||||||
|
|
||||||
|
<TargetPath>$(TargetName).StaticWebAssets.xml</TargetPath>
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
|
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
|
||||||
</Content>
|
</ContentWithTargetPath>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
@ -273,7 +284,7 @@ Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
|
||||||
<_ThisProjectStaticWebAsset
|
<_ThisProjectStaticWebAsset
|
||||||
Include="@(Content)"
|
Include="@(Content)"
|
||||||
Condition="$([System.String]::Copy('%(Identity)').StartsWith('wwwroot'))">
|
Condition="$([System.String]::Copy('%(Identity)').Replace('\','/').StartsWith('wwwroot/'))">
|
||||||
|
|
||||||
<!-- Remove the wwwroot\ prefix -->
|
<!-- Remove the wwwroot\ prefix -->
|
||||||
<RelativePath>$([System.String]::Copy('%(Identity)').Substring(8))</RelativePath>
|
<RelativePath>$([System.String]::Copy('%(Identity)').Substring(8))</RelativePath>
|
||||||
|
|
@ -506,14 +517,15 @@ Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
|
||||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||||
<RelativePath>$([MSBuild]::MakeRelative('$(MSBuildProjectDirectory)','$([MSBuild]::NormalizePath('wwwroot\%(BasePath)\%(RelativePath)'))'))</RelativePath>
|
<RelativePath>$([MSBuild]::MakeRelative('$(MSBuildProjectDirectory)','$([MSBuild]::NormalizePath('wwwroot\%(BasePath)\%(RelativePath)'))'))</RelativePath>
|
||||||
|
|
||||||
</_ExternalPublishStaticWebAsset>
|
</_ExternalPublishStaticWebAsset>
|
||||||
|
|
||||||
<!-- Remove any existing external static web asset that might have been added as part of the
|
<!-- Remove any existing external static web asset that might have been added as part of the
|
||||||
regular publish pipeline. -->
|
regular publish pipeline. -->
|
||||||
<ResolvedFileToPublish Remove="@(_ExternalPublishStaticWebAsset)" />
|
<ResolvedFileToPublish Remove="@(_ExternalPublishStaticWebAsset)" />
|
||||||
|
|
||||||
<ResolvedFileToPublish Include="@(_ExternalPublishStaticWebAsset)" />
|
<ResolvedFileToPublish Include="@(_ExternalPublishStaticWebAsset)">
|
||||||
|
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||||
|
</ResolvedFileToPublish>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Target>
|
</Target>
|
||||||
|
|
|
||||||
|
|
@ -89,12 +89,14 @@ namespace Microsoft.AspNetCore.Razor.Tasks
|
||||||
CreateItem(Path.Combine("wwwroot","sample.js"), new Dictionary<string,string>
|
CreateItem(Path.Combine("wwwroot","sample.js"), new Dictionary<string,string>
|
||||||
{
|
{
|
||||||
["BasePath"] = "MyLibrary",
|
["BasePath"] = "MyLibrary",
|
||||||
["ContentRoot"] = Path.Combine("nuget","MyLibrary")
|
["ContentRoot"] = Path.Combine("nuget", "MyLibrary"),
|
||||||
|
["SourceId"] = "MyLibrary"
|
||||||
}),
|
}),
|
||||||
CreateItem(Path.Combine("wwwroot", "otherLib.js"), new Dictionary<string,string>
|
CreateItem(Path.Combine("wwwroot", "otherLib.js"), new Dictionary<string,string>
|
||||||
{
|
{
|
||||||
["BasePath"] = "MyLibrary",
|
["BasePath"] = "MyLibrary",
|
||||||
["ContentRoot"] = Path.Combine("nuget", "MyOtherLibrary")
|
["ContentRoot"] = Path.Combine("nuget", "MyOtherLibrary"),
|
||||||
|
["SourceId"] = "MyOtherLibrary"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -111,6 +113,58 @@ namespace Microsoft.AspNetCore.Razor.Tasks
|
||||||
message);
|
message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AllowsMultipleContentRootsWithSameBasePath_ForTheSameSourceId()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var file = Path.GetTempFileName();
|
||||||
|
var expectedDocument = $@"<StaticWebAssets Version=""1.0"">
|
||||||
|
<ContentRoot BasePath=""Blazor.Client"" Path=""{Path.Combine(".", "nuget", $"Blazor.Client{Path.DirectorySeparatorChar}")}"" />
|
||||||
|
<ContentRoot BasePath=""Blazor.Client"" Path=""{Path.Combine(".", "nuget", "bin", "debug", $"netstandard2.1{Path.DirectorySeparatorChar}")}"" />
|
||||||
|
</StaticWebAssets>";
|
||||||
|
|
||||||
|
var buildEngine = new Mock<IBuildEngine>();
|
||||||
|
|
||||||
|
var task = new GenerateStaticWebAssetsManifest
|
||||||
|
{
|
||||||
|
BuildEngine = buildEngine.Object,
|
||||||
|
ContentRootDefinitions = new TaskItem[]
|
||||||
|
{
|
||||||
|
CreateItem(Path.Combine("wwwroot","sample.js"), new Dictionary<string,string>
|
||||||
|
{
|
||||||
|
["BasePath"] = "Blazor.Client",
|
||||||
|
["ContentRoot"] = Path.Combine(".", "nuget","Blazor.Client"),
|
||||||
|
["SourceId"] = "Blazor.Client"
|
||||||
|
}),
|
||||||
|
CreateItem(Path.Combine("wwwroot", "otherLib.js"), new Dictionary<string,string>
|
||||||
|
{
|
||||||
|
["BasePath"] = "Blazor.Client",
|
||||||
|
["ContentRoot"] = Path.Combine(".", "nuget", "bin","debug","netstandard2.1"),
|
||||||
|
["SourceId"] = "Blazor.Client"
|
||||||
|
})
|
||||||
|
},
|
||||||
|
TargetManifestPath = file
|
||||||
|
};
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Act
|
||||||
|
var result = task.Execute();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(result);
|
||||||
|
var document = File.ReadAllText(file);
|
||||||
|
Assert.Equal(expectedDocument, document);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (File.Exists(file))
|
||||||
|
{
|
||||||
|
File.Delete(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ReturnsError_ForDuplicateContentRoots()
|
public void ReturnsError_ForDuplicateContentRoots()
|
||||||
{
|
{
|
||||||
|
|
@ -128,11 +182,13 @@ namespace Microsoft.AspNetCore.Razor.Tasks
|
||||||
CreateItem(Path.Combine("wwwroot","sample.js"), new Dictionary<string,string>
|
CreateItem(Path.Combine("wwwroot","sample.js"), new Dictionary<string,string>
|
||||||
{
|
{
|
||||||
["BasePath"] = "MyLibrary",
|
["BasePath"] = "MyLibrary",
|
||||||
|
["SourceId"] = "MyLibrary",
|
||||||
["ContentRoot"] = Path.Combine(".", "MyLibrary")
|
["ContentRoot"] = Path.Combine(".", "MyLibrary")
|
||||||
}),
|
}),
|
||||||
CreateItem(Path.Combine("wwwroot", "otherLib.js"), new Dictionary<string,string>
|
CreateItem(Path.Combine("wwwroot", "otherLib.js"), new Dictionary<string,string>
|
||||||
{
|
{
|
||||||
["BasePath"] = "MyOtherLibrary",
|
["BasePath"] = "MyOtherLibrary",
|
||||||
|
["SourceId"] = "MyOtherLibrary",
|
||||||
["ContentRoot"] = Path.Combine(".", "MyLibrary")
|
["ContentRoot"] = Path.Combine(".", "MyLibrary")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -191,7 +247,7 @@ namespace Microsoft.AspNetCore.Razor.Tasks
|
||||||
// Arrange
|
// Arrange
|
||||||
var file = Path.GetTempFileName();
|
var file = Path.GetTempFileName();
|
||||||
var expectedDocument = $@"<StaticWebAssets Version=""1.0"">
|
var expectedDocument = $@"<StaticWebAssets Version=""1.0"">
|
||||||
<ContentRoot BasePath=""MyLibrary"" Path=""{Path.Combine(".", "nuget", "MyLibrary", "razorContent")}"" />
|
<ContentRoot BasePath=""MyLibrary"" Path=""{Path.Combine(".", "nuget", "MyLibrary", $"razorContent{Path.DirectorySeparatorChar}")}"" />
|
||||||
</StaticWebAssets>";
|
</StaticWebAssets>";
|
||||||
|
|
||||||
try
|
try
|
||||||
|
|
@ -206,7 +262,8 @@ namespace Microsoft.AspNetCore.Razor.Tasks
|
||||||
CreateItem(Path.Combine("wwwroot","sample.js"), new Dictionary<string,string>
|
CreateItem(Path.Combine("wwwroot","sample.js"), new Dictionary<string,string>
|
||||||
{
|
{
|
||||||
["BasePath"] = "MyLibrary",
|
["BasePath"] = "MyLibrary",
|
||||||
["ContentRoot"] = Path.Combine(".", "nuget", "MyLibrary", "razorContent")
|
["ContentRoot"] = Path.Combine(".", "nuget", "MyLibrary", "razorContent"),
|
||||||
|
["SourceId"] = "MyLibrary"
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
TargetManifestPath = file
|
TargetManifestPath = file
|
||||||
|
|
@ -235,7 +292,7 @@ namespace Microsoft.AspNetCore.Razor.Tasks
|
||||||
// Arrange
|
// Arrange
|
||||||
var file = Path.GetTempFileName();
|
var file = Path.GetTempFileName();
|
||||||
var expectedDocument = $@"<StaticWebAssets Version=""1.0"">
|
var expectedDocument = $@"<StaticWebAssets Version=""1.0"">
|
||||||
<ContentRoot BasePath=""Base/MyLibrary"" Path=""{Path.Combine(".", "nuget", "MyLibrary", "razorContent")}"" />
|
<ContentRoot BasePath=""Base/MyLibrary"" Path=""{Path.Combine(".", "nuget", "MyLibrary", $"razorContent{Path.DirectorySeparatorChar}")}"" />
|
||||||
</StaticWebAssets>";
|
</StaticWebAssets>";
|
||||||
|
|
||||||
try
|
try
|
||||||
|
|
@ -251,12 +308,14 @@ namespace Microsoft.AspNetCore.Razor.Tasks
|
||||||
{
|
{
|
||||||
// Base path needs to be normalized to '/' as it goes in the url
|
// Base path needs to be normalized to '/' as it goes in the url
|
||||||
["BasePath"] = "Base\\MyLibrary",
|
["BasePath"] = "Base\\MyLibrary",
|
||||||
|
["SourceId"] = "MyLibrary",
|
||||||
["ContentRoot"] = Path.Combine(".", "nuget", "MyLibrary", "razorContent")
|
["ContentRoot"] = Path.Combine(".", "nuget", "MyLibrary", "razorContent")
|
||||||
}),
|
}),
|
||||||
// Comparisons are case insensitive
|
// Comparisons are case insensitive
|
||||||
CreateItem(Path.Combine("wwwroot, site.css"), new Dictionary<string,string>
|
CreateItem(Path.Combine("wwwroot, site.css"), new Dictionary<string,string>
|
||||||
{
|
{
|
||||||
["BasePath"] = "Base\\MyLIBRARY",
|
["BasePath"] = "Base\\MyLIBRARY",
|
||||||
|
["SourceId"] = "MyLibrary",
|
||||||
["ContentRoot"] = Path.Combine(".", "nuget", "MyLIBRARY", "razorContent")
|
["ContentRoot"] = Path.Combine(".", "nuget", "MyLIBRARY", "razorContent")
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,10 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Testing;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
|
|
@ -221,5 +224,49 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
Assert.BuildOutputContainsLine(result, "Content: appsettings.json CopyToOutputDirectory= CopyToPublishDirectory=PreserveNewest ExcludeFromSingleFile=true");
|
Assert.BuildOutputContainsLine(result, "Content: appsettings.json CopyToOutputDirectory= CopyToPublishDirectory=PreserveNewest ExcludeFromSingleFile=true");
|
||||||
Assert.BuildOutputContainsLine(result, "Content: appsettings.Development.json CopyToOutputDirectory= CopyToPublishDirectory=PreserveNewest ExcludeFromSingleFile=true");
|
Assert.BuildOutputContainsLine(result, "Content: appsettings.Development.json CopyToOutputDirectory= CopyToPublishDirectory=PreserveNewest ExcludeFromSingleFile=true");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[InitializeTestProject("SimpleMvc")]
|
||||||
|
public async Task IntrospectRazorTasksDllPath()
|
||||||
|
{
|
||||||
|
// Regression test for https://github.com/aspnet/AspNetCore/issues/17308
|
||||||
|
var solutionRoot = GetType().Assembly.GetCustomAttributes<AssemblyMetadataAttribute>()
|
||||||
|
.First(a => a.Key == "Testing.RepoRoot")
|
||||||
|
.Value;
|
||||||
|
|
||||||
|
var tfm =
|
||||||
|
#if NETCOREAPP3_1
|
||||||
|
"netcoreapp3.1";
|
||||||
|
#else
|
||||||
|
#error Target framework needs to be updated.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
var expected = Path.Combine(solutionRoot, "artifacts", "bin", "Microsoft.NET.Sdk.Razor", Configuration, "sdk-output", "tasks", tfm, "Microsoft.NET.Sdk.Razor.Tasks.dll");
|
||||||
|
|
||||||
|
// Verifies the fix for https://github.com/aspnet/AspNetCore/issues/17308
|
||||||
|
var result = await DotnetMSBuild("_IntrospectRazorTasks");
|
||||||
|
|
||||||
|
Assert.BuildPassed(result);
|
||||||
|
Assert.BuildOutputContainsLine(result, $"RazorTasksPath: {expected}");
|
||||||
|
}
|
||||||
|
|
||||||
|
[ConditionalFact]
|
||||||
|
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
|
||||||
|
[InitializeTestProject("SimpleMvc")]
|
||||||
|
public async Task IntrospectRazorTasksDllPath_DesktopMsBuild()
|
||||||
|
{
|
||||||
|
var solutionRoot = GetType().Assembly.GetCustomAttributes<AssemblyMetadataAttribute>()
|
||||||
|
.First(a => a.Key == "Testing.RepoRoot")
|
||||||
|
.Value;
|
||||||
|
|
||||||
|
var tfm = "net46";
|
||||||
|
var expected = Path.Combine(solutionRoot, "artifacts", "bin", "Microsoft.NET.Sdk.Razor", Configuration, "sdk-output", "tasks", tfm, "Microsoft.NET.Sdk.Razor.Tasks.dll");
|
||||||
|
|
||||||
|
// Verifies the fix for https://github.com/aspnet/AspNetCore/issues/17308
|
||||||
|
var result = await DotnetMSBuild("_IntrospectRazorTasks", msBuildProcessKind: MSBuildProcessKind.Desktop);
|
||||||
|
|
||||||
|
Assert.BuildPassed(result);
|
||||||
|
Assert.BuildOutputContainsLine(result, $"RazorTasksPath: {expected}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,8 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
|
|
||||||
protected string PublishOutputPath => Path.Combine(OutputPath, "publish");
|
protected string PublishOutputPath => Path.Combine(OutputPath, "publish");
|
||||||
|
|
||||||
|
protected string GetRidSpecificPublishOutputPath(string rid) => Path.Combine(OutputPath, rid, "publish");
|
||||||
|
|
||||||
// Used by the test framework to set the project that we're working with
|
// Used by the test framework to set the project that we're working with
|
||||||
internal static ProjectDirectory Project
|
internal static ProjectDirectory Project
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,31 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
Assert.FileDoesNotExist(result, PublishOutputPath, "AppWithPackageAndP2PReference.StaticWebAssets.xml");
|
Assert.FileDoesNotExist(result, PublishOutputPath, "AppWithPackageAndP2PReference.StaticWebAssets.xml");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[InitializeTestProject("AppWithPackageAndP2PReference", additionalProjects: new[] { "ClassLibrary", "ClassLibrary2" })]
|
||||||
|
public async Task Publish_CopiesStaticWebAssetsToDestinationFolder_PublishSingleFile()
|
||||||
|
{
|
||||||
|
var runtimeIdentifier = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "win-x64" : (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "osx-x64" : "linux-x64");
|
||||||
|
var result = await DotnetMSBuild("Publish", $"/restore /p:PublishSingleFile=true /p:RuntimeIdentifier={runtimeIdentifier}");
|
||||||
|
|
||||||
|
Assert.BuildPassed(result);
|
||||||
|
var publishOutputPath = GetRidSpecificPublishOutputPath(runtimeIdentifier);
|
||||||
|
Assert.FileExists(result, publishOutputPath, Path.Combine("wwwroot", "_content", "ClassLibrary", "js", "project-transitive-dep.js"));
|
||||||
|
Assert.FileExists(result, publishOutputPath, Path.Combine("wwwroot", "_content", "ClassLibrary", "js", "project-transitive-dep.v4.js"));
|
||||||
|
Assert.FileExists(result, publishOutputPath, Path.Combine("wwwroot", "_content", "ClassLibrary2", "css", "site.css"));
|
||||||
|
Assert.FileExists(result, publishOutputPath, Path.Combine("wwwroot", "_content", "ClassLibrary2", "js", "project-direct-dep.js"));
|
||||||
|
Assert.FileExists(result, publishOutputPath, Path.Combine("wwwroot", "_content", "PackageLibraryDirectDependency", "css", "site.css"));
|
||||||
|
Assert.FileExists(result, publishOutputPath, Path.Combine("wwwroot", "_content", "PackageLibraryDirectDependency", "js", "pkg-direct-dep.js"));
|
||||||
|
Assert.FileExists(result, publishOutputPath, Path.Combine("wwwroot", "_content", "PackageLibraryTransitiveDependency", "js", "pkg-transitive-dep.js"));
|
||||||
|
|
||||||
|
// Validate that static web assets don't get published as content too on their regular path
|
||||||
|
Assert.FileDoesNotExist(result, publishOutputPath, Path.Combine("wwwroot", "js", "project-transitive-dep.js"));
|
||||||
|
Assert.FileDoesNotExist(result, publishOutputPath, Path.Combine("wwwroot", "js", "project-transitive-dep.v4.js"));
|
||||||
|
|
||||||
|
// Validate that the manifest never gets copied
|
||||||
|
Assert.FileDoesNotExist(result, publishOutputPath, "AppWithPackageAndP2PReference.StaticWebAssets.xml");
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[InitializeTestProject("AppWithPackageAndP2PReference", additionalProjects: new[] { "ClassLibrary", "ClassLibrary2" })]
|
[InitializeTestProject("AppWithPackageAndP2PReference", additionalProjects: new[] { "ClassLibrary", "ClassLibrary2" })]
|
||||||
public async Task Publish_WithBuildReferencesDisabled_CopiesStaticWebAssetsToDestinationFolder()
|
public async Task Publish_WithBuildReferencesDisabled_CopiesStaticWebAssetsToDestinationFolder()
|
||||||
|
|
@ -104,6 +129,26 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
Assert.FileExists(publish, PublishOutputPath, Path.Combine("wwwroot", "_content", "PackageLibraryTransitiveDependency", "js", "pkg-transitive-dep.js"));
|
Assert.FileExists(publish, PublishOutputPath, Path.Combine("wwwroot", "_content", "PackageLibraryTransitiveDependency", "js", "pkg-transitive-dep.js"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[InitializeTestProject("AppWithPackageAndP2PReference", additionalProjects: new[] { "ClassLibrary", "ClassLibrary2" })]
|
||||||
|
public async Task Publish_NoBuild_CopiesStaticWebAssetsToDestinationFolder()
|
||||||
|
{
|
||||||
|
var build = await DotnetMSBuild("Build", "/restore");
|
||||||
|
|
||||||
|
Assert.BuildPassed(build);
|
||||||
|
|
||||||
|
var publish = await DotnetMSBuild("Publish", "/p:NoBuild=true");
|
||||||
|
|
||||||
|
Assert.BuildPassed(publish);
|
||||||
|
|
||||||
|
Assert.FileExists(publish, PublishOutputPath, Path.Combine("wwwroot", "_content", "ClassLibrary", "js", "project-transitive-dep.js"));
|
||||||
|
Assert.FileExists(publish, PublishOutputPath, Path.Combine("wwwroot", "_content", "ClassLibrary", "js", "project-transitive-dep.v4.js"));
|
||||||
|
Assert.FileExists(publish, PublishOutputPath, Path.Combine("wwwroot", "_content", "ClassLibrary2", "css", "site.css"));
|
||||||
|
Assert.FileExists(publish, PublishOutputPath, Path.Combine("wwwroot", "_content", "ClassLibrary2", "js", "project-direct-dep.js"));
|
||||||
|
Assert.FileExists(publish, PublishOutputPath, Path.Combine("wwwroot", "_content", "PackageLibraryDirectDependency", "css", "site.css"));
|
||||||
|
Assert.FileExists(publish, PublishOutputPath, Path.Combine("wwwroot", "_content", "PackageLibraryDirectDependency", "js", "pkg-direct-dep.js"));
|
||||||
|
Assert.FileExists(publish, PublishOutputPath, Path.Combine("wwwroot", "_content", "PackageLibraryTransitiveDependency", "js", "pkg-transitive-dep.js"));
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[InitializeTestProject("SimpleMvc")]
|
[InitializeTestProject("SimpleMvc")]
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,11 @@
|
||||||
<_Parameter2>$(ProcDumpPath)</_Parameter2>
|
<_Parameter2>$(ProcDumpPath)</_Parameter2>
|
||||||
</AssemblyAttribute>
|
</AssemblyAttribute>
|
||||||
|
|
||||||
|
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
|
||||||
|
<_Parameter1>Testing.RepoRoot</_Parameter1>
|
||||||
|
<_Parameter2>$(RepoRoot)</_Parameter2>
|
||||||
|
</AssemblyAttribute>
|
||||||
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<!-- The test projects rely on these binaries being available -->
|
<!-- The test projects rely on these binaries being available -->
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,141 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using Microsoft.Build.Framework;
|
||||||
|
using Microsoft.Build.Utilities;
|
||||||
|
using Moq;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Razor.Tasks
|
||||||
|
{
|
||||||
|
public class ValidateStaticWebAssetsUniquePathsTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void ReturnsError_WhenStaticWebAssetsWebRootPathMatchesExistingContentItemPath()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var errorMessages = new List<string>();
|
||||||
|
var buildEngine = new Mock<IBuildEngine>();
|
||||||
|
buildEngine.Setup(e => e.LogErrorEvent(It.IsAny<BuildErrorEventArgs>()))
|
||||||
|
.Callback<BuildErrorEventArgs>(args => errorMessages.Add(args.Message));
|
||||||
|
|
||||||
|
var task = new ValidateStaticWebAssetsUniquePaths
|
||||||
|
{
|
||||||
|
BuildEngine = buildEngine.Object,
|
||||||
|
StaticWebAssets = new TaskItem[]
|
||||||
|
{
|
||||||
|
CreateItem(Path.Combine(".", "Library", "wwwroot", "sample.js"), new Dictionary<string,string>
|
||||||
|
{
|
||||||
|
["BasePath"] = "/",
|
||||||
|
["RelativePath"] = "/sample.js",
|
||||||
|
})
|
||||||
|
},
|
||||||
|
WebRootFiles = new TaskItem[]
|
||||||
|
{
|
||||||
|
CreateItem(Path.Combine(".", "App", "wwwroot", "sample.js"), new Dictionary<string,string>
|
||||||
|
{
|
||||||
|
["TargetPath"] = "/SAMPLE.js",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = task.Execute();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
var message = Assert.Single(errorMessages);
|
||||||
|
Assert.Equal($"The static web asset '{Path.Combine(".", "Library", "wwwroot", "sample.js")}' has a conflicting web root path '/SAMPLE.js' with the project file '{Path.Combine(".", "App", "wwwroot", "sample.js")}'.", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ReturnsError_WhenMultipleStaticWebAssetsHaveTheSameWebRootPath()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var errorMessages = new List<string>();
|
||||||
|
var buildEngine = new Mock<IBuildEngine>();
|
||||||
|
buildEngine.Setup(e => e.LogErrorEvent(It.IsAny<BuildErrorEventArgs>()))
|
||||||
|
.Callback<BuildErrorEventArgs>(args => errorMessages.Add(args.Message));
|
||||||
|
|
||||||
|
var task = new ValidateStaticWebAssetsUniquePaths
|
||||||
|
{
|
||||||
|
BuildEngine = buildEngine.Object,
|
||||||
|
StaticWebAssets = new TaskItem[]
|
||||||
|
{
|
||||||
|
CreateItem(Path.Combine(".", "Library", "wwwroot", "sample.js"), new Dictionary<string,string>
|
||||||
|
{
|
||||||
|
["BasePath"] = "/",
|
||||||
|
["RelativePath"] = "/sample.js",
|
||||||
|
}),
|
||||||
|
CreateItem(Path.Combine(".", "Library", "bin", "dist", "sample.js"), new Dictionary<string,string>
|
||||||
|
{
|
||||||
|
["BasePath"] = "/",
|
||||||
|
["RelativePath"] = "/sample.js",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = task.Execute();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
var message = Assert.Single(errorMessages);
|
||||||
|
Assert.Equal($"Conflicting assets with the same path '/sample.js' for content root paths '{Path.Combine(".", "Library", "bin", "dist", "sample.js")}' and '{Path.Combine(".", "Library", "wwwroot", "sample.js")}'.", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ReturnsSuccess_WhenStaticWebAssetsDontConflictWithApplicationContentItems()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var errorMessages = new List<string>();
|
||||||
|
var buildEngine = new Mock<IBuildEngine>();
|
||||||
|
|
||||||
|
var task = new ValidateStaticWebAssetsUniquePaths
|
||||||
|
{
|
||||||
|
BuildEngine = buildEngine.Object,
|
||||||
|
StaticWebAssets = new TaskItem[]
|
||||||
|
{
|
||||||
|
CreateItem(Path.Combine(".", "Library", "wwwroot", "sample.js"), new Dictionary<string,string>
|
||||||
|
{
|
||||||
|
["BasePath"] = "/_library",
|
||||||
|
["RelativePath"] = "/sample.js",
|
||||||
|
}),
|
||||||
|
CreateItem(Path.Combine(".", "Library", "wwwroot", "sample.js"), new Dictionary<string,string>
|
||||||
|
{
|
||||||
|
["BasePath"] = "/_library",
|
||||||
|
["RelativePath"] = "/sample.js",
|
||||||
|
})
|
||||||
|
},
|
||||||
|
WebRootFiles = new TaskItem[]
|
||||||
|
{
|
||||||
|
CreateItem(Path.Combine(".", "App", "wwwroot", "sample.js"), new Dictionary<string,string>
|
||||||
|
{
|
||||||
|
["TargetPath"] = "/SAMPLE.js",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = task.Execute();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TaskItem CreateItem(
|
||||||
|
string spec,
|
||||||
|
IDictionary<string, string> metadata)
|
||||||
|
{
|
||||||
|
var result = new TaskItem(spec);
|
||||||
|
foreach (var (key, value) in metadata)
|
||||||
|
{
|
||||||
|
result.SetMetadata(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -46,4 +46,11 @@
|
||||||
<Target Name="_IntrospectContentItems">
|
<Target Name="_IntrospectContentItems">
|
||||||
<Message Text="Content: %(Content.Identity) CopyToOutputDirectory=%(Content.CopyToOutputDirectory) CopyToPublishDirectory=%(Content.CopyToPublishDirectory) ExcludeFromSingleFile=%(Content.ExcludeFromSingleFile)" Importance="High" />
|
<Message Text="Content: %(Content.Identity) CopyToOutputDirectory=%(Content.CopyToOutputDirectory) CopyToPublishDirectory=%(Content.CopyToPublishDirectory) ExcludeFromSingleFile=%(Content.ExcludeFromSingleFile)" Importance="High" />
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="_IntrospectRazorTasks">
|
||||||
|
<PropertyGroup>
|
||||||
|
<_SdkTaskPath>$([System.IO.Path]::GetFullPath('$(RazorSdkBuildTasksAssembly)'))</_SdkTaskPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Message Text="RazorTasksPath: $(_SdkTaskPath)" Importance="High" />
|
||||||
|
</Target>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue