private bool ProcessPullRequestStatusAndGetShouldWait(
            GitClient client,
            PullRequestStatus pullRequestStatus,
            string pullRequestNumber,
            string sha)
        {
            var pullRequestLink = client.GetPullRequestLink(pullRequestNumber);

            switch (pullRequestStatus)
            {
            case PullRequestStatus.InProcess:
                Console.WriteLine($"Pull request {pullRequestLink} is in process, waiting.");
                return(true);

            case PullRequestStatus.CanBeMerged:
                client.Merge(pullRequestNumber, sha);
                Console.WriteLine($"Pull request {pullRequestLink} merged.");
                return(false);

            case PullRequestStatus.Merged:
                // Видимо мы замержили его руками, всё ок
                return(false);

            default:
                throw new InvalidOperationException(
                          $"Can't merge pull request {pullRequestLink} with status {pullRequestStatus}");
            }
        }
示例#2
0
        public async Task <PullRequestStatus> Status(PullRequest pullRequest, string projectKey)
        {
            string requestUrl = UrlBuilder.FormatRestApiUrl(PULL_REQUEST_MERGEABLE, null, projectKey,
                                                            pullRequest.FromRef.Repository.Slug, pullRequest.Id);

            PullRequestStatus pr = await _httpWorker.GetAsync <PullRequestStatus>(requestUrl).ConfigureAwait(false);

            return(pr);
        }
示例#3
0
            public void Should_Return_Correct_Value(PullRequestStatus state, AzureDevOpsPullRequestState expectedResult)
            {
                // Given

                // When
                var result = state.ToAzureDevOpsPullRequestState();

                // Then
                result.ShouldBe(expectedResult);
            }
示例#4
0
            public void Should_Throw_If_Invalid_Value_Is_Passed(PullRequestStatus state)
            {
                // Given

                // When
                var result =
                    Record.Exception(() => state.ToAzureDevOpsPullRequestState());

                // Then
                result.IsArgumentOutOfRangeException("state");
            }
示例#5
0
        public async Task UpdateStatus(
            string organisation,
            int pullRequestId,
            PullRequestStatus status)
        {
            var table = await _azureStorage.GetTable(PullRequestsTable);

            var entity = new DynamicTableEntity(organisation.ToLowerInvariant(), pullRequestId.ToString())
            {
                ETag       = "*",
                Properties = { { "Status", new EntityProperty(status.ToString()) } }
            };

            var mergeOperation = TableOperation.Merge(entity);
            await table.ExecuteAsync(mergeOperation);
        }
        private DateTime GetPullRequestWatermark(TeamProjectReference project, PullRequestStatus status)
        {
            // Default by going back to 1 month if no data has been ingested for this repo
            DateTime mostRecentDate = DateTime.UtcNow.AddMonths(-1);

            // Get latest ingested date for pull request from pull request watermark table
            using VssDbContext context = new VssDbContext(logger, this.sqlConnectionString);
            VssPullRequestWatermarkEntity latestWatermark = context.VssPullRequestWatermarkEntities.Where(v => v.ProjectId == project.Id && v.PullRequestStatus == status.ToString()).FirstOrDefault();

            if (latestWatermark != null)
            {
                mostRecentDate = latestWatermark.RowUpdatedDate;
            }

            return(mostRecentDate);
        }
        private void UpdatePullRequestWatermark(PullRequestStatus status, TeamProjectReference project)
        {
            VssPullRequestWatermarkEntity vssPullRequestWatermarkEntity = new VssPullRequestWatermarkEntity
            {
                RowUpdatedDate    = Helper.UtcNow,
                Organization      = this.vssClient.OrganizationName,
                ProjectId         = project.Id,
                ProjectName       = project.Name,
                PullRequestStatus = status.ToString(),
            };

            this.logger.LogInformation("Start ingesting pull request data...");
            using VssDbContext context = new VssDbContext(logger, this.sqlConnectionString);
            int ingestedResult = context.BulkInsertOrUpdate(new List <VssPullRequestWatermarkEntity> {
                vssPullRequestWatermarkEntity
            });

            this.logger.LogInformation($"Done ingesting {ingestedResult} records");
        }
