From e7b90f996aaf32ce02101657668675ef3d9dc3f4 Mon Sep 17 00:00:00 2001 From: Paul Cowan Date: Wed, 5 Oct 2022 21:09:09 +0100 Subject: [PATCH 01/13] add filterBy and orderBy props to the github-issues plugin Signed-off-by: Paul Cowan --- app-config.yaml | 2 +- packages/app/package.json | 1 + .../app/src/components/catalog/EntityPage.tsx | 6 ++ .../github-issues/src/api/gitHubIssuesApi.ts | 49 +++++++++++- .../components/GitHubIssues/GitHubIssues.tsx | 6 +- .../src/hooks/useGetIssuesByRepoFromGitHub.ts | 3 + plugins/github-issues/src/types.ts | 34 ++++++++ query.graphql | 77 +++++++++++++++++++ yarn.lock | 3 +- 9 files changed, 175 insertions(+), 6 deletions(-) create mode 100644 plugins/github-issues/src/types.ts create mode 100644 query.graphql diff --git a/app-config.yaml b/app-config.yaml index 22ca1fcaff..8dacce900c 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -300,7 +300,7 @@ auth: development: clientId: ${AUTH_GITHUB_CLIENT_ID} clientSecret: ${AUTH_GITHUB_CLIENT_SECRET} - enterpriseInstanceUrl: ${AUTH_GITHUB_ENTERPRISE_INSTANCE_URL} + # enterpriseInstanceUrl: ${AUTH_GITHUB_ENTERPRISE_INSTANCE_URL} gitlab: development: clientId: ${AUTH_GITLAB_CLIENT_ID} diff --git a/packages/app/package.json b/packages/app/package.json index 4181b036e9..ade10e9c14 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -33,6 +33,7 @@ "@backstage/plugin-gcalendar": "workspace:^", "@backstage/plugin-gcp-projects": "workspace:^", "@backstage/plugin-github-actions": "workspace:^", + "@backstage/plugin-github-issues": "workspace:^", "@backstage/plugin-gocd": "workspace:^", "@backstage/plugin-graphiql": "workspace:^", "@backstage/plugin-home": "workspace:^", diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx index c2f297a2d7..4cf6779607 100644 --- a/packages/app/src/components/catalog/EntityPage.tsx +++ b/packages/app/src/components/catalog/EntityPage.tsx @@ -153,6 +153,8 @@ import { ReportIssue, } from '@backstage/plugin-techdocs-module-addons-contrib'; +import { GitHubIssuesCard } from '@backstage/plugin-github-issues'; + const customEntityFilterKind = ['Component', 'API', 'System']; const EntityLayoutWrapper = (props: { children?: ReactNode }) => { @@ -342,6 +344,10 @@ const overviewContent = ( + + + + diff --git a/plugins/github-issues/src/api/gitHubIssuesApi.ts b/plugins/github-issues/src/api/gitHubIssuesApi.ts index 816345940c..a07e4f5790 100644 --- a/plugins/github-issues/src/api/gitHubIssuesApi.ts +++ b/plugins/github-issues/src/api/gitHubIssuesApi.ts @@ -22,6 +22,7 @@ import { } from '@backstage/core-plugin-api'; import { readGitHubIntegrationConfigs } from '@backstage/integration'; import { ForwardedError } from '@backstage/errors'; +import { IssuesByRepoOptions, IssuesFilters } from '../types'; /** @internal */ export type Assignee = { @@ -103,6 +104,13 @@ export const gitHubIssuesApi = ( const fetchIssuesByRepoFromGitHub = async ( repos: Array, itemsPerRepo: number, + { + filterBy, + orderBy = { + field: 'UPDATED_AT', + direction: 'DESC', + }, + }: IssuesByRepoOptions = {}, ): Promise => { const graphql = await getOctokit(); const safeNames: Array = []; @@ -126,10 +134,17 @@ export const gitHubIssuesApi = ( }; }); + // eslint-disable-next-line no-console + console.log(` + --------------------------------------------------- + ${createIssueByRepoQuery(repositories, itemsPerRepo, { filterBy })} + --------------------------------------------------- + `); + let issuesByRepo: IssuesByRepo = {}; try { issuesByRepo = await graphql( - createIssueByRepoQuery(repositories, itemsPerRepo), + createIssueByRepoQuery(repositories, itemsPerRepo, { filterBy }), ); } catch (e) { if (e.data) { @@ -151,6 +166,34 @@ export const gitHubIssuesApi = ( return { fetchIssuesByRepoFromGitHub }; }; +function formatFilterValue(value: IssuesFilters[keyof IssuesFilters]): string { + if (Array.isArray(value)) { + return `[ ${value.map(formatFilterValue).join(', ')}`; + } + + return typeof value === 'string' ? `\"${value}\"` : `${value}`; +} + +function createFilterByClause(filterBy?: IssuesFilters): string { + if (typeof filterBy === 'undefined') { + return ''; + } + + return Object.entries(filterBy) + .flatMap(([field, value]) => { + if (typeof value === 'undefined') { + return []; + } + + if (field === 'states') { + return [`${field}: ${value.join(', ')}`]; + } + + return [`${field}: ${formatFilterValue}`]; + }) + .join(', '); +} + function createIssueByRepoQuery( repositories: Array<{ safeName: string; @@ -158,13 +201,15 @@ function createIssueByRepoQuery( owner: string; }>, itemsPerRepo: number, + { filterBy, orderBy }: IssuesByRepoOptions, ): string { const fragment = ` fragment issues on Repository { issues( states: OPEN first: ${itemsPerRepo} - orderBy: { field: UPDATED_AT, direction: DESC } + filterBy: { ${createFilterByClause(filterBy)} } + orderBy: { field: ${orderBy?.field}, direction: ${orderBy?.direction} } ) { totalCount edges { diff --git a/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx b/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx index 574c15d3b3..78cdfbd708 100644 --- a/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx +++ b/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx @@ -24,6 +24,7 @@ import { useGetIssuesByRepoFromGitHub } from '../../hooks/useGetIssuesByRepoFrom import { IssuesList } from './IssuesList'; import { NoRepositoriesInfo } from './NoRepositoriesInfo'; +import { IssuesByRepoOptions } from '../../types'; /** * @public @@ -31,17 +32,18 @@ import { NoRepositoriesInfo } from './NoRepositoriesInfo'; export type GitHubIssuesProps = { itemsPerPage?: number; itemsPerRepo?: number; + queryOptions?: IssuesByRepoOptions; }; export const GitHubIssues = (props: GitHubIssuesProps) => { - const { itemsPerPage = 10, itemsPerRepo = 40 } = props; + const { itemsPerPage = 10, itemsPerRepo = 40, queryOptions } = props; const { repositories } = useEntityGitHubRepositories(); const { isLoading, gitHubIssuesByRepo: issuesByRepository, retry, - } = useGetIssuesByRepoFromGitHub(repositories, itemsPerRepo); + } = useGetIssuesByRepoFromGitHub(repositories, itemsPerRepo, queryOptions); if (!repositories.length) { return ; diff --git a/plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts b/plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts index 8d1d0c2056..ab9305693d 100644 --- a/plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts +++ b/plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts @@ -17,10 +17,12 @@ import { useApi } from '@backstage/core-plugin-api'; import useAsyncRetry from 'react-use/lib/useAsyncRetry'; import { gitHubIssuesApiRef } from '../api'; +import { IssuesByRepoOptions } from '../types'; export const useGetIssuesByRepoFromGitHub = ( repos: Array, itemsPerRepo: number, + options?: IssuesByRepoOptions, ) => { const gitHubIssuesApi = useApi(gitHubIssuesApiRef); @@ -33,6 +35,7 @@ export const useGetIssuesByRepoFromGitHub = ( return await gitHubIssuesApi.fetchIssuesByRepoFromGitHub( repos, itemsPerRepo, + options, ); } diff --git a/plugins/github-issues/src/types.ts b/plugins/github-issues/src/types.ts new file mode 100644 index 0000000000..ee245929b8 --- /dev/null +++ b/plugins/github-issues/src/types.ts @@ -0,0 +1,34 @@ +/* + * 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. + */ +type IssueState = 'OPEN' | 'CLOSED'; + +/** @internal */ +export interface IssuesFilters { + assignee?: string; + createdBy?: string; + labels?: string[]; + mentioned?: string; + milestone?: string; + states?: IssueState[]; +} + +export interface IssuesByRepoOptions { + filterBy?: IssuesFilters; + orderBy?: { + field: 'CREATED_AT' | 'UPDATED_AT' | 'COMMENTS'; + direction: 'ASC' | 'DESC'; + }; +} diff --git a/query.graphql b/query.graphql new file mode 100644 index 0000000000..98a72fac26 --- /dev/null +++ b/query.graphql @@ -0,0 +1,77 @@ +/* http://localhost:7007/api/auth/github /* + +{ + repository(owner: "backstage", name: "backstage") { + issues(first: 1, filterBy: { labels: ["bug"] }) { + nodes { + title + body + bodyHTML + bodyText + number + labels(first: 100) { + nodes { + color + name + id + } + } + author { + url + avatarUrl + login + } + } + } + } +} + + + +fragment issues on Repository { + issues( + states: OPEN + first: 40 + 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 + } + } + } + } +} + + +query { + + backstage: repository(name: "backstage", owner: "backstage") { + ...issues + } + +} + \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index e5f10c942a..1df05d3c22 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5604,7 +5604,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-github-issues@workspace:plugins/github-issues": +"@backstage/plugin-github-issues@workspace:^, @backstage/plugin-github-issues@workspace:plugins/github-issues": version: 0.0.0-use.local resolution: "@backstage/plugin-github-issues@workspace:plugins/github-issues" dependencies: @@ -22004,6 +22004,7 @@ __metadata: "@backstage/plugin-gcalendar": "workspace:^" "@backstage/plugin-gcp-projects": "workspace:^" "@backstage/plugin-github-actions": "workspace:^" + "@backstage/plugin-github-issues": "workspace:^" "@backstage/plugin-gocd": "workspace:^" "@backstage/plugin-graphiql": "workspace:^" "@backstage/plugin-home": "workspace:^" From 0a968bb1dfe69f64a831e53e34386416516531f2 Mon Sep 17 00:00:00 2001 From: Paul Cowan Date: Wed, 5 Oct 2022 21:33:59 +0100 Subject: [PATCH 02/13] make orderBy direction optional Signed-off-by: Paul Cowan --- .../app/src/components/catalog/EntityPage.tsx | 10 +++++++++- plugins/github-issues/src/api/gitHubIssuesApi.ts | 15 +++++++++------ .../src/components/GitHubIssues/GitHubIssues.tsx | 10 +++++++--- plugins/github-issues/src/types.ts | 2 +- 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx index 4cf6779607..6991f3fd67 100644 --- a/packages/app/src/components/catalog/EntityPage.tsx +++ b/packages/app/src/components/catalog/EntityPage.tsx @@ -345,7 +345,15 @@ const overviewContent = ( - + diff --git a/plugins/github-issues/src/api/gitHubIssuesApi.ts b/plugins/github-issues/src/api/gitHubIssuesApi.ts index a07e4f5790..dc5623a7bc 100644 --- a/plugins/github-issues/src/api/gitHubIssuesApi.ts +++ b/plugins/github-issues/src/api/gitHubIssuesApi.ts @@ -110,7 +110,7 @@ export const gitHubIssuesApi = ( field: 'UPDATED_AT', direction: 'DESC', }, - }: IssuesByRepoOptions = {}, + }: IssuesByRepoOptions, ): Promise => { const graphql = await getOctokit(); const safeNames: Array = []; @@ -137,14 +137,17 @@ export const gitHubIssuesApi = ( // eslint-disable-next-line no-console console.log(` --------------------------------------------------- - ${createIssueByRepoQuery(repositories, itemsPerRepo, { filterBy })} + ${createIssueByRepoQuery(repositories, itemsPerRepo, { filterBy, orderBy })} --------------------------------------------------- `); let issuesByRepo: IssuesByRepo = {}; try { issuesByRepo = await graphql( - createIssueByRepoQuery(repositories, itemsPerRepo, { filterBy }), + createIssueByRepoQuery(repositories, itemsPerRepo, { + filterBy, + orderBy, + }), ); } catch (e) { if (e.data) { @@ -168,7 +171,7 @@ export const gitHubIssuesApi = ( function formatFilterValue(value: IssuesFilters[keyof IssuesFilters]): string { if (Array.isArray(value)) { - return `[ ${value.map(formatFilterValue).join(', ')}`; + return `[ ${value.map(formatFilterValue).join(', ')}]`; } return typeof value === 'string' ? `\"${value}\"` : `${value}`; @@ -189,9 +192,9 @@ function createFilterByClause(filterBy?: IssuesFilters): string { return [`${field}: ${value.join(', ')}`]; } - return [`${field}: ${formatFilterValue}`]; + return [`${field}: ${formatFilterValue(value)}`]; }) - .join(', '); + .join(', '); } function createIssueByRepoQuery( diff --git a/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx b/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx index 78cdfbd708..a620797574 100644 --- a/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx +++ b/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx @@ -32,18 +32,22 @@ import { IssuesByRepoOptions } from '../../types'; export type GitHubIssuesProps = { itemsPerPage?: number; itemsPerRepo?: number; - queryOptions?: IssuesByRepoOptions; + filterBy?: IssuesByRepoOptions['filterBy']; + orderBy?: IssuesByRepoOptions['orderBy']; }; export const GitHubIssues = (props: GitHubIssuesProps) => { - const { itemsPerPage = 10, itemsPerRepo = 40, queryOptions } = props; + const { itemsPerPage = 10, itemsPerRepo = 40, filterBy, orderBy } = props; const { repositories } = useEntityGitHubRepositories(); const { isLoading, gitHubIssuesByRepo: issuesByRepository, retry, - } = useGetIssuesByRepoFromGitHub(repositories, itemsPerRepo, queryOptions); + } = useGetIssuesByRepoFromGitHub(repositories, itemsPerRepo, { + filterBy, + orderBy, + }); if (!repositories.length) { return ; diff --git a/plugins/github-issues/src/types.ts b/plugins/github-issues/src/types.ts index ee245929b8..c8d238fa4f 100644 --- a/plugins/github-issues/src/types.ts +++ b/plugins/github-issues/src/types.ts @@ -29,6 +29,6 @@ export interface IssuesByRepoOptions { filterBy?: IssuesFilters; orderBy?: { field: 'CREATED_AT' | 'UPDATED_AT' | 'COMMENTS'; - direction: 'ASC' | 'DESC'; + direction?: 'ASC' | 'DESC'; }; } From d27181ca2978ce1055aeec65fcef62a3de12b106 Mon Sep 17 00:00:00 2001 From: Paul Cowan Date: Thu, 6 Oct 2022 13:47:33 +0100 Subject: [PATCH 03/13] clear mocks in github-issues tests Signed-off-by: Paul Cowan --- .../src/api/gitHubIssuesApi.test.ts | 161 +++++++++++------- .../github-issues/src/api/gitHubIssuesApi.ts | 9 +- 2 files changed, 103 insertions(+), 67 deletions(-) diff --git a/plugins/github-issues/src/api/gitHubIssuesApi.test.ts b/plugins/github-issues/src/api/gitHubIssuesApi.test.ts index 4d1c3ffff3..070e9ab2f6 100644 --- a/plugins/github-issues/src/api/gitHubIssuesApi.test.ts +++ b/plugins/github-issues/src/api/gitHubIssuesApi.test.ts @@ -22,80 +22,123 @@ import { ConfigApi, ErrorApi } from '@backstage/core-plugin-api'; import { ForwardedError } from '@backstage/errors'; import { gitHubIssuesApi } from './gitHubIssuesApi'; +function getFragment( + filterBy = '', + orderBy = 'field: UPDATED_AT, direction: DESC', +) { + return ( + '\n' + + ' \n' + + ' fragment issues on Repository {\n' + + ' issues(\n' + + ' states: OPEN\n' + + ' first: 10\n' + + ` filterBy: { ${filterBy} }\n` + + ` orderBy: { ${orderBy} }\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' + + ' ' + ); +} + describe('gitHubIssuesApi', () => { describe('fetchIssuesByRepoFromGitHub', () => { - it('should call GitHub API with correct query with fragment for each repo', async () => { - const api = gitHubIssuesApi( + let api: ReturnType; + + afterEach(() => { + jest.clearAllMocks(); + }); + + beforeEach(() => { + api = gitHubIssuesApi( { getAccessToken: jest.fn() }, { getOptionalConfigArray: jest.fn(), } as unknown as ConfigApi, { post: jest.fn() } as unknown as ErrorApi, ); + }); + it('should call GitHub API with correct query with fragment for each repo', async () => { await api.fetchIssuesByRepoFromGitHub( ['mrwolny/yo-yo', 'mrwolny/yoyo', 'mrwolny/yo.yo'], 10, ); + + expect(mockGraphQLQuery).toHaveBeenCalledTimes(1); + expect(mockGraphQLQuery).toHaveBeenCalledWith(getFragment()); + }); + + it('should call Github API with the correct filterBy and orderBy clauses', async () => { + await api.fetchIssuesByRepoFromGitHub( + ['mrwolny/yo-yo', 'mrwolny/yoyo', 'mrwolny/yo.yo'], + 10, + { + filterBy: { + labels: ['bug'], + states: ['OPEN'], + assignee: 'someone', + }, + orderBy: { + field: 'COMMENTS', + direction: 'ASC', + }, + }, + ); + + const expectedFilterBy = `labels: [ "bug"], states: OPEN, assignee: "someone"`; + const expectedOrderBy = 'field: COMMENTS, direction: ASC'; + 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' + - ' ', + getFragment(expectedFilterBy, expectedOrderBy), ); }); }); diff --git a/plugins/github-issues/src/api/gitHubIssuesApi.ts b/plugins/github-issues/src/api/gitHubIssuesApi.ts index dc5623a7bc..01a6a59532 100644 --- a/plugins/github-issues/src/api/gitHubIssuesApi.ts +++ b/plugins/github-issues/src/api/gitHubIssuesApi.ts @@ -110,7 +110,7 @@ export const gitHubIssuesApi = ( field: 'UPDATED_AT', direction: 'DESC', }, - }: IssuesByRepoOptions, + }: IssuesByRepoOptions = {}, ): Promise => { const graphql = await getOctokit(); const safeNames: Array = []; @@ -134,13 +134,6 @@ export const gitHubIssuesApi = ( }; }); - // eslint-disable-next-line no-console - console.log(` - --------------------------------------------------- - ${createIssueByRepoQuery(repositories, itemsPerRepo, { filterBy, orderBy })} - --------------------------------------------------- - `); - let issuesByRepo: IssuesByRepo = {}; try { issuesByRepo = await graphql( From df226e124c6244d52c3d7b1f3058d86ca6a9e1da Mon Sep 17 00:00:00 2001 From: Paul Cowan Date: Thu, 6 Oct 2022 14:51:23 +0100 Subject: [PATCH 04/13] create changeset and run api-reports Signed-off-by: Paul Cowan --- .changeset/young-olives-cheer.md | 5 ++ app-config.yaml | 2 +- packages/app/package.json | 1 - .../app/src/components/catalog/EntityPage.tsx | 14 ---- plugins/github-issues/api-report.md | 34 ++++++++ .../github-issues/src/api/gitHubIssuesApi.ts | 29 ++++++- .../components/GitHubIssues/GitHubIssues.tsx | 6 +- .../src/hooks/useGetIssuesByRepoFromGitHub.ts | 3 +- plugins/github-issues/src/index.ts | 5 ++ plugins/github-issues/src/types.ts | 34 -------- query.graphql | 77 ------------------- yarn.lock | 3 +- 12 files changed, 78 insertions(+), 135 deletions(-) create mode 100644 .changeset/young-olives-cheer.md delete mode 100644 plugins/github-issues/src/types.ts delete mode 100644 query.graphql diff --git a/.changeset/young-olives-cheer.md b/.changeset/young-olives-cheer.md new file mode 100644 index 0000000000..a74f34eb42 --- /dev/null +++ b/.changeset/young-olives-cheer.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-github-issues': minor +--- + +Add filtering and ordering to the graphql query diff --git a/app-config.yaml b/app-config.yaml index 8dacce900c..22ca1fcaff 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -300,7 +300,7 @@ auth: development: clientId: ${AUTH_GITHUB_CLIENT_ID} clientSecret: ${AUTH_GITHUB_CLIENT_SECRET} - # enterpriseInstanceUrl: ${AUTH_GITHUB_ENTERPRISE_INSTANCE_URL} + enterpriseInstanceUrl: ${AUTH_GITHUB_ENTERPRISE_INSTANCE_URL} gitlab: development: clientId: ${AUTH_GITLAB_CLIENT_ID} diff --git a/packages/app/package.json b/packages/app/package.json index ade10e9c14..4181b036e9 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -33,7 +33,6 @@ "@backstage/plugin-gcalendar": "workspace:^", "@backstage/plugin-gcp-projects": "workspace:^", "@backstage/plugin-github-actions": "workspace:^", - "@backstage/plugin-github-issues": "workspace:^", "@backstage/plugin-gocd": "workspace:^", "@backstage/plugin-graphiql": "workspace:^", "@backstage/plugin-home": "workspace:^", diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx index 6991f3fd67..c2f297a2d7 100644 --- a/packages/app/src/components/catalog/EntityPage.tsx +++ b/packages/app/src/components/catalog/EntityPage.tsx @@ -153,8 +153,6 @@ import { ReportIssue, } from '@backstage/plugin-techdocs-module-addons-contrib'; -import { GitHubIssuesCard } from '@backstage/plugin-github-issues'; - const customEntityFilterKind = ['Component', 'API', 'System']; const EntityLayoutWrapper = (props: { children?: ReactNode }) => { @@ -344,18 +342,6 @@ const overviewContent = ( - - - - diff --git a/plugins/github-issues/api-report.md b/plugins/github-issues/api-report.md index eb69fc8e8e..0ce8b77975 100644 --- a/plugins/github-issues/api-report.md +++ b/plugins/github-issues/api-report.md @@ -27,7 +27,41 @@ export const gitHubIssuesPlugin: BackstagePlugin< export type GitHubIssuesProps = { itemsPerPage?: number; itemsPerRepo?: number; + filterBy?: IssuesFilters; + orderBy?: IssuesOrdering; }; +// @public (undocumented) +export interface IssuesByRepoOptions { + // (undocumented) + filterBy?: IssuesFilters; + // (undocumented) + orderBy?: IssuesOrdering; +} + +// @public (undocumented) +export interface IssuesFilters { + // (undocumented) + assignee?: string; + // (undocumented) + createdBy?: string; + // (undocumented) + labels?: string[]; + // (undocumented) + mentioned?: string; + // (undocumented) + milestone?: string; + // (undocumented) + states?: ('OPEN' | 'CLOSED')[]; +} + +// @public (undocumented) +export interface IssuesOrdering { + // (undocumented) + direction?: 'ASC' | 'DESC'; + // (undocumented) + field: 'CREATED_AT' | 'UPDATED_AT' | 'COMMENTS'; +} + // (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 01a6a59532..4d90f11de6 100644 --- a/plugins/github-issues/src/api/gitHubIssuesApi.ts +++ b/plugins/github-issues/src/api/gitHubIssuesApi.ts @@ -22,7 +22,6 @@ import { } from '@backstage/core-plugin-api'; import { readGitHubIntegrationConfigs } from '@backstage/integration'; import { ForwardedError } from '@backstage/errors'; -import { IssuesByRepoOptions, IssuesFilters } from '../types'; /** @internal */ export type Assignee = { @@ -74,6 +73,34 @@ export type IssuesByRepo = Record; /** @internal */ export type GitHubIssuesApi = ReturnType; +/** + * @public + */ +export interface IssuesFilters { + assignee?: string; + createdBy?: string; + labels?: string[]; + mentioned?: string; + milestone?: string; + states?: ('OPEN' | 'CLOSED')[]; +} + +/** + * @public + */ +export interface IssuesOrdering { + field: 'CREATED_AT' | 'UPDATED_AT' | 'COMMENTS'; + direction?: 'ASC' | 'DESC'; +} + +/** + * @public + */ +export interface IssuesByRepoOptions { + filterBy?: IssuesFilters; + orderBy?: IssuesOrdering; +} + /** @internal */ export const gitHubIssuesApiRef = createApiRef({ id: 'plugin.githubissues.service', diff --git a/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx b/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx index a620797574..a8a192dece 100644 --- a/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx +++ b/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx @@ -24,7 +24,7 @@ import { useGetIssuesByRepoFromGitHub } from '../../hooks/useGetIssuesByRepoFrom import { IssuesList } from './IssuesList'; import { NoRepositoriesInfo } from './NoRepositoriesInfo'; -import { IssuesByRepoOptions } from '../../types'; +import type { IssuesFilters, IssuesOrdering } from '../../api/gitHubIssuesApi'; /** * @public @@ -32,8 +32,8 @@ import { IssuesByRepoOptions } from '../../types'; export type GitHubIssuesProps = { itemsPerPage?: number; itemsPerRepo?: number; - filterBy?: IssuesByRepoOptions['filterBy']; - orderBy?: IssuesByRepoOptions['orderBy']; + filterBy?: IssuesFilters; + orderBy?: IssuesOrdering; }; export const GitHubIssues = (props: GitHubIssuesProps) => { diff --git a/plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts b/plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts index ab9305693d..670cb0596a 100644 --- a/plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts +++ b/plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts @@ -16,8 +16,7 @@ import { useApi } from '@backstage/core-plugin-api'; import useAsyncRetry from 'react-use/lib/useAsyncRetry'; -import { gitHubIssuesApiRef } from '../api'; -import { IssuesByRepoOptions } from '../types'; +import { gitHubIssuesApiRef, IssuesByRepoOptions } from '../api'; export const useGetIssuesByRepoFromGitHub = ( repos: Array, diff --git a/plugins/github-issues/src/index.ts b/plugins/github-issues/src/index.ts index 5f6c248db7..f17cc1e2e6 100644 --- a/plugins/github-issues/src/index.ts +++ b/plugins/github-issues/src/index.ts @@ -20,3 +20,8 @@ export { } from './plugin'; export type { GitHubIssuesProps } from './components/GitHubIssues'; +export type { + IssuesFilters, + IssuesOrdering, + IssuesByRepoOptions, +} from './api/gitHubIssuesApi'; diff --git a/plugins/github-issues/src/types.ts b/plugins/github-issues/src/types.ts deleted file mode 100644 index c8d238fa4f..0000000000 --- a/plugins/github-issues/src/types.ts +++ /dev/null @@ -1,34 +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. - */ -type IssueState = 'OPEN' | 'CLOSED'; - -/** @internal */ -export interface IssuesFilters { - assignee?: string; - createdBy?: string; - labels?: string[]; - mentioned?: string; - milestone?: string; - states?: IssueState[]; -} - -export interface IssuesByRepoOptions { - filterBy?: IssuesFilters; - orderBy?: { - field: 'CREATED_AT' | 'UPDATED_AT' | 'COMMENTS'; - direction?: 'ASC' | 'DESC'; - }; -} diff --git a/query.graphql b/query.graphql deleted file mode 100644 index 98a72fac26..0000000000 --- a/query.graphql +++ /dev/null @@ -1,77 +0,0 @@ -/* http://localhost:7007/api/auth/github /* - -{ - repository(owner: "backstage", name: "backstage") { - issues(first: 1, filterBy: { labels: ["bug"] }) { - nodes { - title - body - bodyHTML - bodyText - number - labels(first: 100) { - nodes { - color - name - id - } - } - author { - url - avatarUrl - login - } - } - } - } -} - - - -fragment issues on Repository { - issues( - states: OPEN - first: 40 - 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 - } - } - } - } -} - - -query { - - backstage: repository(name: "backstage", owner: "backstage") { - ...issues - } - -} - \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 1df05d3c22..e5f10c942a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5604,7 +5604,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-github-issues@workspace:^, @backstage/plugin-github-issues@workspace:plugins/github-issues": +"@backstage/plugin-github-issues@workspace:plugins/github-issues": version: 0.0.0-use.local resolution: "@backstage/plugin-github-issues@workspace:plugins/github-issues" dependencies: @@ -22004,7 +22004,6 @@ __metadata: "@backstage/plugin-gcalendar": "workspace:^" "@backstage/plugin-gcp-projects": "workspace:^" "@backstage/plugin-github-actions": "workspace:^" - "@backstage/plugin-github-issues": "workspace:^" "@backstage/plugin-gocd": "workspace:^" "@backstage/plugin-graphiql": "workspace:^" "@backstage/plugin-home": "workspace:^" From 4bb79f7cddce6dda30f8011f12190f2af4bc7e6f Mon Sep 17 00:00:00 2001 From: Paul Cowan Date: Thu, 6 Oct 2022 15:20:46 +0100 Subject: [PATCH 05/13] update github-issues README Signed-off-by: Paul Cowan --- plugins/github-issues/README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/plugins/github-issues/README.md b/plugins/github-issues/README.md index eeb93ab27b..d35f2c5d3f 100644 --- a/plugins/github-issues/README.md +++ b/plugins/github-issues/README.md @@ -61,3 +61,20 @@ However, you can configure the plugin with props: - `itemsPerPage: number = 10` - Issues in the list are paginated, number of issues on a single page is controlled with this prop - `itemsPerRepo: number = 40` - the plugin doesn't download all Issues available on GitHub. By default, it will get at most 40 Issues - this prop controls this behaviour +- `filterBy: object` - the plugin can be configured to filter the query by `assignee`, `createdBy`, `labels`, `states`, `mentioned` or `milestone`. +- `orderBy: object = { field: 'UPDATED_AT', direction: 'DESC' }` - The ordering that the issues are returned can be configured by the `orderBy` field. + +### `filterBy` and `orderBy` example + +```ts + +``` From fa6d6a2551a7af22b27fc44b486eca3a83ef545e Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 7 Oct 2022 10:32:48 +0100 Subject: [PATCH 06/13] Update .changeset/young-olives-cheer.md Co-authored-by: Johan Haals Signed-off-by: Paul Signed-off-by: Paul Cowan --- .changeset/young-olives-cheer.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/young-olives-cheer.md b/.changeset/young-olives-cheer.md index a74f34eb42..536a8d6370 100644 --- a/.changeset/young-olives-cheer.md +++ b/.changeset/young-olives-cheer.md @@ -1,5 +1,5 @@ --- -'@backstage/plugin-github-issues': minor +'@backstage/plugin-github-issues': patch --- Add filtering and ordering to the graphql query From c950a3aa72f7a1e6121dbaf257dfb31980010047 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 7 Oct 2022 10:33:17 +0100 Subject: [PATCH 07/13] Update plugins/github-issues/src/api/gitHubIssuesApi.ts Co-authored-by: Johan Haals Signed-off-by: Paul Signed-off-by: Paul Cowan --- plugins/github-issues/src/api/gitHubIssuesApi.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/github-issues/src/api/gitHubIssuesApi.ts b/plugins/github-issues/src/api/gitHubIssuesApi.ts index 4d90f11de6..3be9d06c8a 100644 --- a/plugins/github-issues/src/api/gitHubIssuesApi.ts +++ b/plugins/github-issues/src/api/gitHubIssuesApi.ts @@ -198,7 +198,7 @@ function formatFilterValue(value: IssuesFilters[keyof IssuesFilters]): string { } function createFilterByClause(filterBy?: IssuesFilters): string { - if (typeof filterBy === 'undefined') { + if (!filterBy) { return ''; } From 27828db4a7377f66abf0f631b09290f5d5ac4cbc Mon Sep 17 00:00:00 2001 From: Paul Cowan Date: Fri, 7 Oct 2022 10:44:17 +0100 Subject: [PATCH 08/13] falsy check in createFilterByClause Signed-off-by: Paul Cowan --- plugins/github-issues/src/api/gitHubIssuesApi.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/github-issues/src/api/gitHubIssuesApi.ts b/plugins/github-issues/src/api/gitHubIssuesApi.ts index 3be9d06c8a..c813e35be5 100644 --- a/plugins/github-issues/src/api/gitHubIssuesApi.ts +++ b/plugins/github-issues/src/api/gitHubIssuesApi.ts @@ -204,7 +204,7 @@ function createFilterByClause(filterBy?: IssuesFilters): string { return Object.entries(filterBy) .flatMap(([field, value]) => { - if (typeof value === 'undefined') { + if (!value) { return []; } From 663fd697f188b4cfe21789ea152833fb6a0a23b7 Mon Sep 17 00:00:00 2001 From: Paul Cowan Date: Fri, 7 Oct 2022 13:06:08 +0100 Subject: [PATCH 09/13] prefix IssuesFilters and IssuesOrdering with Github Signed-off-by: Paul Cowan --- plugins/github-issues/src/api/gitHubIssuesApi.ts | 14 ++++++++------ .../src/components/GitHubIssues/GitHubIssues.tsx | 9 ++++++--- plugins/github-issues/src/index.ts | 4 ++-- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/plugins/github-issues/src/api/gitHubIssuesApi.ts b/plugins/github-issues/src/api/gitHubIssuesApi.ts index c813e35be5..d80ec3bce8 100644 --- a/plugins/github-issues/src/api/gitHubIssuesApi.ts +++ b/plugins/github-issues/src/api/gitHubIssuesApi.ts @@ -76,7 +76,7 @@ export type GitHubIssuesApi = ReturnType; /** * @public */ -export interface IssuesFilters { +export interface GithubIssuesFilters { assignee?: string; createdBy?: string; labels?: string[]; @@ -88,7 +88,7 @@ export interface IssuesFilters { /** * @public */ -export interface IssuesOrdering { +export interface GithubIssuesOrdering { field: 'CREATED_AT' | 'UPDATED_AT' | 'COMMENTS'; direction?: 'ASC' | 'DESC'; } @@ -97,8 +97,8 @@ export interface IssuesOrdering { * @public */ export interface IssuesByRepoOptions { - filterBy?: IssuesFilters; - orderBy?: IssuesOrdering; + filterBy?: GithubIssuesFilters; + orderBy?: GithubIssuesOrdering; } /** @internal */ @@ -189,7 +189,9 @@ export const gitHubIssuesApi = ( return { fetchIssuesByRepoFromGitHub }; }; -function formatFilterValue(value: IssuesFilters[keyof IssuesFilters]): string { +function formatFilterValue( + value: GithubIssuesFilters[keyof GithubIssuesFilters], +): string { if (Array.isArray(value)) { return `[ ${value.map(formatFilterValue).join(', ')}]`; } @@ -197,7 +199,7 @@ function formatFilterValue(value: IssuesFilters[keyof IssuesFilters]): string { return typeof value === 'string' ? `\"${value}\"` : `${value}`; } -function createFilterByClause(filterBy?: IssuesFilters): string { +function createFilterByClause(filterBy?: GithubIssuesFilters): string { if (!filterBy) { return ''; } diff --git a/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx b/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx index a8a192dece..cb6639c83c 100644 --- a/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx +++ b/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx @@ -24,7 +24,10 @@ import { useGetIssuesByRepoFromGitHub } from '../../hooks/useGetIssuesByRepoFrom import { IssuesList } from './IssuesList'; import { NoRepositoriesInfo } from './NoRepositoriesInfo'; -import type { IssuesFilters, IssuesOrdering } from '../../api/gitHubIssuesApi'; +import type { + GithubIssuesFilters, + GithubIssuesOrdering, +} from '../../api/gitHubIssuesApi'; /** * @public @@ -32,8 +35,8 @@ import type { IssuesFilters, IssuesOrdering } from '../../api/gitHubIssuesApi'; export type GitHubIssuesProps = { itemsPerPage?: number; itemsPerRepo?: number; - filterBy?: IssuesFilters; - orderBy?: IssuesOrdering; + filterBy?: GithubIssuesFilters; + orderBy?: GithubIssuesOrdering; }; export const GitHubIssues = (props: GitHubIssuesProps) => { diff --git a/plugins/github-issues/src/index.ts b/plugins/github-issues/src/index.ts index f17cc1e2e6..e6447a69c7 100644 --- a/plugins/github-issues/src/index.ts +++ b/plugins/github-issues/src/index.ts @@ -21,7 +21,7 @@ export { export type { GitHubIssuesProps } from './components/GitHubIssues'; export type { - IssuesFilters, - IssuesOrdering, + GithubIssuesFilters, + GithubIssuesOrdering, IssuesByRepoOptions, } from './api/gitHubIssuesApi'; From eaafa1cb37e18f9ffe4d94a77a99ec9809b0d9e2 Mon Sep 17 00:00:00 2001 From: Paul Cowan Date: Fri, 7 Oct 2022 13:38:37 +0100 Subject: [PATCH 10/13] run api-reports Signed-off-by: Paul Cowan --- plugins/github-issues/api-report.md | 56 ++++++++++++++--------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/plugins/github-issues/api-report.md b/plugins/github-issues/api-report.md index 0ce8b77975..d319133783 100644 --- a/plugins/github-issues/api-report.md +++ b/plugins/github-issues/api-report.md @@ -11,6 +11,30 @@ import { RouteRef } from '@backstage/core-plugin-api'; // @public (undocumented) export const GitHubIssuesCard: (props: GitHubIssuesProps) => JSX.Element; +// @public (undocumented) +export interface GithubIssuesFilters { + // (undocumented) + assignee?: string; + // (undocumented) + createdBy?: string; + // (undocumented) + labels?: string[]; + // (undocumented) + mentioned?: string; + // (undocumented) + milestone?: string; + // (undocumented) + states?: ('OPEN' | 'CLOSED')[]; +} + +// @public (undocumented) +export interface GithubIssuesOrdering { + // (undocumented) + direction?: 'ASC' | 'DESC'; + // (undocumented) + field: 'CREATED_AT' | 'UPDATED_AT' | 'COMMENTS'; +} + // @public (undocumented) export const GitHubIssuesPage: (props: GitHubIssuesProps) => JSX.Element; @@ -27,40 +51,16 @@ export const gitHubIssuesPlugin: BackstagePlugin< export type GitHubIssuesProps = { itemsPerPage?: number; itemsPerRepo?: number; - filterBy?: IssuesFilters; - orderBy?: IssuesOrdering; + filterBy?: GithubIssuesFilters; + orderBy?: GithubIssuesOrdering; }; // @public (undocumented) export interface IssuesByRepoOptions { // (undocumented) - filterBy?: IssuesFilters; + filterBy?: GithubIssuesFilters; // (undocumented) - orderBy?: IssuesOrdering; -} - -// @public (undocumented) -export interface IssuesFilters { - // (undocumented) - assignee?: string; - // (undocumented) - createdBy?: string; - // (undocumented) - labels?: string[]; - // (undocumented) - mentioned?: string; - // (undocumented) - milestone?: string; - // (undocumented) - states?: ('OPEN' | 'CLOSED')[]; -} - -// @public (undocumented) -export interface IssuesOrdering { - // (undocumented) - direction?: 'ASC' | 'DESC'; - // (undocumented) - field: 'CREATED_AT' | 'UPDATED_AT' | 'COMMENTS'; + orderBy?: GithubIssuesOrdering; } // (No @packageDocumentation comment for this package) From 7a6ba9f4f3331f45e218cffee2edb76c4a49378c Mon Sep 17 00:00:00 2001 From: Paul Cowan Date: Fri, 7 Oct 2022 14:04:29 +0100 Subject: [PATCH 11/13] add tests for filterByClause Signed-off-by: Paul Cowan --- .../src/api/gitHubIssuesApi.test.ts | 27 ++++++++++++++++++- .../github-issues/src/api/gitHubIssuesApi.ts | 14 +++++----- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/plugins/github-issues/src/api/gitHubIssuesApi.test.ts b/plugins/github-issues/src/api/gitHubIssuesApi.test.ts index 070e9ab2f6..b2be54a2d1 100644 --- a/plugins/github-issues/src/api/gitHubIssuesApi.test.ts +++ b/plugins/github-issues/src/api/gitHubIssuesApi.test.ts @@ -20,7 +20,8 @@ jest.mock('octokit', () => ({ import { ConfigApi, ErrorApi } from '@backstage/core-plugin-api'; import { ForwardedError } from '@backstage/errors'; -import { gitHubIssuesApi } from './gitHubIssuesApi'; +import { createFilterByClause, gitHubIssuesApi } from './gitHubIssuesApi'; +import type { GithubIssuesFilters } from './gitHubIssuesApi'; function getFragment( filterBy = '', @@ -141,6 +142,30 @@ describe('gitHubIssuesApi', () => { getFragment(expectedFilterBy, expectedOrderBy), ); }); + + describe('filterBy', () => { + const cases: [GithubIssuesFilters | undefined, string][] = [ + [{}, ''], + [undefined, ''], + [{ states: ['OPEN'] }, 'states: OPEN'], + [ + { labels: ['bug', 'enhancement'], assignee: 'someone' }, + `labels: [ \"bug\", \"enhancement\"], assignee: "someone"`, + ], + [ + { + createdBy: 'someone', + mentioned: 'someone else', + milestone: 'milestone', + }, + `createdBy: \"someone\", mentioned: \"someone else\", milestone: \"milestone\"`, + ], + ]; + + test.each(cases)('filterBy(%s) should be %s', (filterBy, expected) => { + expect(createFilterByClause(filterBy)).toEqual(expected); + }); + }); }); it('should return data for repos with successfully retrieved issues when GitHub returns partial failure', async () => { diff --git a/plugins/github-issues/src/api/gitHubIssuesApi.ts b/plugins/github-issues/src/api/gitHubIssuesApi.ts index d80ec3bce8..12d38ad3c8 100644 --- a/plugins/github-issues/src/api/gitHubIssuesApi.ts +++ b/plugins/github-issues/src/api/gitHubIssuesApi.ts @@ -199,22 +199,20 @@ function formatFilterValue( return typeof value === 'string' ? `\"${value}\"` : `${value}`; } -function createFilterByClause(filterBy?: GithubIssuesFilters): string { +/** @internal */ +export function createFilterByClause(filterBy?: GithubIssuesFilters): string { if (!filterBy) { return ''; } return Object.entries(filterBy) - .flatMap(([field, value]) => { - if (!value) { - return []; - } - + .filter(value => value) + .map(([field, value]) => { if (field === 'states') { - return [`${field}: ${value.join(', ')}`]; + return `${field}: ${value.join(', ')}`; } - return [`${field}: ${formatFilterValue(value)}`]; + return `${field}: ${formatFilterValue(value)}`; }) .join(', '); } From 5fc85ed46133d81c970735db6b377276e174c664 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 7 Oct 2022 14:44:58 +0100 Subject: [PATCH 12/13] Update plugins/github-issues/api-report.md Co-authored-by: Johan Haals Signed-off-by: Paul Signed-off-by: Paul Cowan --- plugins/github-issues/api-report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/github-issues/api-report.md b/plugins/github-issues/api-report.md index d319133783..12b0653acc 100644 --- a/plugins/github-issues/api-report.md +++ b/plugins/github-issues/api-report.md @@ -56,7 +56,7 @@ export type GitHubIssuesProps = { }; // @public (undocumented) -export interface IssuesByRepoOptions { +export interface GithubIssuesByRepoOptions { // (undocumented) filterBy?: GithubIssuesFilters; // (undocumented) From 29de9091cff86638ede92798de61e5db1fc3dce0 Mon Sep 17 00:00:00 2001 From: Paul Cowan Date: Fri, 7 Oct 2022 14:54:21 +0100 Subject: [PATCH 13/13] rename IssuesByRepoOptions to GithubIssuesByRepoOptions Signed-off-by: Paul Cowan --- plugins/github-issues/api-report.md | 2 +- plugins/github-issues/src/api/gitHubIssuesApi.ts | 6 +++--- .../github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts | 4 ++-- plugins/github-issues/src/index.ts | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/plugins/github-issues/api-report.md b/plugins/github-issues/api-report.md index 12b0653acc..41b4f87064 100644 --- a/plugins/github-issues/api-report.md +++ b/plugins/github-issues/api-report.md @@ -56,7 +56,7 @@ export type GitHubIssuesProps = { }; // @public (undocumented) -export interface GithubIssuesByRepoOptions { +export interface GitubIssuesByRepoOptions { // (undocumented) filterBy?: GithubIssuesFilters; // (undocumented) diff --git a/plugins/github-issues/src/api/gitHubIssuesApi.ts b/plugins/github-issues/src/api/gitHubIssuesApi.ts index 12d38ad3c8..b4be445d13 100644 --- a/plugins/github-issues/src/api/gitHubIssuesApi.ts +++ b/plugins/github-issues/src/api/gitHubIssuesApi.ts @@ -96,7 +96,7 @@ export interface GithubIssuesOrdering { /** * @public */ -export interface IssuesByRepoOptions { +export interface GitubIssuesByRepoOptions { filterBy?: GithubIssuesFilters; orderBy?: GithubIssuesOrdering; } @@ -137,7 +137,7 @@ export const gitHubIssuesApi = ( field: 'UPDATED_AT', direction: 'DESC', }, - }: IssuesByRepoOptions = {}, + }: GitubIssuesByRepoOptions = {}, ): Promise => { const graphql = await getOctokit(); const safeNames: Array = []; @@ -224,7 +224,7 @@ function createIssueByRepoQuery( owner: string; }>, itemsPerRepo: number, - { filterBy, orderBy }: IssuesByRepoOptions, + { filterBy, orderBy }: GitubIssuesByRepoOptions, ): string { const fragment = ` fragment issues on Repository { diff --git a/plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts b/plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts index 670cb0596a..693be9e4d9 100644 --- a/plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts +++ b/plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts @@ -16,12 +16,12 @@ import { useApi } from '@backstage/core-plugin-api'; import useAsyncRetry from 'react-use/lib/useAsyncRetry'; -import { gitHubIssuesApiRef, IssuesByRepoOptions } from '../api'; +import { gitHubIssuesApiRef, GitubIssuesByRepoOptions } from '../api'; export const useGetIssuesByRepoFromGitHub = ( repos: Array, itemsPerRepo: number, - options?: IssuesByRepoOptions, + options?: GitubIssuesByRepoOptions, ) => { const gitHubIssuesApi = useApi(gitHubIssuesApiRef); diff --git a/plugins/github-issues/src/index.ts b/plugins/github-issues/src/index.ts index e6447a69c7..7717ba5f33 100644 --- a/plugins/github-issues/src/index.ts +++ b/plugins/github-issues/src/index.ts @@ -23,5 +23,5 @@ export type { GitHubIssuesProps } from './components/GitHubIssues'; export type { GithubIssuesFilters, GithubIssuesOrdering, - IssuesByRepoOptions, + GitubIssuesByRepoOptions, } from './api/gitHubIssuesApi';