Trigger rebuild when the CLI changed
- Stamp each project with the CLI version it was last compiled with - Rebuild those projects with a local version file that does not match the one of the current CLI that is building it
This commit is contained in:
parent
7a82a98e4c
commit
f14b4cbd3d
6 changed files with 142 additions and 23 deletions
16
src/Microsoft.DotNet.Cli.Utils/DotnetFiles.cs
Normal file
16
src/Microsoft.DotNet.Cli.Utils/DotnetFiles.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.DotNet.Cli.Utils
|
||||
{
|
||||
public static class DotnetFiles
|
||||
{
|
||||
/// <summary>
|
||||
/// The CLI ships with a .version file that stores the commit information and CLI version
|
||||
/// </summary>
|
||||
public static string VersionFile => Path.GetFullPath(Path.Combine(typeof(DotnetFiles).GetTypeInfo().Assembly.Location, "..", ".version"));
|
||||
}
|
||||
}
|
|
@ -31,6 +31,11 @@ namespace Microsoft.DotNet.Cli.Compiler.Common
|
|||
return baseOption;
|
||||
}
|
||||
|
||||
public static string GetSDKVersionFile(this ProjectContext context, string configuration, string buildBasePath, string outputPath)
|
||||
{
|
||||
var intermediatePath = context.GetOutputPaths(configuration, buildBasePath, outputPath).IntermediateOutputDirectoryPath;
|
||||
return Path.Combine(intermediatePath, ".SDKVersion");
|
||||
}
|
||||
|
||||
// used in incremental compilation for the key file
|
||||
public static CommonCompilerOptions ResolveCompilationOptions(this ProjectContext context, string configuration)
|
||||
|
|
|
@ -159,8 +159,7 @@ namespace Microsoft.DotNet.Cli
|
|||
|
||||
private static string GetCommitSha()
|
||||
{
|
||||
// The CLI ships with a .version file that stores the commit information
|
||||
var versionFile = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, ".version"));
|
||||
var versionFile = DotnetFiles.VersionFile;
|
||||
|
||||
if (File.Exists(versionFile))
|
||||
{
|
||||
|
|
|
@ -53,17 +53,23 @@ namespace Microsoft.DotNet.Tools.Build
|
|||
|
||||
private bool CompileRootProject(bool incremental)
|
||||
{
|
||||
if (incremental && !NeedsRebuilding(_rootProject, _rootProjectDependencies))
|
||||
try
|
||||
{
|
||||
// todo: what if the previous build had errors / warnings and nothing changed? Need to propagate them in case of incremental
|
||||
return true;
|
||||
if (incremental && !NeedsRebuilding(_rootProject, _rootProjectDependencies))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var success = InvokeCompileOnRootProject();
|
||||
|
||||
PrintSummary(success);
|
||||
|
||||
return success;
|
||||
}
|
||||
finally
|
||||
{
|
||||
StampProjectWithSDKVersion(_rootProject);
|
||||
}
|
||||
|
||||
var success = InvokeCompileOnRootProject();
|
||||
|
||||
PrintSummary(success);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
private bool CompileDependencies(bool incremental)
|
||||
|
@ -75,28 +81,37 @@ namespace Microsoft.DotNet.Tools.Build
|
|||
|
||||
foreach (var dependency in Sort(_rootProjectDependencies.ProjectDependenciesWithSources))
|
||||
{
|
||||
if (incremental && !DependencyNeedsRebuilding(dependency))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var dependencyProjectContext = ProjectContext.Create(dependency.Path, dependency.Framework, new[] { _rootProject.RuntimeIdentifier });
|
||||
|
||||
if (!InvokeCompileOnDependency(dependency))
|
||||
try
|
||||
{
|
||||
return false;
|
||||
if (incremental && !NeedsRebuilding(dependencyProjectContext, new ProjectDependenciesFacade(dependencyProjectContext, _args.ConfigValue)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!InvokeCompileOnDependency(dependency))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
StampProjectWithSDKVersion(dependencyProjectContext);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool DependencyNeedsRebuilding(ProjectDescription dependency)
|
||||
{
|
||||
var dependencyProjectContext = ProjectContext.Create(dependency.Path, dependency.Framework, new[] { _rootProject.RuntimeIdentifier });
|
||||
return NeedsRebuilding(dependencyProjectContext, new ProjectDependenciesFacade(dependencyProjectContext, _args.ConfigValue));
|
||||
}
|
||||
|
||||
private bool NeedsRebuilding(ProjectContext project, ProjectDependenciesFacade dependencies)
|
||||
{
|
||||
if (CLIChangedSinceLastCompilation(project))
|
||||
{
|
||||
Reporter.Output.WriteLine($"Project {project.GetDisplayName()} will be compiled because the CLI changed");
|
||||
return true;
|
||||
}
|
||||
|
||||
var compilerIO = GetCompileIO(project, dependencies);
|
||||
|
||||
// rebuild if empty inputs / outputs
|
||||
|
@ -174,6 +189,48 @@ namespace Microsoft.DotNet.Tools.Build
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool CLIChangedSinceLastCompilation(ProjectContext project)
|
||||
{
|
||||
var currentVersionFile = DotnetFiles.VersionFile;
|
||||
var versionFileFromLastCompile = project.GetSDKVersionFile(_args.ConfigValue, _args.BuildBasePathValue, _args.OutputValue);
|
||||
|
||||
if (!File.Exists(currentVersionFile))
|
||||
{
|
||||
// this CLI does not have a version file; cannot tell if CLI changed
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!File.Exists(versionFileFromLastCompile))
|
||||
{
|
||||
// this is the first compilation; cannot tell if CLI changed
|
||||
return false;
|
||||
}
|
||||
|
||||
var versionsAreEqual = string.Equals(File.ReadAllText(currentVersionFile), File.ReadAllText(versionFileFromLastCompile), StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
return !versionsAreEqual;
|
||||
}
|
||||
|
||||
private void StampProjectWithSDKVersion(ProjectContext project)
|
||||
{
|
||||
if (File.Exists(DotnetFiles.VersionFile))
|
||||
{
|
||||
var projectVersionFile = project.GetSDKVersionFile(_args.ConfigValue, _args.BuildBasePathValue,_args.OutputValue);
|
||||
var parentDirectory = Path.GetDirectoryName(projectVersionFile);
|
||||
|
||||
if (!Directory.Exists(parentDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(parentDirectory);
|
||||
}
|
||||
|
||||
File.Copy(DotnetFiles.VersionFile, projectVersionFile, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Reporter.Verbose.WriteLine($"Project {project.GetDisplayName()} was not stamped with a CLI version because the version file does not exist: {DotnetFiles.VersionFile}");
|
||||
}
|
||||
}
|
||||
|
||||
private void PrintSummary(bool success)
|
||||
{
|
||||
|
|
|
@ -124,5 +124,12 @@ namespace Microsoft.DotNet.Tools.Builder.Tests
|
|||
|
||||
return executablePath;
|
||||
}
|
||||
|
||||
protected string GetIntermediaryOutputPath()
|
||||
{
|
||||
var executablePath = Path.Combine(TestProjectRoot, "obj", "Debug", "netstandardapp1.5");
|
||||
|
||||
return executablePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
using Microsoft.DotNet.Cli.Utils;
|
||||
using Microsoft.DotNet.Tools.Test.Utilities;
|
||||
using Xunit;
|
||||
|
@ -79,6 +80,40 @@ namespace Microsoft.DotNet.Tools.Builder.Tests
|
|||
Assert.Contains("does not have a lock file", buildResult.StdErr);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestModifiedVersionFile()
|
||||
{
|
||||
CreateTestInstance();
|
||||
BuildProject().Should().HaveCompiledProject(MainProject);
|
||||
|
||||
//change version file
|
||||
var versionFile = Path.Combine(GetIntermediaryOutputPath(), ".SDKVersion");
|
||||
File.Exists(versionFile).Should().BeTrue();
|
||||
File.AppendAllText(versionFile, "text");
|
||||
|
||||
//assert rebuilt
|
||||
BuildProject().Should().HaveCompiledProject(MainProject);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestNoVersionFile()
|
||||
{
|
||||
CreateTestInstance();
|
||||
BuildProject().Should().HaveCompiledProject(MainProject);
|
||||
|
||||
//delete version file
|
||||
var versionFile = Path.Combine(GetIntermediaryOutputPath(), ".SDKVersion");
|
||||
File.Exists(versionFile).Should().BeTrue();
|
||||
File.Delete(versionFile);
|
||||
File.Exists(versionFile).Should().BeFalse();
|
||||
|
||||
//assert build skipped due to no version file
|
||||
BuildProject().Should().HaveSkippedProjectCompilation(MainProject);
|
||||
|
||||
//the version file should have been regenerated during the build, even if compilation got skipped
|
||||
File.Exists(versionFile).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestRebuildChangedLockFile()
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue