From ba8469382a5c99b7da4f107df10c709dde77ca91 Mon Sep 17 00:00:00 2001 From: Ella Hathaway <67609881+ellahathaway@users.noreply.github.com> Date: Thu, 13 Jun 2024 13:27:58 -0700 Subject: [PATCH] Enhancements to Pull Request Creation/Update in `CreateBaselineUpdatePR` Tool (#41160) --- .../tools/CreateBaselineUpdatePR/PRCreator.cs | 142 ++++++++++++------ 1 file changed, 95 insertions(+), 47 deletions(-) diff --git a/src/SourceBuild/content/eng/tools/CreateBaselineUpdatePR/PRCreator.cs b/src/SourceBuild/content/eng/tools/CreateBaselineUpdatePR/PRCreator.cs index 037e653a1a55..22db665d97f6 100644 --- a/src/SourceBuild/content/eng/tools/CreateBaselineUpdatePR/PRCreator.cs +++ b/src/SourceBuild/content/eng/tools/CreateBaselineUpdatePR/PRCreator.cs @@ -280,72 +280,120 @@ private async Task CreateParentTreeAsync(TreeResponse testResultsT private async Task CreateOrUpdatePullRequestAsync(TreeResponse parentTreeResponse, int buildId, string title, string targetBranch) { - // Look for a pre-existing pull request - var request = new PullRequestRequest - { - Base = targetBranch - }; - var existingPullRequest = await _client.PullRequest.GetAllForRepository(_repoOwner, _repoName, request); - var matchingPullRequest = existingPullRequest.FirstOrDefault(pr => pr.Title == title); + var existingPullRequest = await GetExistingPullRequestAsync(title, targetBranch); // Create the branch name and get the head reference string newBranchName = string.Empty; - Reference? headReference = null; - if (matchingPullRequest == null) + string headSha = await GetHeadShaAsync(targetBranch); + if (existingPullRequest == null) { string utcTime = DateTime.UtcNow.ToString("yyyyMMddHHmmss"); newBranchName = $"pr-baseline-{utcTime}"; - headReference = await _client.Git.Reference.Get(_repoOwner, _repoName, "heads/" + targetBranch); } else { - newBranchName = matchingPullRequest.Head.Ref; - headReference = await _client.Git.Reference.Get(_repoOwner, _repoName, "heads/" + matchingPullRequest.Head.Ref); - } - - // Create the commit - string commitMessage = $"Update baselines for build {BuildLink}{buildId} (internal Microsoft link)"; - var newCommit = new NewCommit(commitMessage, parentTreeResponse.Sha, headReference.Object.Sha); - var commitResponse = await _client.Git.Commit.Create(_repoOwner, _repoName, newCommit); - - string pullRequestBody = $"This PR was created by the `CreateBaselineUpdatePR` tool for build {buildId}. \n\n" + - $"The updated test results can be found at {BuildLink}{buildId} (internal Microsoft link)"; - if (matchingPullRequest != null) - { - // Update the existing pull request with the new commit - var referenceUpdate = new ReferenceUpdate(commitResponse.Sha); - await _client.Git.Reference.Update(_repoOwner, _repoName, $"heads/{newBranchName}", referenceUpdate); + newBranchName = existingPullRequest.Head.Ref; - // Update the body of the pull request - var pullRequestUpdate = new PullRequestUpdate + try { - Body = pullRequestBody - }; - await _client.PullRequest.Update(_repoOwner, _repoName, matchingPullRequest.Number, pullRequestUpdate); + // Merge the target branch into the existing pull request + var merge = new NewMerge(newBranchName, headSha); + await _client.Repository.Merging.Create(_repoOwner, _repoName, merge); + } + catch (Exception e) + { + Log.LogWarning($"Failed to merge the target branch into the existing pull request: {e.Message}"); + Log.LogWarning("Continuing with updating the existing pull request. You may need to resolve conflicts manually in the PR."); + } - Log.LogInformation($"Updated existing pull request #{matchingPullRequest.Number}. URL: {matchingPullRequest.HtmlUrl}"); + headSha = await GetHeadShaAsync(newBranchName); } - else + + var commitSha = await CreateCommitAsync(parentTreeResponse.Sha, headSha, $"Update baselines for build {BuildLink}{buildId} (internal Microsoft link)"); + if (await ShouldMakeUpdatesAsync(headSha, commitSha)) { - var comparison = await _client.Repository.Commit.Compare(_repoOwner, _repoName, headReference.Object.Sha, commitResponse.Sha); - if (!comparison.Files.Any()) + string pullRequestBody = $"This PR was created by the `CreateBaselineUpdatePR` tool for build {buildId}. \n\n" + + $"The updated test results can be found at {BuildLink}{buildId} (internal Microsoft link)"; + if (existingPullRequest != null) { - // No changes to commit - Log.LogInformation("No changes to commit. Skipping PR creation."); - return; + await UpdatePullRequestAsync(newBranchName, commitSha, pullRequestBody, existingPullRequest); } + else + { + await CreatePullRequestAsync(newBranchName, commitSha, targetBranch, title, pullRequestBody); + } + } + } - // Create a new pull request - var newReference = new NewReference("refs/heads/" + newBranchName, commitResponse.Sha); - await _client.Git.Reference.Create(_repoOwner, _repoName, newReference); + private async Task GetExistingPullRequestAsync(string title, string targetBranch) + { + var request = new PullRequestRequest + { + Base = targetBranch + }; + var existingPullRequest = await _client.PullRequest.GetAllForRepository(_repoOwner, _repoName, request); + return existingPullRequest.FirstOrDefault(pr => pr.Title == title); + } - var newPullRequest = new NewPullRequest(title, newBranchName, targetBranch) - { - Body = pullRequestBody - }; - var pullRequest = await _client.PullRequest.Create(_repoOwner, _repoName, newPullRequest); + private async Task CreateCommitAsync(string newSha, string headSha, string commitMessage) + { + var newCommit = new NewCommit(commitMessage, newSha, headSha); + var commit = await _client.Git.Commit.Create(_repoOwner, _repoName, newCommit); + return commit.Sha; + } - Log.LogInformation($"Created pull request #{pullRequest.Number}. URL: {pullRequest.HtmlUrl}"); + private async Task ShouldMakeUpdatesAsync(string headSha, string commitSha) + { + var comparison = await _client.Repository.Commit.Compare(_repoOwner, _repoName, headSha, commitSha); + if (!comparison.Files.Any()) + { + Log.LogInformation("No changes to commit. Skipping PR creation/updates."); + return false; } + return true; + } + + private async Task UpdatePullRequestAsync(string branchName, string commitSha, string body, PullRequest pullRequest) + { + await UpdateReferenceAsync(branchName, commitSha); + + var pullRequestUpdate = new PullRequestUpdate + { + Body = body + }; + await _client.PullRequest.Update(_repoOwner, _repoName, pullRequest.Number, pullRequestUpdate); + + Log.LogInformation($"Updated existing pull request #{pullRequest.Number}. URL: {pullRequest.HtmlUrl}"); + } + + private async Task CreatePullRequestAsync(string newBranchName, string commitSha, string targetBranch, string title, string body) + { + await CreateReferenceAsync(newBranchName, commitSha); + + var newPullRequest = new NewPullRequest(title, newBranchName, targetBranch) + { + Body = body + }; + var pullRequest = await _client.PullRequest.Create(_repoOwner, _repoName, newPullRequest); + + Log.LogInformation($"Created pull request #{pullRequest.Number}. URL: {pullRequest.HtmlUrl}"); + } + + private async Task GetHeadShaAsync(string branchName) + { + var reference = await _client.Git.Reference.Get(_repoOwner, _repoName, $"heads/{branchName}"); + return reference.Object.Sha; + } + + private async Task UpdateReferenceAsync(string branchName, string commitSha) + { + var referenceUpdate = new ReferenceUpdate(commitSha); + await _client.Git.Reference.Update(_repoOwner, _repoName, $"heads/{branchName}", referenceUpdate); + } + + private async Task CreateReferenceAsync(string branchName, string commitSha) + { + var newReference = new NewReference($"refs/heads/{branchName}", commitSha); + await _client.Git.Reference.Create(_repoOwner, _repoName, newReference); } } \ No newline at end of file