Browse Source

Merge branch 'release/2.1' into release/2.2

Nate McMaster 7 years ago
parent
commit
2e96271e69

+ 8 - 2
build/RepositoryBuild.targets

@@ -77,6 +77,8 @@
 
 
   <Target Name="GetRepoBuildProps">
   <Target Name="GetRepoBuildProps">
     <PropertyGroup>
     <PropertyGroup>
+      <SkipTestsDueToMissingSharedFx Condition="'$(InstallSharedRuntimeFromPreviousBuild)' != 'true' And '$(TestsRequiredTheSharedRuntime)' == 'true' ">true</SkipTestsDueToMissingSharedFx>
+
       <!-- Should reduce allowable package feeds to only nuget.org. -->
       <!-- Should reduce allowable package feeds to only nuget.org. -->
       <RepositoryBuildArguments>$(RepositoryBuildArguments) /p:AspNetUniverseBuildOffline=true</RepositoryBuildArguments>
       <RepositoryBuildArguments>$(RepositoryBuildArguments) /p:AspNetUniverseBuildOffline=true</RepositoryBuildArguments>
       <!-- If there are duplicate properties, the properties which are defined later in the order would override the earlier ones -->
       <!-- If there are duplicate properties, the properties which are defined later in the order would override the earlier ones -->
@@ -88,6 +90,7 @@
       <RepositoryBuildArguments>$(RepositoryBuildArguments) /noconsolelogger '/l:RepoTasks.FlowLogger,$(MSBuildThisFileDirectory)tasks\bin\publish\RepoTasks.dll;Summary;FlowId=$(RepositoryToBuild)'</RepositoryBuildArguments>
       <RepositoryBuildArguments>$(RepositoryBuildArguments) /noconsolelogger '/l:RepoTasks.FlowLogger,$(MSBuildThisFileDirectory)tasks\bin\publish\RepoTasks.dll;Summary;FlowId=$(RepositoryToBuild)'</RepositoryBuildArguments>
       <RepositoryBuildArguments>$(RepositoryBuildArguments) '/p:DotNetAssetRootAccessTokenSuffix=$(DotNetAssetRootAccessTokenSuffix)'</RepositoryBuildArguments>
       <RepositoryBuildArguments>$(RepositoryBuildArguments) '/p:DotNetAssetRootAccessTokenSuffix=$(DotNetAssetRootAccessTokenSuffix)'</RepositoryBuildArguments>
       <RepositoryBuildArguments>$(RepositoryBuildArguments) '/p:DotNetAssetRootUrl=$(DotNetAssetRootUrl)'</RepositoryBuildArguments>
       <RepositoryBuildArguments>$(RepositoryBuildArguments) '/p:DotNetAssetRootUrl=$(DotNetAssetRootUrl)'</RepositoryBuildArguments>
+      <RepositoryBuildArguments Condition=" '$(SkipTestsDueToMissingSharedFx)' == 'true' ">$(RepositoryBuildArguments) /p:SkipAspNetCoreRuntimeInstall=true</RepositoryBuildArguments>
 
 
       <SourceLockFile>$(RepositoryRoot)korebuild-lock.txt</SourceLockFile>
       <SourceLockFile>$(RepositoryRoot)korebuild-lock.txt</SourceLockFile>
       <RepoLockFile>$(BuildRepositoryRoot)korebuild-lock.txt</RepoLockFile>
       <RepoLockFile>$(BuildRepositoryRoot)korebuild-lock.txt</RepoLockFile>
@@ -160,9 +163,12 @@
       <RepositoryTestResult Include="$(RepositoryToBuild)" Success="false" />
       <RepositoryTestResult Include="$(RepositoryToBuild)" Success="false" />
     </ItemGroup>
     </ItemGroup>
 
 
+    <!-- To enable this test, either publish the shared runtime to https://dotnetcli.blob.core.windows.net/dotnet, or override the install location by setting AspNetCoreFxFeed. -->
+    <Warning Text="Skipping tests because InstallSharedRuntimeFromPreviousBuild != 'true'." Condition="'$(SkipTestsDueToMissingSharedFx)' == 'true' "/>
+
     <Message Text="============ Testing $(RepositoryToBuild) ============" Importance="High" />
     <Message Text="============ Testing $(RepositoryToBuild) ============" Importance="High" />
 
 
-    <Exec
+    <Exec Condition="'$(SkipTestsDueToMissingSharedFx)' != 'true' "
       Command="./$(_BuildScriptToExecute) -Path $(BuildRepositoryRoot) $(BuildArguments)"
       Command="./$(_BuildScriptToExecute) -Path $(BuildRepositoryRoot) $(BuildArguments)"
       IgnoreStandardErrorWarningFormat="true"
       IgnoreStandardErrorWarningFormat="true"
       WorkingDirectory="$(RepositoryRoot)"
       WorkingDirectory="$(RepositoryRoot)"
@@ -173,7 +179,7 @@
     <CallTarget Targets="_RestoreOriginalRepoLockFile" />
     <CallTarget Targets="_RestoreOriginalRepoLockFile" />
 
 
     <ItemGroup>
     <ItemGroup>
-      <RepositoryTestResult Update="$(RepositoryToBuild)" Success="true" Condition="'$(TestExitCode)' == '0'" />
+      <RepositoryTestResult Update="$(RepositoryToBuild)" Success="true" Condition="'$(TestExitCode)' == '0' OR '$(SkipTestsDueToMissingSharedFx)' == 'true' " />
     </ItemGroup>
     </ItemGroup>
 
 
     <Message Text="============ Done testing $(RepositoryToBuild) ============" Importance="High" />
     <Message Text="============ Done testing $(RepositoryToBuild) ============" Importance="High" />

+ 1 - 6
build/SharedFx.targets

@@ -2,10 +2,6 @@
   <Import Project="common.props" />
   <Import Project="common.props" />
   <Import Project="SharedFx.props" />
   <Import Project="SharedFx.props" />
 
 
-  <PropertyGroup>
-    <GetArtifactInfoDependsOn>$(GetArtifactInfoDependsOn);GetMetapackageArtifactInfo</GetArtifactInfoDependsOn>
-  </PropertyGroup>
-
   <PropertyGroup>
   <PropertyGroup>
     <SharedFxOutputPath>$([MSBuild]::NormalizeDirectory($(ArtifactsDir)))assets\Runtime\$(PackageVersion)\</SharedFxOutputPath>
     <SharedFxOutputPath>$([MSBuild]::NormalizeDirectory($(ArtifactsDir)))assets\Runtime\$(PackageVersion)\</SharedFxOutputPath>
   </PropertyGroup>
   </PropertyGroup>
@@ -71,8 +67,7 @@
       ReferencePackagePath="$(MetapackageWorkDirectory)$(MetapackageName).csproj"
       ReferencePackagePath="$(MetapackageWorkDirectory)$(MetapackageName).csproj"
       MetapackageReferenceType="$(MetapackageReferenceType)"
       MetapackageReferenceType="$(MetapackageReferenceType)"
       DependencyVersionRangeType="$(MetapackageDependencyVersionRangeType)"
       DependencyVersionRangeType="$(MetapackageDependencyVersionRangeType)"
-      BuildArtifacts="@(ArtifactInfo)"
-      PackageArtifacts="@(PackageArtifact)"
+      PackageArtifacts="@(_PackageArtifactSpec)"
       ExternalDependencies="@(ExternalDependency)" />
       ExternalDependencies="@(ExternalDependency)" />
 
 
     <!-- Set _Target=Restore so the project will be re-evaluated to include Internal.AspNetCore.Sdk MSBuild properties on the next step. -->
     <!-- Set _Target=Restore so the project will be re-evaluated to include Internal.AspNetCore.Sdk MSBuild properties on the next step. -->

+ 0 - 78
build/Templating.targets

