Skip to content

Commit 1a2ca58

Browse files
authored
Merge pull request #2324 from aspnet/release/2.1
Merge release/2.1
2 parents 2081663 + a943234 commit 1a2ca58

File tree

8 files changed

+288
-4
lines changed

8 files changed

+288
-4
lines changed

src/Microsoft.NET.Sdk.Razor/build/netstandard2.0/Sdk.Razor.CurrentVersion.targets

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,21 @@ Copyright (c) .NET Foundation. All rights reserved.
6969
_RazorAddDebugSymbolsProjectOutputGroupOutput
7070
</DebugSymbolsProjectOutputGroupDependsOn>
7171

72+
<PrepareForBuildDependsOn>
73+
$(PrepareForBuildDependsOn);
74+
ResolveRazorGenerateInputs
75+
</PrepareForBuildDependsOn>
76+
7277
<PrepareForRunDependsOn>
7378
_RazorPrepareForRun;
7479
$(PrepareForRunDependsOn)
7580
</PrepareForRunDependsOn>
7681

82+
<GetCopyToOutputDirectoryItemsDependsOn>
83+
_RazorGetCopyToOutputDirectoryItems;
84+
$(GetCopyToOutputDirectoryItems)
85+
</GetCopyToOutputDirectoryItemsDependsOn>
86+
7787
</PropertyGroup>
7888

7989
<!--
@@ -180,10 +190,24 @@ Copyright (c) .NET Foundation. All rights reserved.
180190
<RazorIntermediateAssembly Condition="'$(RazorIntermediateAssembly)'==''" Include="$(IntermediateOutputPath)$(RazorTargetName).dll" />
181191
<!-- Used in Compilation.targets -->
182192
<_RazorDebugSymbolsIntermediatePath Condition="'$(_RazorDebugSymbolsProduced)'=='true'" Include="$(IntermediateOutputPath)$(RazorTargetName).pdb" />
183-
<!-- Add all cshtml files to UpToDateCheckInput - a collection used by the IDE's project system to determine if a project needs to be rebuilt -->
193+
</ItemGroup>
194+
195+
<ItemGroup>
196+
<!--
197+
Add all cshtml files to UpToDateCheckInput - a collection of files used by FastUpToDateCheck to determine
198+
if any of the the project inputs have changed.
199+
-->
184200
<UpToDateCheckInput Condition="'$(RazorCompileOnBuild)'=='true'" Include="@(Content->WithMetadataValue('Extension', '.cshtml'))" />
201+
202+
<!--
203+
Add Razor output files to UpToDateCheckBuilt - a collection of files used by FastUpToDateCheck to determine
204+
if any of the project's outputs have changed.
205+
-->
206+
<UpToDateCheckBuilt Include="@(RazorIntermediateAssembly)"
207+
Condition="'$(RazorCompileOnBuild)'=='true' AND '@(Content->WithMetadataValue('Extension', '.cshtml'))' != ''" />
185208
</ItemGroup>
186209

210+
187211
<!--
188212
These are the targets that generate code using Razor, separated from the main file for ease of maintenance.
189213
Most targets related to Razor code generation are defined there.
@@ -266,6 +290,11 @@ Copyright (c) .NET Foundation. All rights reserved.
266290
<!--
267291
Gathers input source files for code generation. This is a separate target so that we can avoid
268292
lots of work when there are no inputs for code generation.
293+
This target runs as part of PrepareForBuild. This gives us an opportunitity to change things like CopyToPublishDirectory
294+
for Content items before they are processed by other Build targets.
295+
296+
NOTE: This target is called as part of an incremental build scenario in VS. Do not perform any work
297+
outside of calculating RazorGenerate items in this target.
269298
-->
270299
<Target Name="ResolveRazorGenerateInputs">
271300
<!--
@@ -283,6 +312,20 @@ Copyright (c) .NET Foundation. All rights reserved.
283312
<ItemGroup Condition="'$(EnableDefaultRazorGenerateItems)'=='true'">
284313
<RazorGenerate Include="@(Content)" Condition="'%(Content.Extension)'=='.cshtml'" />
285314
</ItemGroup>
315+
316+
<!--
317+
Ideally we want to able to update all Content items that also appear in RazorGenerate to have
318+
CopyToPublishDirectory=Never. However, there isn't a simple way to do this (https://github.com/Microsoft/msbuild/issues/1618).
319+
Instead, we'll update all cshtml Content items when EnableDefaultRazorGenerateItems=true and Razor Sdk is used for publishing.
320+
-->
321+
<ItemGroup Condition="
322+
'$(EnableDefaultRazorGenerateItems)'=='true' and
323+
'$(CopyRazorGenerateFilesToPublishDirectory)'=='false' and
324+
'$(ResolvedRazorCompileToolset)'=='RazorSdk' and
325+
'$(RazorCompileOnPublish)'=='true'">
326+
327+
<Content Condition="'%(Content.Extension)'=='.cshtml'" CopyToPublishDirectory="Never" />
328+
</ItemGroup>
286329
</Target>
287330

