mirror of
https://github.com/renovatebot/renovate.git
synced 2026-10-25 06:51:11 +00:00
feat(github): Use schema for issue objects (#27782)
This commit is contained in:
@@ -48,6 +48,7 @@ query(
|
||||
state
|
||||
title
|
||||
body
|
||||
updatedAt
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1632,11 +1632,15 @@ describe('modules/platform/github/index', () => {
|
||||
number: 2,
|
||||
state: 'open',
|
||||
title: 'title-2',
|
||||
body: 'body-2',
|
||||
updatedAt: '2022-01-01T00:00:00Z',
|
||||
},
|
||||
{
|
||||
number: 1,
|
||||
state: 'open',
|
||||
title: 'title-1',
|
||||
body: 'body-1',
|
||||
updatedAt: '2021-01-01T00:00:00Z',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -1665,11 +1669,15 @@ describe('modules/platform/github/index', () => {
|
||||
number: 2,
|
||||
state: 'open',
|
||||
title: 'title-2',
|
||||
body: 'body-2',
|
||||
updatedAt: '2022-01-01T00:00:00Z',
|
||||
},
|
||||
{
|
||||
number: 1,
|
||||
state: 'open',
|
||||
title: 'title-1',
|
||||
body: 'body-1',
|
||||
updatedAt: '2021-01-01T00:00:00Z',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -1677,9 +1685,21 @@ describe('modules/platform/github/index', () => {
|
||||
},
|
||||
})
|
||||
.get('/repos/undefined/issues/2')
|
||||
.reply(200, { body: 'new-content' });
|
||||
.reply(200, {
|
||||
number: 2,
|
||||
state: 'open',
|
||||
title: 'title-2',
|
||||
body: 'new-content',
|
||||
updated_at: '2023-01-01T00:00:00Z',
|
||||
});
|
||||
const res = await github.findIssue('title-2');
|
||||
expect(res).not.toBeNull();
|
||||
expect(res).toEqual({
|
||||
number: 2,
|
||||
state: 'open',
|
||||
title: 'title-2',
|
||||
body: 'new-content',
|
||||
lastModified: '2023-01-01T00:00:00Z',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1704,11 +1724,15 @@ describe('modules/platform/github/index', () => {
|
||||
number: 2,
|
||||
state: 'open',
|
||||
title: 'title-2',
|
||||
body: 'body-2',
|
||||
updatedAt: '2022-01-01T00:00:00Z',
|
||||
},
|
||||
{
|
||||
number: 1,
|
||||
state: 'open',
|
||||
title: 'title-1',
|
||||
body: 'body-1',
|
||||
updatedAt: '2021-01-01T00:00:00Z',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -1744,11 +1768,15 @@ describe('modules/platform/github/index', () => {
|
||||
number: 2,
|
||||
state: 'open',
|
||||
title: 'title-2',
|
||||
body: 'body-2',
|
||||
updatedAt: '2022-01-01T00:00:00Z',
|
||||
},
|
||||
{
|
||||
number: 1,
|
||||
state: 'closed',
|
||||
title: 'title-1',
|
||||
body: 'body-1',
|
||||
updatedAt: '2021-01-01T00:00:00Z',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -1782,11 +1810,15 @@ describe('modules/platform/github/index', () => {
|
||||
number: 2,
|
||||
state: 'open',
|
||||
title: 'title-2',
|
||||
body: 'body-2',
|
||||
updatedAt: '2022-01-01T00:00:00Z',
|
||||
},
|
||||
{
|
||||
number: 1,
|
||||
state: 'closed',
|
||||
title: 'title-1',
|
||||
body: 'body-1',
|
||||
updatedAt: '2021-01-01T00:00:00Z',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -1852,16 +1884,22 @@ describe('modules/platform/github/index', () => {
|
||||
number: 3,
|
||||
state: 'open',
|
||||
title: 'title-1',
|
||||
body: 'body-1',
|
||||
updatedAt: '2021-01-01T00:00:00Z',
|
||||
},
|
||||
{
|
||||
number: 2,
|
||||
state: 'open',
|
||||
title: 'title-2',
|
||||
body: 'body-2',
|
||||
updatedAt: '2022-01-01T00:00:00Z',
|
||||
},
|
||||
{
|
||||
number: 1,
|
||||
state: 'closed',
|
||||
title: 'title-1',
|
||||
body: 'body-1',
|
||||
updatedAt: '2021-01-01T00:00:00Z',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -1899,11 +1937,15 @@ describe('modules/platform/github/index', () => {
|
||||
number: 2,
|
||||
state: 'open',
|
||||
title: 'title-2',
|
||||
body: 'body-2',
|
||||
updatedAt: '2022-01-01T00:00:00Z',
|
||||
},
|
||||
{
|
||||
number: 1,
|
||||
state: 'open',
|
||||
title: 'title-1',
|
||||
body: 'body-1',
|
||||
updatedAt: '2021-01-01T00:00:00Z',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -1911,7 +1953,13 @@ describe('modules/platform/github/index', () => {
|
||||
},
|
||||
})
|
||||
.get('/repos/some/repo/issues/2')
|
||||
.reply(200, { body: 'new-content' })
|
||||
.reply(200, {
|
||||
number: 2,
|
||||
state: 'open',
|
||||
title: 'title-2',
|
||||
body: 'new-content',
|
||||
updated_at: '2023-01-01T00:00:00Z',
|
||||
})
|
||||
.patch('/repos/some/repo/issues/2')
|
||||
.reply(200);
|
||||
const res = await github.ensureIssue({
|
||||
@@ -1942,11 +1990,15 @@ describe('modules/platform/github/index', () => {
|
||||
number: 2,
|
||||
state: 'open',
|
||||
title: 'title-2',
|
||||
body: 'body-2',
|
||||
updatedAt: '2022-01-01T00:00:00Z',
|
||||
},
|
||||
{
|
||||
number: 1,
|
||||
state: 'open',
|
||||
title: 'title-1',
|
||||
body: 'body-1',
|
||||
updatedAt: '2021-01-01T00:00:00Z',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -1954,7 +2006,13 @@ describe('modules/platform/github/index', () => {
|
||||
},
|
||||
})
|
||||
.get('/repos/some/repo/issues/2')
|
||||
.reply(200, { body: 'new-content' })
|
||||
.reply(200, {
|
||||
number: 2,
|
||||
state: 'open',
|
||||
title: 'title-2',
|
||||
body: 'new-content',
|
||||
updated_at: '2023-01-01T00:00:00Z',
|
||||
})
|
||||
.patch('/repos/some/repo/issues/2')
|
||||
.reply(200);
|
||||
const res = await github.ensureIssue({
|
||||
@@ -1986,11 +2044,15 @@ describe('modules/platform/github/index', () => {
|
||||
number: 2,
|
||||
state: 'open',
|
||||
title: 'title-2',
|
||||
body: 'newer-content',
|
||||
updatedAt: '2022-01-01T00:00:00Z',
|
||||
},
|
||||
{
|
||||
number: 1,
|
||||
state: 'open',
|
||||
title: 'title-1',
|
||||
body: 'new-content',
|
||||
updatedAt: '2021-01-01T00:00:00Z',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -2026,21 +2088,31 @@ describe('modules/platform/github/index', () => {
|
||||
number: 2,
|
||||
state: 'open',
|
||||
title: 'title-1',
|
||||
body: 'body-1',
|
||||
updatedAt: '2021-01-01T00:00:00Z',
|
||||
},
|
||||
{
|
||||
number: 1,
|
||||
state: 'open',
|
||||
title: 'title-1',
|
||||
body: 'body-1',
|
||||
updatedAt: '2021-01-01T00:00:00Z',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
.patch('/repos/some/repo/issues/1')
|
||||
.reply(200)
|
||||
.get('/repos/some/repo/issues/2')
|
||||
.reply(200, { body: 'newer-content' });
|
||||
.reply(200, {
|
||||
number: 2,
|
||||
state: 'open',
|
||||
title: 'title-1',
|
||||
body: 'newer-content',
|
||||
updated_at: '2021-01-01T00:00:00Z',
|
||||
})
|
||||
.patch('/repos/some/repo/issues/1')
|
||||
.reply(200);
|
||||
const res = await github.ensureIssue({
|
||||
title: 'title-1',
|
||||
body: 'newer-content',
|
||||
@@ -2068,6 +2140,8 @@ describe('modules/platform/github/index', () => {
|
||||
number: 2,
|
||||
state: 'close',
|
||||
title: 'title-2',
|
||||
body: 'body-2',
|
||||
updatedAt: '2022-01-01T00:00:00Z',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -2075,7 +2149,13 @@ describe('modules/platform/github/index', () => {
|
||||
},
|
||||
})
|
||||
.get('/repos/some/repo/issues/2')
|
||||
.reply(200, { body: 'new-content' })
|
||||
.reply(200, {
|
||||
number: 2,
|
||||
state: 'closed',
|
||||
title: 'title-2',
|
||||
body: 'new-content',
|
||||
updated_at: '2023-01-01T00:00:00Z',
|
||||
})
|
||||
.post('/repos/some/repo/issues')
|
||||
.reply(200);
|
||||
const res = await github.ensureIssue({
|
||||
@@ -2107,6 +2187,8 @@ describe('modules/platform/github/index', () => {
|
||||
number: 2,
|
||||
state: 'open',
|
||||
title: 'title-2',
|
||||
body: 'body-2',
|
||||
updatedAt: '2022-01-01T00:00:00Z',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -2114,7 +2196,13 @@ describe('modules/platform/github/index', () => {
|
||||
},
|
||||
})
|
||||
.get('/repos/some/repo/issues/2')
|
||||
.reply(200, { body: 'new-content' });
|
||||
.reply(200, {
|
||||
number: 2,
|
||||
state: 'open',
|
||||
title: 'title-2',
|
||||
body: 'new-content',
|
||||
updated_at: '2023-01-01T00:00:00Z',
|
||||
});
|
||||
const res = await github.ensureIssue({
|
||||
title: 'title-2',
|
||||
body: 'new-content',
|
||||
@@ -2144,11 +2232,15 @@ describe('modules/platform/github/index', () => {
|
||||
number: 2,
|
||||
state: 'open',
|
||||
title: 'title-2',
|
||||
body: 'body-2',
|
||||
updatedAt: '2022-01-01T00:00:00Z',
|
||||
},
|
||||
{
|
||||
number: 1,
|
||||
state: 'open',
|
||||
title: 'title-1',
|
||||
body: 'body-1',
|
||||
updatedAt: '2021-01-01T00:00:00Z',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -56,7 +56,6 @@ import type {
|
||||
EnsureIssueConfig,
|
||||
EnsureIssueResult,
|
||||
FindPRConfig,
|
||||
Issue,
|
||||
MergePRConfig,
|
||||
PlatformParams,
|
||||
PlatformPrOptions,
|
||||
@@ -75,6 +74,7 @@ import {
|
||||
repoInfoQuery,
|
||||
vulnerabilityAlertsQuery,
|
||||
} from './graphql';
|
||||
import { GithubIssue as Issue } from './issue';
|
||||
import { massageMarkdownLinks } from './massage-markdown-links';
|
||||
import { getPrCache, updatePrCache } from './pr';
|
||||
import type {
|
||||
@@ -1197,9 +1197,8 @@ export async function setBranchStatus({
|
||||
|
||||
// Issue
|
||||
|
||||
/* istanbul ignore next */
|
||||
async function getIssues(): Promise<Issue[]> {
|
||||
const result = await githubApi.queryRepoField<Issue>(
|
||||
const result = await githubApi.queryRepoField<unknown>(
|
||||
getIssuesQuery,
|
||||
'issues',
|
||||
{
|
||||
@@ -1212,10 +1211,7 @@ async function getIssues(): Promise<Issue[]> {
|
||||
);
|
||||
|
||||
logger.debug(`Retrieved ${result.length} issues`);
|
||||
return result.map((issue) => ({
|
||||
...issue,
|
||||
state: issue.state?.toLowerCase(),
|
||||
}));
|
||||
return Issue.array().parse(result);
|
||||
}
|
||||
|
||||
export async function getIssueList(): Promise<Issue[]> {
|
||||
@@ -1239,16 +1235,13 @@ export async function getIssue(
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const issueBody = (
|
||||
await githubApi.getJson<{ body: string }>(
|
||||
`repos/${config.parentRepo ?? config.repository}/issues/${number}`,
|
||||
{ memCache: useCache, repoCache: true },
|
||||
)
|
||||
).body.body;
|
||||
return {
|
||||
number,
|
||||
body: issueBody,
|
||||
};
|
||||
const repo = config.parentRepo ?? config.repository;
|
||||
const { body: issue } = await githubApi.getJson(
|
||||
`repos/${repo}/issues/${number}`,
|
||||
{ memCache: useCache, repoCache: true },
|
||||
Issue,
|
||||
);
|
||||
return issue;
|
||||
} catch (err) /* istanbul ignore next */ {
|
||||
logger.debug({ err, number }, 'Error getting issue');
|
||||
return null;
|
||||
@@ -1264,8 +1257,7 @@ export async function findIssue(title: string): Promise<Issue | null> {
|
||||
return null;
|
||||
}
|
||||
logger.debug(`Found issue ${issue.number}`);
|
||||
// TODO: can number be required? (#22198)
|
||||
return getIssue(issue.number!);
|
||||
return getIssue(issue.number);
|
||||
}
|
||||
|
||||
async function closeIssue(issueNumber: number): Promise<void> {
|
||||
@@ -1319,18 +1311,17 @@ export async function ensureIssue({
|
||||
for (const i of issues) {
|
||||
if (i.state === 'open' && i.number !== issue.number) {
|
||||
logger.warn({ issueNo: i.number }, 'Closing duplicate issue');
|
||||
// TODO #22198
|
||||
await closeIssue(i.number!);
|
||||
await closeIssue(i.number);
|
||||
}
|
||||
}
|
||||
const issueBody = (
|
||||
await githubApi.getJson<{ body: string }>(
|
||||
`repos/${config.parentRepo ?? config.repository}/issues/${
|
||||
issue.number
|
||||
}`,
|
||||
{ repoCache: true },
|
||||
)
|
||||
).body.body;
|
||||
const repo = config.parentRepo ?? config.repository;
|
||||
const {
|
||||
body: { body: issueBody },
|
||||
} = await githubApi.getJson(
|
||||
`repos/${repo}/issues/${issue.number}`,
|
||||
{ repoCache: true },
|
||||
Issue,
|
||||
);
|
||||
if (
|
||||
issue.title === title &&
|
||||
issueBody === body &&
|
||||
@@ -1393,8 +1384,7 @@ export async function ensureIssueClosing(title: string): Promise<void> {
|
||||
const issueList = await getIssueList();
|
||||
for (const issue of issueList) {
|
||||
if (issue.state === 'open' && issue.title === title) {
|
||||
// TODO #22198
|
||||
await closeIssue(issue.number!);
|
||||
await closeIssue(issue.number);
|
||||
logger.debug(`Issue closed, issueNo: ${issue.number}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import { z } from 'zod';
|
||||
import type { GithubIssue as Issue } from './types';
|
||||
|
||||
const GithubIssueBase = z.object({
|
||||
number: z.number(),
|
||||
state: z.string().transform((val) => val.toLowerCase()),
|
||||
title: z.string(),
|
||||
body: z.string(),
|
||||
});
|
||||
|
||||
const GithubGraphqlIssue = GithubIssueBase.extend({
|
||||
updatedAt: z.string(),
|
||||
}).transform((issue): Issue => {
|
||||
const lastModified = issue.updatedAt;
|
||||
const { number, state, title, body } = issue;
|
||||
return { number, state, title, body, lastModified };
|
||||
});
|
||||
|
||||
const GithubRestIssue = GithubIssueBase.extend({
|
||||
updated_at: z.string(),
|
||||
}).transform((issue): Issue => {
|
||||
const lastModified = issue.updated_at;
|
||||
const { number, state, title, body } = issue;
|
||||
return { number, state, title, body, lastModified };
|
||||
});
|
||||
|
||||
export const GithubIssue = z.union([GithubGraphqlIssue, GithubRestIssue]);
|
||||
export type GithubIssue = z.infer<typeof GithubIssue>;
|
||||
@@ -97,7 +97,7 @@ export interface LocalRepoConfig {
|
||||
forkToken?: string;
|
||||
forkCreation?: boolean;
|
||||
prList: GhPr[] | null;
|
||||
issueList: any[] | null;
|
||||
issueList: GithubIssue[] | null;
|
||||
mergeMethod: 'rebase' | 'squash' | 'merge';
|
||||
defaultBranch: string;
|
||||
repositoryOwner: string;
|
||||
@@ -153,3 +153,11 @@ export interface ApiPageCache<T extends ApiPageItem = ApiPageItem> {
|
||||
items: Record<number, T>;
|
||||
lastModified?: string;
|
||||
}
|
||||
|
||||
export interface GithubIssue {
|
||||
body: string;
|
||||
number: number;
|
||||
state: string;
|
||||
title: string;
|
||||
lastModified: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user