@@ -1,78 +0,0 @@
-<Project>
-  <PropertyGroup>
-    <TemplatingProjectRoot>$(MSBuildThisFileDirectory)..\modules\Templating\</TemplatingProjectRoot>
-    <GetArtifactInfoDependsOn>$(GetArtifactInfoDependsOn);GetTemplateArtifactInfo</GetArtifactInfoDependsOn>
-    <TestDependsOn>$(TestDependsOn);TestTemplates</TestDependsOn>
-    <InstallSharedRuntimeFromPreviousBuild>false</InstallSharedRuntimeFromPreviousBuild>
-  </PropertyGroup>
-
-  <PropertyGroup>
-    <TemplateProjProperties>
-      RepositoryRoot=$(TemplatingProjectRoot);
-      BuildNumber=$(BuildNumber);
-      Configuration=$(Configuration);
-      IsFinalBuild=$(IsFinalBuild);
-    </TemplateProjProperties>
-  </PropertyGroup>
-
-  <Target Name="GetTemplateArtifactInfo">
-    <MSBuild Projects="$(MSBuildProjectFullPath)"
-      Targets="GetArtifactInfo"
-      Properties="$(TemplateProjProperties);DesignTimeBuild=true">
-      <Output TaskParameter="TargetOutputs" ItemName="ArtifactInfo" />
-    </MSBuild>
-  </Target>
-
-  <Target Name="BuildTemplates" DependsOnTargets="GeneratePropsFiles">
-    <PropertyGroup>
-      <_BuildTemplateProjProperties>
-        $(TemplateProjProperties);
-        SkipAspNetCoreRuntimeInstall=true;
-        DotNetRestoreSourcePropsPath=$(GeneratedRestoreSourcesPropsPath);
-        DotNetPackageVersionPropsPath=$(GeneratedPackageVersionPropsPath);
-        SkipTests=true;
-      </_BuildTemplateProjProperties>
-    </PropertyGroup>
-
-    <MSBuild Projects="$(MSBuildProjectFullPath)"
-             Targets="CleanArtifacts;Build"
-             Properties="$(_BuildTemplateProjProperties)" />
-
-    <ItemGroup>
-      <TemplateArtifacts Include="$(TemplatingProjectRoot)artifacts\build\*" />
-    </ItemGroup>
-
-    <Copy SourceFiles="@(TemplateArtifacts)" DestinationFolder="$(BuildDir)" />
-  </Target>
-
-  <!--
-    aspnet/Universe doesn't support building the shared framework on one machine, so these tests must be manually enabled on CI by copying
-    the output of the SharedFx.targets build to test machines.
-  -->
-  <Target Name="InstallSharedRuntimeFromPreviousBuild" Condition="'$(InstallSharedRuntimeFromPreviousBuild)' == 'true'" BeforeTargets="InstallDotNet">
-    <ItemGroup>
-      <AspNetCoreRuntime Include="$(PackageVersion)" Feed="$(AspNetCoreFxFeed)" />
-    </ItemGroup>
-  </Target>
-
-  <Target Name="TestTemplates" DependsOnTargets="InstallDotNet;BuildTemplates">
-    <!-- To enable this test, either publish the shared runtime to https://dotnetcli.blob.core.windows.net/dotnet, or override the install location by setting AspNetCoreFxFeed. -->
-    <Warning Text="Skipping template tests because InstallSharedRuntimeFromPreviousBuild != 'true'." Condition="'$(InstallSharedRuntimeFromPreviousBuild)' != 'true'"/>
-
-    <PropertyGroup>
-      <_TestTemplateProjProperties>
-        $(TemplateProjProperties);
-        SkipAspNetCoreRuntimeInstall=true;
-        DotNetRestoreSourcePropsPath=$(GeneratedRestoreSourcesPropsPath);
-        DotNetPackageVersionPropsPath=$(GeneratedPackageVersionPropsPath);
-        NoBuild=true;
-      </_TestTemplateProjProperties>
-    </PropertyGroup>
-
-    <MSBuild Projects="$(MSBuildProjectFullPath)"
-             Targets="Build"
-             Properties="$(_TestTemplateProjProperties)"
-             Condition="'$(InstallSharedRuntimeFromPreviousBuild)' == 'true'" />
-  </Target>
-
-</Project>

+ 4 - 4
build/artifacts.props

@@ -33,8 +33,8 @@
     <PackageArtifact Include="Microsoft.AspNetCore.Antiforgery" Category="ship" AppMetapackage="true" AllMetapackage="true"/>
     <PackageArtifact Include="Microsoft.AspNetCore.Antiforgery" Category="ship" AppMetapackage="true" AllMetapackage="true"/>
     <PackageArtifact Include="Microsoft.AspNetCore.App" Category="ship" />
     <PackageArtifact Include="Microsoft.AspNetCore.App" Category="ship" />
     <PackageArtifact Include="Microsoft.AspNetCore.ApplicationInsights.HostingStartup" Category="ship" AllMetapackage="true" />
     <PackageArtifact Include="Microsoft.AspNetCore.ApplicationInsights.HostingStartup" Category="ship" AllMetapackage="true" />
-    <PackageArtifact Include="Microsoft.AspNetCore.AspNetCoreModule" Category="noship" />
-    <PackageArtifact Include="Microsoft.AspNetCore.AspNetCoreModuleV2" Category="noship" />
+    <PackageArtifact Include="Microsoft.AspNetCore.AspNetCoreModule" Category="noship" Condition=" '$(OS)' == 'Windows_NT' " />
+    <PackageArtifact Include="Microsoft.AspNetCore.AspNetCoreModuleV2" Category="noship" Condition=" '$(OS)' == 'Windows_NT' " />
     <PackageArtifact Include="Microsoft.AspNetCore.Authentication.Abstractions" Category="ship" AppMetapackage="true" AllMetapackage="true"/>
     <PackageArtifact Include="Microsoft.AspNetCore.Authentication.Abstractions" Category="ship" AppMetapackage="true" AllMetapackage="true"/>
     <PackageArtifact Include="Microsoft.AspNetCore.Authentication.AzureAD.UI" Category="ship" />
     <PackageArtifact Include="Microsoft.AspNetCore.Authentication.AzureAD.UI" Category="ship" />
     <PackageArtifact Include="Microsoft.AspNetCore.Authentication.AzureADB2C.UI" Category="ship" />
     <PackageArtifact Include="Microsoft.AspNetCore.Authentication.AzureADB2C.UI" Category="ship" />
@@ -147,8 +147,8 @@
     <PackageArtifact Include="Microsoft.AspNetCore.Routing.DecisionTree.Sources" Category="noship" />
     <PackageArtifact Include="Microsoft.AspNetCore.Routing.DecisionTree.Sources" Category="noship" />
     <PackageArtifact Include="Microsoft.AspNetCore.Routing" Category="ship" AppMetapackage="true" AllMetapackage="true"/>
     <PackageArtifact Include="Microsoft.AspNetCore.Routing" Category="ship" AppMetapackage="true" AllMetapackage="true"/>
     <PackageArtifact Include="Microsoft.AspNetCore.Server.HttpSys" Category="ship" AppMetapackage="true" AllMetapackage="true"/>
     <PackageArtifact Include="Microsoft.AspNetCore.Server.HttpSys" Category="ship" AppMetapackage="true" AllMetapackage="true"/>
-    <PackageArtifact Include="Microsoft.AspNetCore.Server.IIS" Category="ship" AppMetapackage="true" AllMetapackage="true" />
-    <PackageArtifact Include="Microsoft.AspNetCore.Server.IISIntegration" Category="ship" AppMetapackage="true" AllMetapackage="true"/>
+    <PackageArtifact Include="Microsoft.AspNetCore.Server.IIS" Category="ship" AppMetapackage="true" AllMetapackage="true" Condition=" '$(OS)' == 'Windows_NT' "  />
+    <PackageArtifact Include="Microsoft.AspNetCore.Server.IISIntegration" Category="ship" AppMetapackage="true" AllMetapackage="true" />
     <PackageArtifact Include="Microsoft.AspNetCore.Server.IntegrationTesting.IIS" Category="noship" />
     <PackageArtifact Include="Microsoft.AspNetCore.Server.IntegrationTesting.IIS" Category="noship" />
     <PackageArtifact Include="Microsoft.AspNetCore.Server.IntegrationTesting" Category="noship" />
     <PackageArtifact Include="Microsoft.AspNetCore.Server.IntegrationTesting" Category="noship" />
     <PackageArtifact Include="Microsoft.AspNetCore.Server.Kestrel.Core" Category="ship" AppMetapackage="true" AllMetapackage="true"/>
     <PackageArtifact Include="Microsoft.AspNetCore.Server.Kestrel.Core" Category="ship" AppMetapackage="true" AllMetapackage="true"/>

+ 1 - 0
build/buildorder.props

@@ -46,6 +46,7 @@
     <RepositoryBuildOrder Include="MusicStore" Order="16" />
     <RepositoryBuildOrder Include="MusicStore" Order="16" />
     <RepositoryBuildOrder Include="SignalR" Order="16" />
     <RepositoryBuildOrder Include="SignalR" Order="16" />
     <RepositoryBuildOrder Include="AuthSamples" Order="16" />
     <RepositoryBuildOrder Include="AuthSamples" Order="16" />
+    <RepositoryBuildOrder Include="Templating" Order="17" />
 
 
     <RepositoryBuildOrder Update="@(RepositoryBuildOrder)" RootPath="$(SubmoduleRoot)%(Identity)" />
     <RepositoryBuildOrder Update="@(RepositoryBuildOrder)" RootPath="$(SubmoduleRoot)%(Identity)" />
   </ItemGroup>
   </ItemGroup>