288331
<Target Name="AssignRazorGenerateTargetPaths" Condition="'@(RazorGenerate)' != ''">
@@ -384,7 +427,7 @@ Copyright (c) .NET Foundation. All rights reserved.
384427
-->
385428
<Target
386429
Name="_RazorGetCopyToOutputDirectoryItems"
387-
BeforeTargets="GetCopyToOutputDirectoryItems"
430+
DependsOnTargets="ResolveRazorGenerateInputs"
388431
Condition="'$(ResolvedRazorCompileToolset)'=='RazorSdk' and '$(RazorCompileOnBuild)'=='true'">
389432

390433
<!--
@@ -479,6 +522,15 @@ Copyright (c) .NET Foundation. All rights reserved.
479522

480523
<Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
481524
</Copy>
525+
526+
<!--
527+
FastUpToDate check in VS does not consider the Views dll when determining if referencing projects need to be rebuilt.
528+
We'll touch a marker file that is used during as input for up to date check. Based on
529+
https://github.com/Microsoft/msbuild/blob/637f06e31ef46892faeb40044899a62a15b77f79/src/Tasks/Microsoft.Common.CurrentVersion.targets#L4364-L4368
530+
-->
531+
<Touch Files="@(CopyUpToDateMarker)" AlwaysCreate="true" Condition="'@(_RazorAssembly)' != ''">
532+
<Output TaskParameter="TouchedFiles" ItemName="FileWrites" />
533+
</Touch>
482534

483535
</Target>
484536

test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/Assert.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,30 @@ public static void BuildOutputContainsLine(MSBuildResult result, string match)
100100
throw new BuildOutputMissingException(result, match);
101101
}
102102

103+
public static void BuildOutputDoesNotContainLine(MSBuildResult result, string match)
104+
{
105+
if (result == null)
106+
{
107+
throw new ArgumentNullException(nameof(result));
108+
}
109+
110+
if (match == null)
111+
{
112+
throw new ArgumentNullException(nameof(match));
113+
}
114+
115+
// We don't really need to search line by line, I'm doing this so that it's possible/easy to debug.
116+
var lines = result.Output.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
117+
for (var i = 0; i < lines.Length; i++)
118+
{
119+
var line = lines[i].Trim();
120+
if (line == match)
121+
{
122+
throw new BuildOutputContainsLineException(result, match);
123+
}
124+
}
125+
}
126+
103127
public static void FileContains(MSBuildResult result, string filePath, string match)
104128
{
105129
if (result == null)
@@ -432,6 +456,19 @@ public BuildOutputMissingException(MSBuildResult result, string match)
432456
protected override string Heading => $"Build did not contain the line: '{Match}'.";
433457
}
434458

459+
private class BuildOutputContainsLineException : MSBuildXunitException
460+
{
461+
public BuildOutputContainsLineException(MSBuildResult result, string match)
462+
: base(result)
463+
{
464+
Match = match;
465+
}
466+
467+
public string Match { get; }
468+
469+
protected override string Heading => $"Build output contains the line: '{Match}'.";
470+
}
471+
435472
private class FileContentFoundException : MSBuildXunitException
436473
{
437474
public FileContentFoundException(MSBuildResult result, string filePath, string content, string match)

test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/BuildIncrementalismTest.cs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
using System;
45
using System.Collections.Generic;
56
using System.IO;
67
using System.Linq;
@@ -136,5 +137,83 @@ async Task VerifyError()
136137
Assert.FileDoesNotExist(result, IntermediateOutputPath, "Razor", "Views", "Home", "Index.cshtml.g.cs");
137138
}
138139
}
140+
141+
[Fact]
142+
[InitializeTestProject("AppWithP2PReference", additionalProjects: "ClassLibrary")]
143+
public async Task IncrementalBuild_WithP2P_WorksWhenBuildProjectReferencesIsDisabled()
144+
{
145+
// Simulates building the same way VS does by setting BuildProjectReferences=false.
146+
// With this flag, the only target called is GetCopyToOutputDirectoryItems on the referenced project.
147+
// We need to ensure that we continue providing Razor binaries and symbols as files to be copied over.
148+
var result = await DotnetMSBuild(target: default);
149+
150+
Assert.BuildPassed(result);
151+
152+
Assert.FileExists(result, OutputPath, "AppWithP2PReference.dll");
153+
Assert.FileExists(result, OutputPath, "AppWithP2PReference.Views.dll");
154+
Assert.FileExists(result, OutputPath, "ClassLibrary.dll");
155+
Assert.FileExists(result, OutputPath, "ClassLibrary.Views.dll");
156+
Assert.FileExists(result, OutputPath, "ClassLibrary.Views.pdb");
157+
158+
result = await DotnetMSBuild(target: "Clean", "/p:BuildProjectReferences=false", suppressRestore: true);
159+
Assert.BuildPassed(result);
160+
161+
Assert.FileDoesNotExist(result, OutputPath, "AppWithP2PReference.dll");
162+
Assert.FileDoesNotExist(result, OutputPath, "AppWithP2PReference.Views.dll");
163+
Assert.FileDoesNotExist(result, OutputPath, "ClassLibrary.dll");
164+
Assert.FileDoesNotExist(result, OutputPath, "ClassLibrary.Views.dll");
165+
Assert.FileDoesNotExist(result, OutputPath, "ClassLibrary.Views.pdb");
166+
167+
// dotnet msbuild /p:BuildProjectReferences=false
168+
result = await DotnetMSBuild(target: default, "/p:BuildProjectReferences=false", suppressRestore: true);
169+
170+
Assert.BuildPassed(result);
171+
Assert.FileExists(result, OutputPath, "AppWithP2PReference.dll");
172+
Assert.FileExists(result, OutputPath, "AppWithP2PReference.Views.dll");
173+
Assert.FileExists(result, OutputPath, "ClassLibrary.dll");
174+
Assert.FileExists(result, OutputPath, "ClassLibrary.Views.dll");
175+
Assert.FileExists(result, OutputPath, "ClassLibrary.Views.pdb");
176+
}
177+
178+
[Fact]
179+
[InitializeTestProject("ClassLibrary")]
180+
public async Task Build_TouchesUpToDateMarkerFile()
181+
{
182+
var classLibraryDll = Path.Combine(IntermediateOutputPath, "ClassLibrary.dll");
183+
var classLibraryViewsDll = Path.Combine(IntermediateOutputPath, "ClassLibrary.Views.dll");
184+
var markerFile = Path.Combine(IntermediateOutputPath, "ClassLibrary.csproj.CopyComplete");
185+
186+
var result = await DotnetMSBuild("Build");
187+
Assert.BuildPassed(result);
188+
189+
Assert.FileExists(result, classLibraryDll);
190+
Assert.FileExists(result, classLibraryViewsDll);
191+
Assert.FileExists(result, markerFile);
192+
193+
// Gather thumbprints before incremental build.
194+
var classLibraryThumbPrint = GetThumbPrint(classLibraryDll);
195+
var classLibraryViewsThumbPrint = GetThumbPrint(classLibraryViewsDll);
196+
var markerFileThumbPrint = GetThumbPrint(markerFile);
197+
198+
result = await DotnetMSBuild("Build");
199+
Assert.BuildPassed(result);
200+
201+
// Verify thumbprint file is unchanged between true incremental builds
202+
Assert.Equal(classLibraryThumbPrint, GetThumbPrint(classLibraryDll));
203+
Assert.Equal(classLibraryViewsThumbPrint, GetThumbPrint(classLibraryViewsDll));
204+
// In practice, this should remain unchanged. However, since our tests reference
205+
// binaries from other projects, this file gets updated by Microsoft.Common.targets
206+
Assert.NotEqual(markerFileThumbPrint, GetThumbPrint(markerFile));
207+
208+
// Change a cshtml file and verify ClassLibrary.Views.dll and marker file are updated
209+
File.AppendAllText(Path.Combine(Project.DirectoryPath, "Views", "_ViewImports.cshtml"), Environment.NewLine);
210+
211+
result = await DotnetMSBuild("Build");
212+
Assert.BuildPassed(result);
213+
214+
Assert.Equal(classLibraryThumbPrint, GetThumbPrint(classLibraryDll));
215+
Assert.NotEqual(classLibraryViewsThumbPrint, GetThumbPrint(classLibraryViewsDll));
216+
Assert.NotEqual(markerFileThumbPrint, GetThumbPrint(markerFile));
217+
}
139218
}
140219
}

test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/BuildIntrospectionTest.cs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@ public BuildIntrospectionTest(BuildServerTestFixture buildServer)
1818
[InitializeTestProject("SimpleMvc")]
1919
public async Task RazorSdk_AddsCshtmlFilesToUpToDateCheckInput()
2020
{
21-
var result = await DotnetMSBuild("_IntrospectUpToDateCheckInput");
21+
var result = await DotnetMSBuild("_IntrospectUpToDateCheck");
2222

2323
Assert.BuildPassed(result);
2424
Assert.BuildOutputContainsLine(result, $"UpToDateCheckInput: {Path.Combine("Views", "Home", "Index.cshtml")}");
2525
Assert.BuildOutputContainsLine(result, $"UpToDateCheckInput: {Path.Combine("Views", "_ViewStart.cshtml")}");
26+
Assert.BuildOutputContainsLine(result, $"UpToDateCheckBuilt: {Path.Combine(IntermediateOutputPath, "SimpleMvc.Views.dll")}");
2627
}
2728

2829
[Fact]
@@ -45,5 +46,31 @@ public async Task RazorSdk_UsesUseSharedCompilationToSetDefaultValueOfUseRazorBu
4546
Assert.BuildPassed(result);
4647
Assert.BuildOutputContainsLine(result, "UseRazorBuildServer: false");
4748
}
49+
50+
[Fact]
51+
[InitializeTestProject("ClassLibrary")]
52+
public async Task GetCopyToOutputDirectoryItems_WhenNoFileIsPresent_ReturnsEmptySequence()
53+
{
54+
var result = await DotnetMSBuild(target: default);
55+
56+
Assert.BuildPassed(result);
57+
58+
Assert.FileExists(result, OutputPath, "ClassLibrary.dll");
59+
Assert.FileExists(result, OutputPath, "ClassLibrary.Views.dll");
60+
61+
result = await DotnetMSBuild(target: "GetCopyToOutputDirectoryItems", "/t:_IntrospectGetCopyToOutputDirectoryItems /p:BuildProjectReferences=false", suppressRestore: true);
62+
Assert.BuildPassed(result);
63+
Assert.BuildOutputContainsLine(result, "AllItemsFullPathWithTargetPath: ClassLibrary.Views.dll");
64+
Assert.BuildOutputContainsLine(result, "AllItemsFullPathWithTargetPath: ClassLibrary.Views.pdb");
65+
66+
// Remove all views from the class library
67+
Directory.Delete(Path.Combine(Project.DirectoryPath, "Views"), recursive: true);
68+
69+
// dotnet msbuild /p:BuildProjectReferences=false
70+
result = await DotnetMSBuild(target: "GetCopyToOutputDirectoryItems", "/t:_IntrospectGetCopyToOutputDirectoryItems /p:BuildProjectReferences=false", suppressRestore: true);
71+
72+
Assert.BuildOutputDoesNotContainLine(result, "AllItemsFullPathWithTargetPath: ClassLibrary.Views.dll");
73+
Assert.BuildOutputDoesNotContainLine(result, "AllItemsFullPathWithTargetPath: ClassLibrary.Views.pdb");
74+
}
4875
}
4976
}

test/Microsoft.AspNetCore.Razor.Design.Test/IntegrationTests/PublishIntegrationTest.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ public async Task Publish_RazorCompileOnPublish_IsDefault()
2727
Assert.FileExists(result, PublishOutputPath, "SimpleMvc.Views.dll");
2828
Assert.FileExists(result, PublishOutputPath, "SimpleMvc.Views.pdb");
2929

30+
// Verify assets get published
31+
Assert.FileExists(result, PublishOutputPath, "wwwroot", "js", "SimpleMvc.js");
32+
Assert.FileExists(result, PublishOutputPath, "wwwroot", "css", "site.css");
33+
3034
// By default refs and .cshtml files will not be copied on publish
3135
Assert.FileCountEquals(result, 0, Path.Combine(PublishOutputPath, "refs"), "*.dll");
3236
Assert.FileCountEquals(result, 0, Path.Combine(PublishOutputPath, "Views"), "*.cshtml");
@@ -294,6 +298,11 @@ public async Task Publish_WithP2P_AndRazorCompileOnPublish_CopiesRazorAssembly()
294298
Assert.FileExists(result, PublishOutputPath, "ClassLibrary.pdb");
295299
Assert.FileExists(result, PublishOutputPath, "ClassLibrary.Views.dll");
296300
Assert.FileExists(result, PublishOutputPath, "ClassLibrary.Views.pdb");
301+
302+
// Verify fix for https://github.com/aspnet/Razor/issues/2295. No cshtml files should be published from the app
303+
// or the ClassLibrary.
304+
Assert.FileCountEquals(result, 0, Path.Combine(PublishOutputPath, "refs"), "*.dll");
305+
Assert.FileCountEquals(result, 0, Path.Combine(PublishOutputPath, "Views"), "*.cshtml");
297306
}
298307

