Exemple #1
0
        public void NotifyUserAboutPullRequestWithUnresolvedConflicts(
            int pullRequestNumber,
            string gitHubUserName,
            IRepositoryConnectionContext repoContext,
            string pullRequestBranchName,
            string destinationBranch,
            string pullRequestUrl)
        {
            var comment = $"Cannot merge automatically. @{gitHubUserName} please resolve conflicts manually, approve review and merge pull request."
                          + "\r\n\r\n"
                          + "How to do it (using the GIT command line):\r\n"
                          + $"1. Fetch changes from server and checkout '{destinationBranch}' branch\r\n"
                          + "   ```\r\n"
                          + $"   git fetch && git checkout {destinationBranch} && " + "git reset --hard @{u}\r\n"
                          + "   ```\r\n"
                          + $"2. Merge 'origin/{pullRequestBranchName}' branch and resolve conflicts\r\n"
                          + "   ```\r\n"
                          + $"   git merge --no-ff origin/{pullRequestBranchName}\r\n"
                          + "   ```\r\n"
                          + $"4. Approve [pull request]({pullRequestUrl}/files#submit-review) review\r\n"
                          + $"5. Push changes to {destinationBranch}\r\n"
                          + "   ```\r\n"
                          + $"   git push origin {destinationBranch}\r\n"
                          + "   ```\r\n";

            repoContext.AddPullRequestComment(pullRequestNumber, comment);
            repoContext.AddReviewerToPullRequest(pullRequestNumber, new[] { gitHubUserName });
            repoContext.AssignUsersToPullRequest(pullRequestNumber, new[] { gitHubUserName });
        }
Exemple #2
0
        private string RetrieveChangesOriginalAuthorFromPush(
            PushInfoModel pushInfo,
            IRepositoryConnectionContext repoContext,
            out string coAuthorString
            )
        {
            var coAuthoredLineRegex = new Regex(@"^Co-authored-by: (?<author>.+)", RegexOptions.IgnoreCase | RegexOptions.Multiline);

            if (pushInfo.HeadCommitAuthorUserName == _cfg.AutomergeBotGitHubUserName)
            {
                var headCommitMessage = repoContext.GetCommitMessage(pushInfo.HeadCommitSha);
                var match             = coAuthoredLineRegex.Match(headCommitMessage);
                if (match.Success)
                {
                    coAuthorString = match.Value;
                    var r = new Regex(@"^Co-authored-by: (?<author>[\w\.\-]+)");
                    return(r.Match(match.Value).Groups["author"].Value);
                }

                _logger.LogError(
                    "Pushed changes head commit is made by us ({automergeBotGitHubUserName}) but does not contain \"Co-authored-by\" in the message. " +
                    "Merge commit will be missing original author of the changes.", _cfg.AutomergeBotGitHubUserName);
            }

            coAuthorString = CreateCoAuthoredByMessageForNewPullRequest(pushInfo);
            return(pushInfo.HeadCommitAuthorUserName);
        }
 public RepositoryConnectionContextExceptionHandlingWrapper(
     ILogger logger,
     IRepositoryConnectionContext repositoryConnectionContext)
 {
     _logger = logger;
     _repositoryConnectionContext = repositoryConnectionContext;
 }
        private List <PullRequest> GetOpenPullRequestsTargetingBranch(IRepositoryConnectionContext repoContext, string targetBranchName)
        {
            var openPullRequestsTargetingBranch = repoContext
                                                  .GetOpenPullRequests()
                                                  .Where(pr => pr.Base.Ref == targetBranchName)
                                                  .Where(pr => pr.User.Login == _cfg.AutomergeBotGitHubUserName);

            return(openPullRequestsTargetingBranch.ToList());
        }
Exemple #5
0
        private bool IsMonitoredRepository(PushInfoModel pushInfo, IRepositoryConnectionContext repoContext)
        {
            if (repoContext.IsMonitoredRepository(pushInfo.RepositoryId))
            {
                return(true);
            }

            _logger.LogDebug("Push is not from monitored repository ({RepositoryOwner}/{RepositoryName})",
                             _cfg.RepositoryOwner, _cfg.RepositoryName);
            return(false);
        }
        public void RetryMergePullRequestsCreatedBefore(PushInfoModel pushInfo, IRepositoryConnectionContext repoContext)
        {
            var targetBranchName = pushInfo.GetPushedBranchName().Name;

            _logger.LogInformation("Retrying merging pull requests created by AutomergeBot before and not merged yet to branch {targetBranch}", targetBranchName);

            var openPullRequestsTargetingBranch = GetOpenPullRequestsTargetingBranch(repoContext, targetBranchName);

            if (openPullRequestsTargetingBranch.Any())
            {
                _logger.LogDebug("There is {openPullRequestsCount} pull requests which potentially could be merged", openPullRequestsTargetingBranch.Count);
                foreach (var pullRequest in openPullRequestsTargetingBranch)
                {
                    _mergePerformer.TryMergeExistingPullRequest(pullRequest, repoContext);
                }
            }
        }
