// 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; } } }