299308
[Fact]
@@ -310,5 +319,40 @@ public async Task Publish_SimpleMvcFSharp_NoopsWithoutFailing()
310319
Assert.FileDoesNotExist(result, OutputPath, "SimpleMvcFSharp.Views.dll");
311320
Assert.FileDoesNotExist(result, OutputPath, "SimpleMvcFSharp.Views.pdb");
312321
}
322+
323+
[Fact]
324+
[InitializeTestProject("SimpleMvc")]
325+
public async Task Publish_DoesNotPublishCustomRazorGenerateItems()
326+
{
327+
var additionalProjectContent = @"
328+
<PropertyGroup>
329+
<EnableDefaultRazorGenerateItems>false</EnableDefaultRazorGenerateItems>
330+
</PropertyGroup>
331+
<ItemGroup>
332+
<RazorGenerate Include=""Views\_ViewImports.cshtml"" />
333+
<RazorGenerate Include=""Views\Home\Index.cshtml"" />
334+
</ItemGroup>
335+
";
336+
AddProjectFileContent(additionalProjectContent);
337+
var result = await DotnetMSBuild("Publish");
338+
339+
Assert.BuildPassed(result);
340+
341+
Assert.FileExists(result, PublishOutputPath, "SimpleMvc.dll");
342+
Assert.FileExists(result, PublishOutputPath, "SimpleMvc.pdb");
343+
Assert.FileExists(result, PublishOutputPath, "SimpleMvc.Views.dll");
344+
Assert.FileExists(result, PublishOutputPath, "SimpleMvc.Views.pdb");
345+
346+
// Verify assets get published
347+
Assert.FileExists(result, PublishOutputPath, "wwwroot", "js", "SimpleMvc.js");
348+
Assert.FileExists(result, PublishOutputPath, "wwwroot", "css", "site.css");
349+
350+
// By default refs and .cshtml files will not be copied on publish
351+
Assert.FileCountEquals(result, 0, Path.Combine(PublishOutputPath, "refs"), "*.dll");
352+
// Custom RazorGenerate item does not get published
353+
Assert.FileDoesNotExist(result, PublishOutputPath, "Views", "Home", "Home.cshtml");
354+
// cshtml Content item that's not part of RazorGenerate gets published.
355+
Assert.FileExists(result, PublishOutputPath, "Views", "Home", "About.cshtml");
356+
}
313357
}
314358
}

test/testapps/RazorTest.Introspection.targets

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@
77
<Message Text="CompileResource: %(_RazorCoreCompileResourceInputs.Identity) %(_RazorCoreCompileResourceInputs.LogicalName)" Importance="High" />
88
</Target>
99

10-
<Target Name="_IntrospectUpToDateCheckInput">
10+
<Target Name="_IntrospectUpToDateCheck">
1111
<Message Text="UpToDateCheckInput: %(UpToDateCheckInput.Identity)" Importance="High" />
12+
<Message Text="No UpToDateCheckInput input found" Importance="High" Condition="'@(UpToDateCheckInput->Count)' == '0'" />
13+
<Message Text="UpToDateCheckBuilt: %(UpToDateCheckBuilt.Identity)" Importance="High" />
14+
<Message Text="No UpToDateCheckBuilt input found" Importance="High" Condition="'@(UpToDateCheckBuilt->Count)' == '0'" />
1215
</Target>
1316

1417
<Target Name="_IntrospectRazorCompileItems">
@@ -18,4 +21,8 @@
1821
<Target Name="_IntrospectUseRazorBuildServer">
1922
<Message Text="UseRazorBuildServer: $(UseRazorBuildServer)" Importance="High" />
2023
</Target>
24+
25+
<Target Name="_IntrospectGetCopyToOutputDirectoryItems">
26+
<Message Text="AllItemsFullPathWithTargetPath: %(AllItemsFullPathWithTargetPath.TargetPath)" Importance="High" />
27+
</Target>
2128
</Project>

0 commit comments

Comments
 (0)