Example #1
0
        // creates a new pr to the target branch after the old pr is merged
        public async Task CreateNewPR(MergeData data)
        {
            var client = await GetInstallationClientAsync(data.InstallationId);

            // check that the pr went through first
            var mergedPR = await client.PullRequest.Get(data.RepositoryOwner, data.RepositoryName, data.PullRequestNumber);

            if (!mergedPR.Merged)
            {
                log.LogError("The pull request was not merged yet.");
                return;
            }

            var sourceBranch = mergedPR.Base.Ref; // this could? be a commit hash too
            var pr           = new NewPullRequest($"AutoMerge: {sourceBranch} to {data.BranchName} by @{data.MergeIssuer}", sourceBranch, data.BranchName);

            log.LogInformation($"Creating new PR: {sourceBranch} to {data.BranchName}");
            var result = await client.PullRequest.Create(data.RepositoryOwner, data.RepositoryName, pr);

            // assign ownership
            log.LogInformation($"Created PR {result.Number}. Assigning ownership to {data.MergeIssuer}");
            var reviewReq = new PullRequestReviewRequest(new List <string> {
                data.MergeIssuer
            });
            await client.PullRequest.ReviewRequest.Create(data.RepositoryOwner, data.RepositoryName, result.Number, reviewReq);

            // TODO handle invalid BranchName

            log.LogInformation("Leaving a comment on closed PR.");
            // leave a comment on the merged PR
            var comment = $"Ok @{data.MergeIssuer}, I've created Pull Request #{result.Number} for you that merges `{sourceBranch}` into `{data.BranchName}`.";
            await client.Issue.Comment.Create(data.RepositoryOwner, data.RepositoryName, data.PullRequestNumber, comment);
        }
Example #2
0
        public static async Task Run([QueueTrigger("scheduledprsqueue", Connection = "AzureWebJobsStorage")] string myQueueItem, ILogger log)
        {
            MergeData mdQueueObject = Newtonsoft.Json.JsonConvert.DeserializeObject <MergeData>(myQueueItem);

            log.LogInformation($"Queue trigger function processed: Merge time " + mdQueueObject.MergeTime + " and branch name " + mdQueueObject.BranchName);

            // this env var should have an xml body containing an RSA key
            var xmlGHPrivateKey = Environment.GetEnvironmentVariable("GitHubPrivateKey");
            var handler         = new GitHubEventHandlers(log, xmlGHPrivateKey, GitHubWebhook.AppId);

            try
            {
                await handler.PassMergeAsync(mdQueueObject);

                await handler.MergePRAsync(mdQueueObject);

                if (!string.IsNullOrWhiteSpace(mdQueueObject.BranchName))
                {
                    // branchname specified, then create new PR from this PR's dest to the specified dest
                    await handler.CreateNewPR(mdQueueObject);
                }
            }
            catch (Exception e)
            {
                log.LogInformation(e, "Caught exception when handling queue item.");
            }
        }
Example #3
0
        public async Task AckAddToQueueAsync(MergeData data)
        {
            var client = await GetInstallationClientAsync(data.InstallationId);

            log.LogInformation($"ACKing to PR comment {data.RepositoryOwner}/{data.RepositoryName}#{data.PullRequestNumber}");

            var message = $"Ok @{data.MergeIssuer} , I'll merge this Pull Request at `{data.MergeTime}` UTC + about 5 minutes. (Currently it's `{DateTime.UtcNow}` UTC.)";
            await client.Issue.Comment.Create(data.RepositoryOwner, data.RepositoryName, data.PullRequestNumber, message);
        }
 // gets the rest of merge data from one that was created from a tag or PR comment/body
 private static MergeData GetMergeData(this MergeData fromBody, WebhookPayload payload)
 {
     if (fromBody == null)
     {
         return(null);                  // silently fail
     }
     fromBody.RepositoryOwner   = payload.Repository.Owner.Login;
     fromBody.RepositoryName    = payload.Repository.Name;
     fromBody.PullRequestNumber = payload.PullRequest?.Number ?? payload.Issue?.Number ?? -1;
     fromBody.PullRequestAuthor = payload.PullRequest?.User?.Login;
     fromBody.MergeIssuer       = payload.Sender?.Login;
     fromBody.InstallationId    = payload.Installation?.Id ?? 0;
     return(fromBody);
 }
Example #5
0
        public async Task PassMergeAsync(MergeData data)
        {
            var client = await GetInstallationClientAsync(data.InstallationId);

            var pr = await client.PullRequest.Get(data.RepositoryOwner, data.RepositoryName, data.PullRequestNumber);

            var prHead = pr.Head;

            var checkRun = new NewCheckRun($"PublishingScheduler Auto-Merge", prHead.Ref);

            checkRun.Status     = CheckStatus.Completed;
            checkRun.Conclusion = CheckConclusion.Success;
            checkRun.Output     = new NewCheckRunOutput($"{data.MergeTime} UTC", $"An auto-merge is scheduled for {data.MergeTime} UTC.");
            await client.Check.Run.Create(data.RepositoryOwner, data.RepositoryName, checkRun);
        }
        private static string InsertMessageToQueue(CloudQueue cQueueToInsert, MergeData mdMessageData, TimeSpan tsTimeToExecute)
        {
            // AddMessage has no return value, so failure will only show as exception
            try
            {
                // prep object and add to queue
                string            sMessageDataJson = JsonConvert.SerializeObject(mdMessageData);
                CloudQueueMessage cqMessage        = new CloudQueueMessage(sMessageDataJson);
                cQueueToInsert.AddMessage(cqMessage, null, tsTimeToExecute, null, null);

                string sResult = "Message : " + Environment.NewLine + sMessageDataJson + Environment.NewLine + " ---- for " + cqMessage.Id + " inserted into queue.";

                return(sResult);
            } catch (Exception eThrownException)
            {
                return(eThrownException.Message);
            }
        }
Example #7
0
        public async Task MergePRAsync(MergeData data)
        {
            var client = await GetInstallationClientAsync(data.InstallationId);

            log.LogInformation($"Merging Pull Request: {data.RepositoryOwner}/{data.RepositoryName}#{data.PullRequestNumber}");

            var x = await client.PullRequest.Get(data.RepositoryOwner, data.RepositoryName, data.PullRequestNumber);

            log.LogInformation($"PR #{data.PullRequestNumber} mergeable status {x.Mergeable} {x.State}");


            // check requester association
            var valid = new List <string>()
            {
                "MEMBER", "COLLABORATOR", "OWNER"
            };

            if (!valid.Contains(data.RequesterAssociation))
            {
                // user is not allowed to do this
                await client.Issue.Comment.Create(data.RepositoryOwner, data.RepositoryName, data.PullRequestNumber, $"Auto-merge blocked, user @{data.MergeIssuer} ({data.RequesterAssociation}) does not have the association required to merge.");

                return;
            }

            if (x.Mergeable == false)
            {
                await client.Issue.Comment.Create(data.RepositoryOwner, data.RepositoryName, data.PullRequestNumber, $"Auto-merge blocked by unmergeable state. @{data.MergeIssuer}, please resolve this and merge manually.");
            }
            else
            {
                await client.PullRequest.Merge(data.RepositoryOwner, data.RepositoryName, data.PullRequestNumber,
                                               new MergePullRequest()
                {
                    // AutoMerge #123 from Chris-Johnston: Implement the thing and solve world hunger
                    CommitTitle = $"AutoMerge #{data.PullRequestNumber} from {data.MergeIssuer}: {x.Title}",
                    MergeMethod = PullRequestMergeMethod.Squash,     // HACK: need to check which merge methods are allowed by the repo and pick one that will work.
                });
            }
        }