Adds support for packing and publishing static web assets
* Adds support for publishing static web assets
* At publish time, it copies all the referenced assets from referenced
projects and packages into their final locations.
* Automatically pack static web assets for consumption
* Generate Microsoft.AspNetCore.StaticWebAssets.props and pack it into
build\Microsoft.AspNetCore.StaticWebAssets.props
* Generate `<<PackageId>>.props` and pack it into `build\<<PackageId>>.props`
importing Microsoft.AspNetCore.StaticWebAssets.props
* Generate `<<PackageId>>.props` and pack it into buildMultiTargeting\`<<PackageId>>.props`
importing `build\<<PackageId>>.props`
* Generate `<<PackageId>>.props` and pack it into buildTransitive\`<<PackageId>>.props`
importing buildMultiTargeting\`<<PackageId>>.props`
* Pack all the static web assets from the current project into `staticwebassets\**`\n\nCommit migrated from 87817bed3e
This commit is contained in:
parent
33e8098b4f
commit
1c27d78420
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
|
|
@ -85,7 +86,8 @@ namespace Microsoft.AspNetCore.Razor.Tasks
|
|||
}
|
||||
}
|
||||
|
||||
return nodes;
|
||||
// Its important that we order the nodes here to produce a manifest deterministically.
|
||||
return nodes.OrderBy(e=>e.Attribute(BasePath).Value);
|
||||
}
|
||||
|
||||
private XmlWriter GetXmlWriter(XmlWriterSettings settings)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,159 @@
|
|||
// 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 GenerateStaticWebAsssetsPropsFile : Task
|
||||
{
|
||||
private const string SourceType = "SourceType";
|
||||
private const string SourceId = "SourceId";
|
||||
private const string ContentRoot = "ContentRoot";
|
||||
private const string BasePath = "BasePath";
|
||||
private const string RelativePath = "RelativePath";
|
||||
|
||||
[Required]
|
||||
public string TargetPropsFilePath { get; set; }
|
||||
|
||||
[Required]
|
||||
public ITaskItem[] StaticWebAssets { get; set; }
|
||||
|
||||
public override bool Execute()
|
||||
{
|
||||
if (!ValidateArguments())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return ExecuteCore();
|
||||
}
|
||||
|
||||
private bool ExecuteCore()
|
||||
{
|
||||
if (StaticWebAssets.Length == 0)
|
||||
{
|
||||
return !Log.HasLoggedErrors;
|
||||
}
|
||||
|
||||
var template = StaticWebAssets[0];
|
||||
|
||||
var document = new XDocument(new XDeclaration("1.0", "utf-8", "yes"));
|
||||
var root = new XElement(
|
||||
"Project",
|
||||
new XElement("ItemGroup",
|
||||
new XElement("StaticWebAsset",
|
||||
new XAttribute("Include", @"$(MSBuildThisFileDirectory)..\staticwebassets\**"),
|
||||
new XElement(SourceType, "Package"),
|
||||
new XElement(SourceId, template.GetMetadata(SourceId)),
|
||||
new XElement(ContentRoot, @"$(MSBuildThisFileDirectory)..\staticwebassets\"),
|
||||
new XElement(BasePath, template.GetMetadata(BasePath)),
|
||||
new XElement(RelativePath, "%(RecursiveDir)%(FileName)%(Extension)"))));
|
||||
|
||||
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 XmlWriter GetXmlWriter(XmlWriterSettings settings)
|
||||
{
|
||||
var fileStream = new FileStream(TargetPropsFilePath, FileMode.Create);
|
||||
return XmlWriter.Create(fileStream, settings);
|
||||
}
|
||||
|
||||
private bool ValidateArguments()
|
||||
{
|
||||
ITaskItem firstAsset = null;
|
||||
|
||||
for (var i = 0; i < StaticWebAssets.Length; i++)
|
||||
{
|
||||
var webAsset = StaticWebAssets[i];
|
||||
if (!EnsureRequiredMetadata(webAsset, SourceId) ||
|
||||
!EnsureRequiredMetadata(webAsset, SourceType, allowEmpty: true) ||
|
||||
!EnsureRequiredMetadata(webAsset, ContentRoot) ||
|
||||
!EnsureRequiredMetadata(webAsset, BasePath) ||
|
||||
!EnsureRequiredMetadata(webAsset, RelativePath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (firstAsset == null)
|
||||
{
|
||||
firstAsset = webAsset;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ValidateMetadataMatches(firstAsset, webAsset, SourceId) ||
|
||||
!ValidateMetadataMatches(firstAsset, webAsset, SourceType) ||
|
||||
!ValidateMetadataMatches(firstAsset, webAsset, ContentRoot) ||
|
||||
!ValidateMetadataMatches(firstAsset, webAsset, BasePath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool ValidateMetadataMatches(ITaskItem reference, ITaskItem candidate, string metadata)
|
||||
{
|
||||
var referenceMetadata = reference.GetMetadata(metadata);
|
||||
var candidateMetadata = candidate.GetMetadata(metadata);
|
||||
if (!string.Equals(referenceMetadata, candidateMetadata, System.StringComparison.Ordinal))
|
||||
{
|
||||
Log.LogError($"Static web assets have different '{metadata}' metadata values '{referenceMetadata}' and '{candidateMetadata}' for '{reference.ItemSpec}' and '{candidate.ItemSpec}'.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool EnsureRequiredMetadata(ITaskItem item, string metadataName, bool allowEmpty = false)
|
||||
{
|
||||
var value = item.GetMetadata(metadataName);
|
||||
var isInvalidValue = allowEmpty ? !HasMetadata(item, metadataName) : string.IsNullOrEmpty(value);
|
||||
|
||||
if (isInvalidValue)
|
||||
{
|
||||
Log.LogError($"Missing required metadata '{metadataName}' for '{item.ItemSpec}'.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool HasMetadata(ITaskItem item, string metadataName)
|
||||
{
|
||||
foreach (var name in item.MetadataNames)
|
||||
{
|
||||
if (string.Equals(metadataName, (string)name, StringComparison.Ordinal))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
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 StaticWebAssetsGeneratePackagePropsFile : Task
|
||||
{
|
||||
[Required]
|
||||
public string PropsFileImport { get; set; }
|
||||
|
||||
[Required]
|
||||
public string BuildTargetPath { get; set; }
|
||||
|
||||
public override bool Execute()
|
||||
{
|
||||
var document = new XDocument(new XDeclaration("1.0", "utf-8", "yes"));
|
||||
var root = new XElement(
|
||||
"Project",
|
||||
new XElement("Import",
|
||||
new XAttribute("Project", PropsFileImport)));
|
||||
|
||||
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 XmlWriter GetXmlWriter(XmlWriterSettings settings)
|
||||
{
|
||||
var fileStream = new FileStream(BuildTargetPath, FileMode.Create);
|
||||
return XmlWriter.Create(fileStream, settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,6 +20,11 @@ Copyright (c) .NET Foundation. All rights reserved.
|
|||
* Current project.
|
||||
* Referenced project.
|
||||
* Referenced packages.
|
||||
* GenerateStaticWebAssetsPackTargets: Includes the static web assets in the current project
|
||||
under the 'staticwebassets' folder in the nuget package and generates and includes in the
|
||||
package the appropriate .props files to support discovering the packaged static web assets.
|
||||
* GetCurrentProjectStaticWebAssets: Called on each referenced project to retrieve the list of
|
||||
static web assets in the project.
|
||||
-->
|
||||
|
||||
<UsingTask
|
||||
|
|
@ -32,6 +37,16 @@ Copyright (c) .NET Foundation. All rights reserved.
|
|||
AssemblyFile="$(RazorSdkBuildTasksAssembly)"
|
||||
Condition="'$(RazorSdkBuildTasksAssembly)' != ''" />
|
||||
|
||||
<UsingTask
|
||||
TaskName="Microsoft.AspNetCore.Razor.Tasks.GenerateStaticWebAsssetsPropsFile"
|
||||
AssemblyFile="$(RazorSdkBuildTasksAssembly)"
|
||||
Condition="'$(RazorSdkBuildTasksAssembly)' != ''" />
|
||||
|
||||
<UsingTask
|
||||
TaskName="Microsoft.AspNetCore.Razor.Tasks.StaticWebAssetsGeneratePackagePropsFile"
|
||||
AssemblyFile="$(RazorSdkBuildTasksAssembly)"
|
||||
Condition="'$(RazorSdkBuildTasksAssembly)' != ''" />
|
||||
|
||||
<PropertyGroup>
|
||||
<GenerateStaticWebAssetsManifestDependsOn>
|
||||
ResolveStaticWebAssetsInputs;
|
||||
|
|
@ -49,25 +64,76 @@ Copyright (c) .NET Foundation. All rights reserved.
|
|||
$(AssignTargetPathsDependsOn)
|
||||
</AssignTargetPathsDependsOn>
|
||||
|
||||
<ResolveStaticWebAssetsInputsDependsOn>
|
||||
<ResolveStaticWebAssetsInputsDependsOn Condition="$(NoBuild) != 'true'">
|
||||
_ResolveStaticWebAssetsProjectReferences;
|
||||
$(ResolveStaticWebAssetsInputsDependsOn)
|
||||
</ResolveStaticWebAssetsInputsDependsOn>
|
||||
|
||||
<GenerateStaticWebAssetsPackTargetsDependsOn>
|
||||
_CreateStaticWebAssetsCustomPropsCacheFile;
|
||||
$(GenerateStaticWebAssetsPackTargetsDependsOn)
|
||||
</GenerateStaticWebAssetsPackTargetsDependsOn>
|
||||
|
||||
<TargetsForTfmSpecificContentInPackage>
|
||||
GenerateStaticWebAssetsPackTargets;
|
||||
$(TargetsForTfmSpecificContentInPackage)
|
||||
</TargetsForTfmSpecificContentInPackage>
|
||||
|
||||
<PackDependsOn>
|
||||
_RemoveWebRootContentFromPackaging;
|
||||
$(PackDependsOn)
|
||||
</PackDependsOn>
|
||||
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<_GeneratedStaticWebAssetsInputsCacheFile>$(IntermediateOutputPath)$(TargetName).StaticWebAssets.cache</_GeneratedStaticWebAssetsInputsCacheFile>
|
||||
<_GeneratedStaticWebAssetsDevelopmentManifest>$(IntermediateOutputPath)$(TargetName).StaticWebAssets.xml</_GeneratedStaticWebAssetsDevelopmentManifest>
|
||||
<_StaticWebAssetsIntermediateOutputPath>$(IntermediateOutputPath)staticwebassets\</_StaticWebAssetsIntermediateOutputPath>
|
||||
|
||||
<!-- Development manifest generation -->
|
||||
<_GeneratedStaticWebAssetsInputsCacheFile>$(_StaticWebAssetsIntermediateOutputPath)$(TargetName).StaticWebAssets.Manifest.cache</_GeneratedStaticWebAssetsInputsCacheFile>
|
||||
<_GeneratedStaticWebAssetsDevelopmentManifest>$(_StaticWebAssetsIntermediateOutputPath)$(TargetName).StaticWebAssets.xml</_GeneratedStaticWebAssetsDevelopmentManifest>
|
||||
|
||||
<!-- Project packing generation -->
|
||||
<_GeneratedStaticWebAssetsCustomPropsCacheFile>$(_StaticWebAssetsIntermediateOutputPath)$(TargetName).StaticWebAssets.Pack.cache</_GeneratedStaticWebAssetsCustomPropsCacheFile>
|
||||
|
||||
<!-- Temporary files -->
|
||||
<_GeneratedStaticWebAssetsPropsFile>$(_StaticWebAssetsIntermediateOutputPath)msbuild.$(PackageId).Microsoft.AspNetCore.StaticWebAssets.props</_GeneratedStaticWebAssetsPropsFile>
|
||||
<_GeneratedBuildPropsFile>$(_StaticWebAssetsIntermediateOutputPath)msbuild.build.$(PackageId).props</_GeneratedBuildPropsFile>
|
||||
<_GeneratedBuildMultitargetingPropsFile>$(_StaticWebAssetsIntermediateOutputPath)msbuild.buildMultiTargeting.$(PackageId).props</_GeneratedBuildMultitargetingPropsFile>
|
||||
<_GeneratedBuildTransitivePropsFile>$(_StaticWebAssetsIntermediateOutputPath)msbuild.buildTransitive.$(PackageId).props</_GeneratedBuildTransitivePropsFile>
|
||||
|
||||
<!-- Package relative import paths -->
|
||||
<_StaticWebAssetsPropsFileImportPath>Microsoft.AspNetCore.StaticWebAssets.props</_StaticWebAssetsPropsFileImportPath>
|
||||
<_StaticWebAssetsGeneratedBuildPropsFileImportPath>..\build\$(PackageId).props</_StaticWebAssetsGeneratedBuildPropsFileImportPath>
|
||||
<_StaticWebAssetsGeneratedBuildMultiTargetingPropsFileImportPath>..\buildMultiTargeting\$(PackageId).props</_StaticWebAssetsGeneratedBuildMultiTargetingPropsFileImportPath>
|
||||
|
||||
</PropertyGroup>
|
||||
|
||||
<Target
|
||||
<!-- Helper target invoked by other tasks below to ensure that the intermediate output path has the correct
|
||||
shape for the intermediate output files that might be generated.
|
||||
-->
|
||||
<Target Name="_PrepareForStaticWebAssets">
|
||||
<MakeDir
|
||||
Directories="$(_StaticWebAssetsIntermediateOutputPath)"
|
||||
Condition="!Exists('$(_StaticWebAssetsIntermediateOutputPath)')" />
|
||||
</Target>
|
||||
|
||||
<!--
|
||||
============================================================
|
||||
Static web assets development manifest generation targets
|
||||
|
||||
The main targets for generating a development manifest with information about the static web
|
||||
assets found in referenced packages and projects.
|
||||
============================================================
|
||||
-->
|
||||
|
||||
<Target
|
||||
Name="_CreateStaticWebAssetsInputsCacheFile"
|
||||
DependsOnTargets="ResolveStaticWebAssetsInputs">
|
||||
|
||||
DependsOnTargets="ResolveStaticWebAssetsInputs;_PrepareForStaticWebAssets">
|
||||
|
||||
<ItemGroup>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<_ExternalStaticWebAsset
|
||||
Include="%(StaticWebAsset.Identity)"
|
||||
|
|
@ -82,10 +148,10 @@ Copyright (c) .NET Foundation. All rights reserved.
|
|||
<Output TaskParameter="HashResult" PropertyName="_StaticWebAssetsCacheHash" />
|
||||
</Hash>
|
||||
|
||||
<WriteLinesToFile
|
||||
Lines="$(_StaticWebAssetsCacheHash)"
|
||||
File="$(_GeneratedStaticWebAssetsInputsCacheFile)"
|
||||
Overwrite="True"
|
||||
<WriteLinesToFile
|
||||
Lines="$(_StaticWebAssetsCacheHash)"
|
||||
File="$(_GeneratedStaticWebAssetsInputsCacheFile)"
|
||||
Overwrite="True"
|
||||
WriteOnlyWhenDifferent="True" />
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -94,7 +160,7 @@ Copyright (c) .NET Foundation. All rights reserved.
|
|||
|
||||
</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
|
||||
|
|
@ -104,21 +170,31 @@ Copyright (c) .NET Foundation. All rights reserved.
|
|||
root, but we don't check for duplicates on either of them.
|
||||
-->
|
||||
|
||||
<Target
|
||||
<Target
|
||||
Name="GenerateStaticWebAssetsManifest"
|
||||
Inputs="$(_GeneratedStaticWebAssetsInputsCacheFile)"
|
||||
Outputs="$(_GeneratedStaticWebAssetsDevelopmentManifest)"
|
||||
DependsOnTargets="$(GenerateStaticWebAssetsManifestDependsOn)">
|
||||
|
||||
<GenerateStaticWebAssetsManifest
|
||||
|
||||
<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" />
|
||||
|
||||
<!-- Include it as content as we plan to avoid using an embedded file for the manifest -->
|
||||
<Content
|
||||
Include="$(_GeneratedStaticWebAssetsDevelopmentManifest)"
|
||||
Condition="'@(_ExternalStaticWebAsset->Count())' != '0'"
|
||||
Link="$(TargetName).StaticWebAssets.xml">
|
||||
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -127,6 +203,15 @@ Copyright (c) .NET Foundation. All rights reserved.
|
|||
|
||||
</Target>
|
||||
|
||||
<!--
|
||||
============================================================
|
||||
Static web assets discovery related targets
|
||||
|
||||
The main targets for discovering static web assets inside referenced packages, projects and
|
||||
the current project.
|
||||
============================================================
|
||||
-->
|
||||
|
||||
<!-- 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
|
||||
|
|
@ -134,7 +219,7 @@ Copyright (c) .NET Foundation. All rights reserved.
|
|||
* 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
|
||||
<Target
|
||||
Name="ResolveStaticWebAssetsInputs"
|
||||
DependsOnTargets="$(ResolveStaticWebAssetsInputsDependsOn)">
|
||||
|
||||
|
|
@ -164,7 +249,7 @@ Copyright (c) .NET Foundation. All rights reserved.
|
|||
<_ThisProjectStaticWebAsset
|
||||
Include="$(MSBuildProjectDirectory)\wwwroot\**"
|
||||
Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
|
||||
<!--
|
||||
<!--
|
||||
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.
|
||||
|
|
@ -174,7 +259,7 @@ Copyright (c) .NET Foundation. All rights reserved.
|
|||
<SourceType></SourceType>
|
||||
<!-- Identifier describing the source, the package id, the project name, empty for the current project. -->
|
||||
<SourceId>$(PackageId)</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
|
||||
|
|
@ -214,7 +299,7 @@ Copyright (c) .NET Foundation. All rights reserved.
|
|||
the static assets for a given application. We do it this way so that we can
|
||||
pass additional build properties to compute the assets from the package when referenced
|
||||
as a project. For example, Identity uses this hook to extend the project reference and
|
||||
pass in the bootstrap version to use.
|
||||
pass in the bootstrap version to use.
|
||||
-->
|
||||
<Target Name="_ResolveStaticWebAssetsProjectReferences"
|
||||
DependsOnTargets="ResolveReferences"
|
||||
|
|
@ -244,4 +329,198 @@ Copyright (c) .NET Foundation. All rights reserved.
|
|||
|
||||
</Target>
|
||||
|
||||
<!--
|
||||
============================================================
|
||||
Static web assets packing related targets
|
||||
|
||||
The main targets to enable auto-packing of static web assets.
|
||||
============================================================
|
||||
-->
|
||||
|
||||
<!-- We need to remove any content item under wwwroot right before packing to prevent it from getting included
|
||||
in the package as content or contentFiles. Unfortunately marking it with pack=false doesn't work as it also
|
||||
prevents the content from being packed even though we are including it explictily in
|
||||
GenerateStaticWebAssetsPackTargets
|
||||
-->
|
||||
<Target Name="_RemoveWebRootContentFromPackaging" DependsOnTargets="_CreateStaticWebAssetsCustomPropsCacheFile" >
|
||||
<ItemGroup>
|
||||
<Content Remove="@(_CurrentProjectStaticWebAsset->'wwwroot\%(RelativePath)')" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<Target
|
||||
Name="_CreateStaticWebAssetsCustomPropsCacheFile"
|
||||
DependsOnTargets="ResolveStaticWebAssetsInputs;_PrepareForStaticWebAssets">
|
||||
|
||||
<ItemGroup>
|
||||
<!-- This is the list of inputs that will be used for generating the props file that will be packed with
|
||||
the package. -->
|
||||
<_CurrentProjectStaticWebAsset
|
||||
Include="@(StaticWebAsset)"
|
||||
Condition="'%(SourceType)' == ''" />
|
||||
</ItemGroup>
|
||||
|
||||
<Hash ItemsToHash="@(_CurrentProjectStaticWebAsset->'%(BasePath)%(SourceId)')">
|
||||
<Output TaskParameter="HashResult" PropertyName="_StaticWebAssetsPropsFileHash" />
|
||||
</Hash>
|
||||
|
||||
<WriteLinesToFile
|
||||
Lines="$(_StaticWebAssetsPropsFileHash)"
|
||||
File="$(_GeneratedStaticWebAssetsCustomPropsCacheFile)"
|
||||
Overwrite="True"
|
||||
WriteOnlyWhenDifferent="True" />
|
||||
|
||||
<ItemGroup>
|
||||
<FileWrites Include="$(_GeneratedStaticWebAssetsCustomPropsCacheFile)" />
|
||||
</ItemGroup>
|
||||
|
||||
</Target>
|
||||
|
||||
<!-- This target makes sure that all static web assets for the current project get included
|
||||
in the package under the folder staticwebassets and generates MSBuild props files to
|
||||
ensure that consuming packages can discover and use the static web assets.
|
||||
This target generates and includes a Microsoft.AspNetCore.StaticWebAssets.props file that
|
||||
goes inside the build directory and describes the static web assets in the package as an
|
||||
item group.
|
||||
This target also generates and includes a $(PackageId).props file under the build, buildMultiTargeting
|
||||
and buildTransitive folders that are setup so that:
|
||||
* buildTransitive\$(PackageId).props simply imports buildMultitargeting\$(PackageId).props
|
||||
* buildMultitargeting\$(PackageId).props simply imports build\$(PackageId).props
|
||||
* build\$(PackageId).props simply imports Microsoft.AspNetCore.StaticWebAssets.props
|
||||
|
||||
We do it this way to preserve the ability of package authors to customize the package in any way
|
||||
they see fit and to make sure the package works in all scenarios. Authors including custom MSBuild
|
||||
targets into their packages are expected to disable the generation of $(PackageId).props files and
|
||||
to manually import build\Microsoft.AspNetCore.StaticWebAssets.props in their custom props files.
|
||||
-->
|
||||
<Target
|
||||
Name="GenerateStaticWebAssetsPackTargets"
|
||||
DependsOnTargets="$(GenerateStaticWebAssetsPackTargetsDependsOn)"
|
||||
Inputs="$(_GeneratedStaticWebAssetsCustomPropsCacheFile)"
|
||||
Outputs="$(_GeneratedStaticWebAssetsPropsFile)">
|
||||
|
||||
<PropertyGroup>
|
||||
<_CurrentProjectHasStaticWebAssets Condition="'@(_CurrentProjectStaticWebAsset->Count())' != '0'">true</_CurrentProjectHasStaticWebAssets>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Generates a props file that goes in build\Microsoft.AspNetCore.StaticWebAssets.props
|
||||
and that describes the static web assets for the package.
|
||||
-->
|
||||
<GenerateStaticWebAsssetsPropsFile
|
||||
Condition="'$(_CurrentProjectHasStaticWebAssets)' == 'true'"
|
||||
StaticWebAssets="@(_CurrentProjectStaticWebAsset)"
|
||||
TargetPropsFilePath="$(_GeneratedStaticWebAssetsPropsFile)" />
|
||||
|
||||
<!-- Generates a props file the goes in build\$(PackageId).props and that simply imports
|
||||
build\Microsoft.AspNetCore.StaticWebAssets.props
|
||||
-->
|
||||
<StaticWebAssetsGeneratePackagePropsFile
|
||||
Condition="'$(_CurrentProjectHasStaticWebAssets)' == 'true'"
|
||||
PropsFileImport="$(_StaticWebAssetsPropsFileImportPath)"
|
||||
BuildTargetPath="$(_GeneratedBuildPropsFile)" />
|
||||
|
||||
<!-- Generates a props file the goes in buildMultiTargeting\$(PackageId).props and that simply imports
|
||||
build\$(PackageId).props
|
||||
-->
|
||||
<StaticWebAssetsGeneratePackagePropsFile
|
||||
Condition="'$(_CurrentProjectHasStaticWebAssets)' == 'true'"
|
||||
PropsFileImport="$(_StaticWebAssetsGeneratedBuildPropsFileImportPath)"
|
||||
BuildTargetPath="$(_GeneratedBuildMultitargetingPropsFile)" />
|
||||
|
||||
<!-- Generates a props file the goes in buildTransitive\$(PackageId).props and that simply imports
|
||||
buildMultiTargeting\$(PackageId)
|
||||
-->
|
||||
<StaticWebAssetsGeneratePackagePropsFile
|
||||
Condition="'$(_CurrentProjectHasStaticWebAssets)' == 'true'"
|
||||
PropsFileImport="$(_StaticWebAssetsGeneratedBuildMultiTargetingPropsFileImportPath)"
|
||||
BuildTargetPath="$(_GeneratedBuildTransitivePropsFile)" />
|
||||
|
||||
<!-- All files potentially created within this target -->
|
||||
<ItemGroup>
|
||||
<FileWrites Include="$(_GeneratedStaticWebAssetsPropsFile)" />
|
||||
<FileWrites Include="$(_GeneratedBuildPropsFile)" />
|
||||
<FileWrites Include="$(_GeneratedBuildMultitargetingPropsFile)" />
|
||||
<FileWrites Include="$(_GeneratedBuildTransitivePropsFile)" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- All files that go into the nuget package -->
|
||||
<ItemGroup Condition="'$(_CurrentProjectHasStaticWebAssets)' == 'true'">
|
||||
|
||||
<!-- MSBuild prop files -->
|
||||
|
||||
<TfmSpecificPackageFile Include="$(_GeneratedStaticWebAssetsPropsFile)"
|
||||
Condition="'$(DisableStaticWebAssetsBuildPropsFileGeneration)' == ''">
|
||||
|
||||
<PackagePath>build\Microsoft.AspNetCore.StaticWebAssets.props</PackagePath>
|
||||
</TfmSpecificPackageFile>
|
||||
|
||||
<TfmSpecificPackageFile Include="$(_GeneratedBuildPropsFile)"
|
||||
Condition="'$(StaticWebAssetsDisableProjectBuildPropsFileGeneration)' == ''">
|
||||
|
||||
<PackagePath>build\$(PackageId).props</PackagePath>
|
||||
</TfmSpecificPackageFile>
|
||||
|
||||
<TfmSpecificPackageFile Include="$(_GeneratedBuildMultitargetingPropsFile)"
|
||||
Condition="'$(StaticWebAssetsDisableProjectBuildMultiTargetingPropsFileGeneration)' == ''">
|
||||
|
||||
<PackagePath>buildMultiTargeting\$(PackageId).props</PackagePath>
|
||||
</TfmSpecificPackageFile>
|
||||
|
||||
<TfmSpecificPackageFile Include="$(_GeneratedBuildTransitivePropsFile)"
|
||||
Condition="'$(StaticWebAssetsDisableProjectBuildTransitivePropsFileGeneration)' == ''">
|
||||
|
||||
<PackagePath>buildTransitive\$(PackageId).props</PackagePath>
|
||||
</TfmSpecificPackageFile>
|
||||
|
||||
<!-- Project file contents -->
|
||||
|
||||
<TfmSpecificPackageFile Include="%(_CurrentProjectStaticWebAsset.Identity)">
|
||||
<PackagePath>staticwebassets\%(_CurrentProjectStaticWebAsset.RelativePath)</PackagePath>
|
||||
</TfmSpecificPackageFile>
|
||||
</ItemGroup>
|
||||
|
||||
</Target>
|
||||
|
||||
|
||||
<!--
|
||||
============================================================
|
||||
Static web assets publish related targets
|
||||
|
||||
The main targets for publishing static web assets coming from referenced projects
|
||||
and packages.
|
||||
============================================================
|
||||
-->
|
||||
|
||||
<!--
|
||||
Called after ComputeRefAssembliesToPublish but before CopyFilesToPublishDirectory - this target is called when
|
||||
publishing the project to get a list of files to the output directory.
|
||||
-->
|
||||
<Target
|
||||
Name="_StaticWebAssetsComputeFilesToPublish"
|
||||
AfterTargets="ComputeRefAssembliesToPublish"
|
||||
DependsOnTargets="ResolveStaticWebAssetsInputs">
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
<!-- Filter the static web assets foreign to the project and then add them to the list of resolved
|
||||
files to publish.
|
||||
-->
|
||||
<_ExternalPublishStaticWebAsset
|
||||
Include="%(StaticWebAsset.FullPath)"
|
||||
Condition="'%(SourceType)' != ''">
|
||||
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
<RelativePath>$([MSBuild]::MakeRelative('$(MSBuildProjectDirectory)','$([MSBuild]::NormalizePath('wwwroot\%(BasePath)\%(RelativePath)'))'))</RelativePath>
|
||||
|
||||
</_ExternalPublishStaticWebAsset>
|
||||
|
||||
<!-- Remove any existing external static web asset that might have been added as part of the
|
||||
regular publish pipeline. -->
|
||||
<ResolvedFileToPublish Remove="@(_ExternalPublishStaticWebAsset)" />
|
||||
|
||||
<ResolvedFileToPublish Include="@(_ExternalPublishStaticWebAsset)" />
|
||||
</ItemGroup>
|
||||
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
|
|
@ -75,7 +75,7 @@ Copyright (c) .NET Foundation. All rights reserved.
|
|||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<EnableRazorSdkContent Condition=" '$(UsingMicrosoftNETSdkWeb)' == '' ">true</EnableRazorSdkContent>
|
||||
<EnableRazorSdkContent Condition="'$(EnableRazorSdkContent)' =='' and '$(UsingMicrosoftNETSdkWeb)' == '' ">true</EnableRazorSdkContent>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import
|
||||
|
|
|
|||
|
|
@ -57,6 +57,10 @@ Copyright (c) .NET Foundation. All rights reserved.
|
|||
'$(RazorLangVersion)' == 'Latest' OR
|
||||
'$(RazorLangVersion)' == 'Experimental' OR
|
||||
('$(RazorLangVersion)' != '' AND '$(RazorLangVersion)' >= '3.0')">true</_Targeting30OrNewerRazorLangVersion>
|
||||
|
||||
<!-- Controls whether or not the static web assets feature is enabled. By default is enabled for netcoreapp3.0
|
||||
applications and RazorLangVersion 3 or above. -->
|
||||
<StaticWebAssetsEnabled Condition="'$(StaticWebAssetsEnabled)' == ''">$(_Targeting30OrNewerRazorLangVersion)</StaticWebAssetsEnabled>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
|
|
@ -338,7 +342,7 @@ Copyright (c) .NET Foundation. All rights reserved.
|
|||
|
||||
<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.StaticWebAssets.targets" Condition="'$(StaticWebAssetsEnabled)' == 'true'" />
|
||||
|
||||
<Import Project="Microsoft.NET.Sdk.Razor.GenerateAssemblyInfo.targets" />
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,433 @@
|
|||
// 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.AspNetCore.Razor.Tasks;
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Tasks
|
||||
{
|
||||
public class GenerateStaticWebAssetsPropsFileTest
|
||||
{
|
||||
[Fact]
|
||||
public void Fails_WhenStaticWebAsset_DoesNotContainSourceType()
|
||||
{
|
||||
// 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 GenerateStaticWebAsssetsPropsFile
|
||||
{
|
||||
BuildEngine = buildEngine.Object,
|
||||
StaticWebAssets = new TaskItem[]
|
||||
{
|
||||
CreateItem(Path.Combine("wwwroot","js","sample.js"), new Dictionary<string,string>
|
||||
{
|
||||
["SourceId"] = "MyLibrary",
|
||||
["ContentRoot"] = @"$(MSBuildThisFileDirectory)..\staticwebassets",
|
||||
["BasePath"] = "_content/mylibrary",
|
||||
["RelativePath"] = Path.Combine("js", "sample.js"),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = task.Execute();
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
var message = Assert.Single(errorMessages);
|
||||
Assert.Equal($"Missing required metadata 'SourceType' for '{Path.Combine("wwwroot", "js", "sample.js")}'.", message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Fails_WhenStaticWebAsset_DoesNotContainSourceId()
|
||||
{
|
||||
// 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 GenerateStaticWebAsssetsPropsFile
|
||||
{
|
||||
BuildEngine = buildEngine.Object,
|
||||
StaticWebAssets = new TaskItem[]
|
||||
{
|
||||
CreateItem(Path.Combine("wwwroot","js","sample.js"), new Dictionary<string,string>
|
||||
{
|
||||
["SourceType"] = "",
|
||||
["ContentRoot"] = @"$(MSBuildThisFileDirectory)..\staticwebassets",
|
||||
["BasePath"] = "_content/mylibrary",
|
||||
["RelativePath"] = Path.Combine("js", "sample.js"),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = task.Execute();
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
var message = Assert.Single(errorMessages);
|
||||
Assert.Equal($"Missing required metadata 'SourceId' for '{Path.Combine("wwwroot", "js", "sample.js")}'.", message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Fails_WhenStaticWebAsset_DoesNotContainContentRoot()
|
||||
{
|
||||
// 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 GenerateStaticWebAsssetsPropsFile
|
||||
{
|
||||
BuildEngine = buildEngine.Object,
|
||||
StaticWebAssets = new TaskItem[]
|
||||
{
|
||||
CreateItem(Path.Combine("wwwroot","js","sample.js"), new Dictionary<string,string>
|
||||
{
|
||||
["SourceType"] = "",
|
||||
["SourceId"] = "MyLibrary",
|
||||
["BasePath"] = "_content/mylibrary",
|
||||
["RelativePath"] = Path.Combine("js", "sample.js"),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = task.Execute();
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
var message = Assert.Single(errorMessages);
|
||||
Assert.Equal($"Missing required metadata 'ContentRoot' for '{Path.Combine("wwwroot", "js", "sample.js")}'.", message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Fails_WhenStaticWebAsset_DoesNotContainBasePath()
|
||||
{
|
||||
// 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 GenerateStaticWebAsssetsPropsFile
|
||||
{
|
||||
BuildEngine = buildEngine.Object,
|
||||
StaticWebAssets = new TaskItem[]
|
||||
{
|
||||
CreateItem(Path.Combine("wwwroot","js","sample.js"), new Dictionary<string,string>
|
||||
{
|
||||
["SourceType"] = "",
|
||||
["SourceId"] = "MyLibrary",
|
||||
["ContentRoot"] = @"$(MSBuildThisFileDirectory)..\staticwebassets",
|
||||
["RelativePath"] = Path.Combine("js", "sample.js"),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = task.Execute();
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
var message = Assert.Single(errorMessages);
|
||||
Assert.Equal($"Missing required metadata 'BasePath' for '{Path.Combine("wwwroot", "js", "sample.js")}'.", message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Fails_WhenStaticWebAsset_DoesNotContainRelativePath()
|
||||
{
|
||||
// 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 GenerateStaticWebAsssetsPropsFile
|
||||
{
|
||||
BuildEngine = buildEngine.Object,
|
||||
StaticWebAssets = new TaskItem[]
|
||||
{
|
||||
CreateItem(Path.Combine("wwwroot","js","sample.js"), new Dictionary<string,string>
|
||||
{
|
||||
["SourceType"] = "",
|
||||
["SourceId"] = "MyLibrary",
|
||||
["ContentRoot"] = @"$(MSBuildThisFileDirectory)..\staticwebassets",
|
||||
["BasePath"] = "_content/mylibrary",
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = task.Execute();
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
var message = Assert.Single(errorMessages);
|
||||
Assert.Equal($"Missing required metadata 'RelativePath' for '{Path.Combine("wwwroot", "js", "sample.js")}'.", message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Fails_WhenStaticWebAsset_HaveDifferentSourceType()
|
||||
{
|
||||
// Arrange
|
||||
var expectedError = "Static web assets have different 'SourceType' metadata values " +
|
||||
"'' and 'Package' " +
|
||||
$"for '{Path.Combine("wwwroot", "js", "sample.js")}' and '{Path.Combine("wwwroot", "css", "site.css")}'.";
|
||||
|
||||
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 GenerateStaticWebAsssetsPropsFile
|
||||
{
|
||||
BuildEngine = buildEngine.Object,
|
||||
StaticWebAssets = new TaskItem[]
|
||||
{
|
||||
CreateItem(Path.Combine("wwwroot","js","sample.js"), new Dictionary<string,string>
|
||||
{
|
||||
["SourceType"] = "",
|
||||
["SourceId"] = "MyLibrary",
|
||||
["ContentRoot"] = @"$(MSBuildThisFileDirectory)..\staticwebassets",
|
||||
["BasePath"] = "_content/mylibrary",
|
||||
["RelativePath"] = Path.Combine("js", "sample.js"),
|
||||
}),
|
||||
CreateItem(Path.Combine("wwwroot","css","site.css"), new Dictionary<string,string>
|
||||
{
|
||||
["SourceType"] = "Package",
|
||||
["SourceId"] = "MyLibrary",
|
||||
["ContentRoot"] = @"$(MSBuildThisFileDirectory)..\staticwebassets",
|
||||
["BasePath"] = "_content/mylibrary",
|
||||
["RelativePath"] = Path.Combine("css", "site.css"),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = task.Execute();
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
var message = Assert.Single(errorMessages);
|
||||
Assert.Equal(expectedError, message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Fails_WhenStaticWebAsset_HaveDifferentSourceId()
|
||||
{
|
||||
// Arrange
|
||||
var expectedError = "Static web assets have different 'SourceId' metadata values " +
|
||||
"'MyLibrary' and 'MyLibrary2' " +
|
||||
$"for '{Path.Combine("wwwroot", "js", "sample.js")}' and '{Path.Combine("wwwroot", "css", "site.css")}'.";
|
||||
|
||||
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 GenerateStaticWebAsssetsPropsFile
|
||||
{
|
||||
BuildEngine = buildEngine.Object,
|
||||
StaticWebAssets = new TaskItem[]
|
||||
{
|
||||
CreateItem(Path.Combine("wwwroot","js","sample.js"), new Dictionary<string,string>
|
||||
{
|
||||
["SourceType"] = "",
|
||||
["SourceId"] = "MyLibrary",
|
||||
["ContentRoot"] = @"$(MSBuildThisFileDirectory)..\staticwebassets",
|
||||
["BasePath"] = "_content/mylibrary",
|
||||
["RelativePath"] = Path.Combine("js", "sample.js"),
|
||||
}),
|
||||
CreateItem(Path.Combine("wwwroot","css","site.css"), new Dictionary<string,string>
|
||||
{
|
||||
["SourceType"] = "",
|
||||
["SourceId"] = "MyLibrary2",
|
||||
["ContentRoot"] = @"$(MSBuildThisFileDirectory)..\staticwebassets",
|
||||
["BasePath"] = "_content/mylibrary",
|
||||
["RelativePath"] = Path.Combine("css", "site.css"),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = task.Execute();
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
var message = Assert.Single(errorMessages);
|
||||
Assert.Equal(expectedError, message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Fails_WhenStaticWebAsset_HaveDifferentContentRoot()
|
||||
{
|
||||
// Arrange
|
||||
var expectedError = "Static web assets have different 'ContentRoot' metadata values " +
|
||||
@"'$(MSBuildThisFileDirectory)..\staticwebassets' and '..\staticwebassets' " +
|
||||
$"for '{Path.Combine("wwwroot", "js", "sample.js")}' and '{Path.Combine("wwwroot", "css", "site.css")}'.";
|
||||
|
||||
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 GenerateStaticWebAsssetsPropsFile
|
||||
{
|
||||
BuildEngine = buildEngine.Object,
|
||||
StaticWebAssets = new TaskItem[]
|
||||
{
|
||||
CreateItem(Path.Combine("wwwroot","js","sample.js"), new Dictionary<string,string>
|
||||
{
|
||||
["SourceType"] = "",
|
||||
["SourceId"] = "MyLibrary",
|
||||
["ContentRoot"] = @"$(MSBuildThisFileDirectory)..\staticwebassets",
|
||||
["BasePath"] = "_content/mylibrary",
|
||||
["RelativePath"] = Path.Combine("js", "sample.js"),
|
||||
}),
|
||||
CreateItem(Path.Combine("wwwroot","css","site.css"), new Dictionary<string,string>
|
||||
{
|
||||
["SourceType"] = "",
|
||||
["SourceId"] = "MyLibrary",
|
||||
["ContentRoot"] = @"..\staticwebassets",
|
||||
["BasePath"] = "_content/mylibrary",
|
||||
["RelativePath"] = Path.Combine("css", "site.css"),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = task.Execute();
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
var message = Assert.Single(errorMessages);
|
||||
Assert.Equal(expectedError, message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Fails_WhenStaticWebAsset_HaveDifferentBasePath()
|
||||
{
|
||||
// Arrange
|
||||
var expectedError = "Static web assets have different 'BasePath' metadata values " +
|
||||
"'_content/mylibrary' and '_content/mylibrary2' " +
|
||||
$"for '{Path.Combine("wwwroot", "js", "sample.js")}' and '{Path.Combine("wwwroot", "css", "site.css")}'.";
|
||||
|
||||
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 GenerateStaticWebAsssetsPropsFile
|
||||
{
|
||||
BuildEngine = buildEngine.Object,
|
||||
StaticWebAssets = new TaskItem[]
|
||||
{
|
||||
CreateItem(Path.Combine("wwwroot","js","sample.js"), new Dictionary<string,string>
|
||||
{
|
||||
["SourceType"] = "",
|
||||
["SourceId"] = "MyLibrary",
|
||||
["ContentRoot"] = @"$(MSBuildThisFileDirectory)..\staticwebassets",
|
||||
["BasePath"] = "_content/mylibrary",
|
||||
["RelativePath"] = Path.Combine("js", "sample.js"),
|
||||
}),
|
||||
CreateItem(Path.Combine("wwwroot","css","site.css"), new Dictionary<string,string>
|
||||
{
|
||||
["SourceType"] = "",
|
||||
["SourceId"] = "MyLibrary",
|
||||
["ContentRoot"] = @"$(MSBuildThisFileDirectory)..\staticwebassets",
|
||||
["BasePath"] = "_content/mylibrary2",
|
||||
["RelativePath"] = Path.Combine("css", "site.css"),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = task.Execute();
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
var message = Assert.Single(errorMessages);
|
||||
Assert.Equal(expectedError, message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WritesPropsFile_WhenThereIsAtLeastOneStaticAsset()
|
||||
{
|
||||
// Arrange
|
||||
var file = Path.GetTempFileName();
|
||||
var expectedDocument = @"<Project>
|
||||
<ItemGroup>
|
||||
<StaticWebAsset Include=""$(MSBuildThisFileDirectory)..\staticwebassets\**"">
|
||||
<SourceType>Package</SourceType>
|
||||
<SourceId>MyLibrary</SourceId>
|
||||
<ContentRoot>$(MSBuildThisFileDirectory)..\staticwebassets\</ContentRoot>
|
||||
<BasePath>_content/mylibrary</BasePath>
|
||||
<RelativePath>%(RecursiveDir)%(FileName)%(Extension)</RelativePath>
|
||||
</StaticWebAsset>
|
||||
</ItemGroup>
|
||||
</Project>";
|
||||
|
||||
try
|
||||
{
|
||||
var buildEngine = new Mock<IBuildEngine>();
|
||||
|
||||
var task = new GenerateStaticWebAsssetsPropsFile
|
||||
{
|
||||
BuildEngine = buildEngine.Object,
|
||||
TargetPropsFilePath = file,
|
||||
StaticWebAssets = new TaskItem[]
|
||||
{
|
||||
CreateItem(Path.Combine("wwwroot","js","sample.js"), new Dictionary<string,string>
|
||||
{
|
||||
["SourceType"] = "",
|
||||
["SourceId"] = "MyLibrary",
|
||||
["ContentRoot"] = @"$(MSBuildThisFileDirectory)..\staticwebassets",
|
||||
["BasePath"] = "_content/mylibrary",
|
||||
["RelativePath"] = Path.Combine("js", "sample.js"),
|
||||
}),
|
||||
}
|
||||
};
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -485,6 +485,40 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
|||
}
|
||||
}
|
||||
|
||||
// This method extracts the nupkg to a fixed directory path. To avoid the extra work of
|
||||
// cleaning up after each invocation, this method accepts multiple files.
|
||||
public static void NupkgDoesNotContain(MSBuildResult result, string nupkgPath, params string[] filePaths)
|
||||
{
|
||||
if (result == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(result));
|
||||
}
|
||||
|
||||
if (nupkgPath == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(nupkgPath));
|
||||
}
|
||||
|
||||
if (filePaths == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(filePaths));
|
||||
}
|
||||
|
||||
nupkgPath = Path.Combine(result.Project.DirectoryPath, nupkgPath);
|
||||
FileExists(result, nupkgPath);
|
||||
|
||||
var unzipped = Path.Combine(result.Project.DirectoryPath, Path.GetFileNameWithoutExtension(nupkgPath));
|
||||
ZipFile.ExtractToDirectory(nupkgPath, unzipped);
|
||||
|
||||
foreach (var filePath in filePaths)
|
||||
{
|
||||
if (File.Exists(Path.Combine(unzipped, filePath)))
|
||||
{
|
||||
throw new NupkgFileFoundException(result, nupkgPath, filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void AssemblyContainsType(MSBuildResult result, string assemblyPath, string fullTypeName)
|
||||
{
|
||||
if (result == null)
|
||||
|
|
@ -872,5 +906,21 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
|||
|
||||
protected override string Heading => $"File: '{FilePath}' was not found was not found in {NupkgPath}.";
|
||||
}
|
||||
|
||||
private class NupkgFileFoundException : MSBuildXunitException
|
||||
{
|
||||
public NupkgFileFoundException(MSBuildResult result, string nupkgPath, string filePath)
|
||||
: base(result)
|
||||
{
|
||||
NupkgPath = nupkgPath;
|
||||
FilePath = filePath;
|
||||
}
|
||||
|
||||
public string FilePath { get; }
|
||||
|
||||
public string NupkgPath { get; }
|
||||
|
||||
protected override string Heading => $"File: '{FilePath}' was found in {NupkgPath}.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// 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 System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
|
|
@ -176,5 +177,150 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
|||
Path.Combine("bin", Configuration, "ClassLibrary.1.0.0.nupkg"),
|
||||
Path.Combine("lib", "netcoreapp3.0", "ClassLibrary.Views.dll"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[InitializeTestProject("PackageLibraryDirectDependency", additionalProjects: new[] { "PackageLibraryTransitiveDependency" })]
|
||||
public async Task Pack_IncludesStaticWebAssets()
|
||||
{
|
||||
var result = await DotnetMSBuild("Pack");
|
||||
|
||||
Assert.BuildPassed(result, allowWarnings: true);
|
||||
|
||||
Assert.FileExists(result, OutputPath, "PackageLibraryDirectDependency.dll");
|
||||
|
||||
Assert.NupkgContains(
|
||||
result,
|
||||
Path.Combine("..", "TestPackageRestoreSource", "PackageLibraryDirectDependency.1.0.0.nupkg"),
|
||||
filePaths: new[]
|
||||
{
|
||||
Path.Combine("staticwebassets", "js", "pkg-direct-dep.js"),
|
||||
Path.Combine("staticwebassets", "css", "site.css"),
|
||||
Path.Combine("build", "Microsoft.AspNetCore.StaticWebAssets.props"),
|
||||
Path.Combine("build", "PackageLibraryDirectDependency.props"),
|
||||
Path.Combine("buildMultiTargeting", "PackageLibraryDirectDependency.props"),
|
||||
Path.Combine("buildTransitive", "PackageLibraryDirectDependency.props")
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[InitializeTestProject("PackageLibraryDirectDependency", additionalProjects: new[] { "PackageLibraryTransitiveDependency" })]
|
||||
public async Task Pack_StaticWebAssetsEnabledFalse_DoesNotPackAnyStaticWebAssets()
|
||||
{
|
||||
var result = await DotnetMSBuild("Pack", "/p:StaticWebAssetsEnabled=false");
|
||||
|
||||
Assert.BuildPassed(result, allowWarnings: true);
|
||||
|
||||
Assert.FileExists(result, OutputPath, "PackageLibraryDirectDependency.dll");
|
||||
|
||||
Assert.NupkgDoesNotContain(
|
||||
result,
|
||||
Path.Combine("..", "TestPackageRestoreSource", "PackageLibraryDirectDependency.1.0.0.nupkg"),
|
||||
filePaths: new[]
|
||||
{
|
||||
Path.Combine("staticwebassets", "js", "pkg-direct-dep.js"),
|
||||
Path.Combine("staticwebassets", "css", "site.css"),
|
||||
Path.Combine("build", "Microsoft.AspNetCore.StaticWebAssets.props"),
|
||||
Path.Combine("build", "PackageLibraryDirectDependency.props"),
|
||||
Path.Combine("buildMultiTargeting", "PackageLibraryDirectDependency.props"),
|
||||
Path.Combine("buildTransitive", "PackageLibraryDirectDependency.props")
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[InitializeTestProject("PackageLibraryDirectDependency", additionalProjects: new[] { "PackageLibraryTransitiveDependency" })]
|
||||
public async Task Pack_NoBuild_IncludesStaticWebAssets()
|
||||
{
|
||||
var result = await DotnetMSBuild("Build");
|
||||
Assert.BuildPassed(result, allowWarnings: true);
|
||||
|
||||
var pack = await DotnetMSBuild("Pack", "/p:NoBuild=true");
|
||||
Assert.BuildPassed(pack, allowWarnings: true);
|
||||
|
||||
Assert.FileExists(pack, OutputPath, "PackageLibraryDirectDependency.dll");
|
||||
|
||||
Assert.NupkgContains(
|
||||
pack,
|
||||
Path.Combine("..", "TestPackageRestoreSource", "PackageLibraryDirectDependency.1.0.0.nupkg"),
|
||||
filePaths: new[]
|
||||
{
|
||||
Path.Combine("staticwebassets", "js", "pkg-direct-dep.js"),
|
||||
Path.Combine("staticwebassets", "css", "site.css"),
|
||||
Path.Combine("build", "Microsoft.AspNetCore.StaticWebAssets.props"),
|
||||
Path.Combine("build", "PackageLibraryDirectDependency.props"),
|
||||
Path.Combine("buildMultiTargeting", "PackageLibraryDirectDependency.props"),
|
||||
Path.Combine("buildTransitive", "PackageLibraryDirectDependency.props")
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[InitializeTestProject("ComponentLibrary")]
|
||||
public async Task Pack_DoesNotIncludeAnyCustomPropsFiles_WhenNoStaticAssetsAreAvailable()
|
||||
{
|
||||
MSBuildIntegrationTestBase.TargetFramework = "netstandard2.0";
|
||||
|
||||
var result = await DotnetMSBuild("Pack");
|
||||
|
||||
Assert.BuildPassed(result, allowWarnings: true);
|
||||
|
||||
Assert.FileExists(result, OutputPath, "ComponentLibrary.dll");
|
||||
|
||||
Assert.NupkgDoesNotContain(
|
||||
result,
|
||||
Path.Combine("bin", Configuration, "ComponentLibrary.1.0.0.nupkg"),
|
||||
filePaths: new[]
|
||||
{
|
||||
Path.Combine("build", "Microsoft.AspNetCore.StaticWebAssets.props"),
|
||||
Path.Combine("build", "ComponentLibrary.props"),
|
||||
Path.Combine("buildMultiTargeting", "ComponentLibrary.props"),
|
||||
Path.Combine("buildTransitive", "ComponentLibrary.props")
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[InitializeTestProject("PackageLibraryTransitiveDependency")]
|
||||
public async Task Pack_Incremental_DoesNotRegenerateCacheAndPropsFiles()
|
||||
{
|
||||
TargetFramework = "netstandard2.0";
|
||||
var result = await DotnetMSBuild("Pack");
|
||||
|
||||
Assert.BuildPassed(result, allowWarnings: true);
|
||||
|
||||
Assert.FileExists(result, OutputPath, "PackageLibraryTransitiveDependency.dll");
|
||||
|
||||
Assert.FileExists(result, IntermediateOutputPath, "staticwebassets", "msbuild.PackageLibraryTransitiveDependency.Microsoft.AspNetCore.StaticWebAssets.props");
|
||||
Assert.FileExists(result, IntermediateOutputPath, "staticwebassets", "msbuild.build.PackageLibraryTransitiveDependency.props");
|
||||
Assert.FileExists(result, IntermediateOutputPath, "staticwebassets", "msbuild.buildMultiTargeting.PackageLibraryTransitiveDependency.props");
|
||||
Assert.FileExists(result, IntermediateOutputPath, "staticwebassets", "msbuild.buildTransitive.PackageLibraryTransitiveDependency.props");
|
||||
Assert.FileExists(result, IntermediateOutputPath, "staticwebassets", "PackageLibraryTransitiveDependency.StaticWebAssets.Pack.cache");
|
||||
|
||||
var directoryPath = Path.Combine(result.Project.DirectoryPath, IntermediateOutputPath, "staticwebassets");
|
||||
var thumbPrints = new Dictionary<string, FileThumbPrint>();
|
||||
var thumbPrintFiles = new[]
|
||||
{
|
||||
Path.Combine(directoryPath, "msbuild.PackageLibraryTransitiveDependency.Microsoft.AspNetCore.StaticWebAssets.props"),
|
||||
Path.Combine(directoryPath, "msbuild.build.PackageLibraryTransitiveDependency.props"),
|
||||
Path.Combine(directoryPath, "msbuild.buildMultiTargeting.PackageLibraryTransitiveDependency.props"),
|
||||
Path.Combine(directoryPath, "msbuild.buildTransitive.PackageLibraryTransitiveDependency.props"),
|
||||
Path.Combine(directoryPath, "PackageLibraryTransitiveDependency.StaticWebAssets.Pack.cache"),
|
||||
};
|
||||
|
||||
foreach (var file in thumbPrintFiles)
|
||||
{
|
||||
var thumbprint = GetThumbPrint(file);
|
||||
thumbPrints[file] = thumbprint;
|
||||
}
|
||||
|
||||
// Act
|
||||
var incremental = await DotnetMSBuild("Pack");
|
||||
|
||||
// Assert
|
||||
Assert.BuildPassed(incremental, allowWarnings: true);
|
||||
|
||||
foreach (var file in thumbPrintFiles)
|
||||
{
|
||||
var thumbprint = GetThumbPrint(file);
|
||||
Assert.Equal(thumbPrints[file], thumbprint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,18 +43,73 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
|||
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");
|
||||
Assert.FileExists(result, IntermediateOutputPath, "staticwebassets", "AppWithPackageAndP2PReference.StaticWebAssets.xml");
|
||||
Assert.FileExists(result, IntermediateOutputPath, "staticwebassets", "AppWithPackageAndP2PReference.StaticWebAssets.Manifest.cache");
|
||||
if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
// Skip this check on mac as the CI seems to use a somewhat different path on OSX.
|
||||
// This check works just fine on a local OSX instance, but the CI path seems to require prepending /private.
|
||||
// There is nothing OS specific about publishing this file, so the chances of this breaking are infinitesimal.
|
||||
Assert.FileExists(result, OutputPath, "AppWithPackageAndP2PReference.StaticWebAssets.xml");
|
||||
}
|
||||
|
||||
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();
|
||||
Output.WriteLine("Manifest:");
|
||||
Output.WriteLine(data);
|
||||
Assert.Equal(expectedManifest, data);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[InitializeTestProject("AppWithPackageAndP2PReference", additionalProjects: new[] { "ClassLibrary", "ClassLibrary2" })]
|
||||
public async Task Publish_CopiesStaticWebAssetsToDestinationFolder()
|
||||
{
|
||||
var result = await DotnetMSBuild("Publish", "/restore");
|
||||
|
||||
Assert.BuildPassed(result);
|
||||
|
||||
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]
|
||||
[InitializeTestProject("AppWithPackageAndP2PReference", additionalProjects: new[] { "ClassLibrary", "ClassLibrary2" })]
|
||||
public async Task Publish_WithBuildReferencesDisabled_CopiesStaticWebAssetsToDestinationFolder()
|
||||
{
|
||||
var build = await DotnetMSBuild("Build", "/restore");
|
||||
|
||||
Assert.BuildPassed(build);
|
||||
|
||||
var publish = await DotnetMSBuild("Publish", "/p:BuildProjectReferences=false");
|
||||
|
||||
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]
|
||||
[InitializeTestProject("SimpleMvc")]
|
||||
public async Task Build_DoesNotEmbedManifestWhen_NoStaticResourcesAvailable()
|
||||
|
|
@ -64,8 +119,9 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
|||
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");
|
||||
Assert.FileExists(result, IntermediateOutputPath, "staticwebassets", "SimpleMvc.StaticWebAssets.xml");
|
||||
Assert.FileExists(result, IntermediateOutputPath, "staticwebassets", "SimpleMvc.StaticWebAssets.Manifest.cache");
|
||||
Assert.FileDoesNotExist(result, OutputPath, "SimpleMvc.StaticWebAssets.xml");
|
||||
|
||||
var path = Assert.FileExists(result, OutputPath, "SimpleMvc.dll");
|
||||
Assert.DoesNotContainEmbeddedResource(path, "SimpleMvc.StaticWebAssets.xml");
|
||||
|
|
@ -80,16 +136,16 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
|||
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");
|
||||
Assert.FileExists(result, IntermediateOutputPath, "staticwebassets", "AppWithPackageAndP2PReference.StaticWebAssets.xml");
|
||||
Assert.FileExists(result, IntermediateOutputPath, "staticwebassets", "AppWithPackageAndP2PReference.StaticWebAssets.Manifest.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");
|
||||
Assert.FileDoesNotExist(result, IntermediateOutputPath, "staticwebassets", "AppWithPackageAndP2PReference.StaticWebAssets.Manifest.cache");
|
||||
Assert.FileDoesNotExist(result, IntermediateOutputPath, "staticwebassets", "AppWithPackageAndP2PReference.StaticWebAssets.xml");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -104,15 +160,15 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
|||
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");
|
||||
Assert.FileExists(result, IntermediateOutputPath, "staticwebassets", "AppWithPackageAndP2PReference.StaticWebAssets.xml");
|
||||
Assert.FileExists(result, IntermediateOutputPath, "staticwebassets", "AppWithPackageAndP2PReference.StaticWebAssets.Manifest.cache");
|
||||
|
||||
var directoryPath = Path.Combine(result.Project.DirectoryPath, IntermediateOutputPath);
|
||||
var directoryPath = Path.Combine(result.Project.DirectoryPath, IntermediateOutputPath, "staticwebassets");
|
||||
var thumbPrints = new Dictionary<string, FileThumbPrint>();
|
||||
var thumbPrintFiles = new[]
|
||||
{
|
||||
Path.Combine(directoryPath, "AppWithPackageAndP2PReference.StaticWebAssets.xml"),
|
||||
Path.Combine(directoryPath, "AppWithPackageAndP2PReference.StaticWebAssets.cache"),
|
||||
Path.Combine(directoryPath, "AppWithPackageAndP2PReference.StaticWebAssets.Manifest.cache"),
|
||||
};
|
||||
|
||||
foreach (var file in thumbPrintFiles)
|
||||
|
|
@ -151,15 +207,15 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
|||
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");
|
||||
Assert.FileExists(result, IntermediateOutputPath, "staticwebassets", "AppWithPackageAndP2PReference.StaticWebAssets.xml");
|
||||
Assert.FileExists(result, IntermediateOutputPath, "staticwebassets", "AppWithPackageAndP2PReference.StaticWebAssets.Manifest.cache");
|
||||
|
||||
var directoryPath = Path.Combine(result.Project.DirectoryPath, IntermediateOutputPath);
|
||||
var directoryPath = Path.Combine(result.Project.DirectoryPath, IntermediateOutputPath, "staticwebassets");
|
||||
var thumbPrints = new Dictionary<string, FileThumbPrint>();
|
||||
var thumbPrintFiles = new[]
|
||||
{
|
||||
Path.Combine(directoryPath, "AppWithPackageAndP2PReference.StaticWebAssets.xml"),
|
||||
Path.Combine(directoryPath, "AppWithPackageAndP2PReference.StaticWebAssets.cache"),
|
||||
Path.Combine(directoryPath, "AppWithPackageAndP2PReference.StaticWebAssets.Manifest.cache"),
|
||||
};
|
||||
|
||||
foreach (var file in thumbPrintFiles)
|
||||
|
|
@ -201,17 +257,17 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
|||
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,
|
||||
Path.Combine(restorePath, "packagelibrarytransitivedependency", "1.0.0", "build", "..", "staticwebassets") + Path.DirectorySeparatorChar,
|
||||
Path.Combine(restorePath, "packagelibrarydirectdependency", "1.0.0", "build", "..", "staticwebassets") + Path.DirectorySeparatorChar,
|
||||
Path.GetFullPath(Path.Combine(source, "ClassLibrary", "wwwroot")) + Path.DirectorySeparatorChar,
|
||||
Path.GetFullPath(Path.Combine(source, "ClassLibrary2", "wwwroot")) + Path.DirectorySeparatorChar
|
||||
};
|
||||
|
||||
return $@"<StaticWebAssets Version=""1.0"">
|
||||
<ContentRoot BasePath=""_content/PackageLibraryTransitiveDependency"" Path=""{projects[0]}"" />
|
||||
<ContentRoot BasePath=""_content/PackageLibraryDirectDependency"" Path=""{projects[1]}"" />
|
||||
<ContentRoot BasePath=""_content/classlibrary"" Path=""{projects[2]}"" />
|
||||
<ContentRoot BasePath=""_content/classlibrary2"" Path=""{projects[3]}"" />
|
||||
<ContentRoot BasePath=""_content/packagelibrarydirectdependency"" Path=""{projects[1]}"" />
|
||||
<ContentRoot BasePath=""_content/packagelibrarytransitivedependency"" Path=""{projects[0]}"" />
|
||||
</StaticWebAssets>";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
// 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 Microsoft.AspNetCore.Razor.Tasks;
|
||||
using Microsoft.Build.Framework;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Tasks
|
||||
{
|
||||
public class StaticWebAssetsGeneratePackagePropsFileTest
|
||||
{
|
||||
[Fact]
|
||||
public void WritesPropsFile_WithProvidedImportPath()
|
||||
{
|
||||
// Arrange
|
||||
var file = Path.GetTempFileName();
|
||||
var expectedDocument = @"<Project>
|
||||
<Import Project=""Microsoft.AspNetCore.StaticWebAssets.props"" />
|
||||
</Project>";
|
||||
|
||||
try
|
||||
{
|
||||
var buildEngine = new Mock<IBuildEngine>();
|
||||
|
||||
var task = new StaticWebAssetsGeneratePackagePropsFile
|
||||
{
|
||||
BuildEngine = buildEngine.Object,
|
||||
PropsFileImport="Microsoft.AspNetCore.StaticWebAssets.props",
|
||||
BuildTargetPath=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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -36,9 +36,9 @@
|
|||
<!-- Test Placeholder -->
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="build\**" Pack="true" PackagePath="build" />
|
||||
<!-- <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" />
|
||||
<!-- <Content Update="wwwroot\**" Pack="true" PackagePath="razorContent" /> -->
|
||||
<ProjectReference Include="..\PackageLibraryTransitiveDependency\PackageLibraryTransitiveDependency.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
<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>
|
||||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
<PropertyGroup>
|
||||
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>
|
||||
<RazorLangVersion>3.0</RazorLangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
|
@ -35,10 +36,4 @@
|
|||
|
||||
<!-- 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>
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
<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>
|
||||
Loading…
Reference in New Issue