From eccf44c2004eab9c96e3d1df40f4443ce412eae1 Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Mon, 7 Mar 2016 14:24:36 -0600 Subject: [PATCH] Add initial update-dependencies script. This script can be used to automatically update dotnet/cli's dependencies on other repos like CoreFX, NuGet, etc. Currently the script supports updating the CoreFX dependencies. --- Microsoft.DotNet.Cli.sln | 19 ++ .../CommandResult.cs | 17 +- scripts/update-dependencies.ps1 | 51 ++++ scripts/update-dependencies/Config.cs | 74 ++++++ scripts/update-dependencies/Dirs.cs | 12 + scripts/update-dependencies/Program.cs | 25 ++ scripts/update-dependencies/PushPRTargets.cs | 108 ++++++++ .../update-dependencies/UpdateFilesTargets.cs | 233 ++++++++++++++++++ scripts/update-dependencies/project.json | 25 ++ .../update-dependencies.xproj | 18 ++ 10 files changed, 575 insertions(+), 7 deletions(-) create mode 100644 scripts/update-dependencies.ps1 create mode 100644 scripts/update-dependencies/Config.cs create mode 100644 scripts/update-dependencies/Dirs.cs create mode 100644 scripts/update-dependencies/Program.cs create mode 100644 scripts/update-dependencies/PushPRTargets.cs create mode 100644 scripts/update-dependencies/UpdateFilesTargets.cs create mode 100644 scripts/update-dependencies/project.json create mode 100644 scripts/update-dependencies/update-dependencies.xproj diff --git a/Microsoft.DotNet.Cli.sln b/Microsoft.DotNet.Cli.sln index e2ce9023a..044847001 100644 --- a/Microsoft.DotNet.Cli.sln +++ b/Microsoft.DotNet.Cli.sln @@ -79,6 +79,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "dotnet-test.UnitTests", "te EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "dotnet-test.Tests", "test\dotnet-test.Tests\dotnet-test.Tests.xproj", "{60C33D0A-A5D8-4AB0-9956-1F804654DF05}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "update-dependencies", "scripts\update-dependencies\update-dependencies.xproj", "{A28BD8AC-DF15-4F58-8299-98A9AE2B8726}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -555,6 +557,22 @@ Global {60C33D0A-A5D8-4AB0-9956-1F804654DF05}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU {60C33D0A-A5D8-4AB0-9956-1F804654DF05}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU {60C33D0A-A5D8-4AB0-9956-1F804654DF05}.RelWithDebInfo|x64.Build.0 = Release|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.Debug|x64.ActiveCfg = Debug|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.Debug|x64.Build.0 = Debug|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.MinSizeRel|x64.Build.0 = Debug|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.Release|Any CPU.Build.0 = Release|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.Release|x64.ActiveCfg = Release|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.Release|x64.Build.0 = Release|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.RelWithDebInfo|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -591,5 +609,6 @@ Global {0724ED7C-56E3-4604-9970-25E600611383} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F} {857274AC-E741-4266-A7FD-14DEE0C1CC96} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7} {60C33D0A-A5D8-4AB0-9956-1F804654DF05} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7} + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726} = {88278B81-7649-45DC-8A6A-D3A645C5AFC3} EndGlobalSection EndGlobal diff --git a/scripts/Microsoft.DotNet.Cli.Build.Framework/CommandResult.cs b/scripts/Microsoft.DotNet.Cli.Build.Framework/CommandResult.cs index d6e657e2f..e93320453 100644 --- a/scripts/Microsoft.DotNet.Cli.Build.Framework/CommandResult.cs +++ b/scripts/Microsoft.DotNet.Cli.Build.Framework/CommandResult.cs @@ -24,20 +24,23 @@ namespace Microsoft.DotNet.Cli.Build.Framework StdErr = stdErr; } - public void EnsureSuccessful() + public void EnsureSuccessful(bool suppressOutput = false) { if(ExitCode != 0) { StringBuilder message = new StringBuilder($"Command failed with exit code {ExitCode}: {StartInfo.FileName} {StartInfo.Arguments}"); - if (!string.IsNullOrEmpty(StdOut)) + if (!suppressOutput) { - message.AppendLine($"{Environment.NewLine}Standard Output:{Environment.NewLine}{StdOut}"); - } + if (!string.IsNullOrEmpty(StdOut)) + { + message.AppendLine($"{Environment.NewLine}Standard Output:{Environment.NewLine}{StdOut}"); + } - if (!string.IsNullOrEmpty(StdErr)) - { - message.AppendLine($"{Environment.NewLine}Standard Error:{Environment.NewLine}{StdErr}"); + if (!string.IsNullOrEmpty(StdErr)) + { + message.AppendLine($"{Environment.NewLine}Standard Error:{Environment.NewLine}{StdErr}"); + } } throw new BuildFailureException(message.ToString()); diff --git a/scripts/update-dependencies.ps1 b/scripts/update-dependencies.ps1 new file mode 100644 index 000000000..e7050cec1 --- /dev/null +++ b/scripts/update-dependencies.ps1 @@ -0,0 +1,51 @@ +# +# 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. +# + +param( + [string[]]$Targets=@("Default"), + [switch]$Help) + +if($Help) +{ + Write-Host "Usage: .\update-dependencies.ps1 [-Targets ]" + Write-Host "" + Write-Host "Options:" + Write-Host " -Targets Comma separated build targets to run (UpdateFiles, PushPR; Default is everything)" + Write-Host " -Help Display this help message" + exit 0 +} + +# Use a repo-local install directory (but not the artifacts directory because that gets cleaned a lot +if (!$env:DOTNET_INSTALL_DIR) +{ + $env:DOTNET_INSTALL_DIR="$PSScriptRoot\..\.dotnet_stage0\Windows\$Architecture" +} + +# Install a stage 0 +Write-Host "Installing .NET Core CLI Stage 0" +& "$PSScriptRoot\obtain\install.ps1" -Architecture x64 + +# Put the stage0 on the path +$env:PATH = "$env:DOTNET_INSTALL_DIR\cli\bin;$env:PATH" + +$appPath = "$PSScriptRoot\update-dependencies" + +# Restore the build scripts +Write-Host "Restoring Build Script projects..." +pushd $PSScriptRoot +dotnet restore +if($LASTEXITCODE -ne 0) { throw "Failed to restore" } +popd + +# Publish the app +Write-Host "Compiling App $appPath..." +dotnet publish "$appPath" -o "$appPath\bin" --framework netstandardapp1.5 +if($LASTEXITCODE -ne 0) { throw "Failed to compile build scripts" } + +# Run the app +Write-Host "Invoking App $appPath..." +Write-Host " Configuration: $env:CONFIGURATION" +& "$appPath\bin\update-dependencies.exe" @Targets +if($LASTEXITCODE -ne 0) { throw "Build failed" } diff --git a/scripts/update-dependencies/Config.cs b/scripts/update-dependencies/Config.cs new file mode 100644 index 000000000..c0e446ec3 --- /dev/null +++ b/scripts/update-dependencies/Config.cs @@ -0,0 +1,74 @@ +// 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; +using Microsoft.DotNet.Cli.Build.Framework; + +namespace Microsoft.DotNet.Scripts +{ + /// + /// Holds the configuration information for the update-dependencies script. + /// + /// + /// The following Environment Variables are required by this script: + /// + /// GITHUB_USER - The user to commit the changes as. + /// GITHUB_EMAIL - The user's email to commit the changes as. + /// GITHUB_PASSWORD - The password/personal access token of the GitHub user. + /// + /// The following Environment Variables can optionally be specified: + /// + /// COREFX_VERSION_URL - The Url to get the current CoreFx version. (ex. "https://raw.githubusercontent.com/dotnet/versions/master/dotnet/corefx/release/1.0.0-rc2/LKG.txt") + /// GITHUB_ORIGIN_OWNER - The owner of the GitHub fork to push the commit and create the PR from. (ex. "dotnet-bot") + /// GITHUB_UPSTREAM_OWNER - The owner of the GitHub base repo to create the PR to. (ex. "dotnet") + /// GITHUB_PROJECT - The repo name under the ORIGIN and UPSTREAM owners. (ex. "cli") + /// GITHUB_UPSTREAM_BRANCH - The branch in the GitHub base repo to create the PR to. (ex. "rel/1.0.0") + /// + public class Config + { + public static Config Instance { get; } = Read(); + + public string UserName { get; set; } + public string Email { get; set; } + public string Password { get; set; } + public string CoreFxVersionUrl { get; set; } + public string GitHubOriginOwner { get; set; } + public string GitHubUpstreamOwner { get; set; } + public string GitHubProject { get; set; } + public string GitHubUpstreamBranch { get; set; } + + private static Config Read() + { + string userName = GetEnvironmentVariable("GITHUB_USER"); + + return new Config + { + UserName = userName, + Email = GetEnvironmentVariable("GITHUB_EMAIL"), + Password = GetEnvironmentVariable("GITHUB_PASSWORD"), + + CoreFxVersionUrl = GetEnvironmentVariable("COREFX_VERSION_URL", "https://raw.githubusercontent.com/dotnet/versions/master/dotnet/corefx/release/1.0.0-rc2/LKG.txt"), + GitHubOriginOwner = GetEnvironmentVariable("GITHUB_ORIGIN_OWNER", userName), + GitHubUpstreamOwner = GetEnvironmentVariable("GITHUB_UPSTREAM_OWNER", "dotnet"), + GitHubProject = GetEnvironmentVariable("GITHUB_PROJECT", "cli"), + GitHubUpstreamBranch = GetEnvironmentVariable("GITHUB_UPSTREAM_BRANCH", "rel/1.0.0"), + }; + } + + private static string GetEnvironmentVariable(string name, string defaultValue = null) + { + string value = Environment.GetEnvironmentVariable(name); + if (string.IsNullOrEmpty(value)) + { + value = defaultValue; + } + + if (string.IsNullOrEmpty(value)) + { + throw new BuildFailureException($"Can't find environment variable '{name}'."); + } + + return value; + } + } +} diff --git a/scripts/update-dependencies/Dirs.cs b/scripts/update-dependencies/Dirs.cs new file mode 100644 index 000000000..302928f02 --- /dev/null +++ b/scripts/update-dependencies/Dirs.cs @@ -0,0 +1,12 @@ +// 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; + +namespace Microsoft.DotNet.Scripts +{ + public static class Dirs + { + public static readonly string RepoRoot = Directory.GetCurrentDirectory(); + } +} diff --git a/scripts/update-dependencies/Program.cs b/scripts/update-dependencies/Program.cs new file mode 100644 index 000000000..f0fc8f8d1 --- /dev/null +++ b/scripts/update-dependencies/Program.cs @@ -0,0 +1,25 @@ +// 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 Microsoft.DotNet.Cli.Build.Framework; + +namespace Microsoft.DotNet.Scripts +{ + public class Program + { + public static int Main(string[] args) + { + DebugHelper.HandleDebugSwitch(ref args); + + return BuildSetup.Create(".NET CLI Dependency Updater") + .UseTargets(new[] + { + new BuildTarget("Default", "Dependency Updater Goals", new [] { "UpdateFiles", "PushPR" }), + new BuildTarget("UpdateFiles", "Dependency Updater Goals"), + new BuildTarget("PushPR", "Dependency Updater Goals"), + }) + .UseAllTargetsFromAssembly() + .Run(args); + } + } +} diff --git a/scripts/update-dependencies/PushPRTargets.cs b/scripts/update-dependencies/PushPRTargets.cs new file mode 100644 index 000000000..4d9ca44c1 --- /dev/null +++ b/scripts/update-dependencies/PushPRTargets.cs @@ -0,0 +1,108 @@ +// 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; +using Microsoft.DotNet.Cli.Build.Framework; +using Octokit; + +using static Microsoft.DotNet.Cli.Build.Framework.BuildHelpers; + +namespace Microsoft.DotNet.Scripts +{ + /// + /// Creates a GitHub Pull Request for the current changes in the repo. + /// + public static class PushPRTargets + { + private const string PullRequestTitle = "Updating dependencies from last known good builds"; + + private static readonly Config s_config = Config.Instance; + + [Target(nameof(CommitChanges), nameof(CreatePR))] + public static BuildTargetResult PushPR(BuildTargetContext c) => c.Success(); + + /// + /// Commits all the current changes in the repo and pushes the commit to a remote + /// so a PR can be created for it. + /// + [Target] + public static BuildTargetResult CommitChanges(BuildTargetContext c) + { + Cmd("git", "add", ".") + .Execute() + .EnsureSuccessful(); + + string userName = s_config.UserName; + string email = s_config.Email; + + Cmd("git", "commit", "-m", PullRequestTitle, "--author", $"{userName} <{email}>") + .EnvironmentVariable("GIT_COMMITTER_NAME", userName) + .EnvironmentVariable("GIT_COMMITTER_EMAIL", email) + .Execute() + .EnsureSuccessful(); + + string remoteUrl = $"github.com/{s_config.GitHubOriginOwner}/{s_config.GitHubProject}.git"; + string remoteBranchName = $"UpdateDependencies{DateTime.UtcNow.ToString("yyyyMMddhhmmss")}"; + string refSpec = $"HEAD:refs/heads/{remoteBranchName}"; + + string logMessage = $"git push https://{remoteUrl} {refSpec}"; + BuildReporter.BeginSection("EXEC", logMessage); + + CommandResult pushResult = + Cmd("git", "push", $"https://{userName}:{s_config.Password}@{remoteUrl}", refSpec) + .QuietBuildReporter() // we don't want secrets showing up in our logs + .CaptureStdErr() // git push will write to StdErr upon success, disable that + .CaptureStdOut() + .Execute(); + + var message = logMessage + $" exited with {pushResult.ExitCode}"; + if (pushResult.ExitCode == 0) + { + BuildReporter.EndSection("EXEC", message.Green(), success: true); + } + else + { + BuildReporter.EndSection("EXEC", message.Red().Bold(), success: false); + } + + pushResult.EnsureSuccessful(suppressOutput: true); + + c.SetRemoteBranchName(remoteBranchName); + + return c.Success(); + } + + /// + /// Creates a GitHub PR for the remote branch created above. + /// + [Target] + public static BuildTargetResult CreatePR(BuildTargetContext c) + { + string remoteBranchName = c.GetRemoteBranchName(); + + NewPullRequest prInfo = new NewPullRequest( + PullRequestTitle, + s_config.GitHubOriginOwner + ":" + remoteBranchName, + s_config.GitHubUpstreamBranch); + + GitHubClient gitHub = new GitHubClient(new ProductHeaderValue("dotnetDependencyUpdater")); + + gitHub.Credentials = new Credentials(s_config.Password); + + PullRequest createdPR = gitHub.PullRequest.Create(s_config.GitHubUpstreamOwner, s_config.GitHubProject, prInfo).Result; + c.Info($"Created Pull Request: {createdPR.HtmlUrl}"); + + return c.Success(); + } + + private static string GetRemoteBranchName(this BuildTargetContext c) + { + return (string)c.BuildContext["RemoteBranchName"]; + } + + private static void SetRemoteBranchName(this BuildTargetContext c, string value) + { + c.BuildContext["RemoteBranchName"] = value; + } + } +} diff --git a/scripts/update-dependencies/UpdateFilesTargets.cs b/scripts/update-dependencies/UpdateFilesTargets.cs new file mode 100644 index 000000000..31527ce59 --- /dev/null +++ b/scripts/update-dependencies/UpdateFilesTargets.cs @@ -0,0 +1,233 @@ +// 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; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Text.RegularExpressions; +using Microsoft.DotNet.Cli.Build.Framework; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using NuGet.Versioning; + +namespace Microsoft.DotNet.Scripts +{ + public static class UpdateFilesTargets + { + private static HttpClient s_client = new HttpClient(); + + [Target(nameof(GetDependencies), nameof(ReplaceVersions))] + public static BuildTargetResult UpdateFiles(BuildTargetContext c) => c.Success(); + + /// + /// Gets all the dependency information and puts it in the build properties. + /// + [Target] + public static BuildTargetResult GetDependencies(BuildTargetContext c) + { + string coreFxLkgVersion = s_client.GetStringAsync(Config.Instance.CoreFxVersionUrl).Result; + coreFxLkgVersion = coreFxLkgVersion.Trim(); + + const string coreFxIdPattern = @"^(?i)((System\..*)|(NETStandard\.Library)|(Microsoft\.CSharp)|(Microsoft\.NETCore.*)|(Microsoft\.TargetingPack\.Private\.(CoreCLR|NETNative))|(Microsoft\.Win32\..*)|(Microsoft\.VisualBasic))$"; + const string coreFxIdExclusionPattern = @"System.CommandLine"; + + List dependencyInfos = c.GetDependencyInfo(); + dependencyInfos.Add(new DependencyInfo() + { + Name = "CoreFx", + IdPattern = coreFxIdPattern, + IdExclusionPattern = coreFxIdExclusionPattern, + NewReleaseVersion = coreFxLkgVersion + }); + + return c.Success(); + } + + private static List GetDependencyInfo(this BuildTargetContext c) + { + const string propertyName = "DependencyInfo"; + + List dependencyInfos; + object dependencyInfosObj; + if (c.BuildContext.Properties.TryGetValue(propertyName, out dependencyInfosObj)) + { + dependencyInfos = (List)dependencyInfosObj; + } + else + { + dependencyInfos = new List(); + c.BuildContext[propertyName] = dependencyInfos; + } + + return dependencyInfos; + } + + [Target(nameof(ReplaceProjectJson), nameof(ReplaceCrossGen))] + public static BuildTargetResult ReplaceVersions(BuildTargetContext c) => c.Success(); + + /// + /// Replaces all the dependency versions in the project.json files. + /// + [Target] + public static BuildTargetResult ReplaceProjectJson(BuildTargetContext c) + { + List dependencyInfos = c.GetDependencyInfo(); + + IEnumerable projectJsonFiles = Enumerable.Union( + Directory.GetFiles(Dirs.RepoRoot, "project.json", SearchOption.AllDirectories), + Directory.GetFiles(Path.Combine(Dirs.RepoRoot, @"src\dotnet\commands\dotnet-new"), "project.json.template", SearchOption.AllDirectories)); + + JObject projectRoot; + foreach (string projectJsonFile in projectJsonFiles) + { + try + { + projectRoot = ReadProject(projectJsonFile); + } + catch (Exception e) + { + c.Warn($"Non-fatal exception occurred reading '{projectJsonFile}'. Skipping file. Exception: {e}. "); + continue; + } + + bool changedAnyPackage = FindAllDependencyProperties(projectRoot) + .Select(dependencyProperty => ReplaceDependencyVersion(dependencyProperty, dependencyInfos)) + .ToArray() + .Any(shouldWrite => shouldWrite); + + if (changedAnyPackage) + { + c.Info($"Writing changes to {projectJsonFile}"); + WriteProject(projectRoot, projectJsonFile); + } + } + + return c.Success(); + } + + /// + /// Replaces the single dependency with the updated version, if it matches any of the dependencies that need to be updated. + /// + private static bool ReplaceDependencyVersion(JProperty dependencyProperty, List dependencyInfos) + { + string id = dependencyProperty.Name; + foreach (DependencyInfo dependencyInfo in dependencyInfos) + { + if (Regex.IsMatch(id, dependencyInfo.IdPattern)) + { + if (string.IsNullOrEmpty(dependencyInfo.IdExclusionPattern) || !Regex.IsMatch(id, dependencyInfo.IdExclusionPattern)) + { + string version; + if (dependencyProperty.Value is JObject) + { + version = dependencyProperty.Value["version"].Value(); + } + else if (dependencyProperty.Value is JValue) + { + version = dependencyProperty.Value.ToString(); + } + else + { + throw new Exception($"Invalid package project.json version {dependencyProperty}"); + } + + VersionRange dependencyVersionRange = VersionRange.Parse(version); + NuGetVersion dependencyVersion = dependencyVersionRange.MinVersion; + + string newReleaseVersion = dependencyInfo.NewReleaseVersion; + + if (!string.IsNullOrEmpty(dependencyVersion.Release) && dependencyVersion.Release != newReleaseVersion) + { + string newVersion = new NuGetVersion( + dependencyVersion.Major, + dependencyVersion.Minor, + dependencyVersion.Patch, + newReleaseVersion, + dependencyVersion.Metadata).ToNormalizedString(); + + if (dependencyProperty.Value is JObject) + { + dependencyProperty.Value["version"] = newVersion; + } + else + { + dependencyProperty.Value = newVersion; + } + + return true; + } + } + } + } + + return false; + } + + private static JObject ReadProject(string projectJsonPath) + { + using (TextReader projectFileReader = File.OpenText(projectJsonPath)) + { + var projectJsonReader = new JsonTextReader(projectFileReader); + + var serializer = new JsonSerializer(); + return serializer.Deserialize(projectJsonReader); + } + } + + private static void WriteProject(JObject projectRoot, string projectJsonPath) + { + string projectJson = JsonConvert.SerializeObject(projectRoot, Formatting.Indented); + + File.WriteAllText(projectJsonPath, projectJson + Environment.NewLine); + } + + private static IEnumerable FindAllDependencyProperties(JObject projectJsonRoot) + { + return projectJsonRoot + .Descendants() + .OfType() + .Where(property => property.Name == "dependencies") + .Select(property => property.Value) + .SelectMany(o => o.Children()); + } + + private class DependencyInfo + { + public string Name { get; set; } + public string IdPattern { get; set; } + public string IdExclusionPattern { get; set; } + public string NewReleaseVersion { get; set; } + } + + /// + /// Replaces version number that is hard-coded in the CrossGen script. + /// + [Target] + public static BuildTargetResult ReplaceCrossGen(BuildTargetContext c) + { + DependencyInfo coreFXInfo = c.GetDependencyInfo().Single(d => d.Name == "CoreFx"); + + string compileTargetsPath = Path.Combine(Dirs.RepoRoot, @"scripts\dotnet-cli-build\CompileTargets.cs"); + string compileTargetsContent = File.ReadAllText(compileTargetsPath); + + Regex regex = new Regex(@"CoreCLRVersion = ""(?\d.\d.\d)-(?.*)"";"); + compileTargetsContent = regex.Replace(compileTargetsContent, m => + { + string replacedValue = m.Value; + Group releaseGroup = m.Groups["release"]; + + replacedValue = replacedValue.Remove(releaseGroup.Index - m.Index, releaseGroup.Length); + replacedValue = replacedValue.Insert(releaseGroup.Index - m.Index, coreFXInfo.NewReleaseVersion); + + return replacedValue; + }); + + File.WriteAllText(compileTargetsPath, compileTargetsContent, Encoding.UTF8); + + return c.Success(); + } + } +} diff --git a/scripts/update-dependencies/project.json b/scripts/update-dependencies/project.json new file mode 100644 index 000000000..d5a24cc82 --- /dev/null +++ b/scripts/update-dependencies/project.json @@ -0,0 +1,25 @@ +{ + "version": "1.0.0-*", + "description": "Updates the repos dependencies", + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911", + "Microsoft.CSharp": "4.0.1-rc2-23911", + "System.Runtime.Serialization.Primitives": "4.1.1-rc2-23911", + "Microsoft.DotNet.Cli.Build.Framework": "1.0.0-*", + "NuGet.Versioning": "3.4.0-rtm-0764", + "Newtonsoft.Json": "7.0.1", + "Octokit": "0.18.0", + "Microsoft.Net.Http": "2.2.29" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": [ + "dnxcore50", + "portable-net45+win" + ] + } + } +} diff --git a/scripts/update-dependencies/update-dependencies.xproj b/scripts/update-dependencies/update-dependencies.xproj new file mode 100644 index 000000000..07cff1695 --- /dev/null +++ b/scripts/update-dependencies/update-dependencies.xproj @@ -0,0 +1,18 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + a28bd8ac-df15-4f58-8299-98a9ae2b8726 + Microsoft.DotNet.Scripts + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin + + + 2.0 + + + \ No newline at end of file