private string GetUpdateBlockedReason(
     GitHubPullRequest pr,
     GitCommit headCommit,
     string upgradeBranchPrefix,
     GitHubProject origin)
 {
     if (pr.Head.User.Login != origin.Owner)
     {
         return($"Owner of head repo '{pr.Head.User.Login}' is not '{origin.Owner}'");
     }
     if (!pr.Head.Ref.StartsWith(upgradeBranchPrefix))
     {
         return($"Ref name '{pr.Head.Ref}' does not start with '{upgradeBranchPrefix}'");
     }
     if (headCommit.Author.Name != GitAuthorName)
     {
         return($"Head commit author '{headCommit.Author.Name}' is not '{GitAuthorName}'");
     }
     if (headCommit.Committer.Name != GitAuthorName)
     {
         return($"Head commit committer '{headCommit.Committer.Name}' is not '{GitAuthorName}'");
     }
     if (pr.Labels?.Any(IsMaestroStopUpdatesLabel) ?? false)
     {
         return($"Label `{MaestroStopUpdatesLabel}` is attached");
     }
     return(null);
 }
        public GitHubVersionsRepoUpdater(GitHubAuth gitHubAuth, GitHubProject project, INupkgInfoFactory nupkgInfoFactory) : base(nupkgInfoFactory)
        {
            if (gitHubAuth == null)
            {
                throw new ArgumentNullException(nameof(gitHubAuth));
            }
            _gitHubAuth = gitHubAuth;

            if (project == null)
            {
                throw new ArgumentNullException(nameof(project));
            }
            _project = project;
        }
        public GitHubBranch(string name, GitHubProject project)
        {
            if (name == null)
            {
                throw new ArgumentNullException(nameof(name));
            }
            Name = name;

            if (project == null)
            {
                throw new ArgumentNullException(nameof(project));
            }
            Project = project;
        }
Exemple #4
0
        public GitHubVersionsRepoUpdater(GitHubAuth gitHubAuth, GitHubProject project)
        {
            if (gitHubAuth == null)
            {
                throw new ArgumentNullException(nameof(gitHubAuth));
            }
            _gitHubAuth = gitHubAuth;

            if (project == null)
            {
                throw new ArgumentNullException(nameof(project));
            }
            _project = project;
        }
        public VersionsRepoUpdater(GitHubAuth gitHubAuth, GitHubProject project)
        {
            if (gitHubAuth == null)
            {
                throw new ArgumentNullException(nameof(gitHubAuth));
            }
            _gitHubAuth = gitHubAuth;

            if (project == null)
            {
                throw new ArgumentNullException(nameof(project));
            }
            _project = project;
        }
