private async Task <ActionResult <bool?> > CheckMergePolicyAsync(string prUrl, IRemote darc) { IReadOnlyList <MergePolicyDefinition> policyDefinitions = await GetMergePolicyDefinitions(); MergePolicyEvaluationResult result = await MergePolicyEvaluator.EvaluateAsync( prUrl, darc, policyDefinitions); if (result.Failed || result.Pending) { await UpdateStatusCommentAsync( darc, prUrl, $@"## Auto-Merge Status This pull request has not been merged because Maestro++ is waiting on the following merge policies. {string.Join("\n", result.Results.OrderBy(r => r.Policy == null ? " " : r.Policy.Name).Select(DisplayPolicy))}"); return(ActionResult.Create( result.Pending ? (bool?)null : false, $"NOT Merged: PR '{prUrl}' failed policies {string.Join(", ", result.Results.Where(r => r.Success == null || r.Success == false).Select(r => r.Policy?.Name + r.Message))}")); } if (result.Succeeded) { var merged = false; try { await darc.MergePullRequestAsync(prUrl, new MergePullRequestParameters()); merged = true; } catch { // Failure to merge is not exceptional, report on it. } await UpdateStatusCommentAsync( darc, prUrl, $@"## Auto-Merge Status This pull request {(merged ? "has been merged" : "will be merged")} because the following merge policies have succeeded. {string.Join("\n", result.Results.OrderBy(r => r.Policy == null ? " " : r.Policy.Name).Select(DisplayPolicy))}"); if (merged) { return(ActionResult.Create( (bool?)true, $"Merged: PR '{prUrl}' passed policies {string.Join(", ", policyDefinitions.Select(p => p.Name))}")); } return(ActionResult.Create((bool?)false, $"NOT Merged: PR '{prUrl}' has merge conflicts.")); } return(ActionResult.Create((bool?)false, "NOT Merged: There are no merge policies")); }
private async Task <string> CheckMergePolicyInternalAsync( IRemote darc, IList <MergePolicyDefinition> policyDefinitions, InProgressPullRequest pr) { var results = new List <(MergePolicy policy, MergePolicyEvaluationResult result)>(); if (policyDefinitions != null) { foreach (MergePolicyDefinition policyDefinition in policyDefinitions) { var context = new MergePolicyEvaluationContext(pr.Url, darc, Logger, policyDefinition.Properties); if (PolicyEvaluators.TryGetValue(policyDefinition.Name, out MergePolicy policyEvaluator)) { MergePolicyEvaluationResult result = await policyEvaluator.EvaluateAsync(context); results.Add((policyEvaluator, result)); } else { results.Add((null, context.Fail($"Unknown Merge Policy '{policyDefinition.Name}'"))); } } } if (results.Count == 0) { await UpdateStatusCommentAsync( darc, pr, $@"## Auto-Merge Status This pull request will not be merged automatically because the subscription with id '{SubscriptionId}' does not have any merge policies."); return(NotMergedNoPolicies()); } string DisplayPolicy((MergePolicy policy, MergePolicyEvaluationResult result) p) { (MergePolicy policy, MergePolicyEvaluationResult result) = p; if (policy == null) { return($"- ❌ **{result.Message}**"); } if (result.Succeeded) { return($"- ✔️ **{policy.DisplayName}** Succeeded"); } return($"- ❌ **{policy.DisplayName}** {result.Message}"); } if (results.Any(r => !r.result.Succeeded)) { await UpdateStatusCommentAsync( darc, pr, $@"## Auto-Merge Status This pull request has not been merged because the subscription with id '{SubscriptionId}' is waiting on the following merge policies. {string.Join("\n", results.OrderBy(r => r.policy == null ? " " : r.policy.Name).Select(DisplayPolicy))}"); return(NotMergedFailedPolicies(results.Where(r => !r.result.Succeeded), pr.Url)); } await UpdateStatusCommentAsync( darc, pr, $@"## Auto-Merge Status This pull request has been merged because the following merge policies have succeeded. {string.Join("\n", results.OrderBy(r => r.policy == null ? " " : r.policy.Name).Select(DisplayPolicy))}"); await darc.MergePullRequestAsync(pr.Url, null); return(Merged(policyDefinitions, pr.Url)); }
public async Task SynchronizeInProgressPRAsync() { Subscription subscription = await Context.Subscriptions.FindAsync(SubscriptionId); if (subscription == null) { await Reminders.TryUnregisterReminderAsync(PullRequestCheck); await StateManager.TryRemoveStateAsync(PullRequest); return; } ConditionalValue <InProgressPullRequest> maybePr = await StateManager.TryGetStateAsync <InProgressPullRequest>(PullRequest); if (maybePr.HasValue) { InProgressPullRequest pr = maybePr.Value; long installationId = await Context.GetInstallationId(subscription.TargetRepository); IRemote darc = await DarcFactory.CreateAsync(pr.Url, installationId); MergePolicy policy = subscription.PolicyObject.MergePolicy; PrStatus status = await darc.GetPullRequestStatusAsync(pr.Url); switch (status) { case PrStatus.Open: switch (policy) { case MergePolicy.Never: return; case MergePolicy.BuildSucceeded: case MergePolicy.UnitTestPassed: // for now both of these cases are the same if (await ShouldMergePrAsync(darc, pr.Url, policy)) { await darc.MergePullRequestAsync(pr.Url); goto merged; } return; default: Logger.LogError("Unknown merge policy '{policy}'", policy); return; } case PrStatus.Merged: merged: subscription.LastAppliedBuildId = pr.BuildId; await Context.SaveChangesAsync(); goto case PrStatus.Closed; case PrStatus.Closed: await StateManager.RemoveStateAsync(PullRequest); break; default: Logger.LogError("Unknown pr status '{status}'", status); return; } } await Reminders.TryUnregisterReminderAsync(PullRequestCheck); }