Exemple #7
0
        public bool CanProcessPush(PushInfoModel pushInfo, IRepositoryConnectionContext repoContext)
        {
            if (!IsMonitoredRepository(pushInfo, repoContext))
            {
                return(false);
            }
            if (!IsPushAddingNewCommits(pushInfo))
            {
                return(false);
            }
            if (IsPushedToIgnoredBranch(pushInfo))
            {
                return(false);
            }
            if (!IsAutomergeEnabledForAuthorOfLastestCommit(pushInfo))
            {
                return(false);
            }

            return(true);
        }
Exemple #8
0
        private bool TryCreatePullRequest(BranchName sourceBranch,
                                          BranchName destinationBranchName,
                                          IRepositoryConnectionContext repoContext,
                                          out PullRequest pullRequest,
                                          PushInfoModel pushInfo,
                                          string changesOriginalAuthor)
        {
            var title = $"{Consts.AutomergeBotPullRequestTitlePrefix} {pushInfo.GetPushedBranchName()} @{pushInfo.GetHeadCommitShaShort()} -> {destinationBranchName}";
            var body  = $"Last change author: {changesOriginalAuthor}";

            try
            {
                pullRequest = repoContext.CreatePullRequest(sourceBranch, destinationBranchName, title, body);
                return(true);
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Creating pull request failed.");
                pullRequest = null;
                return(false);
            }
        }
        private void TryDoMerges(PushInfoModel pushInfo, IRepositoryConnectionContext repoContext)
        {
            if (!TryGetMergeDestinationBranches(pushInfo.GetPushedBranchName(), out var destinationBranchNames))
            {
                return;
            }

            _logger.LogInformation("Merging to {destinationBranchesCount} branches: {destinationBranchNames}",
                                   destinationBranchNames.Length, destinationBranchNames);

            foreach (var destinationBranchName in destinationBranchNames)
            {
                try
                {
                    _mergePerformer.TryMergePushedChanges(pushInfo, destinationBranchName, repoContext);
                }
                catch (Exception e)
                {
                    _logger.LogCritical(e, "Failed merging {commitSha} to {branchName}", pushInfo.HeadCommitSha, pushInfo.GetPushedBranchName());
                }
            }
        }
Exemple #10
0
        public void TryMergePushedChanges(
            PushInfoModel pushInfo,
            BranchName destinationBranchName,
            IRepositoryConnectionContext repoContext)
        {
            var branchForPullRequest = CreateBranchNameForPush(pushInfo.GetPushedBranchName(), pushInfo.HeadCommitSha, destinationBranchName);

            repoContext.CreateBranch(branchForPullRequest, pushInfo.HeadCommitSha);

            var changesOriginalAuthor = RetrieveChangesOriginalAuthorFromPush(pushInfo, repoContext, out var coAuthorString);

            var createPullRequestSucceeded = TryCreatePullRequest(branchForPullRequest, destinationBranchName, repoContext, out var pullRequest, pushInfo, changesOriginalAuthor);

            if (!createPullRequestSucceeded)
            {
                _logger.LogWarning("Temp branch {branchName} for not created pull request has to be removed manually", branchForPullRequest);
                return;
            }

            var mergeCommitMessage = CreateMergeCommitMessage(pullRequest, coAuthorString);

            if (repoContext.MergePullRequest(pullRequest.Number, mergeCommitMessage))
            {
                _logger.LogInformation("Pull request {pullRequestNumber} created and merged", pullRequest.Number);
            }
            else
            {
                _logger.LogInformation("Pull request {pullRequestNumber} created but could not be merged automatically", pullRequest.Number);

                _userNotifier.NotifyUserAboutPullRequestWithUnresolvedConflicts(
                    pullRequest.Number,
                    changesOriginalAuthor,
                    repoContext,
                    branchForPullRequest.Name,
                    destinationBranchName.Name,
                    pullRequest.HtmlUrl);
            }
        }
Exemple #11
0
        public void TryMergeExistingPullRequest(
            PullRequest pullRequest,
            IRepositoryConnectionContext repoContext)
        {
            var coAuthorString     = CreateCoAuthoredByMessageForExistingPullRequest(pullRequest);
            var mergeCommitMessage = CreateMergeCommitMessage(pullRequest, coAuthorString);

            if (repoContext.MergePullRequest(pullRequest.Number, mergeCommitMessage))
            {
                _logger.LogInformation(
                    "Successfully merged pull request #{pullRequestNumber} into {branchName}",
                    pullRequest.Number,
                    pullRequest.Base.Ref);

                repoContext.AddPullRequestComment(pullRequest.Number, Consts.SuccessfulMergeComment);
            }
            else
            {
                _logger.LogInformation(
                    "Merging pull request #{pullRequestNumber} into {branchName} cannot be done automatically",
                    pullRequest.Number,
                    pullRequest.Base.Ref);
            }
        }