Initial support for static assets in Razor Class Libraries (dotnet/aspnetcore-tooling#580)
* Imports static assets from packages containing custom msbuild
targets defining a StaticWebAsset item group.
* Generates an embeds a manifest into the application assembly
that contains a list of paths to the content roots of the
assets defined in the packages custom msbuild targets.\n\nCommit migrated from 8e70013b70
This commit is contained in:
parent
111e26dd03
commit
13397dd4d6
|
|
@ -0,0 +1,184 @@
|
||||||
|
// 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 System.Text;
|
||||||
|
using System.Xml;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
using Microsoft.Build.Framework;
|
||||||
|
using Microsoft.Build.Utilities;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Razor.Tasks
|
||||||
|
{
|
||||||
|
public class GenerateStaticWebAssetsManifest : Task
|
||||||
|
{
|
||||||
|
private const string ContentRoot = "ContentRoot";
|
||||||
|
private const string BasePath = "BasePath";
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public string TargetManifestPath { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public ITaskItem[] ContentRootDefinitions { get; set; }
|
||||||
|
|
||||||
|
public override bool Execute()
|
||||||
|
{
|
||||||
|
if (!ValidateArguments())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExecuteCore();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ExecuteCore()
|
||||||
|
{
|
||||||
|
var document = new XDocument(new XDeclaration("1.0", "utf-8", "yes"));
|
||||||
|
var root = new XElement(
|
||||||
|
"StaticWebAssets",
|
||||||
|
new XAttribute("Version", "1.0"),
|
||||||
|
CreateNodes());
|
||||||
|
|
||||||
|
document.Add(root);
|
||||||
|
|
||||||
|
var settings = new XmlWriterSettings
|
||||||
|
{
|
||||||
|
Encoding = Encoding.UTF8,
|
||||||
|
CloseOutput = true,
|
||||||
|
OmitXmlDeclaration = true,
|
||||||
|
Indent = true,
|
||||||
|
NewLineOnAttributes = false,
|
||||||
|
Async = true
|
||||||
|
};
|
||||||
|
|
||||||
|
using (var xmlWriter = GetXmlWriter(settings))
|
||||||
|
{
|
||||||
|
document.WriteTo(xmlWriter);
|
||||||
|
}
|
||||||
|
|
||||||
|
return !Log.HasLoggedErrors;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<XElement> CreateNodes()
|
||||||
|
{
|
||||||
|
var nodes = new List<XElement>();
|
||||||
|
for (var i = 0; i < ContentRootDefinitions.Length; i++)
|
||||||
|
{
|
||||||
|
var contentRootDefinition = ContentRootDefinitions[i];
|
||||||
|
var basePath = contentRootDefinition.GetMetadata(BasePath);
|
||||||
|
var contentRoot = contentRootDefinition.GetMetadata(ContentRoot);
|
||||||
|
|
||||||
|
// basePath is meant to be a prefix for the files under contentRoot. MSbuild
|
||||||
|
// normalizes '\' according to the OS, but this is going to be part of the url
|
||||||
|
// so it needs to always be '/'.
|
||||||
|
var normalizedBasePath = basePath.Replace("\\", "/");
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
if (!nodes.Exists(e => e.Attribute(BasePath).Value.Equals(normalizedBasePath, StringComparison.OrdinalIgnoreCase)))
|
||||||
|
{
|
||||||
|
nodes.Add(new XElement("ContentRoot",
|
||||||
|
new XAttribute("BasePath", normalizedBasePath),
|
||||||
|
new XAttribute("Path", contentRoot)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private XmlWriter GetXmlWriter(XmlWriterSettings settings)
|
||||||
|
{
|
||||||
|
var fileStream = new FileStream(TargetManifestPath, FileMode.Create);
|
||||||
|
return XmlWriter.Create(fileStream, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ValidateArguments()
|
||||||
|
{
|
||||||
|
for (var i = 0; i < ContentRootDefinitions.Length; i++)
|
||||||
|
{
|
||||||
|
var contentRootDefinition = ContentRootDefinitions[i];
|
||||||
|
if (!EnsureRequiredMetadata(contentRootDefinition, BasePath) ||
|
||||||
|
!EnsureRequiredMetadata(contentRootDefinition, ContentRoot))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We want to validate that there are no different item groups that share either the same base path
|
||||||
|
// but different content roots or that share the same content root but different base paths.
|
||||||
|
// We pass in all the static web assets that we discovered to this task without making any distinction for
|
||||||
|
// duplicates, so here we skip elements for which we are already tracking an element with the same
|
||||||
|
// content root path and same base path.
|
||||||
|
|
||||||
|
// Case-sensitivity depends on the underlying OS so we are not going to do anything to enforce it here.
|
||||||
|
// Any two items that match base path and content root in a case-insensitive way won't produce an error.
|
||||||
|
// Any other two items will produce an error even if there is only a casing difference between either the
|
||||||
|
// base paths or the content roots.
|
||||||
|
var basePaths = new Dictionary<string, ITaskItem>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
var contentRootPaths = new Dictionary<string, ITaskItem>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
for (var i = 0; i < ContentRootDefinitions.Length; i++)
|
||||||
|
{
|
||||||
|
var contentRootDefinition = ContentRootDefinitions[i];
|
||||||
|
var basePath = contentRootDefinition.GetMetadata(BasePath);
|
||||||
|
var contentRoot = contentRootDefinition.GetMetadata(ContentRoot);
|
||||||
|
|
||||||
|
if (basePaths.TryGetValue(basePath, out var existingBasePath))
|
||||||
|
{
|
||||||
|
var existingBasePathContentRoot = existingBasePath.GetMetadata(ContentRoot);
|
||||||
|
if (!string.Equals(contentRoot, existingBasePathContentRoot, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
// Case:
|
||||||
|
// Item1: /_content/Library, /package/aspnetContent1
|
||||||
|
// Item2: /_content/Library, /package/aspnetContent2
|
||||||
|
Log.LogError($"Duplicate base paths '{basePath}' for content root paths '{contentRoot}' and '{existingBasePathContentRoot}'. " +
|
||||||
|
$"('{contentRootDefinition.ItemSpec}', '{existingBasePath.ItemSpec}')");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// It was a duplicate, so we skip it.
|
||||||
|
// Case:
|
||||||
|
// Item1: /_content/Library, /package/aspnetContent
|
||||||
|
// Item2: /_content/Library, /package/aspnetContent
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (contentRootPaths.TryGetValue(contentRoot, out var existingContentRoot))
|
||||||
|
{
|
||||||
|
// Case:
|
||||||
|
// Item1: /_content/Library1, /package/aspnetContent
|
||||||
|
// Item2: /_content/Library2, /package/aspnetContent
|
||||||
|
Log.LogError($"Duplicate content root paths '{contentRoot}' for base paths '{basePath}' and '{existingContentRoot.GetMetadata(BasePath)}' " +
|
||||||
|
$"('{contentRootDefinition.ItemSpec}', '{existingContentRoot.ItemSpec}')");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!basePaths.ContainsKey(basePath))
|
||||||
|
{
|
||||||
|
basePaths.Add(basePath, contentRootDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!contentRootPaths.ContainsKey(contentRoot))
|
||||||
|
{
|
||||||
|
contentRootPaths.Add(contentRoot, contentRootDefinition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,172 @@
|
||||||
|
<!--
|
||||||
|
***********************************************************************************************
|
||||||
|
Microsoft.NET.Sdk.Razor.StaticWebAssets.targets
|
||||||
|
|
||||||
|
WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
|
||||||
|
created a backup copy. Incorrect changes to this file will make it
|
||||||
|
impossible to load or build your projects from the command-line or the IDE.
|
||||||
|
|
||||||
|
Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
***********************************************************************************************
|
||||||
|
-->
|
||||||
|
|
||||||
|
<Project ToolsVersion="14.0">
|
||||||
|
|
||||||
|
<!-- Targets that support static content scenarios in ASP.NET Core.
|
||||||
|
The main targets are:
|
||||||
|
* GenerateStaticWebAssetsManifest: Creates a manifest file to use in development with
|
||||||
|
the paths to all the references packages and projects content roots.
|
||||||
|
* ResolveStaticWebAssetsInputs: Collects all the static assets from different sources
|
||||||
|
* Current project.
|
||||||
|
* Referenced project.
|
||||||
|
* Referenced packages.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<UsingTask
|
||||||
|
TaskName="Microsoft.AspNetCore.Razor.Tasks.GenerateStaticWebAssetsManifest"
|
||||||
|
AssemblyFile="$(RazorSdkBuildTasksAssembly)"
|
||||||
|
Condition="'$(RazorSdkBuildTasksAssembly)' != ''" />
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<GenerateStaticWebAssetsManifestDependsOn>
|
||||||
|
ResolveStaticWebAssetsInputs;
|
||||||
|
_CreateStaticWebAssetsInputsCacheFile
|
||||||
|
</GenerateStaticWebAssetsManifestDependsOn>
|
||||||
|
|
||||||
|
<AssignTargetPathsDependsOn>
|
||||||
|
GenerateStaticWebAssetsManifest;
|
||||||
|
$(AssignTargetPathsDependsOn)
|
||||||
|
</AssignTargetPathsDependsOn>
|
||||||
|
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<_GeneratedStaticWebAssetsInputsCacheFile>$(IntermediateOutputPath)$(TargetName).StaticWebAssets.cache</_GeneratedStaticWebAssetsInputsCacheFile>
|
||||||
|
<_GeneratedStaticWebAssetsDevelopmentManifest>$(IntermediateOutputPath)$(TargetName).StaticWebAssets.xml</_GeneratedStaticWebAssetsDevelopmentManifest>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Target
|
||||||
|
Name="_CreateStaticWebAssetsInputsCacheFile"
|
||||||
|
DependsOnTargets="ResolveStaticWebAssetsInputs">
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<!--
|
||||||
|
This is the list of inputs that will be used for generating the manifest used during development.
|
||||||
|
-->
|
||||||
|
<_ExternalStaticWebAsset
|
||||||
|
Include="%(StaticWebAsset.Identity)"
|
||||||
|
Condition="'%(SourceType)' != ''">
|
||||||
|
<BasePath>%(StaticWebAsset.BasePath)</BasePath>
|
||||||
|
<ContentRoot>%(StaticWebAsset.ContentRoot)</ContentRoot>
|
||||||
|
</_ExternalStaticWebAsset>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- We need a transform here to make sure we hash the metadata -->
|
||||||
|
<Hash ItemsToHash="@(_ExternalStaticWebAsset->'%(Identity)%(BasePath)%(ContentRoot)')">
|
||||||
|
<Output TaskParameter="HashResult" PropertyName="_StaticWebAssetsCacheHash" />
|
||||||
|
</Hash>
|
||||||
|
|
||||||
|
<WriteLinesToFile
|
||||||
|
Lines="$(_StaticWebAssetsCacheHash)"
|
||||||
|
File="$(_GeneratedStaticWebAssetsInputsCacheFile)"
|
||||||
|
Overwrite="True"
|
||||||
|
WriteOnlyWhenDifferent="True" />
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<FileWrites Include="$(_GeneratedStaticWebAssetsInputsCacheFile)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
This target generates a manifest for development time that includes information
|
||||||
|
about the base path for the referenced package and project static web assets. The
|
||||||
|
manifest includes the content root and the base path for each of the referenced
|
||||||
|
packages and projects.
|
||||||
|
|
||||||
|
Ideally, each package/project contains a unique base path and a given content
|
||||||
|
root, but we don't check for duplicates on either of them.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<Target
|
||||||
|
Name="GenerateStaticWebAssetsManifest"
|
||||||
|
Inputs="$(_GeneratedStaticWebAssetsInputsCacheFile)"
|
||||||
|
Outputs="$(_GeneratedStaticWebAssetsDevelopmentManifest)"
|
||||||
|
DependsOnTargets="$(GenerateStaticWebAssetsManifestDependsOn)">
|
||||||
|
|
||||||
|
<GenerateStaticWebAssetsManifest
|
||||||
|
ContentRootDefinitions="@(_ExternalStaticWebAsset)"
|
||||||
|
TargetManifestPath="$(_GeneratedStaticWebAssetsDevelopmentManifest)" />
|
||||||
|
|
||||||
|
<!-- This is the list of inputs that will be used for generating the manifest used during development. -->
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Condition="'@(_ExternalStaticWebAsset->Count())' != '0'"
|
||||||
|
Include="$(_GeneratedStaticWebAssetsDevelopmentManifest)"
|
||||||
|
LogicalName="Microsoft.AspNetCore.StaticWebAssets.xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<FileWrites Include="$(_GeneratedStaticWebAssetsDevelopmentManifest)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<!-- This target collects all the StaticWebAssets from different sources:
|
||||||
|
* The current project StaticWebAssets that come from wwwroot\** by default.
|
||||||
|
* Assets from referenced projects that get retrieved invoking an MSBuild target on
|
||||||
|
the referenced projects.
|
||||||
|
* Assets from the referenced packages. These will be implicitly included when nuget
|
||||||
|
restores the package and includes the package props file for the package.
|
||||||
|
-->
|
||||||
|
<Target
|
||||||
|
Name="ResolveStaticWebAssetsInputs">
|
||||||
|
<PropertyGroup>
|
||||||
|
<!-- The _SafeBasePath is used as a path segment in the urls that we will
|
||||||
|
be exposing content from when the library is referenced as a package
|
||||||
|
or as a project by a web application. Our convention will be to expose
|
||||||
|
content directly on _content/<<_SafeBasePath>>
|
||||||
|
|
||||||
|
We simply remove the dots from the package id so that a package
|
||||||
|
like Microsoft.AspNetCore.Identity becomes MicrosoftAspNetCoreIdentity
|
||||||
|
|
||||||
|
TODO: Investigate if we need to do something more sophisticated here.
|
||||||
|
-->
|
||||||
|
<_SafeBasePath>$(PackageId.Replace('.',''))</_SafeBasePath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<!-- StaticWebAssets from the current project -->
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<!--
|
||||||
|
Should we promote 'wwwroot\**'' to a property?
|
||||||
|
We don't want to capture any content outside the content root, that's why we don't do
|
||||||
|
@(Content) here.
|
||||||
|
-->
|
||||||
|
<StaticWebAsset Include="wwwroot\**" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)">
|
||||||
|
<!-- (PackageReference,ProjectReference,'' (CurrentProject)) -->
|
||||||
|
<SourceType></SourceType>
|
||||||
|
<!-- Identifier describing the source, the package id, the project name, empty for the current project. -->
|
||||||
|
<SourceId></SourceId>
|
||||||
|
<!--
|
||||||
|
Full path to the content root for the item:
|
||||||
|
* For packages it corresponds to %userprofile%/.nuget/packages/<<PackageId>>/<<PackageVersion>>/razorContent
|
||||||
|
* For referenced projects it corresponds to <<FullProjectRefPath>>/wwwroot
|
||||||
|
* For the current projects it corresponds to $(MSBuildThisProjectFileDirectory)wwwroot\
|
||||||
|
-->
|
||||||
|
<ContentRoot>$(MSBuildProjectDirectory)\wwwroot\</ContentRoot>
|
||||||
|
<!-- Subsection (folder) from the url space where content for this library will be served. -->
|
||||||
|
<BasePath>_content\$(_SafeBasePath)\</BasePath>
|
||||||
|
<!-- Relative path from the content root for the file. At publish time, we combine the BasePath + Relative
|
||||||
|
path to determine the final path for the file. -->
|
||||||
|
<RelativePath>%(RecursiveDir)%(FileName)%(Extension)</RelativePath>
|
||||||
|
|
||||||
|
</StaticWebAsset>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- StaticWebAssets from referenced projects. -->
|
||||||
|
<!-- TODO: Include implementation -->
|
||||||
|
|
||||||
|
<!-- StaticWebAssets from packages are already available, so we don't do anything. -->
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
|
@ -74,6 +74,10 @@ Copyright (c) .NET Foundation. All rights reserved.
|
||||||
<None Remove="**\*.razor" />
|
<None Remove="**\*.razor" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<EnableRazorSdkContent Condition=" '$(UsingMicrosoftNETSdkWeb)' == '' ">true</EnableRazorSdkContent>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<Import
|
<Import
|
||||||
Project="$(MSBuildThisFileDirectory)..\..\Sdk\Sdk.Razor.StaticAssets.ProjectSystem.props"
|
Project="$(MSBuildThisFileDirectory)..\..\Sdk\Sdk.Razor.StaticAssets.ProjectSystem.props"
|
||||||
Condition=" '$(EnableRazorSdkContent)' == 'true' " />
|
Condition=" '$(EnableRazorSdkContent)' == 'true' " />
|
||||||
|
|
|
||||||
|
|
@ -338,6 +338,8 @@ Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
|
||||||
<Import Project="Microsoft.NET.Sdk.Razor.Component.targets" Condition="'$(_Targeting30OrNewerRazorLangVersion)' == 'true'" />
|
<Import Project="Microsoft.NET.Sdk.Razor.Component.targets" Condition="'$(_Targeting30OrNewerRazorLangVersion)' == 'true'" />
|
||||||
|
|
||||||
|
<Import Project="Microsoft.NET.Sdk.Razor.StaticWebAssets.targets" Condition="'$(_Targeting30OrNewerRazorLangVersion)' == 'true'" />
|
||||||
|
|
||||||
<Import Project="Microsoft.NET.Sdk.Razor.GenerateAssemblyInfo.targets" />
|
<Import Project="Microsoft.NET.Sdk.Razor.GenerateAssemblyInfo.targets" />
|
||||||
|
|
||||||
<Import Project="Microsoft.NET.Sdk.Razor.MvcApplicationPartsDiscovery.targets" Condition="'$(_TargetingNETCoreApp30OrLater)' == 'true'" />
|
<Import Project="Microsoft.NET.Sdk.Razor.MvcApplicationPartsDiscovery.targets" Condition="'$(_TargetingNETCoreApp30OrLater)' == 'true'" />
|
||||||
|
|
@ -480,6 +482,7 @@ Copyright (c) .NET Foundation. All rights reserved.
|
||||||
'$(EnableDefaultRazorGenerateItems)'=='true'">
|
'$(EnableDefaultRazorGenerateItems)'=='true'">
|
||||||
|
|
||||||
<Content Condition="'%(Content.Extension)'=='.cshtml'" Pack="$(IncludeRazorContentInPack)" />
|
<Content Condition="'%(Content.Extension)'=='.cshtml'" Pack="$(IncludeRazorContentInPack)" />
|
||||||
|
<Content Condition="'%(Content.Extension)'=='.razor'" Pack="$(IncludeRazorContentInPack)" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,296 @@
|
||||||
|
// 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 GenerateStaticWebAssetsManifestTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void ReturnsError_WhenBasePathIsMissing()
|
||||||
|
{
|
||||||
|
// 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 GenerateStaticWebAssetsManifest
|
||||||
|
{
|
||||||
|
BuildEngine = buildEngine.Object,
|
||||||
|
ContentRootDefinitions = new TaskItem[]
|
||||||
|
{
|
||||||
|
CreateItem(Path.Combine("wwwroot", "sample.js"), new Dictionary<string,string>
|
||||||
|
{
|
||||||
|
["ContentRoot"] = "/"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = task.Execute();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
var message = Assert.Single(errorMessages);
|
||||||
|
Assert.Equal($"Missing required metadata 'BasePath' for '{Path.Combine("wwwroot", "sample.js")}'.", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ReturnsError_WhenContentRootIsMissing()
|
||||||
|
{
|
||||||
|
// 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 GenerateStaticWebAssetsManifest
|
||||||
|
{
|
||||||
|
BuildEngine = buildEngine.Object,
|
||||||
|
ContentRootDefinitions = new TaskItem[]
|
||||||
|
{
|
||||||
|
CreateItem(Path.Combine("wwwroot","sample.js"), new Dictionary<string,string>
|
||||||
|
{
|
||||||
|
["BasePath"] = "MyLibrary"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = task.Execute();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
var message = Assert.Single(errorMessages);
|
||||||
|
Assert.Equal($"Missing required metadata 'ContentRoot' for '{Path.Combine("wwwroot", "sample.js")}'.", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ReturnsError_ForDuplicateBasePaths()
|
||||||
|
{
|
||||||
|
// 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 GenerateStaticWebAssetsManifest
|
||||||
|
{
|
||||||
|
BuildEngine = buildEngine.Object,
|
||||||
|
ContentRootDefinitions = new TaskItem[]
|
||||||
|
{
|
||||||
|
CreateItem(Path.Combine("wwwroot","sample.js"), new Dictionary<string,string>
|
||||||
|
{
|
||||||
|
["BasePath"] = "MyLibrary",
|
||||||
|
["ContentRoot"] = Path.Combine("nuget","MyLibrary")
|
||||||
|
}),
|
||||||
|
CreateItem(Path.Combine("wwwroot", "otherLib.js"), new Dictionary<string,string>
|
||||||
|
{
|
||||||
|
["BasePath"] = "MyLibrary",
|
||||||
|
["ContentRoot"] = Path.Combine("nuget", "MyOtherLibrary")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = task.Execute();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
var message = Assert.Single(errorMessages);
|
||||||
|
Assert.Equal(
|
||||||
|
$"Duplicate base paths 'MyLibrary' for content root paths '{Path.Combine("nuget", "MyOtherLibrary")}' and '{Path.Combine("nuget", "MyLibrary")}'. " +
|
||||||
|
$"('{Path.Combine("wwwroot", "otherLib.js")}', '{Path.Combine("wwwroot", "sample.js")}')",
|
||||||
|
message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ReturnsError_ForDuplicateContentRoots()
|
||||||
|
{
|
||||||
|
// 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 GenerateStaticWebAssetsManifest
|
||||||
|
{
|
||||||
|
BuildEngine = buildEngine.Object,
|
||||||
|
ContentRootDefinitions = new TaskItem[]
|
||||||
|
{
|
||||||
|
CreateItem(Path.Combine("wwwroot","sample.js"), new Dictionary<string,string>
|
||||||
|
{
|
||||||
|
["BasePath"] = "MyLibrary",
|
||||||
|
["ContentRoot"] = Path.Combine(".", "MyLibrary")
|
||||||
|
}),
|
||||||
|
CreateItem(Path.Combine("wwwroot", "otherLib.js"), new Dictionary<string,string>
|
||||||
|
{
|
||||||
|
["BasePath"] = "MyOtherLibrary",
|
||||||
|
["ContentRoot"] = Path.Combine(".", "MyLibrary")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = task.Execute();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
var message = Assert.Single(errorMessages);
|
||||||
|
Assert.Equal(
|
||||||
|
$"Duplicate content root paths '{Path.Combine(".", "MyLibrary")}' for base paths 'MyOtherLibrary' and 'MyLibrary' " +
|
||||||
|
$"('{Path.Combine("wwwroot", "otherLib.js")}', '{Path.Combine("wwwroot", "sample.js")}')",
|
||||||
|
message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Generates_EmptyManifest_WhenNoItems_Passed()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var file = Path.GetTempFileName();
|
||||||
|
var expectedDocument = @"<StaticWebAssets Version=""1.0"" />";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var buildEngine = new Mock<IBuildEngine>();
|
||||||
|
|
||||||
|
var task = new GenerateStaticWebAssetsManifest
|
||||||
|
{
|
||||||
|
BuildEngine = buildEngine.Object,
|
||||||
|
ContentRootDefinitions = new TaskItem[] { },
|
||||||
|
TargetManifestPath = file
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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]
|
||||||
|
public void Generates_Manifest_WhenContentRootsAvailable()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var file = Path.GetTempFileName();
|
||||||
|
var expectedDocument = $@"<StaticWebAssets Version=""1.0"">
|
||||||
|
<ContentRoot BasePath=""MyLibrary"" Path=""{Path.Combine(".", "nuget", "MyLibrary", "razorContent")}"" />
|
||||||
|
</StaticWebAssets>";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
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"] = "MyLibrary",
|
||||||
|
["ContentRoot"] = Path.Combine(".", "nuget", "MyLibrary", "razorContent")
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
TargetManifestPath = file
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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]
|
||||||
|
public void SkipsAdditionalElements_WithSameBasePathAndSameContentRoot()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var file = Path.GetTempFileName();
|
||||||
|
var expectedDocument = $@"<StaticWebAssets Version=""1.0"">
|
||||||
|
<ContentRoot BasePath=""Base/MyLibrary"" Path=""{Path.Combine(".", "nuget", "MyLibrary", "razorContent")}"" />
|
||||||
|
</StaticWebAssets>";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
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>
|
||||||
|
{
|
||||||
|
// Base path needs to be normalized to '/' as it goes in the url
|
||||||
|
["BasePath"] = "Base\\MyLibrary",
|
||||||
|
["ContentRoot"] = Path.Combine(".", "nuget", "MyLibrary", "razorContent")
|
||||||
|
}),
|
||||||
|
// Comparisons are case insensitive
|
||||||
|
CreateItem(Path.Combine("wwwroot, site.css"), new Dictionary<string,string>
|
||||||
|
{
|
||||||
|
["BasePath"] = "Base\\MyLIBRARY",
|
||||||
|
["ContentRoot"] = Path.Combine(".", "nuget", "MyLIBRARY", "razorContent")
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
TargetManifestPath = file
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
@ -344,6 +345,58 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Stream ContainsEmbeddedResource(string assemblyPath, string resourceName)
|
||||||
|
{
|
||||||
|
var stream = ExtractEmbeddedResource(assemblyPath, resourceName);
|
||||||
|
Assert.NotNull(stream);
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DoesNotContainEmbeddedResource(string assemblyPath, string resourceName)
|
||||||
|
{
|
||||||
|
var stream = ExtractEmbeddedResource(assemblyPath, resourceName);
|
||||||
|
Assert.Null(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Stream ExtractEmbeddedResource(string path, string expectedResourceName)
|
||||||
|
{
|
||||||
|
using (var peStream = File.OpenRead(path))
|
||||||
|
{
|
||||||
|
using (var peReader = new PEReader(peStream))
|
||||||
|
{
|
||||||
|
var mdReader = peReader.GetMetadataReader();
|
||||||
|
|
||||||
|
foreach (var resourceHandle in mdReader.ManifestResources)
|
||||||
|
{
|
||||||
|
var resource = mdReader.GetManifestResource(resourceHandle);
|
||||||
|
|
||||||
|
if (!resource.Implementation.IsNil)
|
||||||
|
{
|
||||||
|
continue; // resource is not embedded.
|
||||||
|
}
|
||||||
|
|
||||||
|
var resourceName = mdReader.GetString(resource.Name);
|
||||||
|
if (!string.Equals(expectedResourceName, resourceName))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We are not taking resource.Offset into account here.
|
||||||
|
// We currently only have the casuistic that we are embedding a single resource.
|
||||||
|
// If that changes we'll have to change this test code, but as its hard we won't do it for now.
|
||||||
|
var resourcesSection = peReader.GetSectionData(peReader.PEHeaders.CorHeader.ResourcesDirectory.RelativeVirtualAddress);
|
||||||
|
var resourcesReader = resourcesSection.GetReader();
|
||||||
|
var resourceSizeInBytes = resourcesReader.ReadInt32();
|
||||||
|
var resourceBytes = resourcesReader.ReadBytes(resourceSizeInBytes);
|
||||||
|
return new MemoryStream(resourceBytes, writable: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public static void NuspecContains(MSBuildResult result, string nuspecPath, string expected)
|
public static void NuspecContains(MSBuildResult result, string nuspecPath, string expected)
|
||||||
{
|
{
|
||||||
if (result == null)
|
if (result == null)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
@ -13,6 +15,9 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
{
|
{
|
||||||
public abstract class MSBuildIntegrationTestBase
|
public abstract class MSBuildIntegrationTestBase
|
||||||
{
|
{
|
||||||
|
internal static readonly string LocalNugetPackagesCacheTempPath =
|
||||||
|
Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()) + Path.DirectorySeparatorChar;
|
||||||
|
|
||||||
private static readonly AsyncLocal<ProjectDirectory> _project = new AsyncLocal<ProjectDirectory>();
|
private static readonly AsyncLocal<ProjectDirectory> _project = new AsyncLocal<ProjectDirectory>();
|
||||||
private static readonly AsyncLocal<string> _projectTfm = new AsyncLocal<string>();
|
private static readonly AsyncLocal<string> _projectTfm = new AsyncLocal<string>();
|
||||||
|
|
||||||
|
|
@ -42,6 +47,10 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
set { _project.Value = value; }
|
set { _project.Value = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Whether to use a local cache or not to prevent polluting the global cache
|
||||||
|
// with test packages.
|
||||||
|
public bool UseLocalPackageCache { get; set; }
|
||||||
|
|
||||||
protected string RazorIntermediateOutputPath => Path.Combine(IntermediateOutputPath, "Razor");
|
protected string RazorIntermediateOutputPath => Path.Combine(IntermediateOutputPath, "Razor");
|
||||||
|
|
||||||
protected string RazorComponentIntermediateOutputPath => Path.Combine(IntermediateOutputPath, "RazorDeclaration");
|
protected string RazorComponentIntermediateOutputPath => Path.Combine(IntermediateOutputPath, "RazorDeclaration");
|
||||||
|
|
@ -64,18 +73,42 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
bool runRestoreBeforeBuildOrPublish = true)
|
bool runRestoreBeforeBuildOrPublish = true)
|
||||||
{
|
{
|
||||||
var timeout = suppressTimeout ? (TimeSpan?)Timeout.InfiniteTimeSpan : null;
|
var timeout = suppressTimeout ? (TimeSpan?)Timeout.InfiniteTimeSpan : null;
|
||||||
|
|
||||||
|
// Additional restore sources for packages used in testing
|
||||||
|
var additionalRestoreSources = string.Join(
|
||||||
|
',',
|
||||||
|
typeof(PackageTestProjectsFixture).Assembly.GetCustomAttributes<AssemblyMetadataAttribute>()
|
||||||
|
.Where(a => a.Key == "Testing.AdditionalRestoreSources")
|
||||||
|
.Select(a => a.Value)
|
||||||
|
.ToArray());
|
||||||
|
|
||||||
var buildArgumentList = new List<string>
|
var buildArgumentList = new List<string>
|
||||||
{
|
{
|
||||||
// Disable node-reuse. We don't want msbuild processes to stick around
|
// Disable node-reuse. We don't want msbuild processes to stick around
|
||||||
// once the test is completed.
|
// once the test is completed.
|
||||||
"/nr:false",
|
"/nr:false",
|
||||||
|
|
||||||
|
// Always generate a bin log for debugging purposes
|
||||||
|
"/bl",
|
||||||
|
|
||||||
// Let the test app know it is running as part of a test.
|
// Let the test app know it is running as part of a test.
|
||||||
"/p:RunningAsTest=true",
|
"/p:RunningAsTest=true",
|
||||||
|
|
||||||
$"/p:MicrosoftNETCoreApp30PackageVersion={BuildVariables.MicrosoftNETCoreApp30PackageVersion}",
|
$"/p:MicrosoftNETCoreApp30PackageVersion={BuildVariables.MicrosoftNETCoreApp30PackageVersion}",
|
||||||
|
|
||||||
|
// Additional restore sources for projects that require built packages
|
||||||
|
$"/p:RuntimeAdditionalRestoreSources={additionalRestoreSources}",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (UseLocalPackageCache)
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(LocalNugetPackagesCacheTempPath))
|
||||||
|
{
|
||||||
|
// The local cache folder needs to exist so that nuget
|
||||||
|
Directory.CreateDirectory(LocalNugetPackagesCacheTempPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!suppressBuildServer)
|
if (!suppressBuildServer)
|
||||||
{
|
{
|
||||||
buildArgumentList.Add($@"/p:_RazorBuildServerPipeName=""{buildServerPipeName ?? BuildServer.PipeName}""");
|
buildArgumentList.Add($@"/p:_RazorBuildServerPipeName=""{buildServerPipeName ?? BuildServer.PipeName}""");
|
||||||
|
|
@ -110,7 +143,8 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
Project,
|
Project,
|
||||||
buildArguments,
|
buildArguments,
|
||||||
timeout,
|
timeout,
|
||||||
msBuildProcessKind);
|
msBuildProcessKind,
|
||||||
|
UseLocalPackageCache ? LocalNugetPackagesCacheTempPath : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void AddProjectFileContent(string content)
|
internal void AddProjectFileContent(string content)
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,9 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
@ -16,7 +19,8 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
ProjectDirectory project,
|
ProjectDirectory project,
|
||||||
string arguments,
|
string arguments,
|
||||||
TimeSpan? timeout = null,
|
TimeSpan? timeout = null,
|
||||||
MSBuildProcessKind msBuildProcessKind = MSBuildProcessKind.Dotnet)
|
MSBuildProcessKind msBuildProcessKind = MSBuildProcessKind.Dotnet,
|
||||||
|
string localPackageCache = null)
|
||||||
{
|
{
|
||||||
var processStartInfo = new ProcessStartInfo()
|
var processStartInfo = new ProcessStartInfo()
|
||||||
{
|
{
|
||||||
|
|
@ -26,6 +30,11 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
RedirectStandardOutput = true,
|
RedirectStandardOutput = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (localPackageCache != null)
|
||||||
|
{
|
||||||
|
processStartInfo.Environment.Add("NUGET_PACKAGES", localPackageCache);
|
||||||
|
}
|
||||||
|
|
||||||
if (msBuildProcessKind == MSBuildProcessKind.Desktop)
|
if (msBuildProcessKind == MSBuildProcessKind.Desktop)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(BuildVariables.MSBuildPath))
|
if (string.IsNullOrEmpty(BuildVariables.MSBuildPath))
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,261 @@
|
||||||
|
// 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.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.CommandLineUtils;
|
||||||
|
using Xunit;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
|
{
|
||||||
|
public class StaticWebAssetsIntegrationTest : MSBuildIntegrationTestBase, IClassFixture<BuildServerTestFixture>, IClassFixture<PackageTestProjectsFixture>, IAsyncLifetime
|
||||||
|
{
|
||||||
|
public StaticWebAssetsIntegrationTest(
|
||||||
|
BuildServerTestFixture buildServer,
|
||||||
|
PackageTestProjectsFixture packageTestProjects,
|
||||||
|
ITestOutputHelper output)
|
||||||
|
: base(buildServer)
|
||||||
|
{
|
||||||
|
UseLocalPackageCache = true;
|
||||||
|
PackageTestProjects = packageTestProjects;
|
||||||
|
Output = output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackageTestProjectsFixture PackageTestProjects { get; private set; }
|
||||||
|
|
||||||
|
public ITestOutputHelper Output { get; private set; }
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[InitializeTestProject("AppWithPackageAndP2PReference")]
|
||||||
|
public async Task Build_GeneratesStaticWebAssetsManifest_Success_CreatesManifest()
|
||||||
|
{
|
||||||
|
var result = await DotnetMSBuild("Build", "/restore");
|
||||||
|
|
||||||
|
var expectedManifest = GetExpectedManifest();
|
||||||
|
|
||||||
|
Assert.BuildPassed(result);
|
||||||
|
|
||||||
|
// GenerateStaticWebAssetsManifest should generate the manifest and the cache.
|
||||||
|
Assert.FileExists(result, IntermediateOutputPath, "AppWithPackageAndP2PReference.StaticWebAssets.xml");
|
||||||
|
Assert.FileExists(result, IntermediateOutputPath, "AppWithPackageAndP2PReference.StaticWebAssets.cache");
|
||||||
|
|
||||||
|
var path = Assert.FileExists(result, OutputPath, "AppWithPackageAndP2PReference.dll");
|
||||||
|
var assembly = Assert.ContainsEmbeddedResource(path, "Microsoft.AspNetCore.StaticWebAssets.xml");
|
||||||
|
using (var reader = new StreamReader(assembly))
|
||||||
|
{
|
||||||
|
var data = await reader.ReadToEndAsync();
|
||||||
|
Assert.Equal(expectedManifest, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[InitializeTestProject("SimpleMvc")]
|
||||||
|
public async Task Build_DoesNotEmbedManifestWhen_NoStaticResourcesAvailable()
|
||||||
|
{
|
||||||
|
var result = await DotnetMSBuild("Build", "/restore");
|
||||||
|
|
||||||
|
Assert.BuildPassed(result);
|
||||||
|
|
||||||
|
// GenerateStaticWebAssetsManifest should generate the manifest and the cache.
|
||||||
|
Assert.FileExists(result, IntermediateOutputPath, "SimpleMvc.StaticWebAssets.xml");
|
||||||
|
Assert.FileExists(result, IntermediateOutputPath, "SimpleMvc.StaticWebAssets.cache");
|
||||||
|
|
||||||
|
var path = Assert.FileExists(result, OutputPath, "SimpleMvc.dll");
|
||||||
|
Assert.DoesNotContainEmbeddedResource(path, "SimpleMvc.StaticWebAssets.xml");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[InitializeTestProject("AppWithPackageAndP2PReference")]
|
||||||
|
public async Task Clean_Success_RemovesManifestAndCache()
|
||||||
|
{
|
||||||
|
var result = await DotnetMSBuild("Build", "/restore");
|
||||||
|
|
||||||
|
Assert.BuildPassed(result);
|
||||||
|
|
||||||
|
// GenerateStaticWebAssetsManifest should generate the manifest and the cache.
|
||||||
|
Assert.FileExists(result, IntermediateOutputPath, "AppWithPackageAndP2PReference.StaticWebAssets.xml");
|
||||||
|
Assert.FileExists(result, IntermediateOutputPath, "AppWithPackageAndP2PReference.StaticWebAssets.cache");
|
||||||
|
|
||||||
|
var cleanResult = await DotnetMSBuild("Clean");
|
||||||
|
|
||||||
|
Assert.BuildPassed(cleanResult);
|
||||||
|
|
||||||
|
// Clean should delete the manifest and the cache.
|
||||||
|
Assert.FileDoesNotExist(result, IntermediateOutputPath, "AppWithPackageAndP2PReference.StaticWebAssets.cache");
|
||||||
|
Assert.FileDoesNotExist(result, IntermediateOutputPath, "AppWithPackageAndP2PReference.StaticWebAssets.xml");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[InitializeTestProject("AppWithPackageAndP2PReference")]
|
||||||
|
public async Task Rebuild_Success_RecreatesManifestAndCache()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var result = await DotnetMSBuild("Build", "/restore");
|
||||||
|
|
||||||
|
var expectedManifest = GetExpectedManifest();
|
||||||
|
|
||||||
|
Assert.BuildPassed(result);
|
||||||
|
|
||||||
|
// GenerateStaticWebAssetsManifest should generate the manifest and the cache.
|
||||||
|
Assert.FileExists(result, IntermediateOutputPath, "AppWithPackageAndP2PReference.StaticWebAssets.xml");
|
||||||
|
Assert.FileExists(result, IntermediateOutputPath, "AppWithPackageAndP2PReference.StaticWebAssets.cache");
|
||||||
|
|
||||||
|
var directoryPath = Path.Combine(result.Project.DirectoryPath, IntermediateOutputPath);
|
||||||
|
var thumbPrints = new Dictionary<string, FileThumbPrint>();
|
||||||
|
var thumbPrintFiles = new[]
|
||||||
|
{
|
||||||
|
Path.Combine(directoryPath, "AppWithPackageAndP2PReference.StaticWebAssets.xml"),
|
||||||
|
Path.Combine(directoryPath, "AppWithPackageAndP2PReference.StaticWebAssets.cache"),
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var file in thumbPrintFiles)
|
||||||
|
{
|
||||||
|
var thumbprint = GetThumbPrint(file);
|
||||||
|
thumbPrints[file] = thumbprint;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var rebuild = await DotnetMSBuild("Rebuild");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.BuildPassed(rebuild);
|
||||||
|
|
||||||
|
foreach (var file in thumbPrintFiles)
|
||||||
|
{
|
||||||
|
var thumbprint = GetThumbPrint(file);
|
||||||
|
Assert.NotEqual(thumbPrints[file], thumbprint);
|
||||||
|
}
|
||||||
|
|
||||||
|
var path = Assert.FileExists(result, OutputPath, "AppWithPackageAndP2PReference.dll");
|
||||||
|
var assembly = Assert.ContainsEmbeddedResource(path, "Microsoft.AspNetCore.StaticWebAssets.xml");
|
||||||
|
using (var reader = new StreamReader(assembly))
|
||||||
|
{
|
||||||
|
var data = reader.ReadToEnd();
|
||||||
|
Assert.Equal(expectedManifest, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[InitializeTestProject("AppWithPackageAndP2PReference")]
|
||||||
|
public async Task GenerateStaticWebAssetsManifest_IncrementalBuild_ReusesManifest()
|
||||||
|
{
|
||||||
|
var result = await DotnetMSBuild("GenerateStaticWebAssetsManifest", "/restore");
|
||||||
|
|
||||||
|
Assert.BuildPassed(result);
|
||||||
|
|
||||||
|
// GenerateStaticWebAssetsManifest should generate the manifest and the cache.
|
||||||
|
Assert.FileExists(result, IntermediateOutputPath, "AppWithPackageAndP2PReference.StaticWebAssets.xml");
|
||||||
|
Assert.FileExists(result, IntermediateOutputPath, "AppWithPackageAndP2PReference.StaticWebAssets.cache");
|
||||||
|
|
||||||
|
var directoryPath = Path.Combine(result.Project.DirectoryPath, IntermediateOutputPath);
|
||||||
|
var thumbPrints = new Dictionary<string, FileThumbPrint>();
|
||||||
|
var thumbPrintFiles = new[]
|
||||||
|
{
|
||||||
|
Path.Combine(directoryPath, "AppWithPackageAndP2PReference.StaticWebAssets.xml"),
|
||||||
|
Path.Combine(directoryPath, "AppWithPackageAndP2PReference.StaticWebAssets.cache"),
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var file in thumbPrintFiles)
|
||||||
|
{
|
||||||
|
var thumbprint = GetThumbPrint(file);
|
||||||
|
thumbPrints[file] = thumbprint;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var incremental = await DotnetMSBuild("GenerateStaticWebAssetsManifest");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.BuildPassed(incremental);
|
||||||
|
|
||||||
|
foreach (var file in thumbPrintFiles)
|
||||||
|
{
|
||||||
|
var thumbprint = GetThumbPrint(file);
|
||||||
|
Assert.Equal(thumbPrints[file], thumbprint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task InitializeAsync()
|
||||||
|
{
|
||||||
|
return PackageTestProjects.PackAsync(Output);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DisposeAsync()
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetExpectedManifest()
|
||||||
|
{
|
||||||
|
var restorePath = LocalNugetPackagesCacheTempPath;
|
||||||
|
var projects = new[]
|
||||||
|
{
|
||||||
|
Path.Combine(restorePath, "packagelibrarytransitivedependency", "1.0.0", "buildTransitive", "..", "razorContent") + Path.DirectorySeparatorChar,
|
||||||
|
Path.Combine(restorePath, "packagelibrarydirectdependency", "1.0.0", "build", "..", "razorContent") + Path.DirectorySeparatorChar
|
||||||
|
};
|
||||||
|
|
||||||
|
return $@"<StaticWebAssets Version=""1.0"">
|
||||||
|
<ContentRoot BasePath=""_content/PackageLibraryTransitiveDependency"" Path=""{projects[0]}"" />
|
||||||
|
<ContentRoot BasePath=""_content/PackageLibraryDirectDependency"" Path=""{projects[1]}"" />
|
||||||
|
</StaticWebAssets>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PackageTestProjectsFixture
|
||||||
|
{
|
||||||
|
private bool _packed;
|
||||||
|
|
||||||
|
internal async Task PackAsync(ITestOutputHelper output)
|
||||||
|
{
|
||||||
|
if (_packed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var projectsToPack = GetProjectsToPack();
|
||||||
|
|
||||||
|
foreach (var project in projectsToPack)
|
||||||
|
{
|
||||||
|
output.WriteLine(project);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var project in projectsToPack)
|
||||||
|
{
|
||||||
|
var psi = new ProcessStartInfo
|
||||||
|
{
|
||||||
|
FileName = DotNetMuxer.MuxerPathOrDefault(),
|
||||||
|
#if DEBUG
|
||||||
|
Arguments = "msbuild /t:Restore;Pack /p:Configuration=Debug",
|
||||||
|
#else
|
||||||
|
Arguments = "msbuild /t:Restore;Pack /p:Configuration=Release",
|
||||||
|
#endif
|
||||||
|
WorkingDirectory = project,
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
RedirectStandardError = true
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await MSBuildProcessManager.RunProcessCoreAsync(
|
||||||
|
psi,
|
||||||
|
TimeSpan.FromMinutes(2));
|
||||||
|
|
||||||
|
output.WriteLine(result.Output);
|
||||||
|
Assert.Equal(0, result.ExitCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
_packed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string[] GetProjectsToPack()
|
||||||
|
{
|
||||||
|
return typeof(PackageTestProjectsFixture).Assembly.GetCustomAttributes<AssemblyMetadataAttribute>()
|
||||||
|
.Where(a => a.Key == "Testing.ProjectToPack")
|
||||||
|
.Select(a => a.Value)
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -21,11 +21,30 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="$(MicrosoftBuildUtilitiesCorePackageVersion)" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="$(MicrosoftExtensionsDependencyModelPackageVersion)" />
|
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="$(MicrosoftExtensionsDependencyModelPackageVersion)" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Testing" Version="$(MicrosoftAspNetCoreTestingPackageVersion)" />
|
<PackageReference Include="Microsoft.AspNetCore.Testing" Version="$(MicrosoftAspNetCoreTestingPackageVersion)" />
|
||||||
<PackageReference Include="Moq" Version="$(MoqPackageVersion)" />
|
<PackageReference Include="Moq" Version="$(MoqPackageVersion)" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
|
||||||
|
<_Parameter1>Testing.ProjectToPack</_Parameter1>
|
||||||
|
<_Parameter2>$(MSBuildThisFileDirectory)..\testapps\PackageLibraryDirectDependency</_Parameter2>
|
||||||
|
</AssemblyAttribute>
|
||||||
|
|
||||||
|
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
|
||||||
|
<_Parameter1>Testing.ProjectToPack</_Parameter1>
|
||||||
|
<_Parameter2>$(MSBuildThisFileDirectory)..\testapps\PackageLibraryTransitiveDependency</_Parameter2>
|
||||||
|
</AssemblyAttribute>
|
||||||
|
|
||||||
|
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
|
||||||
|
<_Parameter1>Testing.AdditionalRestoreSources</_Parameter1>
|
||||||
|
<_Parameter2>$(MSBuildThisFileDirectory)..\testapps\TestPackageRestoreSource</_Parameter2>
|
||||||
|
</AssemblyAttribute>
|
||||||
|
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<!-- The test projects rely on these binaries being available -->
|
<!-- The test projects rely on these binaries being available -->
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="$(SystemDiagnosticsDiagnosticSourcePackageVersion)" />
|
<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="$(SystemDiagnosticsDiagnosticSourcePackageVersion)" />
|
||||||
|
|
@ -51,11 +70,7 @@
|
||||||
Inputs="$(MSBuildAllProjects)"
|
Inputs="$(MSBuildAllProjects)"
|
||||||
Outputs="$(MSBuildLocationFileOutput)">
|
Outputs="$(MSBuildLocationFileOutput)">
|
||||||
|
|
||||||
<Exec
|
<Exec Condition="'$(OS)' == 'Windows_NT'" Command=""$(NuGetPackageRoot)vswhere\$(VSWhereVersion)\tools\vswhere.exe" -latest -prerelease -property installationPath -requires Microsoft.Component.MSBuild" ConsoleToMsBuild="true" StandardErrorImportance="high">
|
||||||
Condition="'$(OS)' == 'Windows_NT'"
|
|
||||||
Command='"$(NuGetPackageRoot)vswhere\$(VSWhereVersion)\tools\vswhere.exe" -latest -prerelease -property installationPath -requires Microsoft.Component.MSBuild'
|
|
||||||
ConsoleToMsBuild="true"
|
|
||||||
StandardErrorImportance="high">
|
|
||||||
<Output TaskParameter="ConsoleOutput" PropertyName="_VSInstallDir" />
|
<Output TaskParameter="ConsoleOutput" PropertyName="_VSInstallDir" />
|
||||||
</Exec>
|
</Exec>
|
||||||
<Error Condition="'$(OS)' == 'Windows_NT' and '$(_VSInstallDir)'==''" Text="Visual Studio not found on Windows." />
|
<Error Condition="'$(OS)' == 'Windows_NT' and '$(_VSInstallDir)'==''" Text="Visual Studio not found on Windows." />
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<RazorSdkDirectoryRoot>$(RazorSdkArtifactsDirectory)$(Configuration)\sdk-output\</RazorSdkDirectoryRoot>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||||
|
<RuntimeAdditionalRestoreSources Condition="'$(RuntimeAdditionalRestoreSources)' == ''">$(MSBuildThisFileDirectory)..\TestPackageRestoreSource\</RuntimeAdditionalRestoreSources>
|
||||||
|
<RestoreSources>
|
||||||
|
$(RestoreSources);
|
||||||
|
$(RuntimeAdditionalRestoreSources)
|
||||||
|
</RestoreSources>
|
||||||
|
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<!-- Avoid referencing the AspNetCore framework since we want the ability to target work-in-progress shims -->
|
||||||
|
<FrameworkReference Remove="Microsoft.AspNetCore.App" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(RunningAsTest)' == ''">
|
||||||
|
<!-- We don't want to run build server when not running as tests. -->
|
||||||
|
<UseRazorBuildServer>false</UseRazorBuildServer>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<!-- Test Placeholder -->
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="PackageLibraryDirectDependency" Version="1.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(BinariesRoot)'==''">
|
||||||
|
<!-- In test scenarios $(BinariesRoot) is defined in a generated Directory.Build.props file -->
|
||||||
|
<BinariesRoot>$(RepositoryRoot)artifacts\bin\Microsoft.AspNetCore.Razor.Test.MvcShim.ClassLib\$(Configuration)\netstandard2.0\</BinariesRoot>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup Condition="'$(BinariesRoot)'!=''">
|
||||||
|
<Reference Include="$(BinariesRoot)\Microsoft.AspNetCore.Razor.Test.ComponentShim.dll" />
|
||||||
|
<Reference Include="$(BinariesRoot)\Microsoft.AspNetCore.Razor.Test.MvcShim.ClassLib.dll" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
namespace AppWithP2PReference
|
||||||
|
{
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
public static void Main(string[] args)
|
||||||
|
{
|
||||||
|
// Just make sure we have a reference to the MvcShim
|
||||||
|
var t = typeof(Microsoft.AspNetCore.Mvc.IActionResult);
|
||||||
|
System.Console.WriteLine(t.FullName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<RazorSdkDirectoryRoot>$(RazorSdkArtifactsDirectory)$(Configuration)\sdk-output\</RazorSdkDirectoryRoot>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||||
|
<Copyright>© Microsoft</Copyright>
|
||||||
|
<Product>Razor Test</Product>
|
||||||
|
<Company>Microsoft</Company>
|
||||||
|
<Description>PackageLibraryDirectDependency Description</Description>
|
||||||
|
<PackageOutputPath>$(MSBuildThisFileDirectory)..\TestPackageRestoreSource</PackageOutputPath>
|
||||||
|
<DeterministicSourcePaths>false</DeterministicSourcePaths>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(RunningAsTest)' == ''">
|
||||||
|
<!-- We don't want to run build server when not running as tests. -->
|
||||||
|
<UseRazorBuildServer>false</UseRazorBuildServer>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(BinariesRoot)'==''">
|
||||||
|
<!-- In test scenarios $(BinariesRoot) is defined in a generated Directory.Build.props file -->
|
||||||
|
<BinariesRoot>$(RepositoryRoot)artifacts\bin\Microsoft.AspNetCore.Razor.Test.MvcShim.ClassLib\$(Configuration)\netstandard2.0\</BinariesRoot>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup Condition="'$(BinariesRoot)'!=''">
|
||||||
|
<Reference Include="$(BinariesRoot)\Microsoft.AspNetCore.Razor.Test.ComponentShim.dll"/>
|
||||||
|
<Reference Include="$(BinariesRoot)\Microsoft.AspNetCore.Razor.Test.MvcShim.ClassLib.dll"/>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Test Placeholder -->
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="build\**" Pack="true" PackagePath="build" />
|
||||||
|
<!-- We will remove the line below when we do the item to support packing -->
|
||||||
|
<Content Update="wwwroot\**" Pack="true" PackagePath="razorContent" />
|
||||||
|
<ProjectReference Include="..\PackageLibraryTransitiveDependency\PackageLibraryTransitiveDependency.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
<Project>
|
||||||
|
<ItemGroup>
|
||||||
|
<StaticWebAsset Include="$(MSBuildThisFileDirectory)..\razorContent\**">
|
||||||
|
<SourceType>Package</SourceType>
|
||||||
|
<SourceId>PackageLibraryDirectDependency</SourceId>
|
||||||
|
<ContentRoot>$([MSBuild]::EnsureTrailingSlash('$(MSBuildThisFileDirectory)..\razorContent'))</ContentRoot>
|
||||||
|
<BasePath>_content\PackageLibraryDirectDependency</BasePath>
|
||||||
|
<RelativePath>%(RecursiveDir)%(FileName)%(Extension)</RelativePath>
|
||||||
|
</StaticWebAsset>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
div.fluent { display: inline-block }
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
(function () {
|
||||||
|
document.getElementById('pkg-direct-dep').innerHTML = 'pkg-direct-dep';
|
||||||
|
})()
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<RazorSdkDirectoryRoot>$(RazorSdkArtifactsDirectory)$(Configuration)\sdk-output\</RazorSdkDirectoryRoot>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
<Copyright>© Microsoft</Copyright>
|
||||||
|
<Product>Razor Test</Product>
|
||||||
|
<Company>Microsoft</Company>
|
||||||
|
<Description>PackageLibraryTransitiveDependency Description</Description>
|
||||||
|
<PackageOutputPath>$(MSBuildThisFileDirectory)..\TestPackageRestoreSource</PackageOutputPath>
|
||||||
|
<DeterministicSourcePaths>false</DeterministicSourcePaths>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(RunningAsTest)' == ''">
|
||||||
|
<!-- We don't want to run build server when not running as tests. -->
|
||||||
|
<UseRazorBuildServer>false</UseRazorBuildServer>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(BinariesRoot)'==''">
|
||||||
|
<!-- In test scenarios $(BinariesRoot) is defined in a generated Directory.Build.props file -->
|
||||||
|
<BinariesRoot>$(RepositoryRoot)artifacts\bin\Microsoft.AspNetCore.Razor.Test.MvcShim.ClassLib\$(Configuration)\netstandard2.0\</BinariesRoot>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup Condition="'$(BinariesRoot)'!=''">
|
||||||
|
<Reference Include="$(BinariesRoot)\Microsoft.AspNetCore.Razor.Test.ComponentShim.dll"/>
|
||||||
|
<Reference Include="$(BinariesRoot)\Microsoft.AspNetCore.Razor.Test.MvcShim.ClassLib.dll"/>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Test Placeholder -->
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="build\**" Pack="true" PackagePath="buildTransitive" />
|
||||||
|
<!-- We will remove the line below when we do the item to support packing -->
|
||||||
|
<Content Update="wwwroot\**" Pack="true" PackagePath="razorContent" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
<Project>
|
||||||
|
<ItemGroup>
|
||||||
|
<StaticWebAsset Include="$(MSBuildThisFileDirectory)..\razorContent\**">
|
||||||
|
<SourceType>Package</SourceType>
|
||||||
|
<SourceId>PackageLibraryTransitiveDependency</SourceId>
|
||||||
|
<ContentRoot>$([MSBuild]::EnsureTrailingSlash('$(MSBuildThisFileDirectory)..\razorContent'))</ContentRoot>
|
||||||
|
<BasePath>_content\PackageLibraryTransitiveDependency</BasePath>
|
||||||
|
<RelativePath>%(RecursiveDir)%(FileName)%(Extension)</RelativePath>
|
||||||
|
</StaticWebAsset>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
(function () {
|
||||||
|
document.getElementById('pkg-transitive-dep').innerHTML = 'pkg-transitive-dep';
|
||||||
|
})()
|
||||||
|
|
@ -4,6 +4,12 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\SimpleMvc11NetFx\SimpleMvc11NetFx.csproj" />
|
||||||
|
<ProjectReference Include="..\SimpleMvc11\SimpleMvc11.csproj" />
|
||||||
|
<ProjectReference Include="..\SimpleMvc21\SimpleMvc21.csproj" />
|
||||||
|
<ProjectReference Include="..\SimpleMvc22\SimpleMvc22.csproj" />
|
||||||
|
<ProjectReference Include="..\ClassLibraryMvc21\ClassLibraryMvc21.csproj" />
|
||||||
|
|
||||||
<ProjectReference Include="..\AppWithP2PReference\AppWithP2PReference.csproj" />
|
<ProjectReference Include="..\AppWithP2PReference\AppWithP2PReference.csproj" />
|
||||||
<ProjectReference Include="..\ClassLibrary\ClassLibrary.csproj" />
|
<ProjectReference Include="..\ClassLibrary\ClassLibrary.csproj" />
|
||||||
<ProjectReference Include="..\ClassLibrary2\ClassLibrary2.csproj" />
|
<ProjectReference Include="..\ClassLibrary2\ClassLibrary2.csproj" />
|
||||||
|
|
@ -14,12 +20,15 @@
|
||||||
<ProjectReference Include="..\MvcWithComponents\MvcWithComponents.csproj" />
|
<ProjectReference Include="..\MvcWithComponents\MvcWithComponents.csproj" />
|
||||||
<ProjectReference Include="..\SimpleMvcFSharp\SimpleMvcFSharp.fsproj" />
|
<ProjectReference Include="..\SimpleMvcFSharp\SimpleMvcFSharp.fsproj" />
|
||||||
<ProjectReference Include="..\SimpleMvc\SimpleMvc.csproj" />
|
<ProjectReference Include="..\SimpleMvc\SimpleMvc.csproj" />
|
||||||
<ProjectReference Include="..\SimpleMvc11NetFx\SimpleMvc11NetFx.csproj" />
|
|
||||||
<ProjectReference Include="..\SimpleMvc11\SimpleMvc11.csproj" />
|
|
||||||
<ProjectReference Include="..\SimpleMvc21\SimpleMvc21.csproj" />
|
|
||||||
<ProjectReference Include="..\SimpleMvc22\SimpleMvc22.csproj" />
|
|
||||||
<ProjectReference Include="..\SimplePages\SimplePages.csproj" />
|
<ProjectReference Include="..\SimplePages\SimplePages.csproj" />
|
||||||
|
|
||||||
|
<!--
|
||||||
|
We don't add AppWithPackageAndP2PReference, PackageLibraryDirectDependency or PackageLibraryTransitiveDependency here
|
||||||
|
as PackageLibraryDirectDependency and PackageLibraryTransitiveDependency are test packages that
|
||||||
|
need to be produced on the fly and AppWithPackageAndP2PReference depends on them so adding them here
|
||||||
|
will make restore fail.
|
||||||
|
-->
|
||||||
|
|
||||||
<ProjectReference Include="..\..\Microsoft.AspNetCore.Razor.Test.MvcShim.ClassLib\Microsoft.AspNetCore.Razor.Test.MvcShim.ClassLib.csproj"/>
|
<ProjectReference Include="..\..\Microsoft.AspNetCore.Razor.Test.MvcShim.ClassLib\Microsoft.AspNetCore.Razor.Test.MvcShim.ClassLib.csproj"/>
|
||||||
<ProjectReference Include="..\..\Microsoft.AspNetCore.Razor.Test.ComponentShim\Microsoft.AspNetCore.Razor.Test.ComponentShim.csproj"/>
|
<ProjectReference Include="..\..\Microsoft.AspNetCore.Razor.Test.ComponentShim\Microsoft.AspNetCore.Razor.Test.ComponentShim.csproj"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue