예제 #1
0
 public static RateLimitInfo Add(RateLimitInfo current, RateLimitInfo next) => new RateLimitInfo()
 {
     Limit     = next.Limit,
     Remaining = next.Remaining,
     Cost      = current.Cost + next.Cost,
     ResetAt   = next.ResetAt
 };
예제 #2
0
        public async Task <SearchResults <IReadOnlyList <IssueData> > > SearchIssuesAsync(string query, string accessToken)
        {
            var queryRequest = new GraphQlQueryRequest(Queries.SearchIssues);

            queryRequest.Variables["searchQuery"]       = query;
            queryRequest.Variables["pageSize"]          = PageSize;
            queryRequest.Variables["assigneeBatchSize"] = AssigneeBatchSize;
            queryRequest.Variables["labelBatchSize"]    = LabelBatchSize;
            queryRequest.Variables["cursor"]            = null;

            var issues    = new List <IssueData>();
            var pageIndex = 0;

            var data          = default(SearchResults <Dtos.ConnectionResult <Dtos.Issue> >);
            var rateLimitInfo = new RateLimitInfo();

            do
            {
                if (data != null)
                {
                    queryRequest.Variables["cursor"] = data.Search.PageInfo.EndCursor;
                }

                var req = new HttpRequestMessage(HttpMethod.Post, GraphQlEndpoint);
                req.Headers.UserAgent.Add(new ProductInfoHeaderValue("hubbup.io", Startup.Version));
                req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

                var json = JsonConvert.SerializeObject(queryRequest, _settings);

                req.Content = new StringContent(json);
                req.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");

                _logger.LogTrace("Requesting page {PageIndex} of search results from GitHub for query '{Query}'", pageIndex, query);

                HttpResponseMessage resp;
                using (_metricsService.Time("GitHubDataSource:RequestSearchResultPage"))
                {
                    resp = await _client.SendAsync(req);

                    _metricsService.Increment($"GitHubDataSource:SearchResultResponses:{(int)resp.StatusCode}");

                    if (!resp.IsSuccessStatusCode)
                    {
                        var content = await resp.Content.ReadAsStringAsync();

                        throw new HttpRequestException($"Received {resp.StatusCode} response from GitHub: {content}");
                    }

                    json = await resp.Content.ReadAsStringAsync();
                }

                var result = JsonConvert.DeserializeObject <Dtos.GraphQlResult <SearchResults <Dtos.ConnectionResult <Dtos.Issue> > > >(json, _settings);
                if (result.Errors != null && result.Errors.Any())
                {
                    throw new InvalidOperationException(result.Errors.First().Message);
                }
                data = result.Data;

                // Add rate limit info
                _logger.LogTrace("Request completed, consumed {Cost} of rate limit {Limit}. Remaining: {Remaining}, resets at {ResetAt}",
                                 data.RateLimit.Cost,
                                 data.RateLimit.Limit,
                                 data.RateLimit.Remaining,
                                 data.RateLimit.ResetAt);
                rateLimitInfo = RateLimitInfo.Add(rateLimitInfo, data.RateLimit);

                var count = 0;
                foreach (var issue in data.Search.Nodes)
                {
                    var issueData = new IssueData()
                    {
                        Id           = issue.Id,
                        IsPr         = string.Equals(issue.Type, "PullRequest", StringComparison.Ordinal),
                        Url          = issue.Url,
                        Number       = issue.Number,
                        Repository   = issue.Repository,
                        Title        = issue.Title,
                        Author       = issue.Author,
                        Milestone    = issue.Milestone,
                        CreatedAt    = issue.CreatedAt.ToPacificTime(),
                        UpdatedAt    = issue.UpdatedAt.ToPacificTime(),
                        CommentCount = issue.Comments.TotalCount
                    };

                    _metricsService.Record("GitHubDataSource:LabelsPerIssue", issue.Labels.TotalCount);
                    _metricsService.Record("GitHubDataSource:AssigneesPerIssue", issue.Assignees.TotalCount);

                    // Log a warning if there are labels or assignees beyond the ones we fetched
                    // We could make additional requests to fetch these if we find we need them.
                    if (issue.Labels.PageInfo.HasNextPage)
                    {
                        _logger.LogWarning("Issue {RepositoryOwner}/{RepositoryName}#{IssueNumber} has more than the limit of {Limit} labels.", issue.Repository.Owner.Name, issue.Repository.Name, issue.Number, AssigneeBatchSize);
                    }
                    if (issue.Assignees.PageInfo.HasNextPage)
                    {
                        _logger.LogWarning("Issue {RepositoryOwner}/{RepositoryName}#{IssueNumber} has more than the limit of {Limit} assignees.", issue.Repository.Owner.Name, issue.Repository.Name, issue.Number, LabelBatchSize);
                    }

                    // Load the assignees and labels
                    foreach (var assignee in issue.Assignees.Nodes)
                    {
                        issueData.Assignees.Add(assignee);
                    }

                    foreach (var label in issue.Labels.Nodes)
                    {
                        label.ForeColor = ColorMath.GetHexForeColorForBackColor(label.Color);
                        issueData.Labels.Add(label);
                    }

                    // Add this to the list of issues
                    issues.Add(issueData);
                    count += 1;
                }
                _metricsService.Increment("GitHubDataSource:IssuesLoaded", count);

                pageIndex += 1;
            } while (data.Search.PageInfo.HasNextPage);

            return(new SearchResults <IReadOnlyList <IssueData> >(issues, rateLimitInfo, pageIndex));
        }