Exemple #6
0
        public GitHubBranch(string name, GitHubProject project)
        {
            if (name == null)
            {
                throw new ArgumentNullException(nameof(name));
            }
            Name = name;

            if (project == null)
            {
                throw new ArgumentNullException(nameof(project));
            }
            Project = project;
        }
        public PullRequestCreator(
            GitHubAuth auth,
            GitHubProject origin,
            GitHubBranch upstreamBranch,
            string gitAuthorName = null,
            IUpdateBranchNamingStrategy namingStrategy = null)
        {
            _auth = auth;

            Origin = origin;
            UpstreamBranch = upstreamBranch;

            GitAuthorName = gitAuthorName ?? auth.User;
            _namingStrategy = namingStrategy ?? new SingleBranchNamingStrategy("UpdateDependencies");
        }
        public PullRequestCreator(
            GitHubAuth auth,
            GitHubProject origin,
            GitHubBranch upstreamBranch,
            string gitAuthorName = null,
            IUpdateBranchNamingStrategy namingStrategy = null)
        {
            _auth = auth;

            Origin         = origin;
            UpstreamBranch = upstreamBranch;

            GitAuthorName   = gitAuthorName ?? auth.User;
            _namingStrategy = namingStrategy ?? new SingleBranchNamingStrategy("UpdateDependencies");
        }
        private async Task PostDiscardedCommitCommentAsync(
            GitHubProject baseProject,
            GitHubPullRequest pullRequestToUpdate,
            GitCommit oldCommit,
            GitHubClient client)
        {
            GitHubCombinedStatus combinedStatus = await client.GetStatusAsync(
                baseProject,
                oldCommit.Sha);

            CiStatusLine[] statuses = combinedStatus
                                      .Statuses
                                      .OrderBy(s => s.State)
                                      .ThenBy(s => s.Context)
                                      .Select(CiStatusLine.Create)
                                      .ToArray();

            string statusLines = statuses
                                 .Aggregate(string.Empty, (acc, line) => acc + line.MarkdownLine + "\r\n");

            string ciSummary = string.Join(
                " ",
                statuses
                .GroupBy(s => s.Emoticon)
                .Select(g => $"{g.Count()}{g.Key}")
                .ToArray());

            string commentBody =
                $"Discarded [`{oldCommit.Sha.Substring(0, 7)}`]({oldCommit.HtmlUrl}): " +
                $"`{oldCommit.Message}`";

            if (statuses.Any())
            {
                commentBody += "\r\n\r\n" +
                               "<details>" +
                               "<summary>" +
                               $"CI Status: {ciSummary} (click to expand)\r\n" +
                               "</summary>" +
                               $"\r\n\r\n{statusLines}\r\n" +
                               "</details>";
            }

            await client.PostCommentAsync(
                baseProject,
                pullRequestToUpdate.Number,
                commentBody);
        }
        public override bool Execute()
        {
            MsBuildTraceListener[] listeners = Trace.Listeners.AddMsBuildTraceListeners(Log);
            try
            {
                IDependencyUpdater[] updaters = GetDependencyUpdaters().ToArray();
                BuildInfo[] buildInfos = GetBuildInfos().ToArray();
                var updater = new DependencyUpdater();

                DependencyUpdateResults updateResults = updater.Update(updaters, buildInfos);

                if (updateResults.ChangesDetected())
                {
                    var gitHubAuth = new GitHubAuth(GitHubAuthToken, GitHubUser, GitHubEmail);

                    var origin = new GitHubProject(ProjectRepoName, GitHubUser);

                    var upstreamBranch = new GitHubBranch(
                        ProjectRepoBranch,
                        new GitHubProject(ProjectRepoName, ProjectRepoOwner));

                    string suggestedMessage = updateResults.GetSuggestedCommitMessage();
                    string body = string.Empty;
                    if (NotifyGitHubUsers != null)
                    {
                        body += PullRequestCreator.NotificationString(NotifyGitHubUsers.Select(item => item.ItemSpec));
                    }

                    var prCreator = new PullRequestCreator(gitHubAuth, origin, upstreamBranch, GitHubAuthor);
                    prCreator.CreateOrUpdateAsync(
                        suggestedMessage,
                        suggestedMessage + $" ({ProjectRepoBranch})",
                        body,
                        forceCreate: AlwaysCreateNewPullRequest).Wait();
                }
            }
            finally
            {
                Trace.Listeners.RemoveMsBuildTraceListeners(listeners);
            }

            return true;
        }
Exemple #11
0
        private async Task <string> CreateDiscardedCommitListBodyAsync(
            GitHubProject baseProject,
            GitHubPullRequest pullRequestToUpdate,
            GitCommit oldCommit,
            GitHubClient client)
        {
            // GitHub returns the HTML "commit" url, but we want "commits" so that CI results show.
            string oldCommitsUrl = oldCommit.HtmlUrl.Replace("commit", "commits");

            GitHubCombinedStatus combinedStatus = await client.GetStatusAsync(
                baseProject,
                oldCommit.Sha);

            string statusLines = combinedStatus
                                 .Statuses
                                 .OrderBy(s => s.State)
                                 .ThenBy(s => s.Context)
                                 .Select(GetStatusLine)
                                 .Aggregate(string.Empty, (acc, line) => acc + line + "\r\n");

            string oldCommitEntry =
                $" * [`{oldCommit.Sha.Substring(0, 7)}`]({oldCommitsUrl}) {oldCommit.Message}\r\n" +
                $"{statusLines}";

            // Find insertion point. GitHub always returns \r\n.
            string insertionMarker    = $"<{DiscardedCommitElementName}>\r\n\r\n";
            string endInsertionMarker = $"\r\n</{DiscardedCommitElementName}>";

            int elementBegin = pullRequestToUpdate.Body.IndexOf(
                insertionMarker,
                StringComparison.Ordinal);

            if (elementBegin != -1)
            {
                return(pullRequestToUpdate.Body.Insert(
                           elementBegin + insertionMarker.Length,
                           oldCommitEntry));
            }
            return(pullRequestToUpdate.Body +
                   "<details><summary>Discarded auto-update commits (click to expand)</summary>" +
                   $"{insertionMarker}{oldCommitEntry}{endInsertionMarker}" +
                   "</details>");
        }
Exemple #12
0
 public async Task CreateOrUpdateAsync(
     string commitMessage,
     string title,
     string description,
     GitHubBranch baseBranch,
     GitHubProject origin,
     PullRequestOptions options)
 {
     using (var client = new GitHubClient(_auth))
     {
         await CreateOrUpdateAsync(
             commitMessage,
             title,
             description,
             baseBranch,
             origin,
             options,
             client);
     }
 }
