Example #1
0
 public async Task <IEnumerable <int> > SearchPullRequestsAsync(string repoUri, string pullRequestBranch, PrStatus status, string keyword = null, string author = null)
 {
     return(await _gitClient.SearchPullRequestsAsync(repoUri, pullRequestBranch, status, keyword, author));
 }
Example #2
0
        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);
        }
Example #3
0
        public async Task <IEnumerable <int> > SearchPullRequestsAsync(string repoUri, string pullRequestBranch, PrStatus status, string keyword = null, string author = null)
        {
            string              repoName = SetApiUriAndGetRepoName(repoUri);
            StringBuilder       query    = new StringBuilder();
            AzureDevOpsPrStatus prStatus;

            switch (status)
            {
            case PrStatus.Open:
                prStatus = AzureDevOpsPrStatus.Active;
                break;

            case PrStatus.Closed:
                prStatus = AzureDevOpsPrStatus.Abandoned;
                break;

            case PrStatus.Merged:
                prStatus = AzureDevOpsPrStatus.Completed;
                break;

            default:
                prStatus = AzureDevOpsPrStatus.None;
                break;
            }

            query.Append($"searchCriteria.sourceRefName=refs/heads/{pullRequestBranch}&searchCriteria.status={prStatus.ToString().ToLower()}");

            if (!string.IsNullOrEmpty(keyword))
            {
                _logger.LogInformation("A keyword was provided but Azure DevOps doesn't support searching for PRs based on keywords and it won't be used...");
            }

            if (!string.IsNullOrEmpty(author))
            {
                query.Append($"&searchCriteria.creatorId={author}");
            }

            HttpResponseMessage response = await this.ExecuteGitCommand(HttpMethod.Get, $"repositories/{repoName}/pullrequests?{query.ToString()}", _logger);

            JObject content = JObject.Parse(await response.Content.ReadAsStringAsync());
            JArray  values  = JArray.Parse(content["value"].ToString());

            IEnumerable <int> prs = values.Select(r => r["pullRequestId"].ToObject <int>());

            return(prs);
        }
Example #4
0
 public Task <IEnumerable <int> > SearchPullRequestsAsync(string repoUri, string pullRequestBranch, PrStatus status, string keyword = null, string author = null)
 {
     throw new NotImplementedException();
 }
Example #5
0
        public async Task Test(
            MergePolicy mergePolicy,
            PrStatus prStatus,
            bool existingPrHasChecks,
            bool existingPrPassedChecks)
        {
            Channel channel       = CreateChannel();
            Build   oldBuild      = CreateOldBuild();
            Build   build         = CreateNewBuild();
            var     buildChannels = new[]
            {
                new BuildChannel {
                    Build = oldBuild, Channel = channel
                },
                new BuildChannel {
                    Build = build, Channel = channel
                }
            };
            Subscription subscription = CreateSubscription(mergePolicy);

            subscription.Channel = channel;
            var repoInstallation =
                new RepoInstallation {
                Repository = subscription.TargetRepository, InstallationId = 1
            };
            Asset asset = build.Assets[0];
            await Context.RepoInstallations.AddAsync(repoInstallation);

            await Context.Subscriptions.AddAsync(subscription);

            await Context.BuildChannels.AddRangeAsync(buildChannels);

            await Context.SaveChangesAsync();

            var actorId    = new ActorId(subscription.Id);
            var existingPr = "https://repo.pr/existing";
            var pr         = "https://repo.pr/new";


            bool shouldMergeExistingPr = prStatus == PrStatus.Open && mergePolicy == MergePolicy.BuildSucceeded &&
                                         existingPrHasChecks && existingPrPassedChecks;

            void SetupCreatePr()
            {
                Darc.Setup(
                    d => d.CreatePullRequestAsync(
                        subscription.TargetRepository,
                        subscription.TargetBranch,
                        build.Commit,
                        It.IsAny <IList <AssetData> >(),
                        null,
                        null,
                        null))
                .ReturnsAsync(
                    (
                        string repo,
                        string branch,
                        string commit,
                        IList <AssetData> assets,
                        string baseBranch,
                        string title,
                        string description) =>
                {
                    assets.Should().BeEquivalentTo(new AssetData {
                        Name = asset.Name, Version = asset.Version
                    });
                    return(pr);
                });
            }

            void SetupUpdatePr()
            {
                Darc.Setup(
                    r => r.UpdatePullRequestAsync(
                        existingPr,
                        build.Commit,
                        subscription.TargetBranch,
                        It.IsAny <IList <AssetData> >(),
                        null,
                        null))
                .ReturnsAsync(
                    (
                        string url,
                        string commit,
                        string branch,
                        IList <AssetData> assets,
                        string title,
                        string description) =>
                {
                    return(url);
                });
            }

            void SetupExistingPr()
            {
                StateManager.Data[SubscriptionActor.PullRequest] =
                    new InProgressPullRequest {
                    BuildId = oldBuild.Id, Url = existingPr
                };
                Darc.Setup(r => r.GetPullRequestStatusAsync(existingPr)).ReturnsAsync(prStatus);
                if (mergePolicy == MergePolicy.BuildSucceeded && prStatus == PrStatus.Open)
                {
                    if (existingPrHasChecks)
                    {
                        Darc.Setup(r => r.GetPullRequestChecksAsync(existingPr))
                        .ReturnsAsync(
                            new List <Check>
                        {
                            new Check(
                                existingPrPassedChecks ? CheckStatus.Succeeded : CheckStatus.Failed,
                                "check",
                                "https://check.stuff/1")
                        });
                    }
                    else
                    {
                        Darc.Setup(r => r.GetPullRequestChecksAsync(existingPr)).ReturnsAsync(new List <Check>());
                    }
                }

                if (shouldMergeExistingPr)
                {
                    Darc.Setup(r => r.MergePullRequestAsync(existingPr, null, null, null, null))
                    .Returns(Task.CompletedTask);
                }
            }

            switch (prStatus)
            {
            case PrStatus.None:
                SetupCreatePr();
                break;

            case PrStatus.Open:
                SetupExistingPr();
                if (shouldMergeExistingPr)
                {
                    SetupCreatePr();
                }
                else
                {
                    SetupUpdatePr();
                }

                break;

            case PrStatus.Merged:
                SetupExistingPr();
                SetupCreatePr();
                break;

            case PrStatus.Closed:
                SetupExistingPr();
                SetupCreatePr();
                break;
            }


            var actor = ActivatorUtilities.CreateInstance <SubscriptionActor>(Scope.ServiceProvider, actorId);
            await actor.UpdateAsync(build.Id);

            if (shouldMergeExistingPr || prStatus == PrStatus.Merged)
            {
                subscription.LastAppliedBuildId.Should().Be(oldBuild.Id);
            }
            else
            {
                subscription.LastAppliedBuildId.Should().Be(null);
            }

            StateManager.Data.Should()
            .BeEquivalentTo(
                new Dictionary <string, object>
            {
                [SubscriptionActor.PullRequest] = new InProgressPullRequest
                {
                    BuildId = build.Id,
                    Url     = prStatus == PrStatus.Open && !shouldMergeExistingPr ? existingPr : pr
                }
            });

            Reminders.Data.Should()
            .BeEquivalentTo(
                new Dictionary <string, MockReminderManager.Reminder>
            {
                [SubscriptionActor.PullRequestCheck] = new MockReminderManager.Reminder(
                    SubscriptionActor.PullRequestCheck,
                    Array.Empty <byte>(),
                    TimeSpan.FromMinutes(5),
                    TimeSpan.FromMinutes(5))
            });
        }
