From a2ee1d73d1f5ba2da31f7d4eb3d4b98c253a2537 Mon Sep 17 00:00:00 2001 From: Kamil Wolny Date: Tue, 9 Aug 2022 23:27:46 +0100 Subject: [PATCH 01/15] feat: generate test issue + new dependencies Signed-off-by: Kamil Wolny --- plugins/github-issues/package.json | 4 +- .../src/utils/generateTestIssue.ts | 53 +++++++++++++++++++ plugins/github-issues/src/utils/index.ts | 16 ++++++ yarn.lock | 7 ++- 4 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 plugins/github-issues/src/utils/generateTestIssue.ts create mode 100644 plugins/github-issues/src/utils/index.ts diff --git a/plugins/github-issues/package.json b/plugins/github-issues/package.json index 2ddb8481c4..98434ce748 100644 --- a/plugins/github-issues/package.json +++ b/plugins/github-issues/package.json @@ -25,15 +25,17 @@ "@backstage/catalog-model": "^1.0.3", "@backstage/core-components": "^0.11.0-next.2", "@backstage/core-plugin-api": "^1.0.5-next.0", + "@backstage/errors": "^1.1.0", "@backstage/integration": "^1.3.0-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.2", "@backstage/theme": "^0.2.15", + "@faker-js/faker": "^7.4.0", "@material-ui/core": "^4.12.4", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "^4.0.0-alpha.61", "luxon": "^2.4.0", "octokit": "^2.0.4", - "react-use": "^17.2.4" + "react-use": "^17.4.0" }, "peerDependencies": { "react": "^16.13.1 || ^17.0.0" diff --git a/plugins/github-issues/src/utils/generateTestIssue.ts b/plugins/github-issues/src/utils/generateTestIssue.ts new file mode 100644 index 0000000000..a07c8dfc57 --- /dev/null +++ b/plugins/github-issues/src/utils/generateTestIssue.ts @@ -0,0 +1,53 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { faker } from '@faker-js/faker'; +import { Issue } from '../api'; + +export const generateTestIssue = ( + overwrites: Partial = {}, +): { node: Issue } => ({ + node: { + ...{ + assignees: { + edges: [ + { + node: { + avatarUrl: faker.internet.avatar(), + login: `${faker.word.adjective()}-${faker.animal.type()}`, + }, + }, + ], + }, + author: { + login: `${faker.word.adjective()}-${faker.animal.type()}`, + }, + repository: { + nameWithOwner: `${faker.animal.type()}/${faker.animal.type()}`, + }, + title: faker.lorem.words(3), + url: faker.internet.url(), + participants: { + totalCount: +faker.random.numeric(), + }, + updatedAt: faker.date.past().toISOString(), + createdAt: faker.date.past().toISOString(), + comments: { + totalCount: +faker.random.numeric(), + }, + }, + ...overwrites, + }, +}); diff --git a/plugins/github-issues/src/utils/index.ts b/plugins/github-issues/src/utils/index.ts new file mode 100644 index 0000000000..16740dac94 --- /dev/null +++ b/plugins/github-issues/src/utils/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export * from './generateTestIssue'; diff --git a/yarn.lock b/yarn.lock index f8d31be28f..4bebec76e1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2673,6 +2673,11 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" +"@faker-js/faker@^7.4.0": + version "7.4.0" + resolved "https://registry.npmjs.org/@faker-js/faker/-/faker-7.4.0.tgz#cac720d860a89d487b47e55e66a4fd114f1d3fe5" + integrity sha512-xDd3Tvkt2jgkx1LkuwwxpNBy/Oe+LkZBTwkgEFTiWpVSZgQ5sc/LenbHKRHbFl0dq/KFeeq/szyyPtpJRKY0fg== + "@fmvilas/pseudo-yaml-ast@^0.3.1": version "0.3.1" resolved "https://registry.npmjs.org/@fmvilas/pseudo-yaml-ast/-/pseudo-yaml-ast-0.3.1.tgz#66c5df2c2d76ba8571dc5bd98fda4d7dce6121de" @@ -22465,7 +22470,7 @@ react-universal-interface@^0.6.2: resolved "https://registry.npmjs.org/react-universal-interface/-/react-universal-interface-0.6.2.tgz#5e8d438a01729a4dbbcbeeceb0b86be146fe2b3b" integrity sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw== -react-use@^17.2.4, react-use@^17.3.1, react-use@^17.3.2: +react-use@^17.2.4, react-use@^17.3.1, react-use@^17.3.2, react-use@^17.4.0: version "17.4.0" resolved "https://registry.npmjs.org/react-use/-/react-use-17.4.0.tgz#cefef258b0a6c534a5c8021c2528ac6e1a4cdc6d" integrity sha512-TgbNTCA33Wl7xzIJegn1HndB4qTS9u03QUwyNycUnXaweZkE4Kq2SB+Yoxx8qbshkZGYBDvUXbXWRUmQDcZZ/Q== From e1c5cd7dbe3f67af2012d1ea447197691ff0b3ab Mon Sep 17 00:00:00 2001 From: Kamil Wolny Date: Tue, 9 Aug 2022 23:34:21 +0100 Subject: [PATCH 02/15] feat: github graphql communicationg moved to new github issues api + fixes the issue with no data rendered on partial failure from api Signed-off-by: Kamil Wolny --- .../src/api/gitHubIssuesApi.test.ts | 300 ++++++++++++++++++ .../github-issues/src/api/gitHubIssuesApi.ts | 207 ++++++++++++ plugins/github-issues/src/api/index.ts | 16 + plugins/github-issues/src/plugin.ts | 17 + 4 files changed, 540 insertions(+) create mode 100644 plugins/github-issues/src/api/gitHubIssuesApi.test.ts create mode 100644 plugins/github-issues/src/api/gitHubIssuesApi.ts create mode 100644 plugins/github-issues/src/api/index.ts diff --git a/plugins/github-issues/src/api/gitHubIssuesApi.test.ts b/plugins/github-issues/src/api/gitHubIssuesApi.test.ts new file mode 100644 index 0000000000..4d1c3ffff3 --- /dev/null +++ b/plugins/github-issues/src/api/gitHubIssuesApi.test.ts @@ -0,0 +1,300 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +const mockGraphQLQuery = jest.fn(() => ({})); +jest.mock('octokit', () => ({ + Octokit: jest.fn(() => ({ graphql: mockGraphQLQuery })), +})); + +import { ConfigApi, ErrorApi } from '@backstage/core-plugin-api'; +import { ForwardedError } from '@backstage/errors'; +import { gitHubIssuesApi } from './gitHubIssuesApi'; + +describe('gitHubIssuesApi', () => { + describe('fetchIssuesByRepoFromGitHub', () => { + it('should call GitHub API with correct query with fragment for each repo', async () => { + const api = gitHubIssuesApi( + { getAccessToken: jest.fn() }, + { + getOptionalConfigArray: jest.fn(), + } as unknown as ConfigApi, + { post: jest.fn() } as unknown as ErrorApi, + ); + + await api.fetchIssuesByRepoFromGitHub( + ['mrwolny/yo-yo', 'mrwolny/yoyo', 'mrwolny/yo.yo'], + 10, + ); + expect(mockGraphQLQuery).toHaveBeenCalledTimes(1); + expect(mockGraphQLQuery).toHaveBeenCalledWith( + '\n' + + ' \n' + + ' fragment issues on Repository {\n' + + ' issues(\n' + + ' states: OPEN\n' + + ' first: 10\n' + + ' orderBy: { field: UPDATED_AT, direction: DESC }\n' + + ' ) {\n' + + ' totalCount\n' + + ' edges {\n' + + ' node {\n' + + ' assignees(first: 10) {\n' + + ' edges {\n' + + ' node {\n' + + ' avatarUrl\n' + + ' login\n' + + ' }\n' + + ' }\n' + + ' }\n' + + ' author {\n' + + ' login\n' + + ' }\n' + + ' repository {\n' + + ' nameWithOwner\n' + + ' }\n' + + ' title\n' + + ' url\n' + + ' participants {\n' + + ' totalCount\n' + + ' }\n' + + ' updatedAt\n' + + ' createdAt\n' + + ' comments(last: 1) {\n' + + ' totalCount\n' + + ' }\n' + + ' }\n' + + ' }\n' + + ' }\n' + + ' }\n' + + ' \n' + + '\n' + + ' query {\n' + + ' \n' + + ' yoyo: repository(name: "yo-yo", owner: "mrwolny") {\n' + + ' ...issues\n' + + ' }\n' + + ' ,\n' + + ' yoyox: repository(name: "yoyo", owner: "mrwolny") {\n' + + ' ...issues\n' + + ' }\n' + + ' ,\n' + + ' yoyoxx: repository(name: "yo.yo", owner: "mrwolny") {\n' + + ' ...issues\n' + + ' }\n' + + ' \n' + + ' } \n' + + ' ', + ); + }); + }); + + it('should return data for repos with successfully retrieved issues when GitHub returns partial failure', async () => { + mockGraphQLQuery.mockImplementationOnce(() => + Promise.reject({ + data: { + yoyo: { + issues: { + totalCount: 1, + edges: [ + { + node: { + assignees: { + edges: [], + }, + author: { + login: 'mrwolny', + }, + repository: { + nameWithOwner: 'mrwolny/yo-yo', + }, + title: "It's the ISSUE!", + url: 'https://github.com/mrwolny/yo-yo/issues/1', + participants: { + totalCount: 1, + }, + updatedAt: '2022-07-04T18:47:33Z', + createdAt: '2022-06-23T18:14:26Z', + comments: { + totalCount: 4, + }, + }, + }, + ], + }, + }, + notfound: null, + }, + errors: [ + { + type: 'NOT_FOUND', + path: ['notfound'], + locations: [ + { + line: 48, + column: 9, + }, + ], + message: + "Could not resolve to a Repository with the name 'notfound/notfound'.", + }, + ], + }), + ); + + const api = gitHubIssuesApi( + { getAccessToken: jest.fn() }, + { + getOptionalConfigArray: jest.fn(), + } as unknown as ConfigApi, + { post: jest.fn() } as unknown as ErrorApi, + ); + + const data = await api.fetchIssuesByRepoFromGitHub( + ['mrwolny/yo-yo', 'mrwolny/notfound'], + 10, + ); + + expect(data).toEqual({ + 'mrwolny/yo-yo': { + issues: { + totalCount: 1, + edges: [ + { + node: { + assignees: { + edges: [], + }, + author: { + login: 'mrwolny', + }, + repository: { + nameWithOwner: 'mrwolny/yo-yo', + }, + title: "It's the ISSUE!", + url: 'https://github.com/mrwolny/yo-yo/issues/1', + participants: { + totalCount: 1, + }, + updatedAt: '2022-07-04T18:47:33Z', + createdAt: '2022-06-23T18:14:26Z', + comments: { + totalCount: 4, + }, + }, + }, + ], + }, + }, + }); + }); + + it('should return empty object when GitHub returns failure with no data', async () => { + mockGraphQLQuery.mockImplementationOnce(() => + Promise.reject({ + data: { + notfound: null, + }, + errors: [ + { + type: 'NOT_FOUND', + path: ['notfound'], + locations: [ + { + line: 48, + column: 9, + }, + ], + message: + "Could not resolve to a Repository with the name 'notfound/notfound'.", + }, + ], + }), + ); + + const api = gitHubIssuesApi( + { getAccessToken: jest.fn() }, + { + getOptionalConfigArray: jest.fn(), + } as unknown as ConfigApi, + { post: jest.fn() } as unknown as ErrorApi, + ); + + const data = await api.fetchIssuesByRepoFromGitHub( + ['mrwolny/notfound'], + 10, + ); + + expect(data).toEqual({}); + }); + + it('should post error to the backstage error API when GitHub returns failure', async () => { + mockGraphQLQuery.mockImplementationOnce(() => + Promise.reject({ + data: { + notfound: null, + }, + errors: [ + { + type: 'NOT_FOUND', + path: ['notfound'], + locations: [ + { + line: 48, + column: 9, + }, + ], + message: + "Could not resolve to a Repository with the name 'notfound/notfound'.", + }, + ], + }), + ); + + const mockErrorApi = { post: jest.fn() }; + + const api = gitHubIssuesApi( + { getAccessToken: jest.fn() }, + { + getOptionalConfigArray: jest.fn(), + } as unknown as ConfigApi, + mockErrorApi as unknown as ErrorApi, + ); + + await api.fetchIssuesByRepoFromGitHub(['mrwolny/notfound'], 10); + + expect(mockErrorApi.post).toHaveBeenCalledTimes(1); + expect(mockErrorApi.post).toHaveBeenCalledWith( + new ForwardedError('GitHub Issues Plugin failure', { + data: { + notfound: null, + }, + errors: [ + { + type: 'NOT_FOUND', + path: ['notfound'], + locations: [ + { + line: 48, + column: 9, + }, + ], + message: + "Could not resolve to a Repository with the name 'notfound/notfound'.", + }, + ], + }), + ); + }); +}); diff --git a/plugins/github-issues/src/api/gitHubIssuesApi.ts b/plugins/github-issues/src/api/gitHubIssuesApi.ts new file mode 100644 index 0000000000..06fdf3d452 --- /dev/null +++ b/plugins/github-issues/src/api/gitHubIssuesApi.ts @@ -0,0 +1,207 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Octokit } from 'octokit'; +import { + createApiRef, + ConfigApi, + ErrorApi, + OAuthApi, +} from '@backstage/core-plugin-api'; +import { readGitHubIntegrationConfigs } from '@backstage/integration'; +import { ForwardedError } from '@backstage/errors'; + +type Assignee = { + avatarUrl: string; + login: string; +}; + +type EdgesWithNodes = { + edges: Array<{ + node: T; + }>; +}; + +type IssueAuthor = { + login: string; +}; + +export type Issue = { + assignees: EdgesWithNodes; + author: IssueAuthor; + repository: { + nameWithOwner: string; + }; + title: string; + url: string; + participants: { + totalCount: number; + }; + createdAt: string; + updatedAt: string; + comments: { + totalCount: number; + }; +}; + +export type RepoIssues = { + issues: { + totalCount: number; + } & EdgesWithNodes; +}; +export type IssuesByRepo = Record; + +export type GitHubIssuesApi = ReturnType; + +export const gitHubIssuesApiRef = createApiRef({ + id: 'plugin.githubissues.service', +}); + +export const gitHubIssuesApi = ( + githubAuthApi: OAuthApi, + configApi: ConfigApi, + errorApi: ErrorApi, +) => { + let octokit: Octokit; + + const getOctokit = async () => { + const baseUrl = readGitHubIntegrationConfigs( + configApi.getOptionalConfigArray('integrations.github') ?? [], + )[0].apiBaseUrl; + + const token = await githubAuthApi.getAccessToken(['repo']); + + if (!octokit) { + octokit = new Octokit({ auth: token, ...(baseUrl && { baseUrl }) }); + } + + return octokit.graphql; + }; + + const fetchIssuesByRepoFromGitHub = async ( + repos: Array, + itemsPerRepo: number, + ): Promise => { + const graphql = await getOctokit(); + const safeNames: Array = []; + + const repositories = repos.map(repo => { + const [owner, name] = repo.split('/'); + + const safeNameRegex = /-|\./gi; + let safeName = name.replace(safeNameRegex, ''); + + while (safeNames.includes(safeName)) { + safeName += 'x'; + } + + safeNames.push(safeName); + + return { + safeName, + name, + owner, + }; + }); + + let issuesByRepo: IssuesByRepo = {}; + try { + issuesByRepo = await graphql( + createIssueByRepoQuery(repositories, itemsPerRepo), + ); + } catch (e) { + if (e.data) { + issuesByRepo = e.data; + } + + errorApi.post(new ForwardedError('GitHub Issues Plugin failure', e)); + } + + return repositories.reduce((acc, { safeName, name, owner }) => { + if (issuesByRepo[safeName]) { + acc[`${owner}/${name}`] = issuesByRepo[safeName]; + } + + return acc; + }, {} as IssuesByRepo); + }; + + return { fetchIssuesByRepoFromGitHub }; +}; + +function createIssueByRepoQuery( + repositories: Array<{ + safeName: string; + name: string; + owner: string; + }>, + itemsPerRepo: number, +): string { + const fragment = ` + fragment issues on Repository { + issues( + states: OPEN + first: ${itemsPerRepo} + orderBy: { field: UPDATED_AT, direction: DESC } + ) { + totalCount + edges { + node { + assignees(first: 10) { + edges { + node { + avatarUrl + login + } + } + } + author { + login + } + repository { + nameWithOwner + } + title + url + participants { + totalCount + } + updatedAt + createdAt + comments(last: 1) { + totalCount + } + } + } + } + } + `; + + const query = ` + ${fragment} + + query { + ${repositories.map( + ({ safeName, name, owner }) => ` + ${safeName}: repository(name: "${name}", owner: "${owner}") { + ...issues + } + `, + )} + } + `; + + return query; +} diff --git a/plugins/github-issues/src/api/index.ts b/plugins/github-issues/src/api/index.ts new file mode 100644 index 0000000000..4cc3372c45 --- /dev/null +++ b/plugins/github-issues/src/api/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export * from './gitHubIssuesApi'; diff --git a/plugins/github-issues/src/plugin.ts b/plugins/github-issues/src/plugin.ts index ece3fd09a2..3d845f4adf 100644 --- a/plugins/github-issues/src/plugin.ts +++ b/plugins/github-issues/src/plugin.ts @@ -15,15 +15,32 @@ */ import { createPlugin, + createApiFactory, createComponentExtension, createRoutableExtension, + configApiRef, + errorApiRef, + githubAuthApiRef, } from '@backstage/core-plugin-api'; +import { gitHubIssuesApi, gitHubIssuesApiRef } from './api'; import { rootRouteRef } from './routes'; /** @public */ export const gitHubIssuesPlugin = createPlugin({ id: 'github-issues', + apis: [ + createApiFactory({ + api: gitHubIssuesApiRef, + deps: { + configApi: configApiRef, + githubAuthApi: githubAuthApiRef, + errorApi: errorApiRef, + }, + factory: ({ configApi, githubAuthApi, errorApi }) => + gitHubIssuesApi(githubAuthApi, configApi, errorApi), + }), + ], routes: { root: rootRouteRef, }, From 19eb6499999e1129e943042effa38b1f844fe414 Mon Sep 17 00:00:00 2001 From: Kamil Wolny Date: Tue, 9 Aug 2022 23:39:14 +0100 Subject: [PATCH 03/15] feat: hooks refactor to use new plugin api Signed-off-by: Kamil Wolny --- .../useGetIssuesBeRepoFromGitHub.test.tsx | 100 ----------- .../src/hooks/useGetIssuesByRepoFromGitHub.ts | 170 +++--------------- .../src/hooks/useOctokitGraphQL.ts | 47 ----- 3 files changed, 20 insertions(+), 297 deletions(-) delete mode 100644 plugins/github-issues/src/hooks/useGetIssuesBeRepoFromGitHub.test.tsx delete mode 100644 plugins/github-issues/src/hooks/useOctokitGraphQL.ts diff --git a/plugins/github-issues/src/hooks/useGetIssuesBeRepoFromGitHub.test.tsx b/plugins/github-issues/src/hooks/useGetIssuesBeRepoFromGitHub.test.tsx deleted file mode 100644 index 547e32db22..0000000000 --- a/plugins/github-issues/src/hooks/useGetIssuesBeRepoFromGitHub.test.tsx +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2022 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -const mockGraphQLQuery = jest.fn(() => ({})); -jest.mock('./useOctokitGraphQL', () => ({ - useOctokitGraphQL: jest.fn(() => mockGraphQLQuery), -})); - -import React from 'react'; -import { render } from '@testing-library/react'; -import { useGetIssuesByRepoFromGitHub } from './useGetIssuesByRepoFromGitHub'; - -describe('useGetIssuesBeRepoFromGitHub', () => { - it('should call GitHub API with correct query with fragment for each repo', async () => { - const Helper = () => { - const getIssues = useGetIssuesByRepoFromGitHub(); - - getIssues(['mrwolny/yo-yo', 'mrwolny/yoyo', 'mrwolny/yo.yo'], 10); - - return
; - }; - - render(); - - expect(mockGraphQLQuery).toHaveBeenCalledTimes(1); - expect(mockGraphQLQuery).toHaveBeenCalledWith( - '\n' + - ' \n' + - ' fragment issues on Repository {\n' + - ' issues(\n' + - ' states: OPEN\n' + - ' first: 10\n' + - ' orderBy: { field: UPDATED_AT, direction: DESC }\n' + - ' ) {\n' + - ' totalCount\n' + - ' edges {\n' + - ' node {\n' + - ' assignees(first: 10) {\n' + - ' edges {\n' + - ' node {\n' + - ' avatarUrl\n' + - ' login\n' + - ' }\n' + - ' }\n' + - ' }\n' + - ' author {\n' + - ' login\n' + - ' avatarUrl\n' + - ' url\n' + - ' }\n' + - ' repository {\n' + - ' nameWithOwner\n' + - ' }\n' + - ' title\n' + - ' url\n' + - ' participants {\n' + - ' totalCount\n' + - ' }\n' + - ' updatedAt\n' + - ' createdAt\n' + - ' comments(last: 1) {\n' + - ' totalCount\n' + - ' }\n' + - ' }\n' + - ' }\n' + - ' }\n' + - ' }\n' + - ' \n' + - '\n' + - ' query {\n' + - ' \n' + - ' yoyo: repository(name: "yo-yo", owner: "mrwolny") {\n' + - ' ...issues\n' + - ' }\n' + - ' ,\n' + - ' yoyox: repository(name: "yoyo", owner: "mrwolny") {\n' + - ' ...issues\n' + - ' }\n' + - ' ,\n' + - ' yoyoxx: repository(name: "yo.yo", owner: "mrwolny") {\n' + - ' ...issues\n' + - ' }\n' + - ' \n' + - ' } \n' + - ' ', - ); - }); -}); diff --git a/plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts b/plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts index 271cd6c741..29e89213dc 100644 --- a/plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts +++ b/plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts @@ -13,161 +13,31 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React from 'react'; -import { useOctokitGraphQL } from './useOctokitGraphQL'; +import { useApi } from '@backstage/core-plugin-api'; -type Assignee = { - avatarUrl: string; - login: string; -}; +import { useAsyncRetry } from 'react-use'; +import { gitHubIssuesApiRef } from '../api'; -export type EdgesWithNodes = { - edges: Array<{ - node: T; - }>; -}; - -export type Node = { - node: T; -}; - -type IssueAuthor = { - login: string; -}; - -export type Issue = { - assignees: EdgesWithNodes; - author: IssueAuthor; - repository: { - nameWithOwner: string; - }; - title: string; - url: string; - participants: { - totalCount: number; - }; - createdAt: string; - updatedAt: string; - comments: { - totalCount: number; - }; -}; - -export type RepoIssues = { - issues: { - totalCount: number; - } & EdgesWithNodes; -}; - -export type RepoIssuesQueryResults = Record; - -const createQuery = ( - repositories: Array<{ - safeName: string; - name: string; - owner: string; - }>, +export const useGetIssuesByRepoFromGitHub = ( + repos: Array, itemsPerRepo: number, -): string => { - const fragment = ` - fragment issues on Repository { - issues( - states: OPEN - first: ${itemsPerRepo} - orderBy: { field: UPDATED_AT, direction: DESC } - ) { - totalCount - edges { - node { - assignees(first: 10) { - edges { - node { - avatarUrl - login - } - } - } - author { - login - avatarUrl - url - } - repository { - nameWithOwner - } - title - url - participants { - totalCount - } - updatedAt - createdAt - comments(last: 1) { - totalCount - } - } - } - } - } - `; +) => { + const gitHubIssuesApi = useApi(gitHubIssuesApiRef); - const query = ` - ${fragment} - - query { - ${repositories.map( - ({ safeName, name, owner }) => ` - ${safeName}: repository(name: "${name}", owner: "${owner}") { - ...issues - } - `, - )} - } - `; - - return query; -}; - -export const useGetIssuesByRepoFromGitHub = () => { - const graphql = useOctokitGraphQL(); - - const fn = React.useRef( - async ( - repos: Array, - itemsPerRepo: number, - ): Promise> => { - const safeNames: Array = []; - - const repositories = repos.map(repo => { - const [owner, name] = repo.split('/'); - - const safeNameRegex = /-|\./gi; - let safeName = name.replace(safeNameRegex, ''); - - while (safeNames.includes(safeName)) { - safeName += 'x'; - } - - safeNames.push(safeName); - - return { - safeName, - name, - owner, - }; - }); - - const issuesByRepo: RepoIssuesQueryResults = await graphql( - createQuery(repositories, itemsPerRepo), + const { + value: issues, + loading: isLoading, + retry, + } = useAsyncRetry(async () => { + if (repos.length > 0) { + return await gitHubIssuesApi.fetchIssuesByRepoFromGitHub( + repos, + itemsPerRepo, ); + } - return repositories.reduce((acc, { safeName, name, owner }) => { - acc[`${owner}/${name}`] = issuesByRepo[safeName]; + return {}; + }, [repos]); - return acc; - }, {} as Record); - }, - ); - - return fn.current; + return { isLoading, gitHubIssuesByRepo: issues, retry }; }; diff --git a/plugins/github-issues/src/hooks/useOctokitGraphQL.ts b/plugins/github-issues/src/hooks/useOctokitGraphQL.ts deleted file mode 100644 index 6b783efd6f..0000000000 --- a/plugins/github-issues/src/hooks/useOctokitGraphQL.ts +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2022 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { Octokit } from 'octokit'; -import { - useApi, - githubAuthApiRef, - configApiRef, -} from '@backstage/core-plugin-api'; -import { readGitHubIntegrationConfigs } from '@backstage/integration'; - -let octokit: Octokit; - -export const useOctokitGraphQL = () => { - const auth = useApi(githubAuthApiRef); - const config = useApi(configApiRef); - - const baseUrl = readGitHubIntegrationConfigs( - config.getOptionalConfigArray('integrations.github') ?? [], - )[0].apiBaseUrl; - - return (path: string, options?: any): Promise => - auth - .getAccessToken(['repo']) - .then((token: string) => { - if (!octokit) { - octokit = new Octokit({ auth: token, ...(baseUrl && { baseUrl }) }); - } - - return octokit; - }) - .then(octokitInstance => { - return octokitInstance.graphql(path, options); - }); -}; From f9f9aa64f8a394bd0fbe641596631ce81a846e43 Mon Sep 17 00:00:00 2001 From: Kamil Wolny Date: Tue, 9 Aug 2022 23:43:17 +0100 Subject: [PATCH 04/15] feat: use refactored hooks in components and component tests for basic rendering of the plugin Signed-off-by: Kamil Wolny --- .../GitHubIssues/GitHubIssues.test.tsx | 127 ++++++++++++++++++ .../components/GitHubIssues/GitHubIssues.tsx | 38 ++---- .../GitHubIssues/IssueCard/IssueCard.tsx | 2 +- .../GitHubIssues/IssuesList/IssuesList.tsx | 9 +- 4 files changed, 142 insertions(+), 34 deletions(-) create mode 100644 plugins/github-issues/src/components/GitHubIssues/GitHubIssues.test.tsx diff --git a/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.test.tsx b/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.test.tsx new file mode 100644 index 0000000000..7b9d6d87b2 --- /dev/null +++ b/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.test.tsx @@ -0,0 +1,127 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import { + EntityProvider, + catalogApiRef, + CatalogApi, +} from '@backstage/plugin-catalog-react'; + +import { generateTestIssue } from '../../utils'; +import { GitHubIssuesApi, gitHubIssuesApiRef } from '../../api'; + +import { GitHubIssues } from './GitHubIssues'; +import { Entity } from '@backstage/catalog-model'; + +jest + .useFakeTimers() + .setSystemTime(new Date('2020-04-20T08:15:47.614Z').getTime()); + +const entityComponent = { + metadata: { + annotations: { + 'github.com/project-slug': 'backstage/backstage', + }, + name: 'backstage', + }, + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', +} as unknown as Entity; + +const mockCatalogApi = { + getEntities: () => ({}), +} as CatalogApi; + +describe('GitHubIssues', () => { + it('should render correctly when there are no issues in GitHub', async () => { + const mockApi = { + fetchIssuesByRepoFromGitHub: async () => ({ + backstage: { + issues: { + totalCount: 0, + edges: [], + }, + }, + }), + } as GitHubIssuesApi; + + const apis = [ + [gitHubIssuesApiRef, mockApi], + [catalogApiRef, mockCatalogApi], + ] as const; + + const { getByTestId } = await renderInTestApp( + + + + + , + ); + + expect(getByTestId('no-issues-msg')).toHaveTextContent( + 'Hurray! No Issues 🚀', + ); + }); + + it('should render correctly', async () => { + const testIssue = generateTestIssue({ + createdAt: '2020-04-19T10:15:47.614Z', + updatedAt: '2020-04-20T00:15:47.614Z', + }); + + const mockApi = { + fetchIssuesByRepoFromGitHub: async () => ({ + backstage: { + issues: { + totalCount: 1, + edges: [testIssue], + }, + }, + }), + } as GitHubIssuesApi; + const apis = [ + [gitHubIssuesApiRef, mockApi], + [catalogApiRef, mockCatalogApi], + ] as const; + + const { getByText, getByTestId } = await renderInTestApp( + + + + + , + ); + + getByText('All repositories (1 Issue)'); + + expect(getByTestId(`issue-${testIssue.node.url}`)).toHaveTextContent( + testIssue.node.title, + ); + + expect(getByTestId(`issue-${testIssue.node.url}`)).toHaveTextContent( + testIssue.node.repository.nameWithOwner, + ); + + expect(getByTestId(`issue-${testIssue.node.url}`)).toHaveTextContent( + `Created at: 22 hours ago by ${testIssue.node.author.login}`, + ); + + expect(getByTestId(`issue-${testIssue.node.url}`)).toHaveTextContent( + `Last update at: 8 hours ago`, + ); + }); +}); diff --git a/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx b/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx index 5380c8eb22..574c15d3b3 100644 --- a/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx +++ b/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx @@ -20,12 +20,9 @@ import { InfoCard, Progress } from '@backstage/core-components'; import RefreshIcon from '@material-ui/icons/Refresh'; import { useEntityGitHubRepositories } from '../../hooks/useEntityGitHubRepositories'; -import { - RepoIssues, - useGetIssuesByRepoFromGitHub, -} from '../../hooks/useGetIssuesByRepoFromGitHub'; +import { useGetIssuesByRepoFromGitHub } from '../../hooks/useGetIssuesByRepoFromGitHub'; -import { IssueList } from './IssuesList'; +import { IssuesList } from './IssuesList'; import { NoRepositoriesInfo } from './NoRepositoriesInfo'; /** @@ -39,29 +36,12 @@ export type GitHubIssuesProps = { export const GitHubIssues = (props: GitHubIssuesProps) => { const { itemsPerPage = 10, itemsPerRepo = 40 } = props; - const [isLoading, setIsLoading] = React.useState(true); - - const [issuesByRepository, setIssuesByRepository] = - React.useState>(); - const { repositories } = useEntityGitHubRepositories(); - const getIssues = useGetIssuesByRepoFromGitHub(); - - const fetchGitHubIssues = React.useCallback(async () => { - setIsLoading(true); - const issuesByRepo = await getIssues(repositories, itemsPerRepo); - - setIssuesByRepository(issuesByRepo); - setIsLoading(false); - }, [itemsPerRepo, getIssues, repositories]); - - React.useEffect(() => { - if (repositories.length) { - fetchGitHubIssues(); - } else { - setIsLoading(false); - } - }, [repositories.length, fetchGitHubIssues]); + const { + isLoading, + gitHubIssuesByRepo: issuesByRepository, + retry, + } = useGetIssuesByRepoFromGitHub(repositories, itemsPerRepo); if (!repositories.length) { return ; @@ -72,7 +52,7 @@ export const GitHubIssues = (props: GitHubIssuesProps) => { title={ Open GitHub Issues - + @@ -80,7 +60,7 @@ export const GitHubIssues = (props: GitHubIssuesProps) => { > {isLoading && } - diff --git a/plugins/github-issues/src/components/GitHubIssues/IssueCard/IssueCard.tsx b/plugins/github-issues/src/components/GitHubIssues/IssueCard/IssueCard.tsx index 95658fb343..ccf30a9a84 100644 --- a/plugins/github-issues/src/components/GitHubIssues/IssueCard/IssueCard.tsx +++ b/plugins/github-issues/src/components/GitHubIssues/IssueCard/IssueCard.tsx @@ -59,7 +59,7 @@ export const IssueCard = (props: IssueCardProps) => { } = props; return ( - + diff --git a/plugins/github-issues/src/components/GitHubIssues/IssuesList/IssuesList.tsx b/plugins/github-issues/src/components/GitHubIssues/IssuesList/IssuesList.tsx index f279294928..b46eab22b6 100644 --- a/plugins/github-issues/src/components/GitHubIssues/IssuesList/IssuesList.tsx +++ b/plugins/github-issues/src/components/GitHubIssues/IssuesList/IssuesList.tsx @@ -19,14 +19,14 @@ import { Box } from '@material-ui/core'; import { Pagination } from '@material-ui/lab'; import { IssueCard } from '../IssueCard'; -import { RepoIssues } from '../../../hooks/useGetIssuesByRepoFromGitHub'; +import { IssuesByRepo } from '../../../api'; import { RepositoryFilters } from './Filters'; export type PluginMode = 'page' | 'card'; export type IssueListProps = { itemsPerPage?: number; - issuesByRepository?: Record; + issuesByRepository?: IssuesByRepo; }; const getIssuesCountForFilterLabel = ( @@ -37,7 +37,7 @@ const getIssuesCountForFilterLabel = ( issuesAvailable < totalIssues ? '*' : '' }`; -export const IssueList = ({ +export const IssuesList = ({ itemsPerPage = 10, issuesByRepository, }: IssueListProps) => { @@ -140,6 +140,7 @@ export const IssueList = ({ index, ) => ( Hurray! No Issues 🚀 +

Hurray! No Issues 🚀

)} {issues.length / itemsPerPage > 1 ? ( Date: Tue, 9 Aug 2022 23:46:18 +0100 Subject: [PATCH 05/15] feat: add basic plugin render page with mocked data for standalon local developement Signed-off-by: Kamil Wolny --- plugins/github-issues/dev/index.tsx | 83 +++++++++++++++++++++++++++++ plugins/github-issues/src/index.ts | 2 + 2 files changed, 85 insertions(+) create mode 100644 plugins/github-issues/dev/index.tsx diff --git a/plugins/github-issues/dev/index.tsx b/plugins/github-issues/dev/index.tsx new file mode 100644 index 0000000000..c214334780 --- /dev/null +++ b/plugins/github-issues/dev/index.tsx @@ -0,0 +1,83 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { createDevApp } from '@backstage/dev-utils'; +import { + CatalogApi, + catalogApiRef, + EntityProvider, +} from '@backstage/plugin-catalog-react'; + +import { + gitHubIssuesPlugin, + GitHubIssuesPage, + GitHubIssuesApi, + gitHubIssuesApiRef, + IssuesByRepo, +} from '../src'; +import { generateTestIssue } from '../src/utils'; + +const response: IssuesByRepo = { + backstage: { + issues: { + totalCount: 464, + edges: Array.from(Array(40)).map(() => + generateTestIssue({ + repository: { nameWithOwner: 'backstage/backstage' }, + }), + ), + }, + }, +}; + +createDevApp() + .registerPlugin(gitHubIssuesPlugin) + .registerApi({ + api: gitHubIssuesApiRef, + deps: {}, + factory: () => + ({ + fetchIssuesByRepoFromGitHub: async () => response, + } as GitHubIssuesApi), + }) + .registerApi({ + api: catalogApiRef, + deps: {}, + factory: () => + ({ + getEntities: () => ({}), + } as CatalogApi), + }) + .addPage({ + title: 'Component Issues', + element: ( + + + + ), + }) + .render(); diff --git a/plugins/github-issues/src/index.ts b/plugins/github-issues/src/index.ts index 5f6c248db7..d69719d136 100644 --- a/plugins/github-issues/src/index.ts +++ b/plugins/github-issues/src/index.ts @@ -19,4 +19,6 @@ export { GitHubIssuesCard, } from './plugin'; +export * from './api'; + export type { GitHubIssuesProps } from './components/GitHubIssues'; From 347ea327c2f015593dc78da8290d9a07d460c33e Mon Sep 17 00:00:00 2001 From: Kamil Wolny Date: Wed, 10 Aug 2022 09:24:12 +0100 Subject: [PATCH 06/15] feat: changeset added Signed-off-by: Kamil Wolny --- .changeset/gold-dots-search.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/gold-dots-search.md diff --git a/.changeset/gold-dots-search.md b/.changeset/gold-dots-search.md new file mode 100644 index 0000000000..e2a679dff7 --- /dev/null +++ b/.changeset/gold-dots-search.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-github-issues': patch +--- + +Moved communication with GitHub graphql API to the dedicated plugin API. +Fixes issue when no GitHub Issues are rendered when partial failure is returned from GitHub API. From 9e64dd3032c35708adf5db8272716b274ba394ab Mon Sep 17 00:00:00 2001 From: Kamil Wolny Date: Wed, 10 Aug 2022 10:14:45 +0100 Subject: [PATCH 07/15] feat: fix plugin api report Signed-off-by: Kamil Wolny --- plugins/github-issues/api-report.md | 74 +++++++++++++++++++ .../github-issues/src/api/gitHubIssuesApi.ts | 16 +++- 2 files changed, 87 insertions(+), 3 deletions(-) diff --git a/plugins/github-issues/api-report.md b/plugins/github-issues/api-report.md index eb69fc8e8e..9852ec80c9 100644 --- a/plugins/github-issues/api-report.md +++ b/plugins/github-issues/api-report.md @@ -5,9 +5,49 @@ ```ts /// +import { ApiRef } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/core-plugin-api'; +import { ConfigApi } from '@backstage/core-plugin-api'; +import { ErrorApi } from '@backstage/core-plugin-api'; +import { OAuthApi } from '@backstage/core-plugin-api'; import { RouteRef } from '@backstage/core-plugin-api'; +// @public (undocumented) +export type Assignee = { + avatarUrl: string; + login: string; +}; + +// @public (undocumented) +export type EdgesWithNodes = { + edges: Array<{ + node: T; + }>; +}; + +// @public (undocumented) +export type GitHubIssuesApi = ReturnType; + +// @public (undocumented) +export const gitHubIssuesApi: ( + githubAuthApi: OAuthApi, + configApi: ConfigApi, + errorApi: ErrorApi, +) => { + fetchIssuesByRepoFromGitHub: ( + repos: Array, + itemsPerRepo: number, + ) => Promise; +}; + +// @public (undocumented) +export const gitHubIssuesApiRef: ApiRef<{ + fetchIssuesByRepoFromGitHub: ( + repos: Array, + itemsPerRepo: number, + ) => Promise; +}>; + // @public (undocumented) export const GitHubIssuesCard: (props: GitHubIssuesProps) => JSX.Element; @@ -29,5 +69,39 @@ export type GitHubIssuesProps = { itemsPerRepo?: number; }; +// @public (undocumented) +export type Issue = { + assignees: EdgesWithNodes; + author: IssueAuthor; + repository: { + nameWithOwner: string; + }; + title: string; + url: string; + participants: { + totalCount: number; + }; + createdAt: string; + updatedAt: string; + comments: { + totalCount: number; + }; +}; + +// @public (undocumented) +export type IssueAuthor = { + login: string; +}; + +// @public (undocumented) +export type IssuesByRepo = Record; + +// @public (undocumented) +export type RepoIssues = { + issues: { + totalCount: number; + } & EdgesWithNodes; +}; + // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/github-issues/src/api/gitHubIssuesApi.ts b/plugins/github-issues/src/api/gitHubIssuesApi.ts index 06fdf3d452..2fea0dd759 100644 --- a/plugins/github-issues/src/api/gitHubIssuesApi.ts +++ b/plugins/github-issues/src/api/gitHubIssuesApi.ts @@ -23,21 +23,25 @@ import { import { readGitHubIntegrationConfigs } from '@backstage/integration'; import { ForwardedError } from '@backstage/errors'; -type Assignee = { +/** @public */ +export type Assignee = { avatarUrl: string; login: string; }; -type EdgesWithNodes = { +/** @public */ +export type EdgesWithNodes = { edges: Array<{ node: T; }>; }; -type IssueAuthor = { +/** @public */ +export type IssueAuthor = { login: string; }; +/** @public */ export type Issue = { assignees: EdgesWithNodes; author: IssueAuthor; @@ -56,19 +60,25 @@ export type Issue = { }; }; +/** @public */ export type RepoIssues = { issues: { totalCount: number; } & EdgesWithNodes; }; + +/** @public */ export type IssuesByRepo = Record; +/** @public */ export type GitHubIssuesApi = ReturnType; +/** @public */ export const gitHubIssuesApiRef = createApiRef({ id: 'plugin.githubissues.service', }); +/** @public */ export const gitHubIssuesApi = ( githubAuthApi: OAuthApi, configApi: ConfigApi, From eb23e4b36298d66db8ad3bcc076c887e0f099254 Mon Sep 17 00:00:00 2001 From: Kamil Wolny Date: Wed, 10 Aug 2022 10:15:27 +0100 Subject: [PATCH 08/15] fix: fix the react-use import to mitigate ts error Signed-off-by: Kamil Wolny --- plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts b/plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts index 29e89213dc..8d1d0c2056 100644 --- a/plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts +++ b/plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts @@ -15,7 +15,7 @@ */ import { useApi } from '@backstage/core-plugin-api'; -import { useAsyncRetry } from 'react-use'; +import useAsyncRetry from 'react-use/lib/useAsyncRetry'; import { gitHubIssuesApiRef } from '../api'; export const useGetIssuesByRepoFromGitHub = ( From 07096fa8432088ba9109d97e6abe7c55052ee519 Mon Sep 17 00:00:00 2001 From: Kamil Wolny Date: Wed, 10 Aug 2022 17:14:21 +0100 Subject: [PATCH 09/15] feat: make plugin api internal Signed-off-by: Kamil Wolny --- plugins/github-issues/api-report.md | 74 ------------------- .../github-issues/src/api/gitHubIssuesApi.ts | 18 ++--- 2 files changed, 9 insertions(+), 83 deletions(-) diff --git a/plugins/github-issues/api-report.md b/plugins/github-issues/api-report.md index 9852ec80c9..eb69fc8e8e 100644 --- a/plugins/github-issues/api-report.md +++ b/plugins/github-issues/api-report.md @@ -5,49 +5,9 @@ ```ts /// -import { ApiRef } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/core-plugin-api'; -import { ConfigApi } from '@backstage/core-plugin-api'; -import { ErrorApi } from '@backstage/core-plugin-api'; -import { OAuthApi } from '@backstage/core-plugin-api'; import { RouteRef } from '@backstage/core-plugin-api'; -// @public (undocumented) -export type Assignee = { - avatarUrl: string; - login: string; -}; - -// @public (undocumented) -export type EdgesWithNodes = { - edges: Array<{ - node: T; - }>; -}; - -// @public (undocumented) -export type GitHubIssuesApi = ReturnType; - -// @public (undocumented) -export const gitHubIssuesApi: ( - githubAuthApi: OAuthApi, - configApi: ConfigApi, - errorApi: ErrorApi, -) => { - fetchIssuesByRepoFromGitHub: ( - repos: Array, - itemsPerRepo: number, - ) => Promise; -}; - -// @public (undocumented) -export const gitHubIssuesApiRef: ApiRef<{ - fetchIssuesByRepoFromGitHub: ( - repos: Array, - itemsPerRepo: number, - ) => Promise; -}>; - // @public (undocumented) export const GitHubIssuesCard: (props: GitHubIssuesProps) => JSX.Element; @@ -69,39 +29,5 @@ export type GitHubIssuesProps = { itemsPerRepo?: number; }; -// @public (undocumented) -export type Issue = { - assignees: EdgesWithNodes; - author: IssueAuthor; - repository: { - nameWithOwner: string; - }; - title: string; - url: string; - participants: { - totalCount: number; - }; - createdAt: string; - updatedAt: string; - comments: { - totalCount: number; - }; -}; - -// @public (undocumented) -export type IssueAuthor = { - login: string; -}; - -// @public (undocumented) -export type IssuesByRepo = Record; - -// @public (undocumented) -export type RepoIssues = { - issues: { - totalCount: number; - } & EdgesWithNodes; -}; - // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/github-issues/src/api/gitHubIssuesApi.ts b/plugins/github-issues/src/api/gitHubIssuesApi.ts index 2fea0dd759..816345940c 100644 --- a/plugins/github-issues/src/api/gitHubIssuesApi.ts +++ b/plugins/github-issues/src/api/gitHubIssuesApi.ts @@ -23,25 +23,25 @@ import { import { readGitHubIntegrationConfigs } from '@backstage/integration'; import { ForwardedError } from '@backstage/errors'; -/** @public */ +/** @internal */ export type Assignee = { avatarUrl: string; login: string; }; -/** @public */ +/** @internal */ export type EdgesWithNodes = { edges: Array<{ node: T; }>; }; -/** @public */ +/** @internal */ export type IssueAuthor = { login: string; }; -/** @public */ +/** @internal */ export type Issue = { assignees: EdgesWithNodes; author: IssueAuthor; @@ -60,25 +60,25 @@ export type Issue = { }; }; -/** @public */ +/** @internal */ export type RepoIssues = { issues: { totalCount: number; } & EdgesWithNodes; }; -/** @public */ +/** @internal */ export type IssuesByRepo = Record; -/** @public */ +/** @internal */ export type GitHubIssuesApi = ReturnType; -/** @public */ +/** @internal */ export const gitHubIssuesApiRef = createApiRef({ id: 'plugin.githubissues.service', }); -/** @public */ +/** @internal */ export const gitHubIssuesApi = ( githubAuthApi: OAuthApi, configApi: ConfigApi, From f9a16edaf3e136246bbdafa613417759aa8d4e8a Mon Sep 17 00:00:00 2001 From: Kamil Wolny Date: Fri, 12 Aug 2022 13:16:37 +0100 Subject: [PATCH 10/15] feat: remove traces of plugin api + moved faker to dev deps Signed-off-by: Kamil Wolny --- plugins/github-issues/package.json | 3 ++- plugins/github-issues/src/index.ts | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/plugins/github-issues/package.json b/plugins/github-issues/package.json index 98434ce748..21693740c7 100644 --- a/plugins/github-issues/package.json +++ b/plugins/github-issues/package.json @@ -29,7 +29,6 @@ "@backstage/integration": "^1.3.0-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.2", "@backstage/theme": "^0.2.15", - "@faker-js/faker": "^7.4.0", "@material-ui/core": "^4.12.4", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "^4.0.0-alpha.61", @@ -45,6 +44,8 @@ "@backstage/core-app-api": "^1.0.5-next.0", "@backstage/dev-utils": "^1.0.5-next.1", "@backstage/test-utils": "^1.1.3-next.0", + "@faker-js/faker": "^7.4.0", + "@spotify/prettier-config": "^14.0.0", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/github-issues/src/index.ts b/plugins/github-issues/src/index.ts index d69719d136..5f6c248db7 100644 --- a/plugins/github-issues/src/index.ts +++ b/plugins/github-issues/src/index.ts @@ -19,6 +19,4 @@ export { GitHubIssuesCard, } from './plugin'; -export * from './api'; - export type { GitHubIssuesProps } from './components/GitHubIssues'; From 5e615bf99cd7cc7660515717a021536830a6123e Mon Sep 17 00:00:00 2001 From: Kamil Wolny Date: Fri, 12 Aug 2022 14:26:22 +0100 Subject: [PATCH 11/15] feat: fix local dev environment Signed-off-by: Kamil Wolny --- plugins/github-issues/dev/index.tsx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/plugins/github-issues/dev/index.tsx b/plugins/github-issues/dev/index.tsx index c214334780..57fd1a86e0 100644 --- a/plugins/github-issues/dev/index.tsx +++ b/plugins/github-issues/dev/index.tsx @@ -21,13 +21,9 @@ import { EntityProvider, } from '@backstage/plugin-catalog-react'; -import { - gitHubIssuesPlugin, - GitHubIssuesPage, - GitHubIssuesApi, - gitHubIssuesApiRef, - IssuesByRepo, -} from '../src'; +import { gitHubIssuesPlugin, GitHubIssuesPage } from '../src'; +import { GitHubIssuesApi, gitHubIssuesApiRef, IssuesByRepo } from '../src/api'; + import { generateTestIssue } from '../src/utils'; const response: IssuesByRepo = { From 824f8dcce071abd224b8178465af1a1ec88cf24a Mon Sep 17 00:00:00 2001 From: Kamil Wolny Date: Mon, 15 Aug 2022 09:15:06 +0100 Subject: [PATCH 12/15] feat: move faker to regular deps of github issues plugin Signed-off-by: Kamil Wolny --- plugins/github-issues/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/github-issues/package.json b/plugins/github-issues/package.json index 21693740c7..d7accb907e 100644 --- a/plugins/github-issues/package.json +++ b/plugins/github-issues/package.json @@ -29,6 +29,7 @@ "@backstage/integration": "^1.3.0-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.2", "@backstage/theme": "^0.2.15", + "@faker-js/faker": "^7.4.0", "@material-ui/core": "^4.12.4", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "^4.0.0-alpha.61", @@ -44,7 +45,6 @@ "@backstage/core-app-api": "^1.0.5-next.0", "@backstage/dev-utils": "^1.0.5-next.1", "@backstage/test-utils": "^1.1.3-next.0", - "@faker-js/faker": "^7.4.0", "@spotify/prettier-config": "^14.0.0", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", From f6fb510ec4ab9162bd9b0d6de5a07493da358e7d Mon Sep 17 00:00:00 2001 From: Kamil Wolny Date: Mon, 15 Aug 2022 12:09:37 +0100 Subject: [PATCH 13/15] feat: faker as dev dependency + use static json as test data for the local dev Signed-off-by: Kamil Wolny --- .../__fixtures__/component-issues-data.json | 1209 +++++++++++++++++ plugins/github-issues/dev/index.tsx | 19 +- plugins/github-issues/package.json | 2 +- 3 files changed, 1213 insertions(+), 17 deletions(-) create mode 100644 plugins/github-issues/dev/__fixtures__/component-issues-data.json diff --git a/plugins/github-issues/dev/__fixtures__/component-issues-data.json b/plugins/github-issues/dev/__fixtures__/component-issues-data.json new file mode 100644 index 0000000000..8192f38838 --- /dev/null +++ b/plugins/github-issues/dev/__fixtures__/component-issues-data.json @@ -0,0 +1,1209 @@ +{ + "backstage": { + "issues": { + "totalCount": 464, + "edges": [ + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/1112.jpg", + "login": "worthless-horse" + } + } + ] + }, + "author": { + "login": "next-dog" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "quasi labore qui", + "url": "http://flowery-muscatel.net", + "participants": { + "totalCount": 3 + }, + "updatedAt": "2022-05-02T09:46:35.885Z", + "createdAt": "2022-06-03T07:11:22.320Z", + "comments": { + "totalCount": 6 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/1061.jpg", + "login": "colorful-bird" + } + } + ] + }, + "author": { + "login": "loud-cow" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "debitis alias voluptatem", + "url": "https://complete-grief.biz", + "participants": { + "totalCount": 5 + }, + "updatedAt": "2022-05-04T19:44:01.090Z", + "createdAt": "2022-02-21T08:07:57.434Z", + "comments": { + "totalCount": 1 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/1222.jpg", + "login": "sharp-cetacean" + } + } + ] + }, + "author": { + "login": "growing-dog" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "non accusamus occaecati", + "url": "http://medium-choosing.com", + "participants": { + "totalCount": 3 + }, + "updatedAt": "2021-10-28T00:36:58.871Z", + "createdAt": "2021-11-08T02:21:55.269Z", + "comments": { + "totalCount": 2 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/513.jpg", + "login": "crafty-crocodilia" + } + } + ] + }, + "author": { + "login": "wooden-crocodilia" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "tenetur distinctio sint", + "url": "http://opulent-prejudice.biz", + "participants": { + "totalCount": 5 + }, + "updatedAt": "2022-08-10T19:22:08.823Z", + "createdAt": "2022-02-21T06:24:45.090Z", + "comments": { + "totalCount": 7 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/785.jpg", + "login": "genuine-cow" + } + } + ] + }, + "author": { + "login": "likely-snake" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "eveniet sed nesciunt", + "url": "http://flickering-atmosphere.com", + "participants": { + "totalCount": 5 + }, + "updatedAt": "2022-02-26T15:54:42.831Z", + "createdAt": "2022-02-13T14:52:35.327Z", + "comments": { + "totalCount": 2 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/503.jpg", + "login": "imaginary-lion" + } + } + ] + }, + "author": { + "login": "lame-bird" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "saepe sequi dolore", + "url": "https://short-term-broccoli.org", + "participants": { + "totalCount": 2 + }, + "updatedAt": "2021-10-11T01:31:28.508Z", + "createdAt": "2022-04-11T12:41:01.234Z", + "comments": { + "totalCount": 3 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/590.jpg", + "login": "funny-snake" + } + } + ] + }, + "author": { + "login": "hollow-snake" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "enim quia magni", + "url": "https://scornful-servant.name", + "participants": { + "totalCount": 5 + }, + "updatedAt": "2022-03-05T19:19:15.147Z", + "createdAt": "2022-03-13T09:25:35.802Z", + "comments": { + "totalCount": 8 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/588.jpg", + "login": "zigzag-bear" + } + } + ] + }, + "author": { + "login": "growling-cow" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "omnis ut nostrum", + "url": "https://worthy-minority.net", + "participants": { + "totalCount": 7 + }, + "updatedAt": "2021-08-18T19:21:40.603Z", + "createdAt": "2022-06-04T16:06:26.277Z", + "comments": { + "totalCount": 4 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/1134.jpg", + "login": "composed-lion" + } + } + ] + }, + "author": { + "login": "overjoyed-crocodilia" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "sit est corrupti", + "url": "http://vital-armpit.com", + "participants": { + "totalCount": 3 + }, + "updatedAt": "2022-07-26T22:13:34.123Z", + "createdAt": "2022-02-28T17:59:42.677Z", + "comments": { + "totalCount": 3 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/802.jpg", + "login": "sarcastic-bear" + } + } + ] + }, + "author": { + "login": "utilized-insect" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "illo perferendis suscipit", + "url": "http://snappy-skywalk.info", + "participants": { + "totalCount": 4 + }, + "updatedAt": "2021-10-02T21:22:35.070Z", + "createdAt": "2021-10-25T11:36:35.561Z", + "comments": { + "totalCount": 2 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/232.jpg", + "login": "pristine-cow" + } + } + ] + }, + "author": { + "login": "adorable-snake" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "assumenda nostrum aut", + "url": "http://loud-legend.info", + "participants": { + "totalCount": 7 + }, + "updatedAt": "2022-06-16T22:45:23.107Z", + "createdAt": "2022-05-23T01:10:35.755Z", + "comments": { + "totalCount": 1 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/652.jpg", + "login": "wrong-insect" + } + } + ] + }, + "author": { + "login": "grizzled-cow" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "qui magnam dolorem", + "url": "http://exhausted-horn.org", + "participants": { + "totalCount": 7 + }, + "updatedAt": "2021-12-18T18:46:10.828Z", + "createdAt": "2022-03-27T06:42:04.192Z", + "comments": { + "totalCount": 7 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/838.jpg", + "login": "humming-cow" + } + } + ] + }, + "author": { + "login": "profuse-bird" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "nostrum numquam porro", + "url": "https://unusual-reaction.org", + "participants": { + "totalCount": 7 + }, + "updatedAt": "2022-05-11T15:14:57.433Z", + "createdAt": "2022-05-06T10:48:16.946Z", + "comments": { + "totalCount": 8 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/573.jpg", + "login": "prime-cow" + } + } + ] + }, + "author": { + "login": "forthright-lion" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "in inventore pariatur", + "url": "https://cheery-accord.info", + "participants": { + "totalCount": 4 + }, + "updatedAt": "2022-06-30T16:22:46.819Z", + "createdAt": "2022-05-11T12:37:36.848Z", + "comments": { + "totalCount": 6 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/1143.jpg", + "login": "limp-bear" + } + } + ] + }, + "author": { + "login": "faraway-rabbit" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "et dolores eaque", + "url": "http://overjoyed-former.info", + "participants": { + "totalCount": 4 + }, + "updatedAt": "2022-04-19T15:14:58.698Z", + "createdAt": "2022-04-28T23:15:49.918Z", + "comments": { + "totalCount": 1 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/347.jpg", + "login": "same-insect" + } + } + ] + }, + "author": { + "login": "smoggy-bird" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "vel error numquam", + "url": "http://submissive-ladder.org", + "participants": { + "totalCount": 3 + }, + "updatedAt": "2021-12-19T23:43:44.987Z", + "createdAt": "2022-01-04T11:52:01.233Z", + "comments": { + "totalCount": 4 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/951.jpg", + "login": "round-dog" + } + } + ] + }, + "author": { + "login": "humming-cetacean" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "doloribus asperiores occaecati", + "url": "http://webbed-underclothes.biz", + "participants": { + "totalCount": 2 + }, + "updatedAt": "2022-04-19T07:07:21.270Z", + "createdAt": "2022-04-20T10:41:00.681Z", + "comments": { + "totalCount": 2 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/1123.jpg", + "login": "tepid-cat" + } + } + ] + }, + "author": { + "login": "colossal-bird" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "reiciendis illum quos", + "url": "http://rusty-repeat.com", + "participants": { + "totalCount": 7 + }, + "updatedAt": "2022-08-04T06:35:11.880Z", + "createdAt": "2022-07-16T15:11:56.116Z", + "comments": { + "totalCount": 7 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/1068.jpg", + "login": "grown-cat" + } + } + ] + }, + "author": { + "login": "superficial-lion" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "tempore et sequi", + "url": "https://defenseless-signal.info", + "participants": { + "totalCount": 2 + }, + "updatedAt": "2022-03-12T10:17:20.598Z", + "createdAt": "2022-05-31T20:12:43.316Z", + "comments": { + "totalCount": 7 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/468.jpg", + "login": "blissful-horse" + } + } + ] + }, + "author": { + "login": "positive-insect" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "aut minima odit", + "url": "https://well-groomed-octave.biz", + "participants": { + "totalCount": 4 + }, + "updatedAt": "2021-08-20T21:00:05.294Z", + "createdAt": "2022-04-11T23:51:45.727Z", + "comments": { + "totalCount": 9 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/1044.jpg", + "login": "crowded-bird" + } + } + ] + }, + "author": { + "login": "unlined-horse" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "aut sunt quisquam", + "url": "https://realistic-student.com", + "participants": { + "totalCount": 5 + }, + "updatedAt": "2021-11-07T11:13:39.158Z", + "createdAt": "2022-01-30T19:35:35.546Z", + "comments": { + "totalCount": 2 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/691.jpg", + "login": "loathsome-insect" + } + } + ] + }, + "author": { + "login": "kooky-crocodilia" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "reprehenderit non eos", + "url": "https://alert-testimony.net", + "participants": { + "totalCount": 3 + }, + "updatedAt": "2022-04-24T16:34:36.616Z", + "createdAt": "2021-11-01T21:35:35.900Z", + "comments": { + "totalCount": 5 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/691.jpg", + "login": "dear-insect" + } + } + ] + }, + "author": { + "login": "wavy-bear" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "quis in earum", + "url": "https://radiant-posterior.net", + "participants": { + "totalCount": 7 + }, + "updatedAt": "2021-09-26T08:50:55.755Z", + "createdAt": "2022-04-10T00:03:40.290Z", + "comments": { + "totalCount": 8 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/952.jpg", + "login": "prestigious-cat" + } + } + ] + }, + "author": { + "login": "quick-cetacean" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "sed ut exercitationem", + "url": "https://portly-clasp.name", + "participants": { + "totalCount": 3 + }, + "updatedAt": "2022-04-06T03:04:16.077Z", + "createdAt": "2022-01-14T10:22:19.619Z", + "comments": { + "totalCount": 5 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/768.jpg", + "login": "fatal-cetacean" + } + } + ] + }, + "author": { + "login": "pricey-dog" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "voluptas error sunt", + "url": "http://second-outcome.info", + "participants": { + "totalCount": 5 + }, + "updatedAt": "2021-08-19T20:35:40.281Z", + "createdAt": "2021-10-02T12:24:16.983Z", + "comments": { + "totalCount": 6 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/283.jpg", + "login": "double-fish" + } + } + ] + }, + "author": { + "login": "liquid-snake" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "sed reprehenderit sunt", + "url": "https://playful-fibrosis.com", + "participants": { + "totalCount": 7 + }, + "updatedAt": "2022-05-24T19:35:19.804Z", + "createdAt": "2022-04-04T20:15:10.303Z", + "comments": { + "totalCount": 3 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/38.jpg", + "login": "separate-cat" + } + } + ] + }, + "author": { + "login": "jolly-bear" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "accusantium cupiditate et", + "url": "http://lined-flood.biz", + "participants": { + "totalCount": 9 + }, + "updatedAt": "2022-01-23T15:45:04.503Z", + "createdAt": "2021-11-29T07:20:44.372Z", + "comments": { + "totalCount": 4 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/410.jpg", + "login": "yummy-dog" + } + } + ] + }, + "author": { + "login": "pesky-bear" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "eum molestiae accusantium", + "url": "http://vast-grub.biz", + "participants": { + "totalCount": 7 + }, + "updatedAt": "2022-05-24T12:02:33.225Z", + "createdAt": "2022-02-26T14:40:38.285Z", + "comments": { + "totalCount": 5 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/186.jpg", + "login": "unique-cow" + } + } + ] + }, + "author": { + "login": "remorseful-horse" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "ea eligendi dolore", + "url": "http://mammoth-wick.biz", + "participants": { + "totalCount": 7 + }, + "updatedAt": "2022-07-02T12:23:03.701Z", + "createdAt": "2022-06-30T03:56:08.273Z", + "comments": { + "totalCount": 4 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/605.jpg", + "login": "soft-insect" + } + } + ] + }, + "author": { + "login": "vengeful-fish" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "eum in esse", + "url": "https://immaculate-liability.info", + "participants": { + "totalCount": 4 + }, + "updatedAt": "2022-06-14T02:40:34.008Z", + "createdAt": "2022-04-07T14:46:48.442Z", + "comments": { + "totalCount": 2 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/916.jpg", + "login": "wretched-cow" + } + } + ] + }, + "author": { + "login": "popular-insect" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "est voluptatem molestiae", + "url": "http://venerated-chocolate.biz", + "participants": { + "totalCount": 1 + }, + "updatedAt": "2021-10-08T18:02:11.052Z", + "createdAt": "2021-09-28T09:48:13.138Z", + "comments": { + "totalCount": 1 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/218.jpg", + "login": "flawless-dog" + } + } + ] + }, + "author": { + "login": "made-up-lion" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "sunt atque corrupti", + "url": "https://secondary-flight.biz", + "participants": { + "totalCount": 7 + }, + "updatedAt": "2021-12-31T07:36:01.831Z", + "createdAt": "2022-03-29T20:52:30.083Z", + "comments": { + "totalCount": 6 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/1099.jpg", + "login": "nervous-dog" + } + } + ] + }, + "author": { + "login": "inconsequential-cat" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "vel quo nam", + "url": "https://third-week.info", + "participants": { + "totalCount": 5 + }, + "updatedAt": "2022-03-06T07:42:44.049Z", + "createdAt": "2021-08-16T14:34:09.635Z", + "comments": { + "totalCount": 8 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/688.jpg", + "login": "dark-dog" + } + } + ] + }, + "author": { + "login": "modest-rabbit" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "rerum non nam", + "url": "http://complete-registry.net", + "participants": { + "totalCount": 5 + }, + "updatedAt": "2022-05-04T02:09:20.355Z", + "createdAt": "2022-06-08T12:23:09.380Z", + "comments": { + "totalCount": 1 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/489.jpg", + "login": "blond-insect" + } + } + ] + }, + "author": { + "login": "terrible-snake" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "accusamus quis non", + "url": "https://rosy-childhood.com", + "participants": { + "totalCount": 6 + }, + "updatedAt": "2021-12-14T12:46:15.628Z", + "createdAt": "2022-02-19T00:45:57.573Z", + "comments": { + "totalCount": 8 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/1094.jpg", + "login": "creative-bird" + } + } + ] + }, + "author": { + "login": "grotesque-dog" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "consectetur id et", + "url": "http://some-innocent.info", + "participants": { + "totalCount": 8 + }, + "updatedAt": "2021-11-27T11:12:58.067Z", + "createdAt": "2021-12-10T00:15:14.640Z", + "comments": { + "totalCount": 8 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/583.jpg", + "login": "drab-horse" + } + } + ] + }, + "author": { + "login": "acceptable-snake" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "ipsum beatae voluptas", + "url": "https://faithful-down.info", + "participants": { + "totalCount": 6 + }, + "updatedAt": "2022-08-13T17:03:33.381Z", + "createdAt": "2021-10-05T11:26:39.392Z", + "comments": { + "totalCount": 8 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/578.jpg", + "login": "esteemed-bird" + } + } + ] + }, + "author": { + "login": "cultured-fish" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "odio perferendis maxime", + "url": "https://minty-tactics.info", + "participants": { + "totalCount": 2 + }, + "updatedAt": "2022-01-25T02:14:59.148Z", + "createdAt": "2021-09-23T04:02:15.225Z", + "comments": { + "totalCount": 4 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/917.jpg", + "login": "quiet-bear" + } + } + ] + }, + "author": { + "login": "ill-fated-lion" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "sed enim laudantium", + "url": "https://welcome-provider.org", + "participants": { + "totalCount": 6 + }, + "updatedAt": "2022-02-24T23:08:19.320Z", + "createdAt": "2021-09-13T03:10:39.303Z", + "comments": { + "totalCount": 2 + } + } + }, + { + "node": { + "assignees": { + "edges": [ + { + "node": { + "avatarUrl": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/973.jpg", + "login": "portly-crocodilia" + } + } + ] + }, + "author": { + "login": "antique-bird" + }, + "repository": { + "nameWithOwner": "backstage/backstage" + }, + "title": "enim accusamus consequuntur", + "url": "http://shady-impudence.net", + "participants": { + "totalCount": 2 + }, + "updatedAt": "2021-12-04T05:35:50.780Z", + "createdAt": "2021-12-21T11:44:33.940Z", + "comments": { + "totalCount": 9 + } + } + } + ] + } + } +} diff --git a/plugins/github-issues/dev/index.tsx b/plugins/github-issues/dev/index.tsx index 57fd1a86e0..a5f20ab9b9 100644 --- a/plugins/github-issues/dev/index.tsx +++ b/plugins/github-issues/dev/index.tsx @@ -22,22 +22,9 @@ import { } from '@backstage/plugin-catalog-react'; import { gitHubIssuesPlugin, GitHubIssuesPage } from '../src'; -import { GitHubIssuesApi, gitHubIssuesApiRef, IssuesByRepo } from '../src/api'; +import { GitHubIssuesApi, gitHubIssuesApiRef } from '../src/api'; -import { generateTestIssue } from '../src/utils'; - -const response: IssuesByRepo = { - backstage: { - issues: { - totalCount: 464, - edges: Array.from(Array(40)).map(() => - generateTestIssue({ - repository: { nameWithOwner: 'backstage/backstage' }, - }), - ), - }, - }, -}; +import testData from './__fixtures__/component-issues-data.json'; createDevApp() .registerPlugin(gitHubIssuesPlugin) @@ -46,7 +33,7 @@ createDevApp() deps: {}, factory: () => ({ - fetchIssuesByRepoFromGitHub: async () => response, + fetchIssuesByRepoFromGitHub: async () => testData, } as GitHubIssuesApi), }) .registerApi({ diff --git a/plugins/github-issues/package.json b/plugins/github-issues/package.json index d7accb907e..21693740c7 100644 --- a/plugins/github-issues/package.json +++ b/plugins/github-issues/package.json @@ -29,7 +29,6 @@ "@backstage/integration": "^1.3.0-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.2", "@backstage/theme": "^0.2.15", - "@faker-js/faker": "^7.4.0", "@material-ui/core": "^4.12.4", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "^4.0.0-alpha.61", @@ -45,6 +44,7 @@ "@backstage/core-app-api": "^1.0.5-next.0", "@backstage/dev-utils": "^1.0.5-next.1", "@backstage/test-utils": "^1.1.3-next.0", + "@faker-js/faker": "^7.4.0", "@spotify/prettier-config": "^14.0.0", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", From ebde1274c8272b228c60132aebc62cf9c639d010 Mon Sep 17 00:00:00 2001 From: Kamil Wolny Date: Mon, 15 Aug 2022 12:35:49 +0100 Subject: [PATCH 14/15] feat: moved generating test issues code to the test file Signed-off-by: Kamil Wolny --- .../GitHubIssues/GitHubIssues.test.tsx | 42 +++++++++++++-- .../src/utils/generateTestIssue.ts | 53 ------------------- plugins/github-issues/src/utils/index.ts | 16 ------ 3 files changed, 39 insertions(+), 72 deletions(-) delete mode 100644 plugins/github-issues/src/utils/generateTestIssue.ts delete mode 100644 plugins/github-issues/src/utils/index.ts diff --git a/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.test.tsx b/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.test.tsx index 7b9d6d87b2..c8486d3d70 100644 --- a/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.test.tsx +++ b/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.test.tsx @@ -20,12 +20,48 @@ import { catalogApiRef, CatalogApi, } from '@backstage/plugin-catalog-react'; +import { faker } from '@faker-js/faker'; +import { Entity } from '@backstage/catalog-model'; -import { generateTestIssue } from '../../utils'; -import { GitHubIssuesApi, gitHubIssuesApiRef } from '../../api'; +import { GitHubIssuesApi, gitHubIssuesApiRef, Issue } from '../../api'; import { GitHubIssues } from './GitHubIssues'; -import { Entity } from '@backstage/catalog-model'; + +const generateTestIssue = ( + overwrites: Partial = {}, +): { node: Issue } => ({ + node: { + ...{ + assignees: { + edges: [ + { + node: { + avatarUrl: faker.internet.avatar(), + login: `${faker.word.adjective()}-${faker.animal.type()}`, + }, + }, + ], + }, + author: { + login: `${faker.word.adjective()}-${faker.animal.type()}`, + }, + repository: { + nameWithOwner: `${faker.animal.type()}/${faker.animal.type()}`, + }, + title: faker.lorem.words(3), + url: faker.internet.url(), + participants: { + totalCount: +faker.random.numeric(), + }, + updatedAt: faker.date.past().toISOString(), + createdAt: faker.date.past().toISOString(), + comments: { + totalCount: +faker.random.numeric(), + }, + }, + ...overwrites, + }, +}); jest .useFakeTimers() diff --git a/plugins/github-issues/src/utils/generateTestIssue.ts b/plugins/github-issues/src/utils/generateTestIssue.ts deleted file mode 100644 index a07c8dfc57..0000000000 --- a/plugins/github-issues/src/utils/generateTestIssue.ts +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2022 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { faker } from '@faker-js/faker'; -import { Issue } from '../api'; - -export const generateTestIssue = ( - overwrites: Partial = {}, -): { node: Issue } => ({ - node: { - ...{ - assignees: { - edges: [ - { - node: { - avatarUrl: faker.internet.avatar(), - login: `${faker.word.adjective()}-${faker.animal.type()}`, - }, - }, - ], - }, - author: { - login: `${faker.word.adjective()}-${faker.animal.type()}`, - }, - repository: { - nameWithOwner: `${faker.animal.type()}/${faker.animal.type()}`, - }, - title: faker.lorem.words(3), - url: faker.internet.url(), - participants: { - totalCount: +faker.random.numeric(), - }, - updatedAt: faker.date.past().toISOString(), - createdAt: faker.date.past().toISOString(), - comments: { - totalCount: +faker.random.numeric(), - }, - }, - ...overwrites, - }, -}); diff --git a/plugins/github-issues/src/utils/index.ts b/plugins/github-issues/src/utils/index.ts deleted file mode 100644 index 16740dac94..0000000000 --- a/plugins/github-issues/src/utils/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright 2022 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -export * from './generateTestIssue'; From 474370b668282e696c821c7383bf37b312a403f0 Mon Sep 17 00:00:00 2001 From: Kamil Wolny Date: Tue, 16 Aug 2022 09:36:35 +0100 Subject: [PATCH 15/15] feat: removed faker-js Signed-off-by: Kamil Wolny --- plugins/github-issues/package.json | 1 - .../GitHubIssues/GitHubIssues.test.tsx | 28 +++++++++---------- yarn.lock | 5 ---- 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/plugins/github-issues/package.json b/plugins/github-issues/package.json index 21693740c7..d31bb52603 100644 --- a/plugins/github-issues/package.json +++ b/plugins/github-issues/package.json @@ -44,7 +44,6 @@ "@backstage/core-app-api": "^1.0.5-next.0", "@backstage/dev-utils": "^1.0.5-next.1", "@backstage/test-utils": "^1.1.3-next.0", - "@faker-js/faker": "^7.4.0", "@spotify/prettier-config": "^14.0.0", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", diff --git a/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.test.tsx b/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.test.tsx index c8486d3d70..33eec79359 100644 --- a/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.test.tsx +++ b/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.test.tsx @@ -20,43 +20,41 @@ import { catalogApiRef, CatalogApi, } from '@backstage/plugin-catalog-react'; -import { faker } from '@faker-js/faker'; import { Entity } from '@backstage/catalog-model'; import { GitHubIssuesApi, gitHubIssuesApiRef, Issue } from '../../api'; import { GitHubIssues } from './GitHubIssues'; -const generateTestIssue = ( - overwrites: Partial = {}, -): { node: Issue } => ({ +const getTestIssue = (overwrites: Partial = {}): { node: Issue } => ({ node: { ...{ assignees: { edges: [ { node: { - avatarUrl: faker.internet.avatar(), - login: `${faker.word.adjective()}-${faker.animal.type()}`, + avatarUrl: + 'https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/1112.jpg', + login: 'worthless-horse', }, }, ], }, author: { - login: `${faker.word.adjective()}-${faker.animal.type()}`, + login: 'next-dog', }, repository: { - nameWithOwner: `${faker.animal.type()}/${faker.animal.type()}`, + nameWithOwner: 'backstage/backstage', }, - title: faker.lorem.words(3), - url: faker.internet.url(), + title: 'quasi labore qui', + url: 'http://flowery-muscatel.net', participants: { - totalCount: +faker.random.numeric(), + totalCount: 3, }, - updatedAt: faker.date.past().toISOString(), - createdAt: faker.date.past().toISOString(), + updatedAt: '2022-05-02T09:46:35.885Z', + createdAt: '2022-06-03T07:11:22.320Z', comments: { - totalCount: +faker.random.numeric(), + totalCount: 6, }, }, ...overwrites, @@ -114,7 +112,7 @@ describe('GitHubIssues', () => { }); it('should render correctly', async () => { - const testIssue = generateTestIssue({ + const testIssue = getTestIssue({ createdAt: '2020-04-19T10:15:47.614Z', updatedAt: '2020-04-20T00:15:47.614Z', }); diff --git a/yarn.lock b/yarn.lock index 4bebec76e1..4894a4b674 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2673,11 +2673,6 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@faker-js/faker@^7.4.0": - version "7.4.0" - resolved "https://registry.npmjs.org/@faker-js/faker/-/faker-7.4.0.tgz#cac720d860a89d487b47e55e66a4fd114f1d3fe5" - integrity sha512-xDd3Tvkt2jgkx1LkuwwxpNBy/Oe+LkZBTwkgEFTiWpVSZgQ5sc/LenbHKRHbFl0dq/KFeeq/szyyPtpJRKY0fg== - "@fmvilas/pseudo-yaml-ast@^0.3.1": version "0.3.1" resolved "https://registry.npmjs.org/@fmvilas/pseudo-yaml-ast/-/pseudo-yaml-ast-0.3.1.tgz#66c5df2c2d76ba8571dc5bd98fda4d7dce6121de"