Exemplo n.º 1
0
        /// <summary>
        /// Retrieves all active pull requests this user has created.
        /// </summary>
        /// <returns>An async stream of <see cref="PullRequestViewElement"/></returns>
        public async IAsyncEnumerable <PullRequestViewElement> FetchCreatedPullRequests()
        {
            foreach (var accountGroup in m_config.AccountsByUri)
            {
                Uri organizationUri = accountGroup.Key;

                using VssConnection connection = await GetConnectionAsync(organizationUri, accountGroup.Value);

                using GitHttpClient client = await connection.GetClientAsync <GitHttpClient>();

                {
                    // Capture the currentUserId so it can be used to filter PR's later.
                    //
                    Guid userId = connection.AuthorizedIdentity.Id;

                    // Only fetch pull requests which are active, and assigned to this user.
                    //
                    GitPullRequestSearchCriteria criteria = new GitPullRequestSearchCriteria
                    {
                        CreatorId    = userId,
                        Status       = PullRequestStatus.Active,
                        IncludeLinks = false,
                    };

                    foreach (AccountConfig account in accountGroup.Value)
                    {
                        List <GitPullRequest> requests = await client.GetPullRequestsByProjectAsync(account.Project, criteria);

                        foreach (var request in requests)
                        {
                            yield return(new PullRequestViewElement(request, account.Handler !)
                            {
                                CreatedMode = true
                            });
Exemplo n.º 2
0
        static void Main(string[] args)
        {
            VssConnection connection = GetVssConnection();

            ProjectHttpClient projectClient = connection.GetClient <ProjectHttpClient>();
            // Call to get the list of projects
            //IEnumerable<TeamProjectReference> projects = projectClient.GetProjects().Result;
            TeamProjectReference project = projectClient.GetProject("MITHRA").Result;


            GitHttpClient gitClient = connection.GetClient <GitHttpClient>();
            WorkItemTrackingHttpClient witClient = connection.GetClient <WorkItemTrackingHttpClient>();


            var repos = gitClient.GetRepositoriesAsync(project.Id, includeLinks: true).Result;
            var pullRequestSearchCriteria = new GitPullRequestSearchCriteria
            {
                Status       = PullRequestStatus.Completed,
                IncludeLinks = true,
            };
            List <GitPullRequest> allPullRequests = new List <GitPullRequest>();
            int skip      = 0;
            int threshold = 1000;

            foreach (var repo in repos)
            {
                Console.WriteLine($"{repo.Name} (DefaultBranch: {repo.DefaultBranch})");
                IList <GitPullRequest> prs = gitClient.GetPullRequestsAsync(repo.Id, pullRequestSearchCriteria, skip: skip, top: threshold
                                                                            ).Result;
                foreach (GitPullRequest pr in prs.Where(x => x.Repository.Id == repo.Id))
                {
                    Console.WriteLine("\t{0} #{1} {2} -> {3} ({4})",
                                      pr.Title.Substring(0, Math.Min(40, pr.Title.Length)),
                                      pr.PullRequestId,
                                      pr.SourceRefName,
                                      pr.TargetRefName,
                                      pr.CreatedBy.DisplayName);
                    //var prcommits = gitClient.GetPullRequestCommitsAsync(repo.Id, pr.PullRequestId).Result;
                    var tags    = gitClient.GetTagRefsAsync(repo.Id).Result;
                    var prlinks = gitClient.GetPullRequestWorkItemRefsAsync(project.Id, repo.Id, pr.PullRequestId).Result;
                    if (prlinks != null)
                    {
                        var wis = prlinks.ToList();
                        foreach (var wi in wis)
                        {
                            var workitem = witClient.GetWorkItemAsync(int.Parse(wi.Id)).Result;
                            Console.WriteLine($"\t\t{wi.Id} - {workitem.Fields["System.Title"]}");
                        }
                    }
                    else
                    {
                        Console.WriteLine("\t\tNo links found");
                    }
                }
            }
        }
        private async Task <List <GitPullRequest> > FetchPullRequests(GitHttpClient gitClient)
        {
            var searchCriteria = new GitPullRequestSearchCriteria
            {
                RepositoryId = _repositoryId,
                Status       = PullRequestStatus.Active
            };
            var prs = await gitClient.GetPullRequestsByProjectAsync(_projectId, searchCriteria);

            return(prs);
        }
Exemplo n.º 4
0
        private async Task <bool> IsDummyBranchAndOpenPrExists(CancellationToken token)
        {
            token.ThrowIfCancellationRequested();
            if (RefsInfo.Where(info => info.Name == DummyBranchName).Any())
            {
                // If the dummy branch exists, check if there is open PR exist
                var searchCriteria = new GitPullRequestSearchCriteria()
                {
                    RepositoryId  = this.RepositoryId,
                    Status        = PullRequestStatus.Active,
                    TargetRefName = DestBranch,
                    SourceRefName = DummyBranchName,
                };

                try
                {
                    var response = await GitHttpClient.GetPullRequestsByProjectAsync(Settings.TFSProjectName, searchCriteria, cancellationToken : token);

                    if (response.Count != 0)
                    {
                        // If there is an open PR, means the preious merge is not finished
                        Logger.Info($"There are existing pull requests between {DummyBranchName} and {DestBranch}");
                        return(true);
                    }
                    else
                    {
                        // If there is no open PR, delete the dummy branch because we are going to create a new PR
                        if (await RemoveBranch(DummyBranchName, token))
                        {
                            return(false);
                        }
                        else
                        {
                            Logger.Error("Fail to delete old dummy branch.");
                            return(true);
                        }
                    }
                }
                catch (OperationCanceledException)
                {
                    Logger.Error("Time out occurs when try to check whether dummy branch and open PR already exist");
                    throw;
                }
                catch (Exception e)
                {
                    Logger.Error($"Exception occurs when try to check whether dummy branch and open PR already exist, message: {e.Message}");
                    throw;
                }
            }
            else
            {
                return(false);
            }
        }
        /// <summary>
        /// TODO: Return an set of objects which contains data like - link to the PR
        /// </summary>
        /// <returns></returns>
        private async Task <int> FindActivePullRequestsAssignedForCurrentUser(Guid userId)
        {
            // TODO: Disabling this to save time
            //var repos = await GitHttpClient.GetRepositoriesAsync(false, null);
            //var vsoRepoId = repos.Where(r => r.Name.Equals("VSO")).FirstOrDefault().Id;

            var searchCriteria = new GitPullRequestSearchCriteria();

            searchCriteria.RepositoryId = VSO_REPO_ID;
            searchCriteria.ReviewerId   = userId;
            var gitClientResult = await GitHttpClient.GetPullRequestsAsync(VSO_REPO_ID, searchCriteria);

            return(gitClientResult.Count);
        }
        public int CreatePullRequest()
        {
            using (var client = CreateGitClient(out var authorizedIdenity))
            {
                var criteria = new GitPullRequestSearchCriteria
                {
                    Status        = PullRequestStatus.Active,
                    SourceRefName = _settings.SourceBranch,
                    TargetRefName = _settings.TargetBranch
                };

                var query = client.GetPullRequestsAsync(_settings.ProjectName, _settings.RepositoryName, criteria).Result;
                if (query.Count > 0)
                {
                    var item = query.First();
                    _log.Information("Pull Request already exists: {0}", item.Url);
                    return(item.PullRequestId);
                }

                var pr = client.CreatePullRequestAsync(
                    new GitPullRequest
                {
                    SourceRefName     = _settings.SourceBranch,
                    TargetRefName     = _settings.TargetBranch,
                    Title             = _settings.Title,
                    Description       = _settings.Description,
                    CompletionOptions = new GitPullRequestCompletionOptions
                    {
                        DeleteSourceBranch = _settings.DeleteSourceBranch,
                        SquashMerge        = _settings.SquashMerge,
                        BypassPolicy       = true,
                        BypassReason       = "Automatic Merge"
                    },
                    AutoCompleteSetBy = new IdentityRef
                    {
                        Id = authorizedIdenity.Id.ToString()
                    }
                },
                    _settings.ProjectName,
                    _settings.RepositoryName).Result;

                _log.Information("New Pull Request was created: {0}", pr.Url);
                return(pr.PullRequestId);
            }
        }
Exemplo n.º 7
0
        private async Task <bool> DoesDummyBranchAndOpenPrExist(IEnumerable <string> branchNames, CancellationToken token)
        {
            token.ThrowIfCancellationRequested();
            if (branchNames.Contains(DummyBranchName))
            {
                // If the dummy branch exists, check if there is open PR exist
                var searchCriteria = new GitPullRequestSearchCriteria()
                {
                    RepositoryId  = this.RepositoryId,
                    Status        = PullRequestStatus.Active,
                    TargetRefName = DestBranch,
                    SourceRefName = DummyBranchName,
                };

                var response = await gitHttpClient.GetPullRequestsByProjectAsync(Settings.TFSProjectName, searchCriteria, cancellationToken : token);

                if (response.Count != 0)
                {
                    // If there is an open PR, means the preious merge is not finished
                    Console.WriteLine($"There are existing pull requests between {DummyBranchName} and {DestBranch}");
                    return(true);
                }
                else
                {
                    // If there is no open PR, delete the dummy branch because we are going to create a new PR
                    if (await TryRemoveBranch(DummyBranchName, token))
                    {
                        return(false);
                    }
                    else
                    {
                        Console.WriteLine("Failed to delete old dummy branch.");
                        return(true);
                    }
                }
            }
            else
            {
                return(false);
            }
        }
Exemplo n.º 8
0
        /// <summary>
        /// Retrieves all active & actionable pull requests for a specific account.
        /// </summary>
        /// <param name="accountConfig">The account to get the pull requests for.</param>
        /// <param name="currentUserId">An out paramter that receives the <see cref="Guid"/> of the current user.</param>
        /// <returns>A stream of <see cref="GitPullRequest"/></returns>
        private static IEnumerable <GitPullRequest> FetchAccountActivePullRequsts(AccountConfig accountConfig, out Guid currentUserId)
        {
            // Create a connection to the AzureDevOps Git API.
            //
            using (VssConnection connection = GetConnection(accountConfig))
                using (GitHttpClient client = connection.GetClient <GitHttpClient>())
                {
                    // Capture the currentUserId so it can be used to filter PR's later.
                    //
                    currentUserId = connection.AuthorizedIdentity.Id;

                    // Only fetch pull requests which are active, and assigned to this user.
                    //
                    GitPullRequestSearchCriteria criteria = new GitPullRequestSearchCriteria
                    {
                        ReviewerId = currentUserId,
                        Status     = PullRequestStatus.Active,
                    };

                    return(client.GetPullRequestsAsync(accountConfig.Project, accountConfig.Project, criteria).Result);
                }
        }
Exemplo n.º 9
0
        public static async Task <IList <GitPullRequest> > GetPullRequests(
            GitHttpClient gitClient,
            string project)
        {
            List <GitPullRequest> pullCollection = new List <GitPullRequest>();
            List <GitRepository>  repos          = await gitClient.GetRepositoriesAsync(project);

            GitPullRequestSearchCriteria searchCriteria = new GitPullRequestSearchCriteria
            {
                Status = PullRequestStatus.Active
            };

            foreach (GitRepository repo in repos)
            {
                var pulls = await gitClient.GetPullRequestsAsync(project, repo.Id, searchCriteria);

                foreach (var pull in pulls)
                {
                    pullCollection.Add(pull);
                }
            }

            return(pullCollection);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="AzureDevOpsPullRequest"/> class.
        /// </summary>
        /// <param name="log">The Cake log context.</param>
        /// <param name="settings">Settings for accessing AzureDevOps.</param>
        /// <param name="gitClientFactory">A factory to communicate with Git client.</param>
        /// <exception cref="AzureDevOpsPullRequestNotFoundException">If <see cref="AzureDevOpsPullRequestSettings.ThrowExceptionIfPullRequestCouldNotBeFound"/>
        /// is set to <c>true</c> and no pull request could be found.</exception>
        internal AzureDevOpsPullRequest(ICakeLog log, AzureDevOpsPullRequestSettings settings, IGitClientFactory gitClientFactory)
        {
            log.NotNull(nameof(log));
            settings.NotNull(nameof(settings));
            gitClientFactory.NotNull(nameof(gitClientFactory));

            this.log = log;
            this.gitClientFactory = gitClientFactory;
            this.credentials      = settings.Credentials;
            this.throwExceptionIfPullRequestCouldNotBeFound = settings.ThrowExceptionIfPullRequestCouldNotBeFound;

            this.repositoryDescription = new RepositoryDescription(settings.RepositoryUrl);

            this.log.Verbose(
                "Repository information:\n  CollectionName: {0}\n  CollectionUrl: {1}\n  ProjectName: {2}\n  RepositoryName: {3}",
                this.repositoryDescription.CollectionName,
                this.repositoryDescription.CollectionUrl,
                this.repositoryDescription.ProjectName,
                this.repositoryDescription.RepositoryName);

            using (var gitClient = this.gitClientFactory.CreateGitClient(this.repositoryDescription.CollectionUrl, settings.Credentials, out var authorizedIdenity))
            {
                this.log.Verbose(
                    "Authorized Identity:\n  Id: {0}\n  DisplayName: {1}",
                    authorizedIdenity.Id,
                    authorizedIdenity.DisplayName);

                if (settings.PullRequestId.HasValue)
                {
                    this.log.Verbose("Read pull request with ID {0}", settings.PullRequestId.Value);
                    this.pullRequest =
                        gitClient
                        .GetPullRequestAsync(
                            this.repositoryDescription.ProjectName,
                            this.repositoryDescription.RepositoryName,
                            settings.PullRequestId.Value)
                        .ConfigureAwait(false)
                        .GetAwaiter()
                        .GetResult();
                }
                else if (!string.IsNullOrWhiteSpace(settings.SourceRefName))
                {
                    this.log.Verbose("Read pull request for branch {0}", settings.SourceRefName);

                    var pullRequestSearchCriteria =
                        new GitPullRequestSearchCriteria()
                    {
                        Status        = Microsoft.TeamFoundation.SourceControl.WebApi.PullRequestStatus.Active,
                        SourceRefName = settings.SourceRefName,
                    };

                    this.pullRequest =
                        gitClient
                        .GetPullRequestsAsync(
                            this.repositoryDescription.ProjectName,
                            this.repositoryDescription.RepositoryName,
                            pullRequestSearchCriteria,
                            top: 1)
                        .ConfigureAwait(false)
                        .GetAwaiter()
                        .GetResult()
                        .SingleOrDefault();
                }
                else
                {
                    throw new ArgumentOutOfRangeException(
                              nameof(settings),
                              "Either PullRequestId or SourceRefName needs to be set");
                }
            }

            if (this.pullRequest == null)
            {
                if (this.throwExceptionIfPullRequestCouldNotBeFound)
                {
                    throw new AzureDevOpsPullRequestNotFoundException("Pull request not found");
                }

                this.log.Warning("Could not find pull request");
                return;
            }

            this.log.Verbose(
                "Pull request information:\n  PullRequestId: {0}\n  RepositoryId: {1}\n  RepositoryName: {2}\n  SourceRefName: {3}",
                this.pullRequest.PullRequestId,
                this.pullRequest.Repository.Id,
                this.pullRequest.Repository.Name,
                this.pullRequest.SourceRefName);
        }
        /// <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);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="TfsPullRequestSystem"/> class.
        /// Connects to the TFS server using NTLM authentication.
        /// </summary>
        /// <param name="log">The Cake log context.</param>
        /// <param name="settings">Settings for accessing TFS.</param>
        public TfsPullRequestSystem(ICakeLog log, TfsPullRequestSettings settings)
            : base(log)
        {
            settings.NotNull(nameof(settings));

            this.settings = settings;

            this.repositoryDescription = new RepositoryDescription(settings.RepositoryUrl);

            this.Log.Verbose(
                "Repository information:\n  CollectionName: {0}\n  CollectionUrl: {1}\n  ProjectName: {2}\n  RepositoryName: {3}",
                this.repositoryDescription.CollectionName,
                this.repositoryDescription.CollectionUrl,
                this.repositoryDescription.ProjectName,
                this.repositoryDescription.RepositoryName);

            Identity authorizedIdenity;

            using (var gitClient = this.CreateGitClient(out authorizedIdenity))
            {
                this.Log.Verbose(
                    "Authorized Identity:\n  Id: {0}\n  DisplayName: {1}",
                    authorizedIdenity.Id,
                    authorizedIdenity.DisplayName);

                if (settings.PullRequestId.HasValue)
                {
                    this.Log.Verbose("Read pull request with ID {0}", settings.PullRequestId.Value);
                    this.pullRequest =
                        gitClient.GetPullRequestAsync(
                            this.repositoryDescription.ProjectName,
                            this.repositoryDescription.RepositoryName,
                            settings.PullRequestId.Value).Result;
                }
                else if (!string.IsNullOrWhiteSpace(settings.SourceBranch))
                {
                    this.Log.Verbose("Read pull request for branch {0}", settings.SourceBranch);

                    var pullRequestSearchCriteria =
                        new GitPullRequestSearchCriteria()
                    {
                        Status        = PullRequestStatus.Active,
                        SourceRefName = settings.SourceBranch
                    };

                    this.pullRequest =
                        gitClient.GetPullRequestsAsync(
                            this.repositoryDescription.ProjectName,
                            this.repositoryDescription.RepositoryName,
                            pullRequestSearchCriteria,
                            top: 1).Result.SingleOrDefault();
                }
                else
                {
                    throw new ArgumentOutOfRangeException(
                              nameof(settings),
                              "Either PullRequestId or SourceBranch needs to be set");
                }
            }

            if (this.pullRequest == null)
            {
                if (this.settings.ThrowExceptionIfPullRequestDoesNotExist)
                {
                    throw new PrcaException("Could not find pull request");
                }

                this.Log.Warning("Could not find pull request");
                return;
            }

            this.Log.Verbose(
                "Pull request information:\n  PullRequestId: {0}\n  RepositoryId: {1}\n  RepositoryName: {2}\n  SourceRefName: {3}",
                this.pullRequest.PullRequestId,
                this.pullRequest.Repository.Id,
                this.pullRequest.Repository.Name,
                this.pullRequest.SourceRefName);
        }
Exemplo n.º 13
0
        public async Task <Tuple <Uri, List <GitPullRequest> > > GetPullRequests(string project, GitPullRequestSearchCriteria searchCriteria, CancellationToken cancelToken = default)
        {
            GitHttpClient gitClient = await this.connection.GetClientAsync <GitHttpClient>(cancelToken);

            List <GitPullRequest> pullRequests = await gitClient.GetPullRequestsByProjectAsync(project, searchCriteria, cancellationToken : cancelToken);

            return(new Tuple <Uri, List <GitPullRequest> >(gitClient.BaseAddress, pullRequests));
        }