+ 4 - 3
build/external-dependencies.props

@@ -122,8 +122,8 @@
     <ExternalDependency Include="Newtonsoft.Json.Bson" Version="$(NewtonsoftJsonBsonPackageVersion)" />
     <ExternalDependency Include="Newtonsoft.Json.Bson" Version="$(NewtonsoftJsonBsonPackageVersion)" />
     <ExternalDependency Include="NuGet.Frameworks" Version="$(NuGetFrameworksPackageVersion)" />
     <ExternalDependency Include="NuGet.Frameworks" Version="$(NuGetFrameworksPackageVersion)" />
     <ExternalDependency Include="Oracle.ManagedDataAccess" Version="$(OracleManagedDataAccessPackageVersion)" />
     <ExternalDependency Include="Oracle.ManagedDataAccess" Version="$(OracleManagedDataAccessPackageVersion)" />
-    <ExternalDependency Include="Polly" Version="$(PollyPackageVersion)" />
     <ExternalDependency Include="Polly.Extensions.Http" Version="$(PollyExtensionsHttpPackageVersion)" />
     <ExternalDependency Include="Polly.Extensions.Http" Version="$(PollyExtensionsHttpPackageVersion)" />
+    <ExternalDependency Include="Polly" Version="$(PollyPackageVersion)" />
     <ExternalDependency Include="Remotion.Linq" Version="$(RemotionLinqPackageVersion)" />
     <ExternalDependency Include="Remotion.Linq" Version="$(RemotionLinqPackageVersion)" />
     <ExternalDependency Include="Selenium.Firefox.WebDriver" Version="$(SeleniumFirefoxWebDriverPackageVersion)" />
     <ExternalDependency Include="Selenium.Firefox.WebDriver" Version="$(SeleniumFirefoxWebDriverPackageVersion)" />
     <ExternalDependency Include="Selenium.Support" Version="$(SeleniumSupportPackageVersion)" />
     <ExternalDependency Include="Selenium.Support" Version="$(SeleniumSupportPackageVersion)" />
@@ -147,8 +147,8 @@
     <ExternalDependency Include="System.Interactive.Async" Version="$(SystemInteractiveAsyncPackageVersion)" />
     <ExternalDependency Include="System.Interactive.Async" Version="$(SystemInteractiveAsyncPackageVersion)" />
     <ExternalDependency Include="System.IO.Pipelines" Version="$(SystemIOPipelinesPackageVersion)" />
     <ExternalDependency Include="System.IO.Pipelines" Version="$(SystemIOPipelinesPackageVersion)" />
     <ExternalDependency Include="System.Memory" Version="$(SystemMemoryPackageVersion)" />
     <ExternalDependency Include="System.Memory" Version="$(SystemMemoryPackageVersion)" />
-    <ExternalDependency Include="System.Net.Http" Version="$(SystemNetHttpPackageVersion)" />
     <ExternalDependency Include="System.Net.Http.WinHttpHandler" Version="$(SystemNetHttpWinHttpHandlerPackageVersion)" />
     <ExternalDependency Include="System.Net.Http.WinHttpHandler" Version="$(SystemNetHttpWinHttpHandlerPackageVersion)" />
+    <ExternalDependency Include="System.Net.Http" Version="$(SystemNetHttpPackageVersion)" />
     <ExternalDependency Include="System.Net.WebSockets.WebSocketProtocol" Version="$(SystemNetWebSocketsWebSocketProtocolPackageVersion)" />
     <ExternalDependency Include="System.Net.WebSockets.WebSocketProtocol" Version="$(SystemNetWebSocketsWebSocketProtocolPackageVersion)" />
     <ExternalDependency Include="System.Numerics.Vectors" Version="$(SystemNumericsVectorsPackageVersion)" />
     <ExternalDependency Include="System.Numerics.Vectors" Version="$(SystemNumericsVectorsPackageVersion)" />
     <ExternalDependency Include="System.Reactive.Linq" Version="$(SystemReactiveLinqPackageVersion)" />
     <ExternalDependency Include="System.Reactive.Linq" Version="$(SystemReactiveLinqPackageVersion)" />
@@ -168,7 +168,6 @@
     <ExternalDependency Include="System.ValueTuple" Version="$(SystemValueTuplePackageVersion)" />
     <ExternalDependency Include="System.ValueTuple" Version="$(SystemValueTuplePackageVersion)" />
     <ExternalDependency Include="Utf8Json" Version="$(Utf8JsonPackageVersion)" />
     <ExternalDependency Include="Utf8Json" Version="$(Utf8JsonPackageVersion)" />
     <ExternalDependency Include="WindowsAzure.Storage" Version="$(WindowsAzureStoragePackageVersion)" />
     <ExternalDependency Include="WindowsAzure.Storage" Version="$(WindowsAzureStoragePackageVersion)" />
-    <ExternalDependency Include="xunit" Version="$(XunitPackageVersion)" />
     <ExternalDependency Include="xunit.abstractions" Version="$(XunitAbstractionsPackageVersion)" />
     <ExternalDependency Include="xunit.abstractions" Version="$(XunitAbstractionsPackageVersion)" />
     <ExternalDependency Include="xunit.analyzers" Version="$(XunitAnalyzersPackageVersion)" />
     <ExternalDependency Include="xunit.analyzers" Version="$(XunitAnalyzersPackageVersion)" />
     <ExternalDependency Include="xunit.assert" Version="$(XunitAssertPackageVersion)" />
     <ExternalDependency Include="xunit.assert" Version="$(XunitAssertPackageVersion)" />
@@ -176,5 +175,7 @@
     <ExternalDependency Include="xunit.extensibility.core" Version="$(XunitExtensibilityCorePackageVersion)" />
     <ExternalDependency Include="xunit.extensibility.core" Version="$(XunitExtensibilityCorePackageVersion)" />
     <ExternalDependency Include="xunit.extensibility.execution" Version="$(XunitExtensibilityExecutionPackageVersion)" />
     <ExternalDependency Include="xunit.extensibility.execution" Version="$(XunitExtensibilityExecutionPackageVersion)" />
     <ExternalDependency Include="xunit.runner.visualstudio" Version="$(XunitRunnerVisualstudioPackageVersion)" />
     <ExternalDependency Include="xunit.runner.visualstudio" Version="$(XunitRunnerVisualstudioPackageVersion)" />
+    <ExternalDependency Include="xunit" Version="$(XunitPackageVersion)" />
   </ItemGroup>
   </ItemGroup>
+
 </Project>
 </Project>

+ 6 - 0
build/repo.props

@@ -52,6 +52,12 @@
       Arch="x86"
       Arch="x86"
       Feed="$(DotNetAssetRootUrl)"
       Feed="$(DotNetAssetRootUrl)"
       FeedCredential="$(DotNetAssetRootAccessTokenSuffix)" />
       FeedCredential="$(DotNetAssetRootAccessTokenSuffix)" />
+    
+      <!--
+        The build doesn't support compiling the shared runtime on one machine along with running tests,
+        so this is enables installing the shared runtime from a previous build.
+      -->
+      <AspNetCoreRuntime Include="$(PackageVersion)" Feed="$(AspNetCoreFxFeed)" Condition="'$(InstallSharedRuntimeFromPreviousBuild)' == 'true'" />
   </ItemGroup>
   </ItemGroup>
 
 
   <!-- Properties for publishing -->
   <!-- Properties for publishing -->

+ 44 - 19
build/repo.targets

@@ -2,7 +2,6 @@
   <Import Project="RepositoryBuild.targets" />
   <Import Project="RepositoryBuild.targets" />
   <Import Project="PackageArchive.targets" />
   <Import Project="PackageArchive.targets" />
   <Import Project="AzureIntegration.targets" />
   <Import Project="AzureIntegration.targets" />
-  <Import Project="Templating.targets" />
   <Import Project="SharedFx.targets" />
   <Import Project="SharedFx.targets" />
   <Import Project="SharedFxInstaller.targets" />
   <Import Project="SharedFxInstaller.targets" />
   <Import Project="Publish.targets" />
   <Import Project="Publish.targets" />
@@ -20,17 +19,16 @@
     <CleanDependsOn>$(CleanDependsOn);CleanArtifacts;CleanUniverseArtifacts</CleanDependsOn>
     <CleanDependsOn>$(CleanDependsOn);CleanArtifacts;CleanUniverseArtifacts</CleanDependsOn>
     <RestoreDependsOn>$(RestoreDependsOn);InstallDotNet</RestoreDependsOn>
     <RestoreDependsOn>$(RestoreDependsOn);InstallDotNet</RestoreDependsOn>
     <CompileDependsOn>$(CompileDependsOn);BuildRepositories</CompileDependsOn>
     <CompileDependsOn>$(CompileDependsOn);BuildRepositories</CompileDependsOn>
-    <PackageDependsOn Condition="'$(TestOnly)' != 'true'">$(PackageDependsOn);BuildMetapackages;BuildTemplates;CheckExpectedPackagesExist</PackageDependsOn>
+    <PackageDependsOn Condition="'$(TestOnly)' != 'true'">$(PackageDependsOn);BuildMetapackages;CheckExpectedPackagesExist</PackageDependsOn>
     <TestDependsOn>$(TestDependsOn);_TestRepositories</TestDependsOn>
     <TestDependsOn>$(TestDependsOn);_TestRepositories</TestDependsOn>
-    <VerifyDependsOn Condition="'$(TestOnly)' != 'true'">$(VerifyDependsOn);VerifyCoherentVersions</VerifyDependsOn>
-    <GetArtifactInfoDependsOn>$(GetArtifactInfoDependsOn);ResolveRepoInfo;GetLineupPackageInfo</GetArtifactInfoDependsOn>
+    <GetArtifactInfoDependsOn>$(GetArtifactInfoDependsOn);ResolveRepoInfo</GetArtifactInfoDependsOn>
   </PropertyGroup>
   </PropertyGroup>
 
 
   <Target Name="PrepareOutputPaths">
   <Target Name="PrepareOutputPaths">
     <MakeDir Directories="$(ArtifactsDir);$(BuildDir)" />
     <MakeDir Directories="$(ArtifactsDir);$(BuildDir)" />
   </Target>
   </Target>
 
 
-  <Target Name="ResolveRepoInfo" DependsOnTargets="_PrepareRepositories">
+  <Target Name="ResolveRepoInfo" DependsOnTargets="_PrepareRepositories;GetMetapackageArtifactInfo;GetLineupPackageInfo">
     <!-- We need to pass the NETCoreApp package versions to msbuild so that it doesn't complain about us using a different one than it was restored against.  -->
     <!-- We need to pass the NETCoreApp package versions to msbuild so that it doesn't complain about us using a different one than it was restored against.  -->
     <PropertyGroup>
     <PropertyGroup>
       <DesignTimeBuildProps>MicrosoftNETCoreAppPackageVersion=$(MicrosoftNETCoreAppPackageVersion);</DesignTimeBuildProps>
       <DesignTimeBuildProps>MicrosoftNETCoreAppPackageVersion=$(MicrosoftNETCoreAppPackageVersion);</DesignTimeBuildProps>
@@ -76,8 +74,41 @@
     </MSBuild>
     </MSBuild>
 
 
     <ItemGroup>
     <ItemGroup>
-      <Solution Update="@(Solution)" Build="true" />
-      <_ShippedSolution Update="@(_ShippedSolution)" Build="false" Shipped="true" />
+      <_Temp Remove="@(_Temp)" />
+      <_Temp Include="@(PackageArtifact)" />
+      <PackageArtifact Remove="@(PackageArtifact)" />
+    </ItemGroup>
+
+    <!-- Join required because shipping category is stored in universe (PackageArtifact), but information about package ID and version comes from repos (ArtifactInfo). -->
+    <RepoTasks.JoinItems
+      Left="@(_Temp)"
+      LeftMetadata="*"
+      Right="@(ArtifactInfo->WithMetadataValue('ArtifactType','NuGetPackage'));@(ShippedArtifactInfo->WithMetadataValue('ArtifactType','NuGetPackage'))"
+      RightKey="PackageId"
+      RightMetadata="Version">
+      <Output TaskParameter="JoinResult" ItemName="PackageArtifact" />
+    </RepoTasks.JoinItems>
+
+    <ItemGroup>
+      <_PackageArtifactWithoutMatchingInfo Include="@(_Temp)" Exclude="@(PackageArtifact)" />
+    </ItemGroup>
+
+    <Error Text="Could not detect version information for package id:%0A * @(_PackageArtifactWithoutMatchingInfo, '%0A * ')"
+           Condition="@(_PackageArtifactWithoutMatchingInfo->Count()) != 0" />
+
+    <ItemGroup>
+      <!-- Adjust the list of what is considered external vs locally built. -->
+      <ExternalDependency Include="%(ShippedArtifactInfo.PackageId)" Condition="'%(ShippedArtifactInfo.ArtifactType)' == 'NuGetPackage'">
+        <Version>%(ShippedArtifactInfo.Version)</Version>
+      </ExternalDependency>
+
+      <!-- capture the original list of PackageArtifacts -->
+      <_PackageArtifactSpec Include="@(PackageArtifact)" />
+
+      <PackageArtifact Remove="%(ShippedArtifactInfo.PackageId)" Condition="'%(ShippedArtifactInfo.ArtifactType)' == 'NuGetPackage'" />
+
+      <Solution Update="@(Solution)" Build="true" IsPatching="true" />
+      <_ShippedSolution Update="@(_ShippedSolution)" Build="false" IsPatching="false" />
       <_NoBuildSolution Update="@(_NoBuildSolution)" Build="false" />
       <_NoBuildSolution Update="@(_NoBuildSolution)" Build="false" />
       <Solution Include="@(_NoBuildSolution);@(_ShippedSolution)" />
       <Solution Include="@(_NoBuildSolution);@(_ShippedSolution)" />
     </ItemGroup>
     </ItemGroup>
@@ -183,6 +214,10 @@
   <Target Name="BuildRepositories"
   <Target Name="BuildRepositories"
      DependsOnTargets="_PrepareRepositories;GeneratePropsFiles;ComputeGraph;_BuildRepositories" />
      DependsOnTargets="_PrepareRepositories;GeneratePropsFiles;ComputeGraph;_BuildRepositories" />
 
 
+  <Target Name="ListExpectedPackages" DependsOnTargets="ResolveRepoInfo">
+    <WriteLinesToFile File="$(RepositoryRoot)artifacts\packages.csv" Lines="PackageId,Version;@(ArtifactInfo->WithMetadataValue('ArtifactType', 'NuGetPackage')->'%(PackageId),%(Version)')" Overwrite="true" />
+  </Target>
+
   <Target Name="ComputeGraph" DependsOnTargets="ResolveRepoInfo;GeneratePropsFiles">
   <Target Name="ComputeGraph" DependsOnTargets="ResolveRepoInfo;GeneratePropsFiles">
     <RepoTasks.CheckRepoGraph Condition=" ! $([MSBuild]::IsOSUnixLike())"
     <RepoTasks.CheckRepoGraph Condition=" ! $([MSBuild]::IsOSUnixLike())"
       Solutions="@(Solution)"
       Solutions="@(Solution)"
@@ -201,7 +236,8 @@
     <!-- Skipped to workaround #1014. The order is hardcoded in buildorder.props -->
     <!-- Skipped to workaround #1014. The order is hardcoded in buildorder.props -->
     <RepoTasks.AnalyzeBuildGraph Condition=" ! $([MSBuild]::IsOSUnixLike())"
     <RepoTasks.AnalyzeBuildGraph Condition=" ! $([MSBuild]::IsOSUnixLike())"
       Solutions="@(Solution)"
       Solutions="@(Solution)"
-      Artifacts="@(ArtifactInfo)"
+      Artifacts="@(ArtifactInfo);@(ShippedArtifactInfo)"
+      Repositories="@(Repository);@(ShippedRepository)"
       Dependencies="@(ExternalDependency)"
       Dependencies="@(ExternalDependency)"
       StartGraphAt="$(BuildGraphOf)"
       StartGraphAt="$(BuildGraphOf)"
       Properties="Configuration=$(Configuration);BuildNumber=$(BuildNumber);DotNetPackageVersionPropsPath=$(GeneratedPackageVersionPropsPath);DotNetRestoreSourcePropsPath=$(GeneratedRestoreSourcesPropsPath)">
       Properties="Configuration=$(Configuration);BuildNumber=$(BuildNumber);DotNetPackageVersionPropsPath=$(GeneratedPackageVersionPropsPath);DotNetRestoreSourcePropsPath=$(GeneratedRestoreSourcesPropsPath)">
@@ -241,17 +277,6 @@
   <Target Name="CheckUniverse"
   <Target Name="CheckUniverse"
     DependsOnTargets="ComputeGraph;VerifyPackageArtifactConfig;VerifyAllReposHaveNuGetPackageVerifier" />
     DependsOnTargets="ComputeGraph;VerifyPackageArtifactConfig;VerifyAllReposHaveNuGetPackageVerifier" />
 
 
