Beispiel #1
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);
        }
Beispiel #2
0
        private bool IsPushAddingNewCommits(PushInfoModel pushInfo)
        {
            if (!pushInfo.Deleted && !pushInfo.Forced && pushInfo.Ref.StartsWith(Consts.RefsHeads))
            {
                return(true);
            }

            _logger.LogDebug("Push does not add new commits. Perhaps it is force push, tags push etc.");
            return(false);
        }
Beispiel #3
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 Handle(PushInfoModel pushInfo)
        {
            if (!CanProcess(pushInfo))
            {
                return;
            }

            DoCriticalTasks(pushInfo);

            DoNonCriticalTasks(pushInfo);
        }
Beispiel #5
0
        private bool IsPushedToIgnoredBranch(PushInfoModel pushInfo)
        {
            var branchName = pushInfo.GetPushedBranchName();

            if (branchName.Name.StartsWith(_cfg.CreatedBranchesPrefix))
            {
                _logger.LogDebug("Push is on branch {branchName} which is created by us", branchName);
                return(true);
            }

            return(false);
        }
        private bool CanProcess(PushInfoModel pushInfo)
        {
            using (var repoContext = _repositoryConnectionProvider.GetRepositoryConnection())
            {
                if (!_processPushPredicate.CanProcessPush(pushInfo, repoContext))
                {
                    return(false);
                }
            }

            return(true);
        }
 private void DoNonCriticalTasks(PushInfoModel pushInfo)
 {
     try
     {
         using (var repoContext = _repositoryConnectionProvider.GetRepositoryConnection())
         {
             _pullRequestMergeRetryier.RetryMergePullRequestsCreatedBefore(pushInfo, repoContext);
         }
     }
     catch (Exception e)
     {
         _logger.LogError(e, "Failed performing non-critical tasks when processing push notification");
     }
 }
 private void DoCriticalTasks(PushInfoModel pushInfo)
 {
     try
     {
         using (var repoContext = _repositoryConnectionProvider.GetRepositoryConnection())
         {
             TryDoMerges(pushInfo, repoContext);
         }
     }
     catch (Exception e)
     {
         _logger.LogCritical(e, "Failed performing critical tasks when processing push notification");
     }
 }
        private void HandlePushNotification(HttpContext context, string payloadJson)
        {
            var pushPayload   = JsonConvert.DeserializeObject <JObject>(payloadJson);
            var pushHandler   = context.RequestServices.GetRequiredService <MergingBranchesPushHandler>();
            var pushInfoModel = PushInfoModel.CreateFromPayload(pushPayload);

            _logger.LogInformation("Started processing push notification {@payloadModel}", pushInfoModel);
            try
            {
                pushHandler.Handle(pushInfoModel);
            }
            finally
            {
                _logger.LogInformation("Finished processing push notification");
            }
        }
        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);
                }
            }
        }
Beispiel #11
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);
        }
Beispiel #12
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);
            }
        }
Beispiel #13
0
        private bool IsAutomergeEnabledForAuthorOfLastestCommit(PushInfoModel pushInfo)
        {
            if (!(_cfg.AutomergeOnlyForAuthors ?? new List <string>()).Any())
            {
                return(true);
            }

            var headCommitAuthor = pushInfo.HeadCommitAuthorUserName.Trim();

            if (headCommitAuthor == _cfg.AutomergeBotGitHubUserName)
            {
                return(true);
            }

            var enabledForAuthor = _cfg.AutomergeOnlyForAuthors.Any(x => x.Trim() == headCommitAuthor);

            if (!enabledForAuthor)
            {
                _logger.LogWarning("Automerging is not enabled for commit author {commitAuthorUserName}", pushInfo.HeadCommitAuthorUserName);
            }
            return(enabledForAuthor);
        }
        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());
                }
            }
        }
Beispiel #15
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);
            }
        }
Beispiel #16
0
 private static string CreateCoAuthoredByMessageForNewPullRequest(PushInfoModel pushInfo)
 {
     return($"Co-authored-by: {pushInfo.HeadCommitAuthorUserName} <{pushInfo.HeadCommitAuthorEmail}>");
 }