mirror of
https://github.com/renovatebot/renovate.git
synced 2025-01-26 22:46:26 +00:00
Merge 74e9069051
into da5c5ed3f6
This commit is contained in:
commit
9a9be5e800
3 changed files with 148 additions and 23 deletions
|
@ -85,3 +85,35 @@ mutation EnablePullRequestAutoMerge(
|
|||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const getIssuesByIssueTypeQuery = `
|
||||
query(
|
||||
$queryStr: String!
|
||||
$count: Int,
|
||||
$cursor: String
|
||||
) {
|
||||
search(
|
||||
type: ISSUE
|
||||
first: $count,
|
||||
after: $cursor,
|
||||
query: $queryStr
|
||||
) {
|
||||
nodes {
|
||||
... on Issue {
|
||||
number
|
||||
title
|
||||
url
|
||||
labels (first:5) {
|
||||
nodes {
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pageInfo {
|
||||
endCursor
|
||||
hasNextPage
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -40,6 +40,9 @@ export interface GithubHttpOptions extends HttpOptions {
|
|||
interface GithubGraphqlRepoData<T = unknown> {
|
||||
repository?: T;
|
||||
}
|
||||
interface GithubGraphqlSearchData<T = unknown> {
|
||||
search?: T;
|
||||
}
|
||||
|
||||
export type GithubGraphqlResponse<T = unknown> =
|
||||
| {
|
||||
|
@ -422,6 +425,78 @@ export class GithubHttp extends Http<GithubHttpOptions> {
|
|||
}
|
||||
}
|
||||
|
||||
async querySearchField<T = Record<string, unknown>>(
|
||||
query: string,
|
||||
fieldName: string,
|
||||
options: GraphqlOptions = {},
|
||||
): Promise<T[]> {
|
||||
const result: T[] = [];
|
||||
|
||||
const { paginate = true } = options;
|
||||
|
||||
let optimalCount: null | number = null;
|
||||
let count = getGraphqlPageSize(
|
||||
fieldName,
|
||||
options.count ?? MAX_GRAPHQL_PAGE_SIZE,
|
||||
);
|
||||
let limit = options.limit ?? 1000;
|
||||
let cursor: string | null = null;
|
||||
|
||||
let isIterating = true;
|
||||
while (isIterating) {
|
||||
const res = await this.requestGraphql<GithubGraphqlSearchData<T>>(query, {
|
||||
...options,
|
||||
count: Math.min(count, limit),
|
||||
cursor,
|
||||
paginate,
|
||||
});
|
||||
const searchData = res?.data;
|
||||
if (
|
||||
is.nonEmptyObject(searchData) &&
|
||||
!is.nullOrUndefined(searchData[fieldName])
|
||||
) {
|
||||
optimalCount = count;
|
||||
|
||||
const {
|
||||
nodes = [],
|
||||
edges = [],
|
||||
pageInfo,
|
||||
} = searchData[fieldName] as GraphqlPaginatedContent<T>;
|
||||
result.push(...nodes);
|
||||
result.push(...edges);
|
||||
|
||||
limit = Math.max(0, limit - nodes.length - edges.length);
|
||||
|
||||
if (limit === 0) {
|
||||
isIterating = false;
|
||||
} else if (paginate && pageInfo) {
|
||||
const { hasNextPage, endCursor } = pageInfo;
|
||||
if (hasNextPage && endCursor) {
|
||||
cursor = endCursor;
|
||||
} else {
|
||||
isIterating = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
count = Math.floor(count / 2);
|
||||
if (count === 0) {
|
||||
logger.warn({ query, options, res }, 'Error fetching GraphQL nodes');
|
||||
isIterating = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!paginate) {
|
||||
isIterating = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (optimalCount && optimalCount < MAX_GRAPHQL_PAGE_SIZE) {
|
||||
setGraphqlPageSize(fieldName, optimalCount);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async queryRepoField<T = Record<string, unknown>>(
|
||||
query: string,
|
||||
fieldName: string,
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import { DateTime } from 'luxon';
|
||||
import { logger } from '../../lib/logger';
|
||||
import { getIssuesByIssueTypeQuery } from '../../lib/modules/platform/github/graphql';
|
||||
import * as hostRules from '../../lib/util/host-rules';
|
||||
import { GithubHttp } from '../../lib/util/http/github';
|
||||
import { getQueryString } from '../../lib/util/url';
|
||||
|
||||
const gitHubApiUrl = 'https://api.github.com/search/issues?';
|
||||
const githubApi = new GithubHttp();
|
||||
|
||||
if (process.env.GITHUB_TOKEN) {
|
||||
|
@ -15,17 +14,12 @@ if (process.env.GITHUB_TOKEN) {
|
|||
});
|
||||
}
|
||||
|
||||
type GithubApiQueryResponse = {
|
||||
total_count: number;
|
||||
incomplete_results: boolean;
|
||||
items: ItemsEntity[];
|
||||
};
|
||||
|
||||
export type ItemsEntity = {
|
||||
html_url: string;
|
||||
number: number;
|
||||
title: string;
|
||||
labels: LabelsEntity[];
|
||||
issueType: 'Bug' | 'Feature';
|
||||
};
|
||||
|
||||
export type LabelsEntity = {
|
||||
|
@ -46,6 +40,39 @@ export interface Items {
|
|||
features: ItemsEntity[];
|
||||
}
|
||||
|
||||
async function getIssuesByIssueType(
|
||||
issueType: 'Bug' | 'Feature',
|
||||
): Promise<ItemsEntity[]> {
|
||||
const queryString = `type:${issueType}, repo:renovatebot/renovate, state:open`;
|
||||
const res = (await githubApi.querySearchField<unknown>(
|
||||
getIssuesByIssueTypeQuery,
|
||||
'search',
|
||||
{
|
||||
variables: {
|
||||
queryStr: queryString,
|
||||
},
|
||||
paginate: true,
|
||||
readOnly: true,
|
||||
},
|
||||
)) as {
|
||||
labels: { nodes: { name: string }[] };
|
||||
number: number;
|
||||
title: string;
|
||||
url: string;
|
||||
}[];
|
||||
|
||||
return (
|
||||
res.map((issue) => {
|
||||
return {
|
||||
...issue,
|
||||
issueType,
|
||||
labels: issue.labels.nodes,
|
||||
html_url: issue.url,
|
||||
};
|
||||
}) ?? []
|
||||
);
|
||||
}
|
||||
|
||||
export async function getOpenGitHubItems(): Promise<RenovateOpenItems> {
|
||||
const result: RenovateOpenItems = {
|
||||
managers: {},
|
||||
|
@ -59,18 +86,10 @@ export async function getOpenGitHubItems(): Promise<RenovateOpenItems> {
|
|||
return result;
|
||||
}
|
||||
|
||||
const q = `repo:renovatebot/renovate type:issue is:open`;
|
||||
const per_page = 100;
|
||||
try {
|
||||
const query = getQueryString({ q, per_page });
|
||||
const res = await githubApi.getJsonUnchecked<GithubApiQueryResponse>(
|
||||
gitHubApiUrl + query,
|
||||
{
|
||||
paginationField: 'items',
|
||||
paginate: true,
|
||||
},
|
||||
const rawItems: ItemsEntity[] = (await getIssuesByIssueType('Bug')).concat(
|
||||
await getIssuesByIssueType('Feature'),
|
||||
);
|
||||
const rawItems = res.body?.items ?? [];
|
||||
|
||||
result.managers = extractIssues(rawItems, 'manager:');
|
||||
result.platforms = extractIssues(rawItems, 'platform:');
|
||||
|
@ -91,9 +110,8 @@ function extractIssues(items: ItemsEntity[], labelPrefix: string): OpenItems {
|
|||
const issuesMap: OpenItems = {};
|
||||
|
||||
for (const item of items) {
|
||||
const type = item.labels
|
||||
.find((l) => l.name.startsWith('type:'))
|
||||
?.name.split(':')[1];
|
||||
const type = item.issueType;
|
||||
|
||||
if (!type) {
|
||||
continue;
|
||||
}
|
||||
|
@ -107,10 +125,10 @@ function extractIssues(items: ItemsEntity[], labelPrefix: string): OpenItems {
|
|||
issuesMap[label] = { bugs: [], features: [] };
|
||||
}
|
||||
switch (type) {
|
||||
case 'bug':
|
||||
case 'Bug':
|
||||
issuesMap[label]?.bugs.push(item);
|
||||
break;
|
||||
case 'feature':
|
||||
case 'Feature':
|
||||
issuesMap[label]?.features.push(item);
|
||||
break;
|
||||
default:
|
||||
|
|
Loading…
Reference in a new issue