-  <Target Name="VerifyCoherentVersions" DependsOnTargets="ResolveRepoInfo">
-    <ItemGroup>
-      <ShippingPackageFiles Include="$(BuildDir)*.nupkg" Exclude="$(BuildDir)*.symbols.nupkg" />
-      <ShippedExternalDependency Include="%(ShippedArtifactInfo.PackageId)" Version="%(ShippedArtifactInfo.Version)" Condition="'%(ShippedArtifactInfo.ArtifactType)' == 'NuGetPackage' " />
-    </ItemGroup>
-
-    <RepoTasks.VerifyCoherentVersions
-      PackageFiles="@(ShippingPackageFiles)"
-      ExternalDependencies="@(ExternalDependency);@(ShippedExternalDependency)" />
-  </Target>
-
   <Target Name="CheckExpectedPackagesExist">
   <Target Name="CheckExpectedPackagesExist">
     <ItemGroup>
     <ItemGroup>
       <PackageArtifactFile Include="$(BuildDir)*.nupkg" Exclude="$(BuildDir)*.symbols.nupkg" />
       <PackageArtifactFile Include="$(BuildDir)*.nupkg" Exclude="$(BuildDir)*.symbols.nupkg" />

+ 36 - 5
build/submodules.props

@@ -2,13 +2,40 @@
   <ItemDefinitionGroup>
   <ItemDefinitionGroup>
     <Repository>
     <Repository>
       <Build>true</Build>
       <Build>true</Build>
+
+      <!--
+        Specifies the ruleset used to determine if a repo should build in a patch update, or not.
+        The default is ProductChangesOnly.
+
+        Rulesets:
+          ProductChangeOnly
+            Only produce new package versions if there were changes to product code.
+            Examples: this is the default. Most repos should use this policy.
+
+          CascadeVersion
+            Produce new package versions if there were changes to product code, or if one of the package dependencies has updated.
+            Examples: metapackages which are not top-level, but should still be used to help users get the latest transitive set of dependencies
+
+          AlwaysUpdate
+            Packages should update in every patch.
+            Examples: top-level metapackages and templates.
+
+       -->
+      <PatchPolicy>ProductChangesOnly</PatchPolicy>
     </Repository>
     </Repository>
+    <ShippedRepository>
+      <Build>false</Build>
+      <PatchPolicy>ProductChangesOnly</PatchPolicy>
+    </ShippedRepository>
   </ItemDefinitionGroup>
   </ItemDefinitionGroup>
 
 
+  <PropertyGroup>
+    <TestsRequiredTheSharedRuntime Condition="'$(RepositoryToBuild)' == 'Templating'">true</TestsRequiredTheSharedRuntime>
+  </PropertyGroup>
+
   <ItemGroup>
   <ItemGroup>
     <Repository Include="AADIntegration" />
     <Repository Include="AADIntegration" />
     <Repository Include="Antiforgery" />
     <Repository Include="Antiforgery" />
-    <Repository Include="AuthSamples" />
     <Repository Include="AzureIntegration" />
     <Repository Include="AzureIntegration" />
     <Repository Include="BasicMiddleware" />
     <Repository Include="BasicMiddleware" />
     <Repository Include="BrowserLink" />
     <Repository Include="BrowserLink" />
@@ -35,9 +62,8 @@
     <Repository Include="KestrelHttpServer" />
     <Repository Include="KestrelHttpServer" />
     <Repository Include="Localization" />
     <Repository Include="Localization" />
     <Repository Include="Logging" />
     <Repository Include="Logging" />
-    <Repository Include="MetaPackages" />
+    <Repository Include="MetaPackages" PatchPolicy="CascadeVersions" />
     <Repository Include="Microsoft.Data.Sqlite" />
     <Repository Include="Microsoft.Data.Sqlite" />
-    <Repository Include="MusicStore" />
     <Repository Include="Mvc" />
     <Repository Include="Mvc" />
     <Repository Include="MvcPrecompilation" />
     <Repository Include="MvcPrecompilation" />
     <Repository Include="Options" />
     <Repository Include="Options" />
@@ -45,12 +71,17 @@
     <Repository Include="Razor" />
     <Repository Include="Razor" />
     <Repository Include="ResponseCaching" />
     <Repository Include="ResponseCaching" />
     <Repository Include="Routing" />
     <Repository Include="Routing" />
-    <Repository Include="Scaffolding" />
+    <Repository Include="Scaffolding" PatchPolicy="AlwaysUpdate" />
     <Repository Include="Security" />
     <Repository Include="Security" />
-    <Repository Include="ServerTests" />
     <Repository Include="Session" />
     <Repository Include="Session" />
     <Repository Include="SignalR" />
     <Repository Include="SignalR" />
     <Repository Include="StaticFiles" />
     <Repository Include="StaticFiles" />
+    <Repository Include="Templating" PatchPolicy="AlwaysUpdateAndCascadeVersions" />
     <Repository Include="WebSockets" />
     <Repository Include="WebSockets" />
+
+    <!-- Test-only repos -->
+    <Repository Include="AuthSamples" PatchPolicy="AlwaysUpdateAndCascadeVersions" />
+    <Repository Include="MusicStore" PatchPolicy="AlwaysUpdateAndCascadeVersions" />
+    <Repository Include="ServerTests" PatchPolicy="AlwaysUpdateAndCascadeVersions" />
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 1 - 19
build/tasks/AddMetapackageReferences.cs

@@ -29,9 +29,6 @@ namespace RepoTasks
             MajorMinor, // [1.1.1, 1.2.0)
             MajorMinor, // [1.1.1, 1.2.0)
         }
         }
 
 
-        [Required]
-        public ITaskItem[] BuildArtifacts { get; set; }
-
         [Required]
         [Required]
         public ITaskItem[] PackageArtifacts { get; set; }
         public ITaskItem[] PackageArtifacts { get; set; }
 
 
@@ -49,9 +46,6 @@ namespace RepoTasks
             // Parse input
             // Parse input
             var metapackageArtifacts = PackageArtifacts.Where(p => p.GetMetadata(MetapackageReferenceType) == "true");
             var metapackageArtifacts = PackageArtifacts.Where(p => p.GetMetadata(MetapackageReferenceType) == "true");
             var externalArtifacts = ExternalDependencies.Where(p => p.GetMetadata(MetapackageReferenceType) == "true");
             var externalArtifacts = ExternalDependencies.Where(p => p.GetMetadata(MetapackageReferenceType) == "true");
-            var buildArtifacts = BuildArtifacts.Select(ArtifactInfo.Parse)
-                .OfType<ArtifactInfo.Package>()
-                .Where(p => !p.IsSymbolsArtifact);
 
 
             var xmlDoc = new XmlDocument();
             var xmlDoc = new XmlDocument();
             xmlDoc.Load(ReferencePackagePath);
             xmlDoc.Load(ReferencePackagePath);