示例#8
0
        /// <summary>
        /// Converts a <see cref="PullRequestStatus"/> to a <see cref="TfsPullRequestState"/>.
        /// </summary>
        /// <param name="state">State to convert.</param>
        /// <returns>Converted state.</returns>
        public static TfsPullRequestState ToTfsPullRequestState(this PullRequestStatus state)
        {
            switch (state)
            {
            case PullRequestStatus.NotSet:
                return(TfsPullRequestState.NotSet);

            case PullRequestStatus.Active:
                return(TfsPullRequestState.Active);

            case PullRequestStatus.Abandoned:
                return(TfsPullRequestState.Abandoned);

            case PullRequestStatus.Completed:
                return(TfsPullRequestState.Completed);

            default:
                throw new ArgumentOutOfRangeException(nameof(state));
            }
        }
        private void RetrieveAndIngestPullRequest(TeamProjectReference project, PullRequestStatus status)
        {
            // Query for most recent date from watermark table first
            DateTime mostRecentDate = this.GetPullRequestWatermark(project, status);

            // Retrieve pull requests from Azure DevOps
            IEnumerable <List <GitPullRequest> > pullRequestLists = this.vssClient.GitClient.GetPullRequestsWithRetry(project.Name, mostRecentDate, status);

            // For each list ingest pull requests retrieved from Azure DevOps
            foreach (List <GitPullRequest> pullRequestList in pullRequestLists)
            {
                this.IngestPullRequests(pullRequestList, project);
            }

            // Update watermark once data is successfully ingested so next time it doesn't repeat
            // Note: If there is an issue before getting to update, data ingestion will have to run again
            // Note: Since we are going back one month ingesting data again if watermark is unable to update
            // Note: shouldn't be much of a problem and likely not happen too often
            this.UpdatePullRequestWatermark(status, project);
        }
示例#10
0
        public int UpdatePullRequest(string[] args)
        {
            if (args.Length < 4)
            {
                Console.Error.WriteLine("usage: {0} <url> Git.UpdatePullRequest <repositoryId> <pullRequestId> <status> <lastMergeSourceCommitId>", Program.ProgramName);
                return(1);
            }

            Guid repositoryId        = new Guid(args[0]);
            int  pullRequestId       = int.Parse(args[1]);
            PullRequestStatus status = (PullRequestStatus)Enum.Parse(typeof(PullRequestStatus), args[2]);
            string            lastMergeSourceCommitId = args[3];

            Task.Run(async() =>
            {
                await Client.Git.UpdatePullRequest(repositoryId, pullRequestId, status, lastMergeSourceCommitId);
            }).Wait();

            return(0);
        }
        private static PullRequestState ConvertToTrackerState(PullRequestStatus status)
        {
            PullRequestState trackerState = PullRequestState.Open;

            switch (status)
            {
            case PullRequestStatus.NotSet:
            case PullRequestStatus.Active:
                trackerState = PullRequestState.Open;
                break;

            case PullRequestStatus.Abandoned:
            case PullRequestStatus.Completed:
                trackerState = PullRequestState.Closed;
                break;

            case PullRequestStatus.All:
                trackerState = PullRequestState.All;
                break;
            }

            return(trackerState);
        }
        /// <summary>
        /// Query all pull requests from today until min creation date where min creation date is in the past (inclusive)
        /// </summary>
        public IEnumerable <List <GitPullRequest> > GetPullRequestsWithRetry(string projectName, DateTime minDate, PullRequestStatus status)
        {
            if (minDate > Helper.UtcNow)
            {
                throw new ArgumentException("minDate must be less than today's date, all in UTC");
            }

            List <GitPullRequest> currentSetOfPullRequests = new List <GitPullRequest>();
            int skip = 0;
            int top  = 100;

            GitPullRequestSearchCriteria searchCriteria = new GitPullRequestSearchCriteria
            {
                Status = status,
            };

            do
            {
                this.logger.LogInformation($"Retrieving {status} pull requests for project {projectName} from {minDate} to {Helper.UtcNow}");

                // The last pull request is the where we want to check before stopping
                if (status == PullRequestStatus.Completed && currentSetOfPullRequests.Count > 0 && currentSetOfPullRequests.Last().ClosedDate < minDate)
                {
                    this.logger.LogInformation($"No more pull requests found before {minDate}");
                    break;
                }
                else if (status == PullRequestStatus.Active && currentSetOfPullRequests.Count > 0 && currentSetOfPullRequests.Last().CreationDate < minDate)
                {
                    this.logger.LogInformation($"No more pull requests found before {minDate}");
                    break;
                }
                else if (status == PullRequestStatus.Abandoned && currentSetOfPullRequests.Count > 0 && currentSetOfPullRequests.Last().ClosedDate < minDate)
                {
                    this.logger.LogInformation($"No more pull requests found before {minDate}");
                    break;
                }

                // Get pull requests from VSTS
                currentSetOfPullRequests = RetryHelper.SleepAndRetry(this.retryAfter, this.logger, async() =>
                {
                    try
                    {
                        return(await this.GetPullRequestsByProjectAsync(projectName, searchCriteria, skip: skip, top: top));
                    }
                    catch (VssServiceException ex)
                    {
                        // VSTS service fails to access a repo once in a while. It looks like an exception that we
                        // don't have control over so we'll catch it and move on.
                        // Sample exception: Microsoft.VisualStudio.Services.Common.VssServiceException: TF401019: The Git
                        // repository with name or identifier C50B9441-B35B-4F42-BDA9-9A01386B968F does not exist or you
                        // do not have permissions for the operation you are attempting.
                        if (ex.Message.Contains("TF401019"))
                        {
                            Console.WriteLine($"Warning: Ignore this error due to external VSTS service. {ex}");
                        }
                    }

                    return(currentSetOfPullRequests);
                }).Result;

                // VSO returns a chunk each time, filter out the ones that meet minDate requirements
                if (status == PullRequestStatus.Completed || status == PullRequestStatus.Abandoned)
                {
                    currentSetOfPullRequests = currentSetOfPullRequests.Where(v => v.ClosedDate > minDate).ToList();
                }
                else if (status == PullRequestStatus.Active)
                {
                    currentSetOfPullRequests = currentSetOfPullRequests.Where(v => v.CreationDate > minDate).ToList();
                }

                // Return a batch of requests at a time
                this.logger.LogInformation($"Retrieved {currentSetOfPullRequests.Count} pull requests");
                yield return(currentSetOfPullRequests);

                // Next set
                skip = skip + top;
            }while (currentSetOfPullRequests.Count > 0);
        }
