Skip to content

Commit

Permalink
Add logic to roll forward to patch versions of .NET Core for self-con…
Browse files Browse the repository at this point in the history
…tained apps but not shared framework apps or libraries

Fixes #983
  • Loading branch information
dsplaisted committed May 24, 2017
1 parent 9cd7443 commit d5b0fe6
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ Copyright (c) .NET Foundation. All rights reserved.
</PropertyGroup>

<!--
Determine the NetCoreImplicitPackageVersion and RuntimeFrameworkVersion when targeting .NET Core
Determine the RuntimeFrameworkVersion when targeting .NET Core
When targeting .NET Core, the TargetFramework is generally used to specify which version of the runtime to use.
Expand All @@ -73,33 +73,72 @@ Copyright (c) .NET Foundation. All rights reserved.
The framework version that is written to the runtimeconfig.json file is based on the actual resolved package version
of Microsoft.NETCore.App. This is to allow floating the verion number.
If RuntimeFrameworkVersion is not specified, the following logic applies:
- When targeting .NET Core 2.0 or higher, Shared Framework apps use the target framework version with a ".0" patch version
- When targeting .NET Core 2.0 or higher, Self-contained apps use the latest patch version (from when the SDK shipped) for
the specified major.minor version of .NET Core
- When targeting .NET Core 1.x, the latest patch version (from when the SDK shipped) is used for both Shared Framework and
Self-Contained apps. This is to preserve the same behavior between 1.x and 2.0 SDKs. If we ship further patch versions
after 1.0.5 and 1.1.2, we may choose to apply the Shared / Self-contained split to 1.x for those versions.
-->

<PropertyGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp'">
<!-- If targeting .NET Core, and the RuntimeFrameworkVersion is not specified, use the latest patch version of that runtime that we know about.
This ensures that if a self-contained app is published where RuntimeFrameworkVersion is not specified, the latest patch
version of the runtime (that the SDK knew about when it shipped) will be used.
This also will fix an issue where Microsoft.NETCore.App 1.1.0 included a version of the Microsoft.DiaSymReader.Native package
that was authored in such a way that Microsoft.DiaSymReader.Native.amd64.dll and Microsoft.DiaSymReader.Native.x86.dll would
be copied to the output folder. Using Microsoft.NETCore.App 1.1.1 fixes this, as it references an updated version of the
DiaSymReader package with the issue fixed. (See https://github.com/dotnet/corefx/issues/14627)
Using the latest patch version that the SDK knows about does mean that an update to the SDK could change the version of
the runtime that a project targets. In general, this should be OK. If a project wants to opt out of this, it can specify
the exact version of the runtime to use with the RuntimeFrameworkVersion property.
-->
<!-- If targeting netcoreapp1.1, and RuntimeFrameworkVersion is not specified, use version 1.1.1 -->
<RuntimeFrameworkVersion Condition="'$(RuntimeFrameworkVersion)' == '' And '$(_TargetFrameworkVersionWithoutV)' == '1.0'">1.0.5</RuntimeFrameworkVersion>
<RuntimeFrameworkVersion Condition="'$(RuntimeFrameworkVersion)' == '' And '$(_TargetFrameworkVersionWithoutV)' == '1.1'">1.1.2</RuntimeFrameworkVersion>
<!-- These properties are mainly here as a test hook, as at the time we're implementing the logic which will choose
different versions depending on whether an app is self-contained or not, there aren't any patch versions of
.NET Core 2.0. So these properties allow us to apply the new behavior to .NET Core 1.x by overriding them.
Once there is a patch version of .NET Core, we may want to remove these properties and just put the version
numbers directly inside the <Choose> element below. -->
<PropertyGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp' And '$(RuntimeFrameworkVersion)' == ''">
<ImplicitRuntimeFrameworkVersionForSharedNetCoreApp1_0
Condition="'$(ImplicitRuntimeFrameworkVersionForSharedNetCoreApp1_0)' == ''">1.0.5</ImplicitRuntimeFrameworkVersionForSharedNetCoreApp1_0>
<ImplicitRuntimeFrameworkVersionForSelfContainedNetCoreApp1_0
Condition="'$(ImplicitRuntimeFrameworkVersionForSelfContainedNetCoreApp1_0)' == ''">1.0.5</ImplicitRuntimeFrameworkVersionForSelfContainedNetCoreApp1_0>
<ImplicitRuntimeFrameworkVersionForSharedNetCoreApp1_1
Condition="'$(ImplicitRuntimeFrameworkVersionForSharedNetCoreApp1_1)' == ''">1.1.2</ImplicitRuntimeFrameworkVersionForSharedNetCoreApp1_1>
<ImplicitRuntimeFrameworkVersionForSelfContainedNetCoreApp1_1
Condition="'$(ImplicitRuntimeFrameworkVersionForSelfContainedNetCoreApp1_1)' == ''">1.1.2</ImplicitRuntimeFrameworkVersionForSelfContainedNetCoreApp1_1>
</PropertyGroup>

<!-- Select implicit runtime framework versions -->
<Choose>
<!-- If not targeting .NET Core, or if RuntimeFrameworkVersion is already set, do nothing -->
<When Condition="'$(TargetFrameworkIdentifier)' != '.NETCoreApp' Or '$(RuntimeFrameworkVersion)' != ''" />

<When Condition="'$(_TargetFrameworkVersionWithoutV)' == '1.0'">
<PropertyGroup>
<ImplicitRuntimeFrameworkVersionForSharedApp>$(ImplicitRuntimeFrameworkVersionForSharedNetCoreApp1_0)</ImplicitRuntimeFrameworkVersionForSharedApp>
<ImplicitRuntimeFrameworkVersionForSelfContainedApp>$(ImplicitRuntimeFrameworkVersionForSelfContainedNetCoreApp1_0)</ImplicitRuntimeFrameworkVersionForSelfContainedApp>
</PropertyGroup>
</When>
<When Condition="'$(_TargetFrameworkVersionWithoutV)' == '1.1'">
<PropertyGroup>
<ImplicitRuntimeFrameworkVersionForSharedApp>$(ImplicitRuntimeFrameworkVersionForSharedNetCoreApp1_1)</ImplicitRuntimeFrameworkVersionForSharedApp>
<ImplicitRuntimeFrameworkVersionForSelfContainedApp>$(ImplicitRuntimeFrameworkVersionForSelfContainedNetCoreApp1_1)</ImplicitRuntimeFrameworkVersionForSelfContainedApp>
</PropertyGroup>
</When>

<!-- If targeting the same release that is bundled with the .NET Core SDK, use the bundled package version provided by Microsoft.NETCoreSdk.BundledVersions.props -->
<RuntimeFrameworkVersion Condition="'$(RuntimeFrameworkVersion)' == '' And '$(_TargetFrameworkVersionWithoutV)' == '$(BundledNETCoreAppTargetFrameworkVersion)'">$(BundledNETCoreAppPackageVersion)</RuntimeFrameworkVersion>
<When Condition="'$(_TargetFrameworkVersionWithoutV)' == '$(BundledNETCoreAppTargetFrameworkVersion)'">
<PropertyGroup>
<ImplicitRuntimeFrameworkVersionForSharedApp>$(BundledNETCoreAppPackageVersion)</ImplicitRuntimeFrameworkVersionForSharedApp>
<ImplicitRuntimeFrameworkVersionForSelfContainedApp>$(BundledNETCoreAppPackageVersion)</ImplicitRuntimeFrameworkVersionForSelfContainedApp>
</PropertyGroup>
</When>

<!-- Default to use the version of the framework runtime matching the target framework version-->
<RuntimeFrameworkVersion Condition="'$(RuntimeFrameworkVersion)' == ''">$(_TargetFrameworkVersionWithoutV)</RuntimeFrameworkVersion>
<!-- If not covered by the previous cases, use the target framework version for the implicit RuntimeFrameworkVersions -->
<Otherwise>
<PropertyGroup>
<ImplicitRuntimeFrameworkVersionForSharedApp>$(_TargetFrameworkVersionWithoutV)</ImplicitRuntimeFrameworkVersionForSharedApp>
<ImplicitRuntimeFrameworkVersionForSelfContainedApp>$(_TargetFrameworkVersionWithoutV)</ImplicitRuntimeFrameworkVersionForSelfContainedApp>
</PropertyGroup>
</Otherwise>
</Choose>

<PropertyGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp' And '$(RuntimeFrameworkVersion)' == ''">
<RuntimeFrameworkVersion Condition="'$(SelfContained)' == 'true' ">$(ImplicitRuntimeFrameworkVersionForSelfContainedApp)</RuntimeFrameworkVersion>
<RuntimeFrameworkVersion Condition="'$(SelfContained)' != 'true' ">$(ImplicitRuntimeFrameworkVersionForSharedApp)</RuntimeFrameworkVersion>
</PropertyGroup>

<UsingTask TaskName="CheckForImplicitPackageReferenceOverrides" AssemblyFile="$(MicrosoftNETBuildTasksAssembly)" />
Expand Down
66 changes: 52 additions & 14 deletions test/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildANetCoreApp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,37 +35,75 @@ public GivenThatWeWantToBuildANetCoreApp(ITestOutputHelper log) : base(log)
[InlineData("netcoreapp1.1", null, "1.1.2", "1.1.2")]
[InlineData("netcoreapp1.1", "1.1.0", "1.1.0", "1.1.0")]
[InlineData("netcoreapp1.1.1", null, "1.1.1", "1.1.1")]
public void It_targets_the_right_shared_framework(string targetFramework, string runtimeFrameworkVersion,
private void It_targets_the_right_shared_framework(string targetFramework, string runtimeFrameworkVersion,
string expectedPackageVersion, string expectedRuntimeVersion)
{
string testIdentifier = "SharedFrameworkTargeting_" + string.Join("_", targetFramework, runtimeFrameworkVersion ?? "null");

It_targets_the_right_framework(testIdentifier, targetFramework, runtimeFrameworkVersion,
selfContained: false, isExe: true,
expectedPackageVersion: expectedPackageVersion, expectedRuntimeVersion: expectedRuntimeVersion);
}

// Test behavior when implicit version differs for shared framework and self-contained apps
[Theory]
[InlineData(false, true, "1.1.1")]
[InlineData(true, true, "1.1.2")]
[InlineData(false, false, "1.1.1")]
public void It_targets_the_right_framework_depending_on_output_type(bool selfContained, bool isExe, string expectedFrameworkVersion)
{
string testIdentifier = "Framework_targeting_" + (isExe ? "App_" : "Lib_") + (selfContained ? "SelfContained" : "SharedFramework");

It_targets_the_right_framework(testIdentifier, "netcoreapp1.1", null, selfContained, isExe, expectedFrameworkVersion, expectedFrameworkVersion,
"/p:ImplicitRuntimeFrameworkVersionForSharedNetCoreApp1_1=1.1.1");
}

private void It_targets_the_right_framework(
string testIdentifier,
string targetFramework, string runtimeFrameworkVersion,
bool selfContained, bool isExe,
string expectedPackageVersion, string expectedRuntimeVersion,
string extraMSBuildArguments = null)
{
string runtimeIdentifier = null;
if (selfContained)
{
runtimeIdentifier = EnvironmentInfo.GetCompatibleRid(targetFramework);
}

var testProject = new TestProject()
{
Name = "SharedFrameworkTest",
Name = "FrameworkTargetTest",
TargetFrameworks = targetFramework,
RuntimeFrameworkVersion = runtimeFrameworkVersion,
IsSdkProject = true,
IsExe = true
};
IsExe = isExe,
RuntimeIdentifier = runtimeIdentifier
};

string testIdentifier = string.Join("_", targetFramework, runtimeFrameworkVersion ?? "null");
var extraArgs = extraMSBuildArguments?.Split(' ') ?? Array.Empty<string>();

var testAsset = _testAssetsManager.CreateTestProject(testProject, nameof(It_targets_the_right_shared_framework), testIdentifier)
.Restore(Log, testProject.Name);
var testAsset = _testAssetsManager.CreateTestProject(testProject, testIdentifier)
.Restore(Log, testProject.Name, extraArgs);

var buildCommand = new BuildCommand(Log, Path.Combine(testAsset.TestRoot, testProject.Name));

buildCommand
.Execute()
.Execute(extraArgs)
.Should()
.Pass();

var outputDirectory = buildCommand.GetOutputDirectory(targetFramework);
string runtimeConfigFile = Path.Combine(outputDirectory.FullName, testProject.Name + ".runtimeconfig.json");
string runtimeConfigContents = File.ReadAllText(runtimeConfigFile);
JObject runtimeConfig = JObject.Parse(runtimeConfigContents);
var outputDirectory = buildCommand.GetOutputDirectory(targetFramework, runtimeIdentifier: runtimeIdentifier);
// Self-contained apps don't write a framework version to the runtimeconfig, so only check this for shared apps
if (isExe && !selfContained)
{
string runtimeConfigFile = Path.Combine(outputDirectory.FullName, testProject.Name + ".runtimeconfig.json");
string runtimeConfigContents = File.ReadAllText(runtimeConfigFile);
JObject runtimeConfig = JObject.Parse(runtimeConfigContents);

string actualRuntimeFrameworkVersion = ((JValue)runtimeConfig["runtimeOptions"]["framework"]["version"]).Value<string>();
actualRuntimeFrameworkVersion.Should().Be(expectedRuntimeVersion);
string actualRuntimeFrameworkVersion = ((JValue)runtimeConfig["runtimeOptions"]["framework"]["version"]).Value<string>();
actualRuntimeFrameworkVersion.Should().Be(expectedRuntimeVersion);
}

LockFile lockFile = LockFileUtilities.GetLockFile(Path.Combine(buildCommand.ProjectRootPath, "obj", "project.assets.json"), NullLogger.Instance);

Expand Down

0 comments on commit d5b0fe6

Please sign in to comment.