@@ -66,19 +60,7 @@ namespace RepoTasks
             foreach (var package in metapackageArtifacts)
             foreach (var package in metapackageArtifacts)
             {
             {
                 var packageName = package.ItemSpec;
                 var packageName = package.ItemSpec;
-                string packageVersion;
-                try
-                {
-                    packageVersion = buildArtifacts
-                        .Single(p => string.Equals(p.PackageInfo.Id, packageName, StringComparison.OrdinalIgnoreCase))
-                        .PackageInfo.Version.ToString();
-                }
-                catch (InvalidOperationException)
-                {
-                    Log.LogError($"Missing Package: {packageName} from build artifacts");
-                    throw;
-                }
-
+                var packageVersion = package.GetMetadata("Version");
                 if (string.IsNullOrEmpty(packageVersion))
                 if (string.IsNullOrEmpty(packageVersion))
                 {
                 {
                     Log.LogError("Missing version information for package {0}", packageName);
                     Log.LogError("Missing version information for package {0}", packageName);

+ 30 - 16
build/tasks/AnalyzeBuildGraph.cs

@@ -29,6 +29,9 @@ namespace RepoTasks
         [Required]
         [Required]
         public ITaskItem[] Artifacts { get; set; }
         public ITaskItem[] Artifacts { get; set; }
 
 
+        [Required]
+        public ITaskItem[] Repositories { get; set; }
+
         [Required]
         [Required]
         public ITaskItem[] Dependencies { get; set; }
         public ITaskItem[] Dependencies { get; set; }
 
 
@@ -67,6 +70,18 @@ namespace RepoTasks
             var solutions = factory.Create(Solutions, props, defaultConfig, _cts.Token);
             var solutions = factory.Create(Solutions, props, defaultConfig, _cts.Token);
             Log.LogMessage($"Found {solutions.Count} and {solutions.Sum(p => p.Projects.Count)} projects");
             Log.LogMessage($"Found {solutions.Count} and {solutions.Sum(p => p.Projects.Count)} projects");
 
 
+            var policies = new Dictionary<string, PatchPolicy>();
+            foreach (var repo in Repositories)
+            {
+                policies.Add(repo.ItemSpec, Enum.Parse<PatchPolicy>(repo.GetMetadata("PatchPolicy")));
+            }
+
+            foreach (var solution in solutions)
+            {
+                var repoName = Path.GetFileName(solution.Directory);
+                solution.PatchPolicy = policies[repoName];
+            }
+
             if (_cts.IsCancellationRequested)
             if (_cts.IsCancellationRequested)
             {
             {
                 return false;
                 return false;
@@ -107,9 +122,7 @@ namespace RepoTasks
             }
             }
 
 
             var inconsistentVersions = new List<VersionMismatch>();
             var inconsistentVersions = new List<VersionMismatch>();
-            var reposThatShouldPatch = new HashSet<string>();
 
 
-            // TODO cleanup the 4-deep nested loops
             foreach (var solution in solutions)
             foreach (var solution in solutions)
             foreach (var project in solution.Projects)
             foreach (var project in solution.Projects)
             foreach (var tfm in project.Frameworks)
             foreach (var tfm in project.Frameworks)
@@ -155,19 +168,25 @@ namespace RepoTasks
                     continue;
                     continue;
                 }
                 }
 
 
-                if (!solution.ShouldBuild && solution.Shipped)
+                var shouldCascade = (solution.PatchPolicy & PatchPolicy.CascadeVersions) != 0;
+                if (!solution.ShouldBuild && !solution.IsPatching && shouldCascade)
                 {
                 {
-                    reposThatShouldPatch.Add(Path.GetFileName(Path.GetDirectoryName(solution.FullPath)));
+                    var repoName = Path.GetFileName(Path.GetDirectoryName(solution.FullPath));
+                    Log.LogError($"{repoName} should not be marked 'IsPatching=false'. Version changes in other repositories mean it should be patched to perserve cascading version upgrades.");
+
                 }
                 }
 
 
-                inconsistentVersions.Add(new VersionMismatch
+                if (shouldCascade)
                 {
                 {
-                    Solution = solution,
-                    Project = project,
-                    PackageId = dependency.Key,
-                    ActualVersion = dependencyVersion,
-                    ExpectedVersion = package.PackageInfo.Version,
-                });
+                    inconsistentVersions.Add(new VersionMismatch
+                    {
+                        Solution = solution,
+                        Project = project,
+                        PackageId = dependency.Key,
+                        ActualVersion = dependency.Value.Version,
+                        ExpectedVersion = package.PackageInfo.Version,
+                    });
+                }
             }
             }
 
 
             if (inconsistentVersions.Count != 0)
             if (inconsistentVersions.Count != 0)
@@ -200,11 +219,6 @@ namespace RepoTasks
                     Log.LogMessage(MessageImportance.Normal, $"Potentially unused external dependency: {item.PackageId}/{item.Version}. See https://github.com/aspnet/Universe/wiki/Build-warning-and-error-codes for details.");
                     Log.LogMessage(MessageImportance.Normal, $"Potentially unused external dependency: {item.PackageId}/{item.Version}. See https://github.com/aspnet/Universe/wiki/Build-warning-and-error-codes for details.");
                 }
                 }
             }
             }
-
-            foreach (var repo in reposThatShouldPatch)
-            {
-                Log.LogError($"{repo} should not be a 'ShippedRepository'. Version changes in other repositories mean it should be patched to perserve cascading version upgrades.");
-            }
         }
         }
 
 
         private ITaskItem[] GetRepositoryBuildOrder(IEnumerable<ArtifactInfo.Package> artifacts, IEnumerable<SolutionInfo> solutions)
         private ITaskItem[] GetRepositoryBuildOrder(IEnumerable<ArtifactInfo.Package> artifacts, IEnumerable<SolutionInfo> solutions)

+ 11 - 2
build/tasks/CheckRepoGraph.cs

@@ -155,6 +155,15 @@ namespace RepoTasks
                 var repoName = GetDirectoryName(src.Directory);
                 var repoName = GetDirectoryName(src.Directory);
                 var repo = repos[repoName];
                 var repo = repos[repoName];
 
 
+                var policy = Enum.Parse<PatchPolicy>(repo.GetMetadata("PatchPolicy"));
+
+                if ((policy & PatchPolicy.AlwaysUpdate) != 0 && !src.IsPatching)
+                {
+                    Log.LogError($"{repoName} is not currently set to patch, but it should because the policy is set to always include this in servicing updates. Update the configuration in submodule.props.");
+                    continue;
+                }
+
+                var srcShouldCascade = (policy & PatchPolicy.CascadeVersions) != 0;
                 for (var j = 0; j < repoGraph.Count; j++)
                 for (var j = 0; j < repoGraph.Count; j++)
                 {
                 {
                     if (j == i) continue;
                     if (j == i) continue;
@@ -164,9 +173,9 @@ namespace RepoTasks
                         var targetRepoName = GetDirectoryName(target.Directory);
                         var targetRepoName = GetDirectoryName(target.Directory);
                         var targetRepo = repos[targetRepoName];
                         var targetRepo = repos[targetRepoName];
 
 
-                        if (src.Shipped && !target.Shipped)
+                        if (srcShouldCascade && !src.IsPatching && target.IsPatching)
                         {
                         {
-                            Log.LogError($"{repoName} cannot depend on {targetRepoName}. Repos marked as 'Shipped' cannot depend on repos that are rebuilding. Update the configuration in submodule.props.");
+                            Log.LogError($"{repoName} should be patching because it depend on {targetRepoName} and its patch policy is to cascade version changes. Update the configuration in submodule.props.");
                         }
                         }
                     }
                     }
                 }
                 }

+ 31 - 0
build/tasks/ProjectModel/PatchPolicy.cs

@@ -0,0 +1,31 @@
+// 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.Linq;
+using NuGet.Frameworks;
+
+namespace RepoTasks.ProjectModel
+{
+    [Flags]
+    internal enum PatchPolicy
+    {
+        /// <summary>
+        ///     Only produce new package versions if there were changes to product code.
+        /// </summary>
+        ProductChangesOnly = 1 << 0,
+
+        /// <summary>
+        ///     Packages should update in every patch.
+        /// </summary>
+        AlwaysUpdate = 1 << 1,
+
+        /// <summary>
+        ///     Produce new package versions if there were changes to product code, or if one of the package dependencies has updated.
+        /// </summary>
+        CascadeVersions = 1 << 2,
+
+        AlwaysUpdateAndCascadeVersions = CascadeVersions | AlwaysUpdate,
+    }
+}

+ 4 - 4
build/tasks/ProjectModel/SolutionInfo.cs