Example #6
0
        public async Task SynchronizeInProgressPRAsync(
            PrStatus prStatus,
            bool existingPrHasChecks,
            bool existingPrPassedChecks)
        {
            Channel channel       = CreateChannel();
            Build   oldBuild      = CreateOldBuild();
            Build   build         = CreateNewBuild();
            var     buildChannels = new[]
            {
                new BuildChannel {
                    Build = oldBuild, Channel = channel
                },
                new BuildChannel {
                    Build = build, Channel = channel
                }
            };
            Subscription subscription = CreateSubscription(MergePolicy.BuildSucceeded);

            subscription.Channel = channel;
            var repoInstallation =
                new RepoInstallation {
                Repository = subscription.TargetRepository, InstallationId = 1
            };
            await Context.RepoInstallations.AddAsync(repoInstallation);

            await Context.Subscriptions.AddAsync(subscription);

            await Context.BuildChannels.AddRangeAsync(buildChannels);

            await Context.SaveChangesAsync();

            var existingPr = "https://repo.pr/existing";
            var actorId    = new ActorId(subscription.Id);

            StateManager.Data[SubscriptionActor.PullRequest] =
                new InProgressPullRequest {
                BuildId = oldBuild.Id, Url = existingPr
            };

            Darc.Setup(d => d.GetPullRequestStatusAsync(existingPr)).ReturnsAsync(prStatus);

            if (prStatus == PrStatus.Open)
            {
                if (existingPrHasChecks)
                {
                    Darc.Setup(d => d.GetPullRequestChecksAsync(existingPr))
                    .ReturnsAsync(
                        new List <Check>
                    {
                        new Check(
                            existingPrPassedChecks ? CheckStatus.Succeeded : CheckStatus.Failed,
                            "check",
                            "https://check.stuff/1")
                    });
                }
                else
                {
                    Darc.Setup(d => d.GetPullRequestChecksAsync(existingPr)).ReturnsAsync(new List <Check>());
                }

                if (existingPrHasChecks && existingPrPassedChecks)
                {
                    Darc.Setup(d => d.MergePullRequestAsync(existingPr, null, null, null, null))
                    .Returns(Task.CompletedTask);
                }
            }

            var actor = ActivatorUtilities.CreateInstance <SubscriptionActor>(Scope.ServiceProvider, actorId);
            await actor.ReceiveReminderAsync(
                SubscriptionActor.PullRequestCheck,
                Array.Empty <byte>(),
                TimeSpan.Zero,
                TimeSpan.FromMinutes(5));

            switch (prStatus)
            {
            case PrStatus.Merged:
                subscription.LastAppliedBuildId.Should().Be(oldBuild.Id);
                goto case PrStatus.Closed;

            case PrStatus.Closed:
                Reminders.Data.Should().BeEmpty();
                StateManager.Data.Should().BeEmpty();
                break;
            }
        }