Exemple #13
0
 private string GetUpdateBlockedReason(
     GitHubHead head,
     GitCommit headCommit,
     string upgradeBranchPrefix,
     GitHubProject origin)
 {
     if (head.User.Login != origin.Owner)
     {
         return($"Owner of head repo '{head.User.Login}' is not '{origin.Owner}'");
     }
     if (!head.Ref.StartsWith(upgradeBranchPrefix))
     {
         return($"Ref name '{head.Ref}' does not start with '{upgradeBranchPrefix}'");
     }
     if (headCommit.Author.Name != GitAuthorName)
     {
         return($"Head commit author '{headCommit.Author.Name}' is not '{GitAuthorName}'");
     }
     if (headCommit.Committer.Name != GitAuthorName)
     {
         return($"Head commit committer '{headCommit.Committer.Name}' is not '{GitAuthorName}'");
     }
     return(null);
 }
        public async Task CreateOrUpdateAsync(
            string commitMessage,
            string title,
            string description,
            GitHubBranch baseBranch,
            GitHubProject origin,
            PullRequestOptions options)
        {
            options = options ?? new PullRequestOptions();

            var upstream = baseBranch.Project;

            using (var client = new GitHubClient(_auth))
            {
                GitHubBranch      originBranch        = null;
                GitHubPullRequest pullRequestToUpdate = null;

                IUpdateBranchNamingStrategy namingStrategy = options.BranchNamingStrategy
                                                             ?? new SingleBranchNamingStrategy("UpdateDependencies");

                string upgradeBranchPrefix = namingStrategy.Prefix(baseBranch.Name);

                if (!options.ForceCreate)
                {
                    pullRequestToUpdate = await client.SearchPullRequestsAsync(
                        upstream,
                        upgradeBranchPrefix,
                        _auth.User);

                    if (pullRequestToUpdate == null)
                    {
                        Trace.TraceInformation($"No existing pull request found.");
                    }
                    else
                    {
                        Trace.TraceInformation(
                            $"Pull request already exists for {upgradeBranchPrefix} in {upstream.Segments}. " +
                            $"#{pullRequestToUpdate.Number}, '{pullRequestToUpdate.Title}'");

                        GitCommit headCommit = await client.GetCommitAsync(
                            origin,
                            pullRequestToUpdate.Head.Sha);

                        string blockedReason = GetUpdateBlockedReason(
                            pullRequestToUpdate,
                            headCommit,
                            upgradeBranchPrefix,
                            origin);

                        if (blockedReason == null)
                        {
                            if (options.TrackDiscardedCommits)
                            {
                                await PostDiscardedCommitCommentAsync(
                                    baseBranch.Project,
                                    pullRequestToUpdate,
                                    headCommit,
                                    client);
                            }

                            originBranch = new GitHubBranch(
                                pullRequestToUpdate.Head.Ref,
                                origin);
                        }
                        else
                        {
                            string comment =
                                $"Couldn't update this pull request: {blockedReason}\n" +
                                $"Would have applied '{commitMessage}'";

                            await client.PostCommentAsync(upstream, pullRequestToUpdate.Number, comment);

                            return;
                        }
                    }
                }

                // No existing branch to update: push to a new one.
                if (originBranch == null)
                {
                    string newBranchName =
                        namingStrategy.Prefix(baseBranch.Name) +
                        namingStrategy.CreateFreshBranchNameSuffix(baseBranch.Name);

                    originBranch = new GitHubBranch(newBranchName, origin);
                }

                PushNewCommit(originBranch, commitMessage);

                if (pullRequestToUpdate != null)
                {
                    await client.UpdateGitHubPullRequestAsync(
                        upstream,
                        pullRequestToUpdate.Number,
                        title,
                        description,
                        maintainersCanModify : options.MaintainersCanModify);
                }
                else
                {
                    await client.PostGitHubPullRequestAsync(
                        title,
                        description,
                        originBranch,
                        baseBranch,
                        options.MaintainersCanModify);
                }
            }
        }
        protected override void TraceListenedExecute()
        {
            // Use the commit sha of versions repo master (not just "master") for stable upgrade.
            var gitHubAuth = new GitHubAuth(GitHubAuthToken, GitHubUser, GitHubEmail);
            var client = new GitHubClient(gitHubAuth);
            string masterSha = client
                .GetReferenceAsync(new GitHubProject("versions", "dotnet"), "heads/master")
                .Result.Object.Sha;

            foreach (ITaskItem item in DependencyBuildInfo)
            {
                if (!string.IsNullOrEmpty(item.GetMetadata(CurrentRefMetadataName)))
                {
                    item.SetMetadata(CurrentRefMetadataName, masterSha);
                }
                string autoUpgradeBranch = item.GetMetadata(AutoUpgradeBranchMetadataName);
                if (!string.IsNullOrEmpty(autoUpgradeBranch))
                {
                    item.SetMetadata(CurrentBranchMetadataName, autoUpgradeBranch);
                }
            }

            DependencyUpdateResults updateResults = DependencyUpdateUtils.Update(
                CreateUpdaters().ToArray(),
                CreateBuildInfoDependencies().ToArray());

            // Update CurrentRef and CurrentBranch for each applicable build info used.
            if (!string.IsNullOrEmpty(CurrentRefXmlPath))
            {
                foreach (BuildInfo info in updateResults.UsedBuildInfos)
                {
                    ITaskItem infoItem = FindDependencyBuildInfo(info.Name);

                    if (!string.IsNullOrEmpty(infoItem.GetMetadata(CurrentRefMetadataName)))
                    {
                        UpdateProperty(
                            CurrentRefXmlPath,
                            $"{info.Name}{CurrentRefMetadataName}",
                            masterSha);
                    }

                    string autoUpgradeBranch = infoItem.GetMetadata(AutoUpgradeBranchMetadataName);
                    if (!string.IsNullOrEmpty(autoUpgradeBranch))
                    {
                        UpdateProperty(
                            CurrentRefXmlPath,
                            $"{info.Name}{CurrentBranchMetadataName}",
                            autoUpgradeBranch);
                    }
                }
            }

            if (updateResults.ChangesDetected())
            {
                var origin = new GitHubProject(ProjectRepoName, GitHubUser);

                var upstreamBranch = new GitHubBranch(
                    ProjectRepoBranch,
                    new GitHubProject(ProjectRepoName, ProjectRepoOwner));

                string suggestedMessage = updateResults.GetSuggestedCommitMessage();
                string body = string.Empty;
                if (NotifyGitHubUsers != null)
                {
                    body += PullRequestCreator.NotificationString(NotifyGitHubUsers.Select(item => item.ItemSpec));
                }

                var prCreator = new PullRequestCreator(gitHubAuth, origin, upstreamBranch, GitHubAuthor);
                prCreator.CreateOrUpdateAsync(
                    suggestedMessage,
                    suggestedMessage + $" ({ProjectRepoBranch})",
                    body,
                    forceCreate: AlwaysCreateNewPullRequest).Wait();
            }
            else
            {
                Log.LogMessage("No update required: no changes detected.");
            }
        }
        protected override void TraceListenedExecute()
        {
            // Use the commit sha of versions repo master (not just "master") for stable upgrade.
            var gitHubAuth = new GitHubAuth(GitHubAuthToken, GitHubUser, GitHubEmail);
            var client = new GitHubClient(gitHubAuth);
            string masterSha = client
                .GetReferenceAsync(new GitHubProject("versions", "dotnet"), "heads/master")
                .Result.Object.Sha;

            foreach (ITaskItem item in DependencyBuildInfo)
            {
                if (!string.IsNullOrEmpty(item.GetMetadata(s_currentRef)))
                {
                    item.SetMetadata(s_currentRef, masterSha);
                }
            }

            DependencyUpdateResults updateResults = DependencyUpdateUtils.Update(
                CreateUpdaters().ToArray(),
                CreateBuildInfoDependencies().ToArray());

            if (!string.IsNullOrEmpty(CurrentRefXmlPath))
            {
                // Update the build info commit sha for each applicable build info used.
                foreach (BuildInfo info in updateResults.UsedBuildInfos)
                {
                    ITaskItem infoItem = FindDependencyBuildInfo(info.Name);
                    if (string.IsNullOrEmpty(infoItem.GetMetadata(s_currentRef)))
                    {
                        continue;
                    }

                    Regex upgrader = CreateXmlUpdateRegex($"{info.Name}{s_currentRef}", s_currentRef);

                    Action replace = FileUtils.ReplaceFileContents(
                        CurrentRefXmlPath,
                        contents =>
                        {
                            Match m = upgrader.Match(contents);
                            Group g = m.Groups[s_currentRef];

                            return contents
                                .Remove(g.Index, g.Length)
                                .Insert(g.Index, masterSha);
                        });
                    replace();
                }
            }

            if (updateResults.ChangesDetected())
            {
                var origin = new GitHubProject(ProjectRepoName, GitHubUser);

                var upstreamBranch = new GitHubBranch(
                    ProjectRepoBranch,
                    new GitHubProject(ProjectRepoName, ProjectRepoOwner));

                string suggestedMessage = updateResults.GetSuggestedCommitMessage();
                string body = string.Empty;
                if (NotifyGitHubUsers != null)
                {
                    body += PullRequestCreator.NotificationString(NotifyGitHubUsers.Select(item => item.ItemSpec));
                }

                var prCreator = new PullRequestCreator(gitHubAuth, origin, upstreamBranch, GitHubAuthor);
                prCreator.CreateOrUpdateAsync(
                    suggestedMessage,
                    suggestedMessage + $" ({ProjectRepoBranch})",
                    body,
                    forceCreate: AlwaysCreateNewPullRequest).Wait();
            }
            else
            {
                Log.LogMessage("No update required: no changes detected.");
            }
        }