@@ -9,7 +9,7 @@ namespace RepoTasks.ProjectModel
 {
 {
     internal class SolutionInfo
     internal class SolutionInfo
     {
     {
-        public SolutionInfo(string fullPath, string configName, IReadOnlyList<ProjectInfo> projects, bool shouldBuild, bool shipped)
+        public SolutionInfo(string fullPath, string configName, IReadOnlyList<ProjectInfo> projects, bool shouldBuild, bool isPatching)
         {
         {
             if (string.IsNullOrEmpty(fullPath))
             if (string.IsNullOrEmpty(fullPath))
             {
             {
@@ -26,8 +26,7 @@ namespace RepoTasks.ProjectModel
             ConfigName = configName;
             ConfigName = configName;
             Projects = projects ?? throw new ArgumentNullException(nameof(projects));
             Projects = projects ?? throw new ArgumentNullException(nameof(projects));
             ShouldBuild = shouldBuild;
             ShouldBuild = shouldBuild;
-            Shipped = shipped;
-
+            IsPatching = isPatching;
             foreach (var proj in Projects)
             foreach (var proj in Projects)
             {
             {
                 proj.SolutionInfo = this;
                 proj.SolutionInfo = this;
@@ -39,6 +38,7 @@ namespace RepoTasks.ProjectModel
         public string ConfigName { get; }
         public string ConfigName { get; }
         public IReadOnlyList<ProjectInfo> Projects { get; }
         public IReadOnlyList<ProjectInfo> Projects { get; }
         public bool ShouldBuild { get; }
         public bool ShouldBuild { get; }
-        public bool Shipped { get; }
+        public bool IsPatching { get; }
+        public PatchPolicy PatchPolicy { get; set; }
     }
     }
 }
 }

+ 2 - 2
build/tasks/ProjectModel/SolutionInfoFactory.cs

@@ -85,14 +85,14 @@ namespace RepoTasks.ProjectModel
                 }
                 }
 
 
                 bool.TryParse(solution.GetMetadata("Build"), out var shouldBuild);
                 bool.TryParse(solution.GetMetadata("Build"), out var shouldBuild);
-                bool.TryParse(solution.GetMetadata("Shipped"), out var shipped);
+                bool.TryParse(solution.GetMetadata("IsPatching"), out var isPatching);
 
 
                 var solutionInfo = new SolutionInfo(
                 var solutionInfo = new SolutionInfo(
                     solutionFile,
                     solutionFile,
                     configName,
                     configName,
                     projects.ToArray(),
                     projects.ToArray(),
                     shouldBuild,
                     shouldBuild,
-                    shipped);
+                    isPatching);
 
 
                 _buildEngine.RegisterTaskObject(key, solutionInfo, RegisteredTaskObjectLifetime.Build, allowEarlyCollection: true);
                 _buildEngine.RegisterTaskObject(key, solutionInfo, RegisteredTaskObjectLifetime.Build, allowEarlyCollection: true);
 
 

+ 0 - 1
build/tasks/RepoTasks.tasks

@@ -18,7 +18,6 @@
   <UsingTask TaskName="RepoTasks.PublishToAzureBlob" AssemblyFile="$(_RepoTaskAssembly)" />
   <UsingTask TaskName="RepoTasks.PublishToAzureBlob" AssemblyFile="$(_RepoTaskAssembly)" />
   <UsingTask TaskName="RepoTasks.ResolveSymbolsRecursivePath" AssemblyFile="$(_RepoTaskAssembly)" />
   <UsingTask TaskName="RepoTasks.ResolveSymbolsRecursivePath" AssemblyFile="$(_RepoTaskAssembly)" />
   <UsingTask TaskName="RepoTasks.TrimDeps" AssemblyFile="$(_RepoTaskAssembly)" />
   <UsingTask TaskName="RepoTasks.TrimDeps" AssemblyFile="$(_RepoTaskAssembly)" />
-  <UsingTask TaskName="RepoTasks.VerifyCoherentVersions" AssemblyFile="$(_RepoTaskAssembly)" />
 
 
   <!-- tools from dotnet-buildtools -->
   <!-- tools from dotnet-buildtools -->
   <PropertyGroup>
   <PropertyGroup>

+ 0 - 150
build/tasks/VerifyCoherentVersions.cs

@@ -1,150 +0,0 @@
-// 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.Linq;
-using Microsoft.Build.Framework;
-using NuGet.Packaging;
-using RepoTasks.ProjectModel;
-
-namespace RepoTasks
-{
-    public class VerifyCoherentVersions : Microsoft.Build.Utilities.Task
-    {
-        [Required]
-        public ITaskItem[] PackageFiles { get; set; }
-
-        [Required]
-        public ITaskItem[] ExternalDependencies { get; set; }
-
-        public override bool Execute()
-        {
-            if (PackageFiles.Length == 0)
-            {
-                Log.LogError("Did not find any packages to verify for version coherence");
-                return false;
-            }
-
-            var packageLookup = new Dictionary<string, PackageInfo>(StringComparer.OrdinalIgnoreCase);
-            var dependencyMap = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
-
-            foreach (var dep in ExternalDependencies)
-            {
-                if (!dependencyMap.TryGetValue(dep.ItemSpec, out var list))
-                {
-                    dependencyMap[dep.ItemSpec] = list = new List<string>();
-                }
-
-                list.Add(dep.GetMetadata("Version"));
-            }
-
-            foreach (var file in PackageFiles)
-            {
-                PackageInfo package;
-                using (var reader = new PackageArchiveReader(file.ItemSpec))
-                {
-                    var identity = reader.GetIdentity();
-                    var metadata = new PackageBuilder(reader.GetNuspec(), basePath: null);
-                    package = new PackageInfo(identity.Id, identity.Version,
-                        source: Path.GetDirectoryName(file.ItemSpec),
-                        dependencyGroups: metadata.DependencyGroups.ToArray());
-                }
-
-                if (packageLookup.TryGetValue(package.Id, out var existingPackage))
-                {
-                    Log.LogError("Multiple copies of the following package were found: " +
-                        Environment.NewLine +
-                        existingPackage +
-                        Environment.NewLine +
-                        package);
-                    continue;
-                }
-
-                packageLookup[package.Id] = package;
-            }
-
-            foreach (var packageInfo in packageLookup.Values)
-            {
-                Visit(packageLookup, dependencyMap, packageInfo);
-            }
-
-            Log.LogMessage(MessageImportance.High, $"Verified {PackageFiles.Length} package(s) have coherent versions");
-            return !Log.HasLoggedErrors;
-        }
-
-        private void Visit(
-            IReadOnlyDictionary<string, PackageInfo> packageLookup,
-            IReadOnlyDictionary<string, List<string>> dependencyMap,
-            PackageInfo packageInfo)
-        {
-            Log.LogMessage(MessageImportance.Low, $"Processing package {packageInfo.Id}");
-            try
-            {
-                foreach (var dependencySet in packageInfo.DependencyGroups)
-                {
-                    foreach (var dependency in dependencySet.Packages)
-                    {
-                        PackageInfo dependencyPackageInfo;
-                        var minVersion = dependency.VersionRange.MinVersion;
-                        var minVersionString = minVersion.ToString();
-                        if (dependencyMap.TryGetValue(dependency.Id, out var externalDepVersions))
-                        {
-                            var matchedVersion = externalDepVersions.FirstOrDefault(d => minVersionString.Equals(d));
-
-                            // If dependency does not match an external dependency version, check if matching version
-                            // will be built in Universe. That's fine in benchmark apps for example.
-                            var universePackageVersion = string.Empty;
-                            if (matchedVersion == null &&
-                                packageLookup.TryGetValue(dependency.Id, out var universePackageInfo))
-                            {
-                                if (universePackageInfo.Version == minVersion)
-                                {
-                                    continue;
-                                }
-
-                                // Include Universe version in following error message.
-                                universePackageVersion = universePackageInfo.Version.ToString();
-                            }
-
-                            if (matchedVersion == null)
-                            {
-                                var versions = string.Join(" or ", externalDepVersions);
-                                if (!string.IsNullOrEmpty(universePackageVersion))
-                                {
-                                    versions += $" or {universePackageVersion}";
-                                }
-
-                                Log.LogError($"Package {packageInfo.Id} has an external dependency on the wrong version of {dependency.Id}. "
-                                    + $"It uses {minVersionString} but only {versions} is allowed.");
-                            }
-
-                            continue;
-                        }
-                        else if (!packageLookup.TryGetValue(dependency.Id, out dependencyPackageInfo))
-                        {
-                            Log.LogError($"Package {packageInfo.Id} has an undefined external dependency on {dependency.Id}/{minVersionString}. " +
-                                "If the package is built in aspnet/Universe, make sure it is also marked as 'ship'. " +
-                                "If it is an external dependency, add it as a new ExternalDependency.");
-                            continue;
-                        }
-
-                        if (dependencyPackageInfo.Version != minVersion)
-                        {
-                            // For any dependency in the universe
-                            // Add a mismatch if the min version doesn't work out
-                            // (we only really care about >= minVersion)
-                            Log.LogError($"{packageInfo.Id} depends on {dependency.Id} " +
-                                    $"{dependency.VersionRange} ({dependencySet.TargetFramework}) when the latest build is {dependencyPackageInfo.Version}.");
-                        }
-                    }
-                }
-            }
-            catch (Exception ex)
-            {
-                Log.LogError($"Unexpected error while attempting to verify package {packageInfo.Id}.\r\n{ex}");
-            }
-        }
-    }
-}

+ 111 - 0
scripts/PatchVersionPrefix.ps1

@@ -0,0 +1,111 @@
+#!/usr/bin/env pwsh -c
+
+<#
+.SYNOPSIS
+    Updates the version.props file in repos to a newer patch version
+.PARAMETER Repos
+    A list of the repositories that should be patched
+.PARAMETER Mode
+    Version bump options: Major, Minor, Patch
+.PARAMETER VersionSuffix
+    The version suffix to use
+#>
+[cmdletbinding(SupportsShouldProcess = $true)]
+param(
+    [Parameter(Mandatory = $true)]
+    [string[]]$Repos,
+    [Parameter(Mandatory = $true)]
+    [ValidateSet('Major', 'Minor', 'Patch')]
+    [string]$Mode,
+    [string]$VersionSuffix = $null,
+    [switch]$NoCommit
+)
+
+$ErrorActionPreference = 'Stop'
+
+Import-Module -Scope Local -Force "$PSScriptRoot/common.psm1"
+
+function SetVersionSuffix([System.Xml.XmlNode]$node) {
+    if (-not $node) {
+        return
+    }
+    $node.InnerText = $VersionSuffix
+    return "Setting $($node.Name) to $VersionSuffix"
+}
+
+function BumpVersion([System.Xml.XmlNode]$node) {
+    if (-not $node) {
+        return
+    }
+    [version] $version = $node.InnerText
+
+    $experimental = $version.Major -eq 0
+
+    switch ($mode) {
+        { ($_ -ne 'Patch') -and $experimental} {
+            $node.InnerText = "{0}.{1}.{2}" -f $version.Major, ($version.Minor + 1), 0
+        }
+        { ($_ -eq 'Major') -and -not $experimental } {
+            $node.InnerText = "{0}.{1}.{2}" -f ($version.Major + 1), 0, 0
+        }
+        { ($_ -eq 'Minor') -and -not $experimental } {
+            $node.InnerText = "{0}.{1}.{2}" -f $version.Major, ($version.Minor + 1), 0
+        }
+        'Patch' {
+            $node.InnerText = "{0}.{1}.{2}" -f $version.Major, $version.Minor, ($version.Build + 1)
+        }
+        default {
+            throw "Could not figure out how to apply patch policy $mode"
+        }
+    }
+    return "Bumping version from $version to $($node.InnerText)"
+}
+
+foreach ($repo in $Repos) {
+    $repoPath = "$PSScriptRoot/../modules/$repo"
+    Push-Location $repoPath
+    try
+    {
+        $path = "$repoPath/version.props"
+        Write-Host -ForegroundColor Magenta "Updating $repo"
+        if (-not (Test-Path $path)) {
+            Write-Warning "$path does not exist"
+            continue
+        }
+        $path = Resolve-Path $path
+        Write-Verbose "$path"
+        [xml] $xml = LoadXml $path
+
+        $suffix = $xml.SelectSingleNode('/Project/PropertyGroup/VersionSuffix')
+        if (-not $suffix) {
+            write-error "$path does not have VersionSuffix"
+        }
+
+        if ($VersionSuffix) {
+            SetVersionSuffix $xml.SelectSingleNode('/Project/PropertyGroup/VersionSuffix') | write-host
+            SetVersionSuffix $xml.SelectSingleNode('/Project/PropertyGroup/ExperimentalProjectVersionSuffix') | write-host
+            SetVersionSuffix $xml.SelectSingleNode('/Project/PropertyGroup/ExperimentalVersionSuffix') | write-host
+        }
+
+        $versionPrefix = $xml.SelectSingleNode('/Project/PropertyGroup/VersionPrefix')
+        $epxVersionPrefix = $xml.SelectSingleNode('/Project/PropertyGroup/ExperimentalProjectVersionPrefix')
+        $exVersionPrefix = $xml.SelectSingleNode('/Project/PropertyGroup/ExperimentalVersionPrefix')
+        BumpVersion $epxVersionPrefix | write-host
+        BumpVersion $exVersionPrefix | write-host
+        $message = BumpVersion $versionPrefix
+        Write-Host $message
+
+        if ($PSCmdlet.ShouldProcess("Update $path")) {
+            SaveXml $xml $path
+            if (-not $NoCommit) {
+                Invoke-Block { & git add $path }
+                Invoke-Block { & git commit -m $message }
+            }
+        }
+    }
+    finally
+    {
+        Pop-Location
+    }
+}
+

+ 5 - 5
src/PackageArchive/Scenario.ConsoleApp/Scenario.ConsoleApp.csproj

@@ -1,17 +1,17 @@
 <Project Sdk="Microsoft.NET.Sdk">
 <Project Sdk="Microsoft.NET.Sdk">
 
 
   <PropertyGroup>
   <PropertyGroup>
-    <TargetFramework>netcoreapp2.2</TargetFramework>
     <!-- aspnet/BuildTools#662 Don't police what version of NetCoreApp we use -->
     <!-- aspnet/BuildTools#662 Don't police what version of NetCoreApp we use -->
     <NETCoreAppMaximumVersion>99.9</NETCoreAppMaximumVersion>
     <NETCoreAppMaximumVersion>99.9</NETCoreAppMaximumVersion>
+    <TargetFramework>netcoreapp2.2</TargetFramework>
     <MaxImplicitVersion>2.2.0</MaxImplicitVersion>
     <MaxImplicitVersion>2.2.0</MaxImplicitVersion>
-    <!-- Use pre-release versions up until 2.1.0, then don't lift higher than "2.1.0" -->
-    <MicrosoftNETCoreAppPackageVersion Condition="$(MicrosoftNETCoreApp22PackageVersion.StartsWith('$(MaxImplicitVersion)-'))">$(MicrosoftNETCoreApp22PackageVersion)</MicrosoftNETCoreAppPackageVersion>
-    <MicrosoftNETCoreAppPackageVersion>$([MSbuild]::ValueOrDefault('$(MicrosoftNETCoreAppPackageVersion)','$(MaxImplicitVersion)'))</MicrosoftNETCoreAppPackageVersion>
+    <!-- Use pre-release versions up until 2.2.0, then don't lift higher than "2.2.0" -->
+    <NETCoreImplicitVersion Condition="$(MicrosoftNETCoreApp22PackageVersion.StartsWith('$(MaxImplicitVersion)-'))">$(MicrosoftNETCoreApp22PackageVersion)</NETCoreImplicitVersion>
+    <NETCoreImplicitVersion>$([MSbuild]::ValueOrDefault('$(NETCoreImplicitVersion)','$(MaxImplicitVersion)'))</NETCoreImplicitVersion>
   </PropertyGroup>
   </PropertyGroup>
 
 
   <ItemGroup>
   <ItemGroup>
-    <PackageReference Include="Microsoft.NETCore.App" Version="$(MicrosoftNETCoreAppPackageVersion)" />
+    <PackageReference Include="Microsoft.NETCore.App" Version="$(NETCoreImplicitVersion)" />
   </ItemGroup>
   </ItemGroup>
 
 
 </Project>
 </Project>

+ 7 - 3
src/PackageArchive/Scenario.WebApp/Scenario.WebApp.csproj

@@ -1,14 +1,18 @@
 <Project Sdk="Microsoft.NET.Sdk">
 <Project Sdk="Microsoft.NET.Sdk">
 
 
   <PropertyGroup>
   <PropertyGroup>
-    <TargetFramework>netcoreapp2.2</TargetFramework>
     <!-- aspnet/BuildTools#662 Don't police what version of NetCoreApp we use -->
     <!-- aspnet/BuildTools#662 Don't police what version of NetCoreApp we use -->
     <NETCoreAppMaximumVersion>99.9</NETCoreAppMaximumVersion>
     <NETCoreAppMaximumVersion>99.9</NETCoreAppMaximumVersion>
+    <TargetFramework>netcoreapp2.2</TargetFramework>
+    <MaxImplicitVersion>2.2.0</MaxImplicitVersion>
+    <!-- Use pre-release versions up until 2.2.0, then don't lift higher -->
+    <AspNetCoreImplicitVersion Condition="$(MicrosoftAspNetCoreAppPackageVersion.StartsWith('$(MaxImplicitVersion)-'))">$(MicrosoftAspNetCoreAppPackageVersion)</AspNetCoreImplicitVersion>
+    <AspNetCoreImplicitVersion>$([MSBuild]::ValueOrDefault('$(AspNetCoreImplicitVersion)','$(MaxImplicitVersion)'))</AspNetCoreImplicitVersion>
   </PropertyGroup>
   </PropertyGroup>
 
 
   <ItemGroup>
   <ItemGroup>
-    <PackageReference Include="Microsoft.AspNetCore.App" Version="$(MicrosoftAspNetCoreAppPackageVersion)" />
-    <PackageReference Include="Microsoft.AspNetCore.All" Version="$(MicrosoftAspNetCoreAllPackageVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.App" Version="$(AspNetCoreImplicitVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.All" Version="$(AspNetCoreImplicitVersion)" />
     <PackageReference Include="Microsoft.AspNetCore.Authentication.AzureAD.UI" Version="$(MicrosoftAspNetCoreAuthenticationAzureADUIPackageVersion)" />
     <PackageReference Include="Microsoft.AspNetCore.Authentication.AzureAD.UI" Version="$(MicrosoftAspNetCoreAuthenticationAzureADUIPackageVersion)" />
     <PackageReference Include="Microsoft.AspNetCore.Authentication.AzureADB2C.UI" Version="$(MicrosoftAspNetCoreAuthenticationAzureADB2CUIPackageVersion)" />
     <PackageReference Include="Microsoft.AspNetCore.Authentication.AzureADB2C.UI" Version="$(MicrosoftAspNetCoreAuthenticationAzureADB2CUIPackageVersion)" />
     <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Contracts" Version="$(MicrosoftVisualStudioWebCodeGenerationContractsPackageVersion)" />
     <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Contracts" Version="$(MicrosoftVisualStudioWebCodeGenerationContractsPackageVersion)" />