示例#13
0
        /// <summary>
        /// Updates the pull request data, abandoning or completing it.
        /// </summary>
        /// <param name="repositoryId">The repository</param>
        /// <param name="pullRequestId">The pull request to update</param>
        /// <param name="status">The new status</param>
        /// <param name="lastMergeSourceCommitId">The last merge source commit ID (to confirm)</param>
        /// <returns>The updated pull request</returns>
        public async Task<PullRequest> UpdatePullRequest(Guid repositoryId, int pullRequestId, PullRequestStatus status, string lastMergeSourceCommitId)
        {
            Assert.NotNull(lastMergeSourceCommitId, "lastMergeSourceCommitId");

            var request = new TfsRestRequest("/_apis/git/repositories/{RepositoryId}/pullRequests/{PullRequestId}", new HttpMethod("PATCH"));
            request.AddUrlSegment("RepositoryId", repositoryId.ToString());
            request.AddUrlSegment("PullRequestId", pullRequestId.ToString());
            request.AddBody(new
            {
                status = status.ToString().ToLower(),
                lastMergeSourceCommit = new { commitId = lastMergeSourceCommitId }
            });

            return await Executor.Execute<PullRequest>(request);
        }
示例#14
0
 public static Uri PullRequestsUri(PullRequestStatus status, int skip)
 {
     return(MakeUri(PullRequests, Settings.Default.SourceTfsRepositoryName, status.ToString(), skip));
 }
示例#15
0
        static async Task Main(string[] args)
        {
            var result = new List <PullRequestStatus>();
            var client = new GitHubClient(new ProductHeaderValue("NsBoardReport"));

            client.Credentials = new Credentials("");

            var orgName  = "dotnet";
            var repoName = "standard";

            var teamByMember = new Dictionary <string, string>();
            var teamNames    = new List <string>();
            var teams        = await client.Organization.Team.GetAll(orgName);

            foreach (var team in teams)
            {
                if (team.Name.StartsWith("nsboard-", StringComparison.OrdinalIgnoreCase))
                {
                    teamNames.Add(team.Name);

                    var members = await client.Organization.Team.GetAllMembers(team.Id);

                    foreach (var member in members)
                    {
                        teamByMember.Add(member.Login, team.Name);
                    }
                }
            }

            var pullRequests = await client.PullRequest.GetAllForRepository(orgName, repoName);

            foreach (var pr in pullRequests)
            {
                var issue = await client.Issue.Get(orgName, repoName, pr.Number);

                if (!HasLabel(issue, "netstandard-api"))
                {
                    continue;
                }

                var teamStatus = new Dictionary <string, PullRequestReviewState>();

                var reviews = await client.PullRequest.Review.GetAll(orgName, repoName, pr.Number);

                foreach (var review in reviews)
                {
                    if (teamByMember.TryGetValue(review.User.Login, out var teamName))
                    {
                        teamStatus[teamName] = review.State.Value;
                    }
                }

                var teamStatusList = new List <PullRequestReviewState>(teamNames.Count);

                foreach (var team in teamNames)
                {
                    if (teamStatus.TryGetValue(team, out var status))
                    {
                        teamStatusList.Add(status);
                    }
                    else
                    {
                        teamStatusList.Add(PullRequestReviewState.Pending);
                    }
                }

                var prStatus = new PullRequestStatus(pr.Number, pr.Title, pr.Url, teamStatusList.ToArray());
                result.Add(prStatus);
            }

            using (var writer = new StreamWriter(@"P:\results.csv"))
            {
                writer.Write("ID;Title;Url;");

                foreach (var team in teamNames)
                {
                    writer.Write(team);
                    writer.Write(";");
                }

                writer.WriteLine();

                foreach (var prStatus in result)
                {
                    writer.Write(prStatus.Number);
                    writer.Write(";");
                    writer.Write(prStatus.Title);
                    writer.Write(";");
                    writer.Write(prStatus.Url);
                    writer.Write(";");

                    foreach (var state in prStatus.BoardStatus)
                    {
                        writer.Write(state);
                        writer.Write(";");
                    }

                    writer.WriteLine();
                }
            }
        }
示例#16
0
 public PullRequestQuery Status(PullRequestStatus status)
 {
     return(AddParameter("statusId[]", status.Id));
 }