From 1de2669c91a1203b415faf13d92f5b887cc73245 Mon Sep 17 00:00:00 2001 From: Jamie Klassen Date: Wed, 20 Jul 2022 15:54:02 -0400 Subject: [PATCH 001/144] refactor tests to give clearer feedback Instead of comments in the table test, use the features of jest that allow each test to give a specific error message. This change also reduces the total number of tests, but coverage should remain the same branch-wise. Signed-off-by: Jamie Klassen --- packages/integration/src/gitlab/core.test.ts | 297 +++++++++---------- 1 file changed, 134 insertions(+), 163 deletions(-) diff --git a/packages/integration/src/gitlab/core.test.ts b/packages/integration/src/gitlab/core.test.ts index d043aba55a..b87c5c3af8 100644 --- a/packages/integration/src/gitlab/core.test.ts +++ b/packages/integration/src/gitlab/core.test.ts @@ -34,13 +34,6 @@ describe('gitlab core', () => { ); }); - const configWithToken: GitLabIntegrationConfig = { - host: 'gitlab.com', - token: '0123456789', - apiBaseUrl: '', - baseUrl: '', - }; - const configWithNoToken: GitLabIntegrationConfig = { host: 'gitlab.com', apiBaseUrl: '', @@ -61,163 +54,141 @@ describe('gitlab core', () => { baseUrl: 'https://gitlab.mycompany.com', }; - describe('getGitLabFileFetchUrl with .yaml extension', () => { - it.each([ - // Project URLs - { - config: configWithNoToken, - url: 'https://gitlab.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file.yaml', - result: - 'https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yaml/raw?ref=branch', - }, - { - config: configSelfHosteWithRelativePath, - url: 'https://gitlab.mycompany.com/gitlab/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file.yaml', - result: - 'https://gitlab.mycompany.com/gitlab/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yaml/raw?ref=branch', - }, - { - config: configSelfHostedWithoutRelativePath, - url: 'https://gitlab.mycompany.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file.yaml', - result: - 'https://gitlab.mycompany.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yaml/raw?ref=branch', - }, - { - config: configWithNoToken, - // Works with non URI encoded link - url: 'https://gitlab.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file with spaces.yaml', - result: - 'https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile%20with%20spaces.yaml/raw?ref=branch', - }, - { - config: configSelfHosteWithRelativePath, - url: 'https://gitlab.mycompany.com/gitlab/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file with spaces.yaml', - result: - 'https://gitlab.mycompany.com/gitlab/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile%20with%20spaces.yaml/raw?ref=branch', - }, - { - config: configSelfHostedWithoutRelativePath, - url: 'https://gitlab.mycompany.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file with spaces.yaml', - result: - 'https://gitlab.mycompany.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile%20with%20spaces.yaml/raw?ref=branch', - }, - { - config: configWithNoToken, - url: 'https://gitlab.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path%20with%20spaces/to/file.yaml', - result: - 'https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%20with%20spaces%2Fto%2Ffile.yaml/raw?ref=branch', - }, - { - config: configWithToken, - url: 'https://gitlab.example.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path%20with%20spaces/to/file.yaml', - result: - 'https://gitlab.example.com/api/v4/projects/12345/repository/files/my%2Fpath%20with%20spaces%2Fto%2Ffile.yaml/raw?ref=branch', - }, - { - config: configWithNoToken, - url: 'https://gitlab.com/groupA/teams/teamA/repoA/-/blob/branch/my/path%20with%20spaces/to/file.yaml', // Repo not in subgroup - result: - 'https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%20with%20spaces%2Fto%2Ffile.yaml/raw?ref=branch', - }, - // Raw URLs - { - config: configWithNoToken, - url: 'https://gitlab.example.com/a/b/blob/master/c.yaml', - result: 'https://gitlab.example.com/a/b/raw/master/c.yaml', - }, - { - config: configWithNoToken, - url: 'https://gitlab.example.com/a/b/repo/blob/master/c.yaml', - result: 'https://gitlab.example.com/a/b/repo/raw/master/c.yaml', - }, - { - config: configWithNoToken, - url: 'https://gitlab.example.com/a/blob/blob/master/c.yaml', - result: 'https://gitlab.example.com/a/blob/raw/master/c.yaml', - }, - { - config: configWithNoToken, - url: 'https://gitlab.example.com/a/b/blob/blob/c.yaml', - result: 'https://gitlab.example.com/a/b/raw/blob/c.yaml', - }, - { - config: configWithNoToken, - url: 'https://gitlab.example.com/a//blob/blob/c.yaml', - result: 'https://gitlab.example.com/a/blob/raw/c.yaml', - }, - ])('should handle happy path %#', async ({ config, url, result }) => { - await expect(getGitLabFileFetchUrl(url, config)).resolves.toBe(result); - }); - }); + describe('getGitLabFileFetchUrl', () => { + describe('when target has a scoped route', () => { + it('returns a projects API URL', async () => { + const target = + 'https://gitlab.com/group/project/-/blob/branch/folder/file.yaml'; + const fetchUrl = + 'https://gitlab.com/api/v4/projects/12345/repository/files/folder%2Ffile.yaml/raw?ref=branch'; + await expect( + getGitLabFileFetchUrl(target, configWithNoToken), + ).resolves.toBe(fetchUrl); + }); - describe('getGitLabFileFetchUrl with .yml extension', () => { - it.each([ - // Project URLs - { - config: configWithNoToken, - url: 'https://gitlab.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file.yml', - result: - 'https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yml/raw?ref=branch', - }, - { - config: configSelfHosteWithRelativePath, - url: 'https://gitlab.mycompany.com/gitlab/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file.yml', - result: - 'https://gitlab.mycompany.com/gitlab/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yml/raw?ref=branch', - }, - { - config: configSelfHostedWithoutRelativePath, - url: 'https://gitlab.mycompany.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file.yml', - result: - 'https://gitlab.mycompany.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yml/raw?ref=branch', - }, - { - config: configWithNoToken, - // Works with non URI encoded link - url: 'https://gitlab.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file with spaces.yml', - result: - 'https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile%20with%20spaces.yml/raw?ref=branch', - }, - { - config: configSelfHosteWithRelativePath, - // Works with non URI encoded link - url: 'https://gitlab.mycompany.com/gitlab/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file with spaces.yml', - result: - 'https://gitlab.mycompany.com/gitlab/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile%20with%20spaces.yml/raw?ref=branch', - }, - { - config: configSelfHostedWithoutRelativePath, - // Works with non URI encoded link - url: 'https://gitlab.mycompany.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file with spaces.yml', - result: - 'https://gitlab.mycompany.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile%20with%20spaces.yml/raw?ref=branch', - }, - { - config: configWithNoToken, - url: 'https://gitlab.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path%20with%20spaces/to/file.yml', - result: - 'https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%20with%20spaces%2Fto%2Ffile.yml/raw?ref=branch', - }, - { - config: configWithToken, - url: 'https://gitlab.example.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path%20with%20spaces/to/file.yml', - result: - 'https://gitlab.example.com/api/v4/projects/12345/repository/files/my%2Fpath%20with%20spaces%2Fto%2Ffile.yml/raw?ref=branch', - }, - { - config: configWithNoToken, - url: 'https://gitlab.com/groupA/teams/teamA/repoA/-/blob/branch/my/path%20with%20spaces/to/file.yml', // Repo not in subgroup - result: - 'https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%20with%20spaces%2Fto%2Ffile.yml/raw?ref=branch', - }, - // Raw URLs - { - config: configWithNoToken, - url: 'https://gitlab.example.com/a/b/blob/master/c.yml', - result: 'https://gitlab.example.com/a/b/raw/master/c.yml', - }, - ])('should handle happy path %#', async ({ config, url, result }) => { - await expect(getGitLabFileFetchUrl(url, config)).resolves.toBe(result); + it('locates projects in subgroups', async () => { + const target = + 'https://gitlab.com/group/subgroup/project/-/blob/branch/folder/file.yaml'; + const fetchUrl = + 'https://gitlab.com/api/v4/projects/12345/repository/files/folder%2Ffile.yaml/raw?ref=branch'; + await expect( + getGitLabFileFetchUrl(target, configWithNoToken), + ).resolves.toBe(fetchUrl); + }); + + it('supports filename with .yml extension', async () => { + const target = + 'https://gitlab.com/group/project/-/blob/branch/folder/file.yml'; + const fetchUrl = + 'https://gitlab.com/api/v4/projects/12345/repository/files/folder%2Ffile.yml/raw?ref=branch'; + await expect( + getGitLabFileFetchUrl(target, configWithNoToken), + ).resolves.toBe(fetchUrl); + }); + + it('supports non-URI-encoded target', async () => { + const target = + 'https://gitlab.com/group/project/-/blob/branch/folder/file with spaces.yaml'; + const fetchUrl = + 'https://gitlab.com/api/v4/projects/12345/repository/files/folder%2Ffile%20with%20spaces.yaml/raw?ref=branch'; + await expect( + getGitLabFileFetchUrl(target, configWithNoToken), + ).resolves.toBe(fetchUrl); + }); + + describe('when gitlab is self-hosted', () => { + it('returns projects API URL', async () => { + const target = + 'https://gitlab.mycompany.com/group/project/-/blob/branch/folder/file.yaml'; + const fetchUrl = + 'https://gitlab.mycompany.com/api/v4/projects/12345/repository/files/folder%2Ffile.yaml/raw?ref=branch'; + await expect( + getGitLabFileFetchUrl(target, configSelfHostedWithoutRelativePath), + ).resolves.toBe(fetchUrl); + }); + + it('handles non-URI-encoded target', async () => { + const target = + 'https://gitlab.mycompany.com/group/project/-/blob/branch/folder/file with spaces.yaml'; + const fetchUrl = + 'https://gitlab.mycompany.com/api/v4/projects/12345/repository/files/folder%2Ffile%20with%20spaces.yaml/raw?ref=branch'; + await expect( + getGitLabFileFetchUrl(target, configSelfHostedWithoutRelativePath), + ).resolves.toBe(fetchUrl); + }); + + describe('with a relative path', () => { + it('returns projects API URL', async () => { + const target = + 'https://gitlab.mycompany.com/gitlab/group/project/-/blob/branch/folder/file.yaml'; + const fetchUrl = + 'https://gitlab.mycompany.com/gitlab/api/v4/projects/12345/repository/files/folder%2Ffile.yaml/raw?ref=branch'; + await expect( + getGitLabFileFetchUrl(target, configSelfHosteWithRelativePath), + ).resolves.toBe(fetchUrl); + }); + + it('handles non-URI-encoded target', async () => { + const target = + 'https://gitlab.mycompany.com/gitlab/group/project/-/blob/branch/folder/file with spaces.yaml'; + const fetchUrl = + 'https://gitlab.mycompany.com/gitlab/api/v4/projects/12345/repository/files/folder%2Ffile%20with%20spaces.yaml/raw?ref=branch'; + await expect( + getGitLabFileFetchUrl(target, configSelfHosteWithRelativePath), + ).resolves.toBe(fetchUrl); + }); + }); + }); + }); + + describe('when target has an unscoped route', () => { + it('returns a raw URL', async () => { + const target = + 'https://gitlab.com/group/project/blob/branch/folder/file.yaml'; + const fetchUrl = + 'https://gitlab.com/group/project/raw/branch/folder/file.yaml'; + await expect( + getGitLabFileFetchUrl(target, configWithNoToken), + ).resolves.toBe(fetchUrl); + }); + + it('supports project in subgroup', async () => { + const target = + 'https://gitlab.com/group/subgroup/project/blob/branch/folder/file.yaml'; + const fetchUrl = + 'https://gitlab.com/group/subgroup/project/raw/branch/folder/file.yaml'; + await expect( + getGitLabFileFetchUrl(target, configWithNoToken), + ).resolves.toBe(fetchUrl); + }); + + it('supports project named "blob"', async () => { + const target = + 'https://gitlab.com/group/blob/blob/branch/folder/file.yaml'; + const fetchUrl = + 'https://gitlab.com/group/blob/raw/branch/folder/file.yaml'; + await expect( + getGitLabFileFetchUrl(target, configWithNoToken), + ).resolves.toBe(fetchUrl); + }); + + it('supports repo with branch named "blob"', async () => { + const target = + 'https://gitlab.com/group/project/blob/blob/folder/file.yaml'; + const fetchUrl = + 'https://gitlab.com/group/project/raw/blob/folder/file.yaml'; + await expect( + getGitLabFileFetchUrl(target, configWithNoToken), + ).resolves.toBe(fetchUrl); + }); + + it('removes empty path segment', async () => { + const target = 'https://gitlab.example.com/group//blob/blob/file.yaml'; + const fetchUrl = 'https://gitlab.example.com/group/blob/raw/file.yaml'; + await expect( + getGitLabFileFetchUrl(target, configWithNoToken), + ).resolves.toBe(fetchUrl); + }); }); }); }); From 56a8ff12fd1858c5922e81c8fef1a83e5468ed9b Mon Sep 17 00:00:00 2001 From: Jamie Klassen Date: Thu, 21 Jul 2022 10:53:32 -0400 Subject: [PATCH 002/144] fake gitlab API more precisely This allows this suite to detect when an unexpected path is passed to the projects API. Signed-off-by: Jamie Klassen --- packages/integration/src/gitlab/core.test.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/integration/src/gitlab/core.test.ts b/packages/integration/src/gitlab/core.test.ts index b87c5c3af8..de785fb41d 100644 --- a/packages/integration/src/gitlab/core.test.ts +++ b/packages/integration/src/gitlab/core.test.ts @@ -28,7 +28,10 @@ describe('gitlab core', () => { beforeEach(() => { worker.use( - rest.get('*/api/v4/projects/:name', (_, res, ctx) => + rest.get('*/api/v4/projects/group%2Fproject', (_, res, ctx) => + res(ctx.status(200), ctx.json({ id: 12345 })), + ), + rest.get('*/api/v4/projects/group%2Fsubgroup%2Fproject', (_, res, ctx) => res(ctx.status(200), ctx.json({ id: 12345 })), ), ); From 3a2254185e3929cf7c95c4a4c5455dd3a10f792e Mon Sep 17 00:00:00 2001 From: Jamie Klassen Date: Thu, 21 Jul 2022 11:16:28 -0400 Subject: [PATCH 003/144] add coverage for "blob" folder edge case Signed-off-by: Jamie Klassen --- packages/integration/src/gitlab/core.test.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/integration/src/gitlab/core.test.ts b/packages/integration/src/gitlab/core.test.ts index de785fb41d..0dae905ce4 100644 --- a/packages/integration/src/gitlab/core.test.ts +++ b/packages/integration/src/gitlab/core.test.ts @@ -69,6 +69,16 @@ describe('gitlab core', () => { ).resolves.toBe(fetchUrl); }); + it('supports folder named "blob"', async () => { + const target = + 'https://gitlab.com/group/project/-/blob/branch/blob/file.yaml'; + const fetchUrl = + 'https://gitlab.com/api/v4/projects/12345/repository/files/blob%2Ffile.yaml/raw?ref=branch'; + await expect( + getGitLabFileFetchUrl(target, configWithNoToken), + ).resolves.toBe(fetchUrl); + }); + it('locates projects in subgroups', async () => { const target = 'https://gitlab.com/group/subgroup/project/-/blob/branch/folder/file.yaml'; From 1e1e436e868ddb776e5168520ef81b1382d3c3ab Mon Sep 17 00:00:00 2001 From: Jamie Klassen Date: Thu, 21 Jul 2022 11:55:27 -0400 Subject: [PATCH 004/144] Look up project IDs for unscoped routes Signed-off-by: Jamie Klassen --- .../src/reading/GitlabUrlReader.test.ts | 6 +- packages/integration/src/gitlab/core.test.ts | 26 ++------- packages/integration/src/gitlab/core.ts | 55 +++---------------- 3 files changed, 16 insertions(+), 71 deletions(-) diff --git a/packages/backend-common/src/reading/GitlabUrlReader.test.ts b/packages/backend-common/src/reading/GitlabUrlReader.test.ts index f422820a29..29ef3f4ce8 100644 --- a/packages/backend-common/src/reading/GitlabUrlReader.test.ts +++ b/packages/backend-common/src/reading/GitlabUrlReader.test.ts @@ -106,7 +106,7 @@ describe('GitlabUrlReader', () => { ); it.each([ - // Project URLs + // Scoped routes { url: 'https://gitlab.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file.yaml', config: createConfig(), @@ -135,12 +135,12 @@ describe('GitlabUrlReader', () => { }), }, - // Raw URLs + // Unscoped route { url: 'https://gitlab.example.com/a/b/blob/master/c.yaml', config: createConfig(), response: expect.objectContaining({ - url: 'https://gitlab.example.com/a/b/raw/master/c.yaml', + url: 'https://gitlab.example.com/api/v4/projects/12345/repository/files/c.yaml/raw?ref=master', }), }, ])('should handle happy path %#', async ({ url, config, response }) => { diff --git a/packages/integration/src/gitlab/core.test.ts b/packages/integration/src/gitlab/core.test.ts index 0dae905ce4..98fd9b7c13 100644 --- a/packages/integration/src/gitlab/core.test.ts +++ b/packages/integration/src/gitlab/core.test.ts @@ -155,11 +155,11 @@ describe('gitlab core', () => { }); describe('when target has an unscoped route', () => { - it('returns a raw URL', async () => { + it('returns projects API URL', async () => { const target = 'https://gitlab.com/group/project/blob/branch/folder/file.yaml'; const fetchUrl = - 'https://gitlab.com/group/project/raw/branch/folder/file.yaml'; + 'https://gitlab.com/api/v4/projects/12345/repository/files/folder%2Ffile.yaml/raw?ref=branch'; await expect( getGitLabFileFetchUrl(target, configWithNoToken), ).resolves.toBe(fetchUrl); @@ -169,17 +169,7 @@ describe('gitlab core', () => { const target = 'https://gitlab.com/group/subgroup/project/blob/branch/folder/file.yaml'; const fetchUrl = - 'https://gitlab.com/group/subgroup/project/raw/branch/folder/file.yaml'; - await expect( - getGitLabFileFetchUrl(target, configWithNoToken), - ).resolves.toBe(fetchUrl); - }); - - it('supports project named "blob"', async () => { - const target = - 'https://gitlab.com/group/blob/blob/branch/folder/file.yaml'; - const fetchUrl = - 'https://gitlab.com/group/blob/raw/branch/folder/file.yaml'; + 'https://gitlab.com/api/v4/projects/12345/repository/files/folder%2Ffile.yaml/raw?ref=branch'; await expect( getGitLabFileFetchUrl(target, configWithNoToken), ).resolves.toBe(fetchUrl); @@ -189,15 +179,7 @@ describe('gitlab core', () => { const target = 'https://gitlab.com/group/project/blob/blob/folder/file.yaml'; const fetchUrl = - 'https://gitlab.com/group/project/raw/blob/folder/file.yaml'; - await expect( - getGitLabFileFetchUrl(target, configWithNoToken), - ).resolves.toBe(fetchUrl); - }); - - it('removes empty path segment', async () => { - const target = 'https://gitlab.example.com/group//blob/blob/file.yaml'; - const fetchUrl = 'https://gitlab.example.com/group/blob/raw/file.yaml'; + 'https://gitlab.com/api/v4/projects/12345/repository/files/folder%2Ffile.yaml/raw?ref=blob'; await expect( getGitLabFileFetchUrl(target, configWithNoToken), ).resolves.toBe(fetchUrl); diff --git a/packages/integration/src/gitlab/core.ts b/packages/integration/src/gitlab/core.ts index 1fcf15a78f..040ca202d6 100644 --- a/packages/integration/src/gitlab/core.ts +++ b/packages/integration/src/gitlab/core.ts @@ -19,7 +19,6 @@ import { GitLabIntegrationConfig, } from './config'; import fetch from 'cross-fetch'; -import { InputError } from '@backstage/errors'; /** * Given a URL pointing to a file on a provider, returns a URL that is suitable @@ -29,7 +28,7 @@ import { InputError } from '@backstage/errors'; * * Converts * from: https://gitlab.example.com/a/b/blob/master/c.yaml - * to: https://gitlab.example.com/a/b/raw/master/c.yaml + * to: https://gitlab.com/api/v4/projects/projectId/repository/c.yaml?ref=master * -or- * from: https://gitlab.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/filepath * to: https://gitlab.com/api/v4/projects/projectId/repository/files/filepath?ref=branch @@ -42,15 +41,8 @@ export async function getGitLabFileFetchUrl( url: string, config: GitLabIntegrationConfig, ): Promise { - // TODO(Rugvip): From the old GitlabReaderProcessor; used - // the existence of /-/blob/ to switch the logic. Don't know if this - // makes sense and it might require some more work. - - if (url.includes('/-/blob/')) { - const projectID = await getProjectId(url, config); - return buildProjectUrl(url, projectID, config).toString(); - } - return buildRawUrl(url).toString(); + const projectID = await getProjectId(url, config); + return buildProjectUrl(url, projectID, config).toString(); } /** @@ -70,38 +62,6 @@ export function getGitLabRequestOptions(config: GitLabIntegrationConfig): { }; } -// Converts -// from: https://gitlab.example.com/groupA/teams/repoA/blob/master/c.yaml -// to: https://gitlab.example.com/groupA/teams/repoA/raw/master/c.yaml -export function buildRawUrl(target: string): URL { - try { - const url = new URL(target); - - const splitPath = url.pathname.split('/').filter(Boolean); - - // Check blob existence - const blobIndex = splitPath.indexOf('blob', 2); - if (blobIndex < 2 || blobIndex === splitPath.length - 1) { - throw new InputError('Wrong GitLab URL'); - } - - // Take repo path - const repoPath = splitPath.slice(0, blobIndex); - const restOfPath = splitPath.slice(blobIndex + 1); - - if (!restOfPath.join('/').match(/\.(yaml|yml)$/)) { - throw new InputError('Wrong GitLab URL'); - } - - // Replace 'blob' with 'raw' - url.pathname = [...repoPath, 'raw', ...restOfPath].join('/'); - - return url; - } catch (e) { - throw new InputError(`Incorrect url: ${target}, ${e}`); - } -} - // Converts // from: https://gitlab.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/filepath // to: https://gitlab.com/api/v4/projects/projectId/repository/files/filepath?ref=branch @@ -113,7 +73,10 @@ export function buildProjectUrl( try { const url = new URL(target); - const branchAndFilePath = url.pathname.split('/-/blob/')[1]; + const branchAndFilePath = url.pathname + .split('/blob/') + .slice(1) + .join('/blob/'); const [branch, ...filePath] = branchAndFilePath.split('/'); const relativePath = getGitLabIntegrationRelativePath(config); @@ -143,12 +106,12 @@ export async function getProjectId( ): Promise { const url = new URL(target); - if (!url.pathname.includes('/-/blob/')) { + if (!url.pathname.includes('/blob/')) { throw new Error('Please provide full path to yaml file from GitLab'); } try { - let repo = url.pathname.split('/-/blob/')[0]; + let repo = url.pathname.split('/-/blob/')[0].split('/blob/')[0]; // Get gitlab relative path const relativePath = getGitLabIntegrationRelativePath(config); From 1f27d839339a44afd6159023cb177ac55619c493 Mon Sep 17 00:00:00 2001 From: Jamie Klassen Date: Thu, 21 Jul 2022 14:43:10 -0400 Subject: [PATCH 005/144] Add changeset Signed-off-by: Jamie Klassen --- .changeset/rotten-moles-give.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/rotten-moles-give.md diff --git a/.changeset/rotten-moles-give.md b/.changeset/rotten-moles-give.md new file mode 100644 index 0000000000..0ca3d3eadc --- /dev/null +++ b/.changeset/rotten-moles-give.md @@ -0,0 +1,7 @@ +--- +'@backstage/integration': patch +--- + +Fixed bug in getGitLabFileFetchUrl where a target whose path did not contain the +`/-/` scope would result in a fetch URL that did not support +private-token-based authentication. From 0be9fb918a4c3fb7eb8e7074ebcd4a1f4c71a440 Mon Sep 17 00:00:00 2001 From: Neemys <36508659+Neemys@users.noreply.github.com> Date: Wed, 8 Jun 2022 13:48:40 +0200 Subject: [PATCH 006/144] create pull request Signed-off-by: Neemys <36508659+Neemys@users.noreply.github.com> From 4d64f22c9d6727f8fd03007e9535dfb28bae1a21 Mon Sep 17 00:00:00 2001 From: Neemys <36508659+Neemys@users.noreply.github.com> Date: Mon, 13 Jun 2022 15:37:30 +0200 Subject: [PATCH 007/144] Add new backend bare plugin intended for sonarqube Signed-off-by: Neemys <36508659+Neemys@users.noreply.github.com> --- plugins/sonarqube-backend/.eslintrc.js | 1 + plugins/sonarqube-backend/README.md | 13 +++++ plugins/sonarqube-backend/package.json | 44 ++++++++++++++++ plugins/sonarqube-backend/src/index.ts | 17 +++++++ plugins/sonarqube-backend/src/run.ts | 33 ++++++++++++ .../src/service/router.test.ts | 45 +++++++++++++++++ .../sonarqube-backend/src/service/router.ts | 40 +++++++++++++++ .../src/service/standaloneServer.ts | 50 +++++++++++++++++++ plugins/sonarqube-backend/src/setupTests.ts | 17 +++++++ 9 files changed, 260 insertions(+) create mode 100644 plugins/sonarqube-backend/.eslintrc.js create mode 100644 plugins/sonarqube-backend/README.md create mode 100644 plugins/sonarqube-backend/package.json create mode 100644 plugins/sonarqube-backend/src/index.ts create mode 100644 plugins/sonarqube-backend/src/run.ts create mode 100644 plugins/sonarqube-backend/src/service/router.test.ts create mode 100644 plugins/sonarqube-backend/src/service/router.ts create mode 100644 plugins/sonarqube-backend/src/service/standaloneServer.ts create mode 100644 plugins/sonarqube-backend/src/setupTests.ts diff --git a/plugins/sonarqube-backend/.eslintrc.js b/plugins/sonarqube-backend/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/sonarqube-backend/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/sonarqube-backend/README.md b/plugins/sonarqube-backend/README.md new file mode 100644 index 0000000000..0fad3b67f3 --- /dev/null +++ b/plugins/sonarqube-backend/README.md @@ -0,0 +1,13 @@ +# sonarqube-backend + +Welcome to the sonarqube-backend backend plugin! + +_This plugin was created through the Backstage CLI_ + +## Getting started + +Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn start` in the root directory, and then navigating to [/sonarqube-backend](http://localhost:3000/sonarqube-backend). + +You can also serve the plugin in isolation by running `yarn start` in the plugin directory. +This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads. +It is only meant for local development, and the setup for it can be found inside the [/dev](/dev) directory. diff --git a/plugins/sonarqube-backend/package.json b/plugins/sonarqube-backend/package.json new file mode 100644 index 0000000000..ca2b98c10e --- /dev/null +++ b/plugins/sonarqube-backend/package.json @@ -0,0 +1,44 @@ +{ + "name": "plugin-sonarqube-backend", + "version": "0.0.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "private": true, + "publishConfig": { + "access": "public", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "backend-plugin" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/backend-common": "^0.13.6-next.1", + "@backstage/config": "^1.0.1", + "@types/express": "*", + "express": "^4.17.1", + "express-promise-router": "^4.1.0", + "winston": "^3.2.1", + "node-fetch": "^2.6.7", + "yn": "^4.0.0" + }, + "devDependencies": { + "@backstage/cli": "^0.17.2-next.1", + "@types/supertest": "^2.0.8", + "supertest": "^4.0.2", + "msw": "^0.42.0" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/sonarqube-backend/src/index.ts b/plugins/sonarqube-backend/src/index.ts new file mode 100644 index 0000000000..ca73cb27ba --- /dev/null +++ b/plugins/sonarqube-backend/src/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 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 './service/router'; diff --git a/plugins/sonarqube-backend/src/run.ts b/plugins/sonarqube-backend/src/run.ts new file mode 100644 index 0000000000..0a3ed2b7f0 --- /dev/null +++ b/plugins/sonarqube-backend/src/run.ts @@ -0,0 +1,33 @@ +/* + * Copyright 2020 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 { getRootLogger } from '@backstage/backend-common'; +import yn from 'yn'; +import { startStandaloneServer } from './service/standaloneServer'; + +const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 7007; +const enableCors = yn(process.env.PLUGIN_CORS, { default: false }); +const logger = getRootLogger(); + +startStandaloneServer({ port, enableCors, logger }).catch(err => { + logger.error(err); + process.exit(1); +}); + +process.on('SIGINT', () => { + logger.info('CTRL+C pressed; exiting.'); + process.exit(0); +}); diff --git a/plugins/sonarqube-backend/src/service/router.test.ts b/plugins/sonarqube-backend/src/service/router.test.ts new file mode 100644 index 0000000000..8b77a04348 --- /dev/null +++ b/plugins/sonarqube-backend/src/service/router.test.ts @@ -0,0 +1,45 @@ +/* + * Copyright 2020 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 { getVoidLogger } from '@backstage/backend-common'; +import express from 'express'; +import request from 'supertest'; + +import { createRouter } from './router'; + +describe('createRouter', () => { + let app: express.Express; + + beforeAll(async () => { + const router = await createRouter({ + logger: getVoidLogger(), + }); + app = express().use(router); + }); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + describe('GET /health', () => { + it('returns ok', async () => { + const response = await request(app).get('/health'); + + expect(response.status).toEqual(200); + expect(response.body).toEqual({ status: 'ok' }); + }); + }); +}); diff --git a/plugins/sonarqube-backend/src/service/router.ts b/plugins/sonarqube-backend/src/service/router.ts new file mode 100644 index 0000000000..9ceaa47627 --- /dev/null +++ b/plugins/sonarqube-backend/src/service/router.ts @@ -0,0 +1,40 @@ +/* + * Copyright 2020 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 { errorHandler } from '@backstage/backend-common'; +import express from 'express'; +import Router from 'express-promise-router'; +import { Logger } from 'winston'; + +export interface RouterOptions { + logger: Logger; +} + +export async function createRouter( + options: RouterOptions, +): Promise { + const { logger } = options; + + const router = Router(); + router.use(express.json()); + + router.get('/health', (_, response) => { + logger.info('PONG!'); + response.send({ status: 'ok' }); + }); + router.use(errorHandler()); + return router; +} diff --git a/plugins/sonarqube-backend/src/service/standaloneServer.ts b/plugins/sonarqube-backend/src/service/standaloneServer.ts new file mode 100644 index 0000000000..78f39b2680 --- /dev/null +++ b/plugins/sonarqube-backend/src/service/standaloneServer.ts @@ -0,0 +1,50 @@ +/* + * Copyright 2020 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 { createServiceBuilder } from '@backstage/backend-common'; +import { Server } from 'http'; +import { Logger } from 'winston'; +import { createRouter } from './router'; + +export interface ServerOptions { + port: number; + enableCors: boolean; + logger: Logger; +} + +export async function startStandaloneServer( + options: ServerOptions, +): Promise { + const logger = options.logger.child({ service: 'sonarqube-backend-backend' }); + logger.debug('Starting application server...'); + const router = await createRouter({ + logger, + }); + + let service = createServiceBuilder(module) + .setPort(options.port) + .addRouter('/sonarqube-backend', router); + if (options.enableCors) { + service = service.enableCors({ origin: 'http://localhost:3000' }); + } + + return await service.start().catch(err => { + logger.error(err); + process.exit(1); + }); +} + +module.hot?.accept(); diff --git a/plugins/sonarqube-backend/src/setupTests.ts b/plugins/sonarqube-backend/src/setupTests.ts new file mode 100644 index 0000000000..d3232290a7 --- /dev/null +++ b/plugins/sonarqube-backend/src/setupTests.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 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 619b5151721ad879cb608efef861f65f76644d3f Mon Sep 17 00:00:00 2001 From: Neemys <36508659+Neemys@users.noreply.github.com> Date: Thu, 16 Jun 2022 17:50:24 +0200 Subject: [PATCH 008/144] Modify sonarqube frontend plugin to call the new sonarqube backend backend only have mock API for now Signed-off-by: Neemys <36508659+Neemys@users.noreply.github.com> --- .changeset/forty-lobsters-guess.md | 9 ++ .../src/service/router.test.ts | 12 +- .../sonarqube-backend/src/service/router.ts | 11 +- .../sonarqube/src/api/SonarQubeClient.test.ts | 138 +++--------------- plugins/sonarqube/src/api/SonarQubeClient.ts | 55 ++----- plugins/sonarqube/src/api/types.ts | 10 +- 6 files changed, 57 insertions(+), 178 deletions(-) create mode 100644 .changeset/forty-lobsters-guess.md diff --git a/.changeset/forty-lobsters-guess.md b/.changeset/forty-lobsters-guess.md new file mode 100644 index 0000000000..50dd22627f --- /dev/null +++ b/.changeset/forty-lobsters-guess.md @@ -0,0 +1,9 @@ +--- +'@backstage/plugin-sonarqube': minor +--- + +**BREAKING** This plugin now call the sonarqube-backend plugin instead of relying on the proxy plugin + +The whole proxy's `'/sonarqube':` key can be removed from your configuration files. + +Then head to the sonarqube-backend plugin page to learn how to set-up the link to your sonarqube instances. diff --git a/plugins/sonarqube-backend/src/service/router.test.ts b/plugins/sonarqube-backend/src/service/router.test.ts index 8b77a04348..24e482896b 100644 --- a/plugins/sonarqube-backend/src/service/router.test.ts +++ b/plugins/sonarqube-backend/src/service/router.test.ts @@ -34,12 +34,18 @@ describe('createRouter', () => { jest.resetAllMocks(); }); - describe('GET /health', () => { + describe('GET /findings', () => { it('returns ok', async () => { - const response = await request(app).get('/health'); + const response = await request(app) + .get('/findings') + .set('componentKey', 'my:app') + .send(); expect(response.status).toEqual(200); - expect(response.body).toEqual({ status: 'ok' }); + expect(response.body).toEqual({ + analysisDate: '2022-10-22T04:55:23Z', + measures: [{ metric: 'coverage', value: '50' }], + }); }); }); }); diff --git a/plugins/sonarqube-backend/src/service/router.ts b/plugins/sonarqube-backend/src/service/router.ts index 9ceaa47627..9d13104d82 100644 --- a/plugins/sonarqube-backend/src/service/router.ts +++ b/plugins/sonarqube-backend/src/service/router.ts @@ -30,10 +30,13 @@ export async function createRouter( const router = Router(); router.use(express.json()); - - router.get('/health', (_, response) => { - logger.info('PONG!'); - response.send({ status: 'ok' }); + // mock api for now + router.get('/findings', (request, response) => { + logger.info(request.params); + response.send({ + analysisDate: '2022-10-22T04:55:23Z', + measures: [{ metric: 'coverage', value: '50' }], + }); }); router.use(errorHandler()); return router; diff --git a/plugins/sonarqube/src/api/SonarQubeClient.test.ts b/plugins/sonarqube/src/api/SonarQubeClient.test.ts index b592953434..1727e73e93 100644 --- a/plugins/sonarqube/src/api/SonarQubeClient.test.ts +++ b/plugins/sonarqube/src/api/SonarQubeClient.test.ts @@ -18,7 +18,7 @@ import { setupRequestMockHandlers } from '@backstage/test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { FindingSummary, SonarQubeClient } from './index'; -import { ComponentWrapper, MeasuresWrapper } from './types'; +import { FindingsWrapper } from './types'; import { UrlPatternDiscovery } from '@backstage/core-app-api'; import { IdentityApi } from '@backstage/core-plugin-api'; @@ -40,133 +40,66 @@ const identityApiGuest: IdentityApi = { describe('SonarQubeClient', () => { setupRequestMockHandlers(server); - const mockBaseUrl = 'http://backstage:9191/api/proxy'; + const mockBaseUrl = 'http://backstage:9191/api/sonarqube'; const discoveryApi = UrlPatternDiscovery.compile(mockBaseUrl); - const setupHandlers = ( - metricKeys = [ - 'alert_status', - 'bugs', - 'reliability_rating', - 'vulnerabilities', - 'security_rating', - 'security_hotspots_reviewed', - 'security_review_rating', - 'code_smells', - 'sqale_rating', - 'coverage', - 'duplicated_lines_density', - ], - ) => { + const setupHandlers = () => { server.use( - rest.get(`${mockBaseUrl}/sonarqube/metrics/search`, (req, res, ctx) => { - expect(req.url.searchParams.get('ps')).toBe('500'); - - // emulate paging to check if everything is requested - if (req.url.searchParams.get('p') === '1') { - return res( - ctx.json({ - metrics: metricKeys.slice(0, 5).map(k => ({ key: k })), - total: metricKeys.length, - }), - ); - } - - // make sure this is only called twice - expect(req.url.searchParams.get('p')).toBe('2'); - return res( - ctx.json({ - metrics: metricKeys.slice(5).map(k => ({ key: k })), - total: metricKeys.length, - }), - ); - }), - ); - - server.use( - rest.get(`${mockBaseUrl}/sonarqube/components/show`, (req, res, ctx) => { - expect(req.url.searchParams.toString()).toBe('component=our%3Aservice'); - return res( - ctx.json({ - component: { - analysisDate: '2020-01-01T00:00:00Z', - }, - } as ComponentWrapper), - ); - }), - ); - - server.use( - rest.get(`${mockBaseUrl}/sonarqube/measures/search`, (req, res, ctx) => { + rest.get(`${mockBaseUrl}/findings`, (req, res, ctx) => { expect(req.url.searchParams.toString()).toBe( - `projectKeys=our%3Aservice&metricKeys=${metricKeys.join('%2C')}`, + 'componentKey=our%3Aservice', ); return res( ctx.json({ + analysisDate: '2020-01-01T00:00:00Z', measures: [ { metric: 'alert_status', value: 'OK', - component: 'our:service', - }, - { - metric: 'alert_status', - value: 'ERROR', - component: 'other-service', }, { metric: 'bugs', value: '2', - component: 'our:service', }, { metric: 'reliability_rating', value: '3.0', - component: 'our:service', }, { metric: 'vulnerabilities', value: '4', - component: 'our:service', }, { metric: 'security_rating', value: '1.0', - component: 'our:service', }, { metric: 'security_hotspots_reviewed', value: '100', - component: 'our:service', }, { metric: 'security_review_rating', value: '1.0', - component: 'our:service', }, { metric: 'code_smells', value: '100', - component: 'our:service', }, { metric: 'sqale_rating', value: '2.0', - component: 'our:service', }, { metric: 'coverage', value: '55.5', - component: 'our:service', }, { metric: 'duplicated_lines_density', value: '1.0', - component: 'our:service', }, - ].filter(m => metricKeys.includes(m.metric)), - } as MeasuresWrapper), + ], + } as FindingsWrapper), ); }), ); @@ -246,47 +179,19 @@ describe('SonarQubeClient', () => { ); }); - it('should only request selected metrics', async () => { - setupHandlers(['alert_status', 'bugs']); - - const client = new SonarQubeClient({ - discoveryApi, - baseUrl: 'http://a.instance.local', - identityApi: identityApiAuthenticated, - }); - - const summary = await client.getFindingSummary('our:service'); - - expect(summary).toEqual( - expect.objectContaining({ - lastAnalysis: '2020-01-01T00:00:00Z', - metrics: { - alert_status: 'OK', - bugs: '2', - }, - projectUrl: 'http://a.instance.local/dashboard?id=our%3Aservice', - }) as FindingSummary, - ); - expect(summary?.getIssuesUrl('CODE_SMELL')).toEqual( - 'http://a.instance.local/project/issues?id=our%3Aservice&types=CODE_SMELL&resolved=false', - ); - expect(summary?.getComponentMeasuresUrl('COVERAGE')).toEqual( - 'http://a.instance.local/component_measures?id=our%3Aservice&metric=coverage&resolved=false&view=list', - ); - }); - it('should add identity token for logged in users', async () => { setupHandlers(); server.use( - rest.get(`${mockBaseUrl}/sonarqube/components/show`, (req, res, ctx) => { - expect(req.url.searchParams.toString()).toBe('component=our%3Aservice'); + rest.get(`${mockBaseUrl}/findings`, (req, res, ctx) => { + expect(req.url.searchParams.toString()).toBe( + 'componentKey=our%3Aservice', + ); expect(req.headers.get('Authorization')).toBe('Bearer fake-id-token'); return res( ctx.json({ - component: { - analysisDate: '2020-01-01T00:00:00Z', - }, - } as ComponentWrapper), + analysisDate: '2020-01-01T00:00:00Z', + measures: [], + } as FindingsWrapper), ); }), ); @@ -304,15 +209,16 @@ describe('SonarQubeClient', () => { it('should omit identity token for guest users', async () => { setupHandlers(); server.use( - rest.get(`${mockBaseUrl}/sonarqube/components/show`, (req, res, ctx) => { - expect(req.url.searchParams.toString()).toBe('component=our%3Aservice'); + rest.get(`${mockBaseUrl}/findings`, (req, res, ctx) => { + expect(req.url.searchParams.toString()).toBe( + 'componentKey=our%3Aservice', + ); expect(req.headers.has('Authorization')).toBeFalsy(); return res( ctx.json({ - component: { - analysisDate: '2020-01-01T00:00:00Z', - }, - } as ComponentWrapper), + analysisDate: '2020-01-01T00:00:00Z', + measures: [], + } as FindingsWrapper), ); }), ); diff --git a/plugins/sonarqube/src/api/SonarQubeClient.ts b/plugins/sonarqube/src/api/SonarQubeClient.ts index 39d0f11369..ed0b7dc3a7 100644 --- a/plugins/sonarqube/src/api/SonarQubeClient.ts +++ b/plugins/sonarqube/src/api/SonarQubeClient.ts @@ -16,7 +16,7 @@ import fetch from 'cross-fetch'; import { FindingSummary, Metrics, SonarQubeApi } from './SonarQubeApi'; -import { ComponentWrapper, MeasuresWrapper } from './types'; +import { FindingsWrapper } from './types'; import { DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api'; export class SonarQubeClient implements SonarQubeApi { @@ -44,7 +44,7 @@ export class SonarQubeClient implements SonarQubeApi { ): Promise { const { token: idToken } = await this.identityApi.getCredentials(); - const apiUrl = `${await this.discoveryApi.getBaseUrl('proxy')}/sonarqube`; + const apiUrl = `${await this.discoveryApi.getBaseUrl('sonarqube')}`; const response = await fetch( `${apiUrl}/${path}?${new URLSearchParams(query).toString()}`, { @@ -60,27 +60,6 @@ export class SonarQubeClient implements SonarQubeApi { return undefined; } - private async getSupportedMetrics(): Promise { - const metrics: string[] = []; - let nextPage: number = 1; - - for (;;) { - const result = await this.callApi<{ - metrics: Array<{ key: string }>; - total: number; - }>('metrics/search', { ps: 500, p: nextPage }); - - metrics.push(...(result?.metrics?.map(m => m.key) ?? [])); - - if (result && metrics.length < result.total) { - nextPage++; - continue; - } - - return metrics; - } - } - async getFindingSummary( componentKey?: string, ): Promise { @@ -88,13 +67,6 @@ export class SonarQubeClient implements SonarQubeApi { return undefined; } - const component = await this.callApi('components/show', { - component: componentKey, - }); - if (!component) { - return undefined; - } - const metrics: Metrics = { alert_status: undefined, bugs: undefined, @@ -109,28 +81,19 @@ export class SonarQubeClient implements SonarQubeApi { duplicated_lines_density: undefined, }; - // select the metrics that are supported by the SonarQube instance - const supportedMetrics = await this.getSupportedMetrics(); - const metricKeys = Object.keys(metrics).filter(m => - supportedMetrics.includes(m), - ); - - const measures = await this.callApi('measures/search', { - projectKeys: componentKey, - metricKeys: metricKeys.join(','), + const findings = await this.callApi('findings', { + componentKey: componentKey, }); - if (!measures) { + if (!findings) { return undefined; } - measures.measures - .filter(m => m.component === componentKey) - .forEach(m => { - metrics[m.metric] = m.value; - }); + findings.measures.forEach(m => { + metrics[m.metric] = m.value; + }); return { - lastAnalysis: component.component.analysisDate, + lastAnalysis: findings.analysisDate, metrics, projectUrl: `${this.baseUrl}dashboard?id=${encodeURIComponent( componentKey, diff --git a/plugins/sonarqube/src/api/types.ts b/plugins/sonarqube/src/api/types.ts index 6e951f9d8b..27f065d36a 100644 --- a/plugins/sonarqube/src/api/types.ts +++ b/plugins/sonarqube/src/api/types.ts @@ -14,15 +14,8 @@ * limitations under the License. */ -export interface ComponentWrapper { - component: Component; -} - -export interface Component { +export interface FindingsWrapper { analysisDate: string; -} - -export interface MeasuresWrapper { measures: Measure[]; } @@ -55,7 +48,6 @@ export type MetricKey = export interface Measure { metric: MetricKey; value: string; - component: string; } export type SonarUrlProcessorFunc = (identifier: string) => string; From f9c310a4395cf79c5c4b2d3c2b33b03bfca8b96c Mon Sep 17 00:00:00 2001 From: Neemys <36508659+Neemys@users.noreply.github.com> Date: Fri, 17 Jun 2022 17:43:40 +0200 Subject: [PATCH 009/144] Modify sonarqube frontend plugin to handle multiple sonarqube instances The instance name should be provided into the annotation in the `catalog-info.yaml` Care has been taken to provide backward compatibility of previous annotation into the default sonarqube instance Signed-off-by: Neemys <36508659+Neemys@users.noreply.github.com> --- .changeset/ten-roses-walk.md | 5 ++ .../sonarqube-backend/src/service/router.ts | 8 ++ plugins/sonarqube/src/api/SonarQubeApi.ts | 5 +- .../sonarqube/src/api/SonarQubeClient.test.ts | 79 ++++++++++++++----- plugins/sonarqube/src/api/SonarQubeClient.ts | 37 ++++++--- plugins/sonarqube/src/api/types.ts | 4 + .../SonarQubeCard/SonarQubeCard.tsx | 6 +- .../sonarqube/src/components/useProjectKey.ts | 32 +++++++- plugins/sonarqube/src/plugin.ts | 5 +- 9 files changed, 139 insertions(+), 42 deletions(-) create mode 100644 .changeset/ten-roses-walk.md diff --git a/.changeset/ten-roses-walk.md b/.changeset/ten-roses-walk.md new file mode 100644 index 0000000000..14d0819c38 --- /dev/null +++ b/.changeset/ten-roses-walk.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-sonarqube': patch +--- + +Add ability to provide an optional sonarqube instance into the annotation in the `catalog-info.yaml` file diff --git a/plugins/sonarqube-backend/src/service/router.ts b/plugins/sonarqube-backend/src/service/router.ts index 9d13104d82..54f0038ca9 100644 --- a/plugins/sonarqube-backend/src/service/router.ts +++ b/plugins/sonarqube-backend/src/service/router.ts @@ -38,6 +38,14 @@ export async function createRouter( measures: [{ metric: 'coverage', value: '50' }], }); }); + router.get('/instanceUrl', (request, response) => { + logger.info(request.params); + response.send({ + instanceUrl: `https://instance.local?${encodeURI( + request.query.instanceKey as string, + )}`, + }); + }); router.use(errorHandler()); return router; } diff --git a/plugins/sonarqube/src/api/SonarQubeApi.ts b/plugins/sonarqube/src/api/SonarQubeApi.ts index 3b39b30eb0..2232a00d9f 100644 --- a/plugins/sonarqube/src/api/SonarQubeApi.ts +++ b/plugins/sonarqube/src/api/SonarQubeApi.ts @@ -38,5 +38,8 @@ export const sonarQubeApiRef = createApiRef({ }); export type SonarQubeApi = { - getFindingSummary(componentKey?: string): Promise; + getFindingSummary( + projectInstance?: string, + componentKey?: string, + ): Promise; }; diff --git a/plugins/sonarqube/src/api/SonarQubeClient.test.ts b/plugins/sonarqube/src/api/SonarQubeClient.test.ts index 1727e73e93..87137ea93f 100644 --- a/plugins/sonarqube/src/api/SonarQubeClient.test.ts +++ b/plugins/sonarqube/src/api/SonarQubeClient.test.ts @@ -18,7 +18,7 @@ import { setupRequestMockHandlers } from '@backstage/test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { FindingSummary, SonarQubeClient } from './index'; -import { FindingsWrapper } from './types'; +import { InstanceUrlWrapper, FindingsWrapper } from './types'; import { UrlPatternDiscovery } from '@backstage/core-app-api'; import { IdentityApi } from '@backstage/core-plugin-api'; @@ -47,7 +47,7 @@ describe('SonarQubeClient', () => { server.use( rest.get(`${mockBaseUrl}/findings`, (req, res, ctx) => { expect(req.url.searchParams.toString()).toBe( - 'componentKey=our%3Aservice', + 'componentKey=our%3Aservice&instanceKey=', ); return res( @@ -103,6 +103,17 @@ describe('SonarQubeClient', () => { ); }), ); + server.use( + rest.get(`${mockBaseUrl}/instanceUrl`, (req, res, ctx) => { + expect(req.url.searchParams.toString()).toBe('instanceKey='); + + return res( + ctx.json({ + instanceUrl: 'https://sonarcloud.io', + } as InstanceUrlWrapper), + ); + }), + ); }; it('should report finding summary', async () => { @@ -143,30 +154,60 @@ describe('SonarQubeClient', () => { it('should report finding summary (custom baseUrl)', async () => { setupHandlers(); + server.use( + rest.get(`${mockBaseUrl}/instanceUrl`, (req, res, ctx) => { + expect(req.url.searchParams.toString()).toBe('instanceKey=custom'); + + return res( + ctx.json({ + instanceUrl: 'http://a.instance.local', + } as InstanceUrlWrapper), + ); + }), + ); + + server.use( + rest.get(`${mockBaseUrl}/findings`, (req, res, ctx) => { + expect(req.url.searchParams.toString()).toBe( + 'componentKey=our%3Aservice&instanceKey=custom', + ); + + return res( + ctx.json({ + analysisDate: '2020-01-03T00:00:00Z', + measures: [ + { + metric: 'alert_status', + value: 'ERROR', + }, + { + metric: 'bugs', + value: '45', + }, + { + metric: 'reliability_rating', + value: '5.0', + }, + ], + } as FindingsWrapper), + ); + }), + ); const client = new SonarQubeClient({ discoveryApi, - baseUrl: 'http://a.instance.local', identityApi: identityApiAuthenticated, }); - const summary = await client.getFindingSummary('our:service'); + const summary = await client.getFindingSummary('our:service', 'custom'); expect(summary).toEqual( expect.objectContaining({ - lastAnalysis: '2020-01-01T00:00:00Z', + lastAnalysis: '2020-01-03T00:00:00Z', metrics: { - alert_status: 'OK', - bugs: '2', - reliability_rating: '3.0', - vulnerabilities: '4', - security_rating: '1.0', - security_hotspots_reviewed: '100', - security_review_rating: '1.0', - code_smells: '100', - sqale_rating: '2.0', - coverage: '55.5', - duplicated_lines_density: '1.0', + alert_status: 'ERROR', + bugs: '45', + reliability_rating: '5.0', }, projectUrl: 'http://a.instance.local/dashboard?id=our%3Aservice', }) as FindingSummary, @@ -184,7 +225,7 @@ describe('SonarQubeClient', () => { server.use( rest.get(`${mockBaseUrl}/findings`, (req, res, ctx) => { expect(req.url.searchParams.toString()).toBe( - 'componentKey=our%3Aservice', + 'componentKey=our%3Aservice&instanceKey=', ); expect(req.headers.get('Authorization')).toBe('Bearer fake-id-token'); return res( @@ -198,7 +239,6 @@ describe('SonarQubeClient', () => { const client = new SonarQubeClient({ discoveryApi, - baseUrl: 'http://a.instance.local', identityApi: identityApiAuthenticated, }); const summary = await client.getFindingSummary('our:service'); @@ -211,7 +251,7 @@ describe('SonarQubeClient', () => { server.use( rest.get(`${mockBaseUrl}/findings`, (req, res, ctx) => { expect(req.url.searchParams.toString()).toBe( - 'componentKey=our%3Aservice', + 'componentKey=our%3Aservice&instanceKey=', ); expect(req.headers.has('Authorization')).toBeFalsy(); return res( @@ -225,7 +265,6 @@ describe('SonarQubeClient', () => { const client = new SonarQubeClient({ discoveryApi, - baseUrl: 'http://a.instance.local', identityApi: identityApiGuest, }); const summary = await client.getFindingSummary('our:service'); diff --git a/plugins/sonarqube/src/api/SonarQubeClient.ts b/plugins/sonarqube/src/api/SonarQubeClient.ts index ed0b7dc3a7..59182d917f 100644 --- a/plugins/sonarqube/src/api/SonarQubeClient.ts +++ b/plugins/sonarqube/src/api/SonarQubeClient.ts @@ -16,26 +16,22 @@ import fetch from 'cross-fetch'; import { FindingSummary, Metrics, SonarQubeApi } from './SonarQubeApi'; -import { FindingsWrapper } from './types'; +import { InstanceUrlWrapper, FindingsWrapper } from './types'; import { DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api'; export class SonarQubeClient implements SonarQubeApi { discoveryApi: DiscoveryApi; - baseUrl: string; identityApi: IdentityApi; constructor({ discoveryApi, identityApi, - baseUrl = 'https://sonarcloud.io/', }: { discoveryApi: DiscoveryApi; identityApi: IdentityApi; - baseUrl?: string; }) { this.discoveryApi = discoveryApi; this.identityApi = identityApi; - this.baseUrl = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`; } private async callApi( @@ -62,11 +58,14 @@ export class SonarQubeClient implements SonarQubeApi { async getFindingSummary( componentKey?: string, + projectInstance?: string, ): Promise { if (!componentKey) { return undefined; } + const instanceKey = projectInstance || ''; + const metrics: Metrics = { alert_status: undefined, bugs: undefined, @@ -81,8 +80,24 @@ export class SonarQubeClient implements SonarQubeApi { duplicated_lines_density: undefined, }; + const baseUrlWrapper = await this.callApi( + 'instanceUrl', + { + instanceKey, + }, + ); + let baseUrl = baseUrlWrapper?.instanceUrl; + if (!baseUrl) { + return undefined; + } + // ensure trailing slash for later on + if (!baseUrl.endsWith('/')) { + baseUrl += '/'; + } + const findings = await this.callApi('findings', { - componentKey: componentKey, + componentKey, + instanceKey, }); if (!findings) { return undefined; @@ -95,21 +110,19 @@ export class SonarQubeClient implements SonarQubeApi { return { lastAnalysis: findings.analysisDate, metrics, - projectUrl: `${this.baseUrl}dashboard?id=${encodeURIComponent( - componentKey, - )}`, + projectUrl: `${baseUrl}dashboard?id=${encodeURIComponent(componentKey)}`, getIssuesUrl: identifier => - `${this.baseUrl}project/issues?id=${encodeURIComponent( + `${baseUrl}project/issues?id=${encodeURIComponent( componentKey, )}&types=${identifier.toLocaleUpperCase('en-US')}&resolved=false`, getComponentMeasuresUrl: identifier => - `${this.baseUrl}component_measures?id=${encodeURIComponent( + `${baseUrl}component_measures?id=${encodeURIComponent( componentKey, )}&metric=${identifier.toLocaleLowerCase( 'en-US', )}&resolved=false&view=list`, getSecurityHotspotsUrl: () => - `${this.baseUrl}project/security_hotspots?id=${encodeURIComponent( + `${baseUrl}project/security_hotspots?id=${encodeURIComponent( componentKey, )}`, }; diff --git a/plugins/sonarqube/src/api/types.ts b/plugins/sonarqube/src/api/types.ts index 27f065d36a..348986149d 100644 --- a/plugins/sonarqube/src/api/types.ts +++ b/plugins/sonarqube/src/api/types.ts @@ -14,6 +14,10 @@ * limitations under the License. */ +export interface InstanceUrlWrapper { + instanceUrl: string; +} + export interface FindingsWrapper { analysisDate: string; measures: Measure[]; diff --git a/plugins/sonarqube/src/components/SonarQubeCard/SonarQubeCard.tsx b/plugins/sonarqube/src/components/SonarQubeCard/SonarQubeCard.tsx index 4527c2a3e3..d8aaec04f2 100644 --- a/plugins/sonarqube/src/components/SonarQubeCard/SonarQubeCard.tsx +++ b/plugins/sonarqube/src/components/SonarQubeCard/SonarQubeCard.tsx @@ -26,7 +26,7 @@ import useAsync from 'react-use/lib/useAsync'; import { sonarQubeApiRef } from '../../api'; import { SONARQUBE_PROJECT_KEY_ANNOTATION, - useProjectKey, + useProjectInfo, } from '../useProjectKey'; import { Percentage } from './Percentage'; import { Rating } from './Rating'; @@ -95,10 +95,10 @@ export const SonarQubeCard = ({ const { entity } = useEntity(); const sonarQubeApi = useApi(sonarQubeApiRef); - const projectTitle = useProjectKey(entity); + const { projectKey: projectTitle, projectInstance } = useProjectInfo(entity); const { value, loading } = useAsync( - async () => sonarQubeApi.getFindingSummary(projectTitle), + async () => sonarQubeApi.getFindingSummary(projectTitle, projectInstance), [sonarQubeApi, projectTitle], ); diff --git a/plugins/sonarqube/src/components/useProjectKey.ts b/plugins/sonarqube/src/components/useProjectKey.ts index 18596a8171..b091ea597c 100644 --- a/plugins/sonarqube/src/components/useProjectKey.ts +++ b/plugins/sonarqube/src/components/useProjectKey.ts @@ -16,11 +16,39 @@ import { Entity } from '@backstage/catalog-model'; +export interface ProjectInfo { + projectInstance: string; + projectKey: string; +} + export const SONARQUBE_PROJECT_KEY_ANNOTATION = 'sonarqube.org/project-key'; +export const SONARQUBE_PROJECT_INSTANCE_SEPARATOR = '/'; export const isSonarQubeAvailable = (entity: Entity) => Boolean(entity.metadata.annotations?.[SONARQUBE_PROJECT_KEY_ANNOTATION]); -export const useProjectKey = (entity: Entity) => { - return entity?.metadata.annotations?.[SONARQUBE_PROJECT_KEY_ANNOTATION] ?? ''; +/** + * Try to parse sonarqube information from an entity. + * + * If part are all info are not found, they will default to an empty string + * + * @param entity entity to find the sonarqube information from. + * @return a ProjectInfo properly populated. + */ +export const useProjectInfo = (entity: Entity): ProjectInfo => { + let projectInstance = ''; + let projectKey = ''; + const annotation = + entity?.metadata.annotations?.[SONARQUBE_PROJECT_KEY_ANNOTATION]; + if (annotation) { + if (annotation.indexOf(SONARQUBE_PROJECT_INSTANCE_SEPARATOR) > -1) { + [projectInstance, projectKey] = annotation.split( + SONARQUBE_PROJECT_INSTANCE_SEPARATOR, + 2, + ); + } else { + projectKey = annotation; + } + } + return { projectInstance, projectKey }; }; diff --git a/plugins/sonarqube/src/plugin.ts b/plugins/sonarqube/src/plugin.ts index 5662a41f2f..4ac49b2350 100644 --- a/plugins/sonarqube/src/plugin.ts +++ b/plugins/sonarqube/src/plugin.ts @@ -16,7 +16,6 @@ import { sonarQubeApiRef, SonarQubeClient } from './api'; import { - configApiRef, createApiFactory, createComponentExtension, createPlugin, @@ -30,14 +29,12 @@ export const sonarQubePlugin = createPlugin({ createApiFactory({ api: sonarQubeApiRef, deps: { - configApi: configApiRef, discoveryApi: discoveryApiRef, identityApi: identityApiRef, }, - factory: ({ configApi, discoveryApi, identityApi }) => + factory: ({ discoveryApi, identityApi }) => new SonarQubeClient({ discoveryApi, - baseUrl: configApi.getOptionalString('sonarQube.baseUrl'), identityApi, }), }), From 4d0fc08d4b0ed36802e0a9263ab050739cd41319 Mon Sep 17 00:00:00 2001 From: Neemys <36508659+Neemys@users.noreply.github.com> Date: Fri, 17 Jun 2022 17:46:52 +0200 Subject: [PATCH 010/144] Update sonarqube plugin's README.md to reflect recent changes No more use for proxy configuration Optional instance name in project annotations Signed-off-by: Neemys <36508659+Neemys@users.noreply.github.com> --- plugins/sonarqube/README.md | 44 +++++-------------------------------- 1 file changed, 5 insertions(+), 39 deletions(-) diff --git a/plugins/sonarqube/README.md b/plugins/sonarqube/README.md index febce4ecfc..d8ed6dfb8d 100644 --- a/plugins/sonarqube/README.md +++ b/plugins/sonarqube/README.md @@ -33,50 +33,14 @@ yarn add --cwd packages/app @backstage/plugin-sonarqube ); ``` -3. Add the proxy config: - - Provide a method for your Backstage backend to get to your SonarQube API end point. Add configuration to your `app-config.yaml` file depending on the product you use. Make sure to keep the trailing colon after the `SONARQUBE_TOKEN`, it is required to call - the Web API (see [docs](https://docs.sonarqube.org/latest/extend/web-api/)). - -**SonarCloud** - -```yaml -proxy: - '/sonarqube': - target: https://sonarcloud.io/api - allowedMethods: ['GET'] - # note that the colon after the token is required - auth: '${SONARQUBE_TOKEN}:' - # Environmental variable: SONARQUBE_TOKEN - # Fetch the sonar-auth-token from https://sonarcloud.io/account/security/ -``` - -**SonarQube** - -```yaml -proxy: - '/sonarqube': - target: https://your.sonarqube.instance.com/api - allowedMethods: ['GET'] - # note that the colon after the token is required - auth: '${SONARQUBE_TOKEN}:' - # Environmental variable: SONARQUBE_TOKEN - # Fetch the sonar-auth-token from https://sonarcloud.io/account/security/ - -sonarQube: - baseUrl: https://your.sonarqube.instance.com -``` - -4. Get and provide `SONARQUBE_TOKEN` as an env variable (https://sonarcloud.io/account/security or https://docs.sonarqube.org/latest/user-guide/user-token/). - -5. Run the following commands in the root folder of the project to install and compile the changes. +3. Run the following commands in the root folder of the project to install and compile the changes. ```yaml yarn install yarn tsc ``` -6. Add the `sonarqube.org/project-key` annotation to the `catalog-info.yaml` file of the target repo for which code quality analysis is needed. +4. Add the `sonarqube.org/project-key` annotation to the `catalog-info.yaml` file of the target repo for which code quality analysis is needed. ```yaml apiVersion: backstage.io/v1alpha1 @@ -86,9 +50,11 @@ metadata: description: | Backstage is an open-source developer portal that puts the developer experience first. annotations: - sonarqube.org/project-key: YOUR_PROJECT_KEY + sonarqube.org/project-key: YOUR_INSTANCE_NAME/YOUR_PROJECT_KEY spec: type: library owner: CNCF lifecycle: experimental ``` + +`YOUR_INSTANCE_NAME/` is optional and will query the default instance if not provided. From 55a31cc7538d8fa7b318fd3a95f8ac016e2d5694 Mon Sep 17 00:00:00 2001 From: Neemys <36508659+Neemys@users.noreply.github.com> Date: Thu, 21 Jul 2022 13:19:55 +0200 Subject: [PATCH 011/144] Add sonarqubeInfoProvider in sonarqube-backend plugin Handle config and sonarqube api call Heavily inspired from the jenkinsInfoProvider in the jenkins-backend plugin Signed-off-by: Neemys <36508659+Neemys@users.noreply.github.com> --- plugins/sonarqube-backend/src/index.ts | 1 + .../src/service/sonarqubeInfoProvider.test.ts | 504 ++++++++++++++++++ .../src/service/sonarqubeInfoProvider.ts | 371 +++++++++++++ 3 files changed, 876 insertions(+) create mode 100644 plugins/sonarqube-backend/src/service/sonarqubeInfoProvider.test.ts create mode 100644 plugins/sonarqube-backend/src/service/sonarqubeInfoProvider.ts diff --git a/plugins/sonarqube-backend/src/index.ts b/plugins/sonarqube-backend/src/index.ts index ca73cb27ba..c91aef09f8 100644 --- a/plugins/sonarqube-backend/src/index.ts +++ b/plugins/sonarqube-backend/src/index.ts @@ -15,3 +15,4 @@ */ export * from './service/router'; +export * from './service/sonarqubeInfoProvider'; diff --git a/plugins/sonarqube-backend/src/service/sonarqubeInfoProvider.test.ts b/plugins/sonarqube-backend/src/service/sonarqubeInfoProvider.test.ts new file mode 100644 index 0000000000..fcb73da926 --- /dev/null +++ b/plugins/sonarqube-backend/src/service/sonarqubeInfoProvider.test.ts @@ -0,0 +1,504 @@ +/* + * Copyright 2020 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 { ConfigReader } from '../../../../packages/config'; +import { + DefaultSonarqubeInfoProvider, + SonarqubeConfig, +} from './sonarqubeInfoProvider'; +import { setupServer } from 'msw/node'; +import { setupRequestMockHandlers } from '../../../../packages/test-utils'; +import { rest, RestRequest } from 'msw'; + +describe('SonarqubeConfig', () => { + const SONARQUBE_DEFAULT_INSTANCE_NAME = 'default'; + const DUMMY_SONAR_URL = 'https://sonarqube.example.com'; + const DUMMY_SONAR_APIKEY = '123456789abcdef0123456789abcedf012'; + const DUMMY_SIMPLE_OBJECT_FOR_DEFAULT_SONARQUBE_CONFIG = { + name: SONARQUBE_DEFAULT_INSTANCE_NAME, + baseUrl: DUMMY_SONAR_URL, + apiKey: DUMMY_SONAR_APIKEY, + }; + const DUMMY_SIMPLE_CONFIG = { + sonarqube: { + baseUrl: DUMMY_SONAR_URL, + apiKey: DUMMY_SONAR_APIKEY, + }, + }; + const DUMMY_NAMED_CONFIG = { + sonarqube: { + instances: [ + { + name: SONARQUBE_DEFAULT_INSTANCE_NAME, + baseUrl: DUMMY_SONAR_URL, + apiKey: DUMMY_SONAR_APIKEY, + }, + ], + }, + }; + + describe('fromConfig', () => { + it('Reads simple config and annotation', async () => { + const config = SonarqubeConfig.fromConfig( + new ConfigReader(DUMMY_SIMPLE_CONFIG), + ); + + expect(config.instances).toEqual([ + { + name: SONARQUBE_DEFAULT_INSTANCE_NAME, + baseUrl: DUMMY_SONAR_URL, + apiKey: DUMMY_SONAR_APIKEY, + }, + ]); + }); + + it('Reads named default config and annotation', async () => { + const config = SonarqubeConfig.fromConfig( + new ConfigReader(DUMMY_NAMED_CONFIG), + ); + + expect(config.instances).toEqual([ + { + name: SONARQUBE_DEFAULT_INSTANCE_NAME, + baseUrl: DUMMY_SONAR_URL, + apiKey: DUMMY_SONAR_APIKEY, + }, + ]); + }); + + it('Parses named default config (amongst named other configs)', async () => { + const config = SonarqubeConfig.fromConfig( + new ConfigReader({ + sonarqube: { + instances: [ + { + name: SONARQUBE_DEFAULT_INSTANCE_NAME, + baseUrl: DUMMY_SONAR_URL, + apiKey: DUMMY_SONAR_APIKEY, + }, + { + name: 'other', + baseUrl: 'https://sonarqube-other.example.com', + apiKey: 'abcdef0123456789abcedf0123456789abc', + }, + ], + }, + }), + ); + + expect(config.instances).toEqual([ + { + name: SONARQUBE_DEFAULT_INSTANCE_NAME, + baseUrl: DUMMY_SONAR_URL, + apiKey: DUMMY_SONAR_APIKEY, + }, + { + name: 'other', + baseUrl: 'https://sonarqube-other.example.com', + apiKey: 'abcdef0123456789abcedf0123456789abc', + }, + ]); + }); + it('Throw an error if both a named default config and top level config', async () => { + expect(() => + SonarqubeConfig.fromConfig( + new ConfigReader({ + sonarqube: { + baseUrl: DUMMY_SONAR_URL, + apiKey: DUMMY_SONAR_APIKEY, + instances: [ + { + name: SONARQUBE_DEFAULT_INSTANCE_NAME, + baseUrl: DUMMY_SONAR_URL, + apiKey: DUMMY_SONAR_APIKEY, + }, + ], + }, + }), + ), + ).toThrowError(Error); + }); + + it('Throw an error if default config is partially provided', async () => { + expect(() => + SonarqubeConfig.fromConfig( + new ConfigReader({ + sonarqube: { + baseUrl: DUMMY_SONAR_URL, + }, + }), + ), + ).toThrowError(Error); + }); + }); + + describe('getInstanceConfig', () => { + it('Gets default instance when no parameter given', async () => { + const config = new SonarqubeConfig([ + DUMMY_SIMPLE_OBJECT_FOR_DEFAULT_SONARQUBE_CONFIG, + { + name: 'other', + baseUrl: 'https://sonarqube-other.example.com', + apiKey: '123456789abcdef0123456789abcedf012', + }, + ]); + + expect(config.getInstanceConfig()).toEqual({ + name: SONARQUBE_DEFAULT_INSTANCE_NAME, + baseUrl: DUMMY_SONAR_URL, + apiKey: DUMMY_SONAR_APIKEY, + }); + }); + + it('Gets default instance when "default" given', async () => { + const config = new SonarqubeConfig([ + DUMMY_SIMPLE_OBJECT_FOR_DEFAULT_SONARQUBE_CONFIG, + { + name: 'other', + baseUrl: 'https://sonarqube-other.example.com', + apiKey: 'abcdef0123456789abcedf0123456789abc', + }, + ]); + + expect(config.getInstanceConfig('default')).toEqual({ + name: 'default', + baseUrl: 'https://sonarqube.example.com', + apiKey: '123456789abcdef0123456789abcedf012', + }); + }); + + it('Gets named instance', async () => { + const config = new SonarqubeConfig([ + DUMMY_SIMPLE_OBJECT_FOR_DEFAULT_SONARQUBE_CONFIG, + { + name: 'other', + baseUrl: 'https://sonarqube-other.example.com', + apiKey: '123456789abcdef0123456789abcedf012', + }, + ]); + + expect(config.getInstanceConfig('other')).toEqual({ + name: 'other', + baseUrl: 'https://sonarqube-other.example.com', + apiKey: '123456789abcdef0123456789abcedf012', + }); + }); + + it('Throw an error if default instance could not be found', async () => { + const config = new SonarqubeConfig([ + { + name: 'other', + baseUrl: 'https://sonarqube-other.example.com', + apiKey: '123456789abcdef0123456789abcedf012', + }, + ]); + + expect(() => config.getInstanceConfig('default')).toThrowError(Error); + }); + + it('Throw an error if named instance could not be found', async () => { + const config = new SonarqubeConfig([ + DUMMY_SIMPLE_OBJECT_FOR_DEFAULT_SONARQUBE_CONFIG, + ]); + + expect(() => config.getInstanceConfig('other')).toThrowError(Error); + }); + }); +}); + +const server = setupServer(); + +describe('DefaultSonarqubeInfoProvider', () => { + function configureProvider(configData: any) { + const config = new ConfigReader(configData); + + return DefaultSonarqubeInfoProvider.fromConfig(config); + } + + describe('getBaseUrl', () => { + it('Provide base url for default from simple config and empty string', async () => { + const provider = configureProvider({ + sonarqube: { + baseUrl: 'https://sonarqube.example.com', + apiKey: '123456789abcdef0123456789abcedf012', + }, + }); + + expect(provider.getBaseUrl('')).toEqual('https://sonarqube.example.com'); + }); + + it('Provide base url for named default config and "default" string', async () => { + const provider = configureProvider({ + sonarqube: { + instances: [ + { + name: 'default', + baseUrl: 'https://sonarqube.example.com', + apiKey: '123456789abcdef0123456789abcedf012', + }, + ], + }, + }); + + expect(provider.getBaseUrl('default')).toEqual( + 'https://sonarqube.example.com', + ); + }); + + it('Provide base url for named config', async () => { + const provider = configureProvider({ + sonarqube: { + instances: [ + { + name: 'default', + baseUrl: 'https://sonarqube.example.com', + apiKey: '123456789abcdef0123456789abcedf012', + }, + { + name: 'other', + baseUrl: 'https://sonarqube-other.example.com', + apiKey: '123456789abcdef0123456789abcedf012', + }, + ], + }, + }); + + expect(provider.getBaseUrl('other')).toEqual( + 'https://sonarqube-other.example.com', + ); + }); + }); + + describe('getFindings', () => { + setupRequestMockHandlers(server); + const MOCK_BASE_URL = 'http://backstage:9191'; + const DUMMY_COMPONENT_KEY = 'dummyComponentKey'; + const DUMMY_ANALYSIS_DATE = '2022-01-01T00:00:00Z'; + const DUMMY_API_KEY = '123456789abcdef0123456789abcedf012'; + + const checkBasicAuthToken = (req: RestRequest) => { + if (req.headers && req.headers.has('Authorization')) { + expect(req.headers.get('Authorization')).toEqual( + `Basic MTIzNDU2Nzg5YWJjZGVmMDEyMzQ1Njc4OWFiY2VkZjAxMjo=`, + ); + } else { + throw new Error('Basic auth token not provided'); + } + }; + + const setupComponentHandler = () => { + server.use( + rest.get(`${MOCK_BASE_URL}/api/components/show`, (req, res, ctx) => { + checkBasicAuthToken(req); + expect(req.url.searchParams.toString()).toBe( + `component=${DUMMY_COMPONENT_KEY}`, + ); + return res( + ctx.json({ + component: { analysisDate: DUMMY_ANALYSIS_DATE }, + }), + ); + }), + ); + }; + const setupMetricsHandler = () => { + server.use( + rest.get(`${MOCK_BASE_URL}/api/metrics/search`, (req, res, ctx) => { + checkBasicAuthToken(req); + return res( + ctx.json({ + total: 4, + metrics: [ + { key: 'coverage' }, + { key: 'code_smells' }, + { key: 'vulnerabilities' }, + { key: 'unused_metric' }, + ], + }), + ); + }), + ); + }; + const setupMeasureHandler = () => { + server.use( + rest.get(`${MOCK_BASE_URL}/api/measures/component`, (req, res, ctx) => { + checkBasicAuthToken(req); + expect(req.url.searchParams.toString()).toBe( + `component=${DUMMY_COMPONENT_KEY}&metricKeys=vulnerabilities%2Ccode_smells%2Ccoverage`, + ); + return res( + ctx.json({ + component: { + measures: [ + { metric: 'coverage', value: '86' }, + { metric: 'code_smells', value: '40' }, + { metric: 'vulnerabilities', value: '3' }, + ], + }, + }), + ); + }), + ); + }; + + const setupHandlers = () => { + setupComponentHandler(); + setupMetricsHandler(); + setupMeasureHandler(); + }; + + const DUMMY_SIMPLE_CONFIG_FOR_PROVIDER = { + sonarqube: { + baseUrl: MOCK_BASE_URL, + apiKey: DUMMY_API_KEY, + }, + }; + it('Provide findings when everything is ok', async () => { + setupHandlers(); + const provider = configureProvider(DUMMY_SIMPLE_CONFIG_FOR_PROVIDER); + expect( + await provider.getFindings(DUMMY_COMPONENT_KEY, 'default'), + ).toEqual({ + analysisDate: DUMMY_ANALYSIS_DATE, + measures: [ + { metric: 'coverage', value: '86' }, + { metric: 'code_smells', value: '40' }, + { metric: 'vulnerabilities', value: '3' }, + ], + }); + }); + + it('Provide undefined as finding if component API answer code is not 200', async () => { + server.use( + rest.get(`${MOCK_BASE_URL}/api/components/show`, (req, res, ctx) => { + checkBasicAuthToken(req); + expect(req.url.searchParams.toString()).toBe( + `component=${DUMMY_COMPONENT_KEY}`, + ); + return res(ctx.status(500)); + }), + ); + + const provider = configureProvider({ + sonarqube: { + baseUrl: MOCK_BASE_URL, + apiKey: '123456789abcdef0123456789abcedf012', + }, + }); + expect( + await provider.getFindings(DUMMY_COMPONENT_KEY, 'default'), + ).toBeUndefined(); + }); + it('Provide undefined as finding if component API answer incorrectly', async () => { + server.use( + rest.get(`${MOCK_BASE_URL}/api/components/show`, (req, res, ctx) => { + checkBasicAuthToken(req); + expect(req.url.searchParams.toString()).toBe( + `component=${DUMMY_COMPONENT_KEY}`, + ); + return res( + ctx.json({ + invalid: true, + }), + ); + }), + ); + + const provider = configureProvider(DUMMY_SIMPLE_CONFIG_FOR_PROVIDER); + expect( + await provider.getFindings(DUMMY_COMPONENT_KEY, 'default'), + ).toBeUndefined(); + }); + it('Provide findings when metrics API uses pages', async () => { + setupComponentHandler(); + setupMeasureHandler(); + // custom metrics handler that provide two pages + server.use( + rest.get(`${MOCK_BASE_URL}/api/metrics/search`, (req, res, ctx) => { + checkBasicAuthToken(req); + if (req.url.searchParams.get('p') === '1') + return res( + ctx.json({ + total: 4, + metrics: [{ key: 'coverage' }, { key: 'code_smells' }], + }), + ); + return res( + ctx.json({ + total: 4, + metrics: [{ key: 'vulnerabilities' }, { key: 'unused_metric' }], + }), + ); + }), + ); + + const provider = configureProvider(DUMMY_SIMPLE_CONFIG_FOR_PROVIDER); + expect( + await provider.getFindings(DUMMY_COMPONENT_KEY, 'default'), + ).toEqual({ + analysisDate: DUMMY_ANALYSIS_DATE, + measures: [ + { metric: 'coverage', value: '86' }, + { metric: 'code_smells', value: '40' }, + { metric: 'vulnerabilities', value: '3' }, + ], + }); + }); + + it('Provide undefined as findings when measure API answer code is not 200', async () => { + setupComponentHandler(); + setupMetricsHandler(); + // custom metrics handler that provide two pages + server.use( + rest.get(`${MOCK_BASE_URL}/api/measures/component`, (req, res, ctx) => { + checkBasicAuthToken(req); + expect(req.url.searchParams.toString()).toBe( + `component=${DUMMY_COMPONENT_KEY}&metricKeys=vulnerabilities%2Ccode_smells%2Ccoverage`, + ); + return res(ctx.status(500)); + }), + ); + + const provider = configureProvider(DUMMY_SIMPLE_CONFIG_FOR_PROVIDER); + expect( + await provider.getFindings(DUMMY_COMPONENT_KEY, 'default'), + ).toBeUndefined(); + }); + + it('Provide findings with empty measures when metrics API answer incorrectly', async () => { + setupComponentHandler(); + setupMetricsHandler(); + // custom metrics handler that provide two pages + server.use( + rest.get(`${MOCK_BASE_URL}/api/measures/component`, (req, res, ctx) => { + checkBasicAuthToken(req); + expect(req.url.searchParams.toString()).toBe( + `component=${DUMMY_COMPONENT_KEY}&metricKeys=vulnerabilities%2Ccode_smells%2Ccoverage`, + ); + return res(ctx.json({})); + }), + ); + + const provider = configureProvider(DUMMY_SIMPLE_CONFIG_FOR_PROVIDER); + expect( + await provider.getFindings(DUMMY_COMPONENT_KEY, 'default'), + ).toEqual({ + analysisDate: DUMMY_ANALYSIS_DATE, + measures: [], + }); + }); + }); +}); diff --git a/plugins/sonarqube-backend/src/service/sonarqubeInfoProvider.ts b/plugins/sonarqube-backend/src/service/sonarqubeInfoProvider.ts new file mode 100644 index 0000000000..0939abaed0 --- /dev/null +++ b/plugins/sonarqube-backend/src/service/sonarqubeInfoProvider.ts @@ -0,0 +1,371 @@ +/* + * Copyright 2020 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 { Config } from '@backstage/config'; +import fetch from 'node-fetch'; + +/** + * Provide information about sonarqube instances and projects contained within + * @public + */ +export interface SonarqubeInfoProvider { + /** + * Get the sonarqube URL in configuration from a provided name. + * + * If name is omitted, default sonarqube instance is queried in config + * + * @param instanceName - Name of the sonarqube instance to get the info from + * @returns the url of the instance + */ + getBaseUrl(instanceName: string): string; + + /** + * Query the sonarqube instance corresponding to the instanceName to get all + * measures for the component of key componentKey. + * @param componentKey - component key of the project we want to get measure from. + * @param instanceName - name of the instance (in config) where the project is hosted. + * @returns All measures with the analysis date. Will return undefined if we + * can't provide the full response + */ + getFindings( + componentKey: string, + instanceName: string, + ): Promise; +} + +/** + * Information retrieved for a specific project in Sonarqube + * @public + */ +export interface SonarqubeFindings { + /** + * Last date of the analysis that have generated this finding + */ + analysisDate: string; + /** + * All measures pertaining to the findings + */ + measures: Measure[]; +} + +interface MeasuresWrapper { + component: { measures: Measure[] }; +} + +/** + * A specific measure on a project in Sonarqube + * @public + */ +export interface Measure { + /** + * Name of the measure + */ + metric: string; + /** + * Value of the measure + */ + value: string; +} + +/** + * Information about a Sonarqube instance. + * @public + */ +export interface SonarqubeInstanceConfig { + /** + * Name of the instance. An instance name in configuration and catalog should match. + */ + name: string; + /** + * Base url to access the instance + */ + baseUrl: string; + /** + * Access token to access the sonarqube instance as generated in user profile. + */ + apiKey: string; +} + +interface ComponentWrapper { + component: { analysisDate: string }; +} + +/** + * Holds multiple Sonarqube configurations. + * @public + */ +export class SonarqubeConfig { + /** + * + * @param instances - All information on all sonarqube instance from the config file + */ + constructor(public readonly instances: SonarqubeInstanceConfig[]) {} + + /** + * Read all Sonarqube instance configurations. + * @param config - Root configuration + * @returns A SonarqubeConfig that contains all configured Sonarqube instances. + */ + static fromConfig(config: Config): SonarqubeConfig { + const DEFAULT_SONARQUBE_NAME = 'default'; + + const sonarqubeConfig = config.getConfig('sonarqube'); + + // load all named instance config + const namedInstanceConfig = + sonarqubeConfig.getOptionalConfigArray('instances')?.map(c => ({ + name: c.getString('name'), + baseUrl: c.getString('baseUrl'), + apiKey: c.getString('apiKey'), + })) || []; + + // load unnamed default config + const hasNamedDefault = namedInstanceConfig.some( + x => x.name === DEFAULT_SONARQUBE_NAME, + ); + + // Get these as optional strings and check to give a better error message + const baseUrl = sonarqubeConfig.getOptionalString('baseUrl'); + const apiKey = sonarqubeConfig.getOptionalString('apiKey'); + + if (hasNamedDefault && (baseUrl || apiKey)) { + throw new Error( + `Found both a named sonarqube instance with name ${DEFAULT_SONARQUBE_NAME} and top level baseUrl or apiKey config. Use only one style of config.`, + ); + } + + const unnamedNonePresent = !baseUrl && !apiKey; + const unnamedAllPresent = baseUrl && apiKey; + if (!(unnamedAllPresent || unnamedNonePresent)) { + throw new Error( + `Found partial default sonarqube config. All (or none) of baseUrl and apiKey must be provided.`, + ); + } + + if (unnamedAllPresent) { + const unnamedInstanceConfig = [ + { name: DEFAULT_SONARQUBE_NAME, baseUrl, apiKey }, + ] as { + name: string; + baseUrl: string; + apiKey: string; + }[]; + + return new SonarqubeConfig([ + ...namedInstanceConfig, + ...unnamedInstanceConfig, + ]); + } + + return new SonarqubeConfig(namedInstanceConfig); + } + + /** + * Gets a Sonarqube instance configuration by name, or the default one if no name is provided. + * @param sonarqubeName - Optional name of the Sonarqube instance. + * @returns The requested Sonarqube instance. + * @throws Error when no default config could be found or the requested name couldn't be found in config. + */ + getInstanceConfig(sonarqubeName?: string): SonarqubeInstanceConfig { + const DEFAULT_SONARQUBE_NAME = 'default'; + + if (!sonarqubeName || sonarqubeName === DEFAULT_SONARQUBE_NAME) { + // no name provided, use default + const instanceConfig = this.instances.find( + c => c.name === DEFAULT_SONARQUBE_NAME, + ); + + if (!instanceConfig) { + throw new Error( + `Couldn't find a default sonarqube instance in the config. Either configure an instance with name ${DEFAULT_SONARQUBE_NAME} or add a prefix to your annotation value.`, + ); + } + + return instanceConfig; + } + + // A name is provided, look it up. + const instanceConfig = this.instances.find(c => c.name === sonarqubeName); + + if (!instanceConfig) { + throw new Error( + `Couldn't find a sonarqube instance in the config with name ${sonarqubeName}`, + ); + } + return instanceConfig; + } +} + +/** + * @public + * + * Use default config and annotations, build using fromConfig static function. + */ +export class DefaultSonarqubeInfoProvider implements SonarqubeInfoProvider { + private constructor(private readonly config: SonarqubeConfig) {} + + /** + * Generate an instance from a Config instance + * @param config - Backend configuration + */ + static fromConfig(config: Config): DefaultSonarqubeInfoProvider { + return new DefaultSonarqubeInfoProvider(SonarqubeConfig.fromConfig(config)); + } + + /** + * Retrieve all supported metrics from a sonarqube instance. + * + * @param instanceUrl - URL of the sonarqube instance + * @param token - token to access the sonarqube instance + * @returns The list of supported metrics, if no metrics are supported an empty list is provided in the promise + * @private + */ + private static async getSupportedMetrics( + instanceUrl: string, + token: string, + ): Promise { + const metrics: string[] = []; + let nextPage: number = 1; + + for (;;) { + const result = await DefaultSonarqubeInfoProvider.callApi<{ + metrics: Array<{ key: string }>; + total: number; + }>(instanceUrl, 'api/metrics/search', token, { ps: 500, p: nextPage }); + metrics.push(...(result?.metrics?.map(m => m.key) ?? [])); + + if (result && metrics.length < result.total) { + nextPage++; + continue; + } + + return metrics; + } + } + + /** + * Call an API with provided arguments + * @param url - URL of the API to call + * @param path - path to call + * @param authToken - token used as basic auth user without password + * @param query - parameters to provide to the call + * @returns A promise on the answer to the API call if the answer status code is 200, undefined otherwise. + * @private + */ + private static async callApi( + url: string, + path: string, + authToken: string, + query: { [key in string]: any }, + ): Promise { + // Sonarqube auth use basic with token as username and no password + // but standard dictate the colon (separator) need to stay here despite the + // lack of password + const encodedAuthToken = Buffer.from(`${authToken}:`).toString('base64'); + + const response = await fetch( + `${url}/${path}?${new URLSearchParams(query).toString()}`, + { + headers: { + 'Content-Type': 'application/json', + Authorization: `Basic ${encodedAuthToken}`, + }, + }, + ); + if (response.status === 200) { + return (await response.json()) as T; + } + return undefined; + } + + /** + * {@inheritDoc SonarqubeInfoProvider.getBaseUrl} + * @throws Error If configuration can't be retrieved. + */ + getBaseUrl(instanceName: string): string { + const instanceConfig = this.config.getInstanceConfig(instanceName ?? ''); + return instanceConfig.baseUrl; + } + + /** + * {@inheritDoc SonarqubeInfoProvider.getFindings} + * @throws Error If configuration can't be retrieved. + */ + async getFindings( + componentKey: string, + instanceName: string, + ): Promise { + const { baseUrl, apiKey } = this.config.getInstanceConfig( + instanceName ?? '', + ); + + // get component info to retrieve analysis date + const component = + await DefaultSonarqubeInfoProvider.callApi( + baseUrl, + 'api/components/show', + apiKey, + { + component: componentKey, + }, + ); + if (!component || !component.component) { + return undefined; + } + + // select the metrics that are supported by the SonarQube instance + const supportedMetrics = + await DefaultSonarqubeInfoProvider.getSupportedMetrics(baseUrl, apiKey); + const wantedMetrics: string[] = [ + 'alert_status', + 'bugs', + 'reliability_rating', + 'vulnerabilities', + 'security_rating', + 'security_hotspots_reviewed', + 'security_review_rating', + 'code_smells', + 'sqale_rating', + 'coverage', + 'duplicated_lines_density', + ]; + + // only retrieve wanted metrics that are supported + const metricsToQuery = wantedMetrics.filter(el => + supportedMetrics.includes(el), + ); + + // get all measures + const measures = + await DefaultSonarqubeInfoProvider.callApi( + baseUrl, + 'api/measures/component', + apiKey, + { + component: componentKey, + metricKeys: metricsToQuery.join(','), + }, + ); + if (!measures) { + return undefined; + } + + return { + analysisDate: component.component.analysisDate, + measures: measures.component?.measures ?? [], + }; + } +} From e9dcea3c92345d93fbc16d020a77f462ec1e0e05 Mon Sep 17 00:00:00 2001 From: Neemys <36508659+Neemys@users.noreply.github.com> Date: Fri, 22 Jul 2022 14:33:50 +0200 Subject: [PATCH 012/144] Implement APIs of sonarqube-backend plugin's router Also update the standalone server to add router dependencies Signed-off-by: Neemys <36508659+Neemys@users.noreply.github.com> --- .../src/service/router.test.ts | 79 ++++++++++++++++-- .../sonarqube-backend/src/service/router.ts | 80 +++++++++++++++---- .../src/service/standaloneServer.ts | 10 ++- 3 files changed, 147 insertions(+), 22 deletions(-) diff --git a/plugins/sonarqube-backend/src/service/router.test.ts b/plugins/sonarqube-backend/src/service/router.test.ts index 24e482896b..756fba6164 100644 --- a/plugins/sonarqube-backend/src/service/router.test.ts +++ b/plugins/sonarqube-backend/src/service/router.test.ts @@ -19,13 +19,23 @@ import express from 'express'; import request from 'supertest'; import { createRouter } from './router'; +import { SonarqubeFindings } from './sonarqubeInfoProvider'; describe('createRouter', () => { let app: express.Express; + const getBaseUrlMock: jest.Mock = jest.fn(); + const getFindingsMock: jest.Mock< + Promise, + [string, string] + > = jest.fn(); beforeAll(async () => { const router = await createRouter({ logger: getVoidLogger(), + sonarqubeInfoProvider: { + getBaseUrl: getBaseUrlMock, + getFindings: getFindingsMock, + }, }); app = express().use(router); }); @@ -35,17 +45,76 @@ describe('createRouter', () => { }); describe('GET /findings', () => { + const DUMMY_COMPONENT_KEY = 'my:component'; + const DUMMY_INSTANCE_KEY = 'myInstance'; it('returns ok', async () => { + const measures = { + analysisDate: '2022-01-01T00:00:00Z', + measures: [{ metric: 'vulnerabilities', value: '54' }], + }; + + getFindingsMock.mockReturnValue(Promise.resolve(measures)); const response = await request(app) .get('/findings') - .set('componentKey', 'my:app') + .query({ + componentKey: DUMMY_COMPONENT_KEY, + instanceKey: DUMMY_INSTANCE_KEY, + }) + .send(); + expect(getFindingsMock).toBeCalledTimes(1); + expect(getFindingsMock).toBeCalledWith( + DUMMY_COMPONENT_KEY, + DUMMY_INSTANCE_KEY, + ); + expect(response.status).toEqual(200); + expect(response.body).toEqual(measures); + }); + it('returns an error when component key is not defined', async () => { + const response = await request(app) + .get('/findings') + .query({ + instanceKey: DUMMY_INSTANCE_KEY, + }) .send(); + expect(response.status).toEqual(400); + }); + + it('use an empty string as instance name when instance key not provided', async () => { + const measures = { + analysisDate: '2021-04-08', + measures: [{ metric: 'vulnerabilities', value: '54' }], + }; + + getFindingsMock.mockReturnValue(Promise.resolve(measures)); + const response = await request(app) + .get('/findings') + .query({ + componentKey: DUMMY_COMPONENT_KEY, + }) + .send(); + + expect(getFindingsMock).toBeCalledTimes(1); + expect(getFindingsMock).toBeCalledWith(DUMMY_COMPONENT_KEY, ''); expect(response.status).toEqual(200); - expect(response.body).toEqual({ - analysisDate: '2022-10-22T04:55:23Z', - measures: [{ metric: 'coverage', value: '50' }], - }); + expect(response.body).toEqual(measures); + }); + }); + describe('GET /instanceUrl', () => { + const DUMMY_INSTANCE_KEY = 'myInstance'; + const DUMMY_INSTANCE_URL = 'http://sonarqube.example.com'; + it('returns ok', async () => { + getBaseUrlMock.mockReturnValue(DUMMY_INSTANCE_URL); + const response = await request(app) + .get('/instanceUrl') + .query({ + instanceKey: DUMMY_INSTANCE_KEY, + }) + .send(); + expect(getBaseUrlMock).toBeCalledTimes(1); + expect(getBaseUrlMock).toBeCalledWith(DUMMY_INSTANCE_KEY); + expect(response.status).toEqual(200); + expect(response.body).toEqual({ instanceUrl: DUMMY_INSTANCE_URL }); }); }); }); diff --git a/plugins/sonarqube-backend/src/service/router.ts b/plugins/sonarqube-backend/src/service/router.ts index 54f0038ca9..c1f672a2c4 100644 --- a/plugins/sonarqube-backend/src/service/router.ts +++ b/plugins/sonarqube-backend/src/service/router.ts @@ -15,37 +15,87 @@ */ import { errorHandler } from '@backstage/backend-common'; -import express from 'express'; +import express, { RequestHandler } from 'express'; import Router from 'express-promise-router'; import { Logger } from 'winston'; +import { + SonarqubeFindings, + SonarqubeInfoProvider, +} from './sonarqubeInfoProvider'; +import { InputError } from '../../../../packages/errors'; +/** + * Dependencies needed by the router + * @public + */ export interface RouterOptions { + /** + * Logger for logging purposes + */ logger: Logger; + /** + * Info provider to be able to get all necessary information for the APIs + */ + sonarqubeInfoProvider: SonarqubeInfoProvider; } +/** + * @public + * + * Constructs a sonarqube router. + * + * Expose endpoint to get information on or for a sonarqube instance. + * + * @param options - Dependencies of the router + */ export async function createRouter( options: RouterOptions, ): Promise { - const { logger } = options; + const { logger, sonarqubeInfoProvider } = options; const router = Router(); router.use(express.json()); // mock api for now - router.get('/findings', (request, response) => { - logger.info(request.params); + router.get('/findings', (async (request, response) => { + const componentKey = request.query.componentKey; + let instanceKey = request.query.instanceKey; + + if (!componentKey) + throw new InputError('ComponentKey must be provided as a single string.'); + + if (!instanceKey) { + instanceKey = ''; + logger.info( + `Retrieving findings for component ${componentKey} in default sonarqube instance`, + ); + } else { + logger.info( + `Retrieving findings for component ${componentKey} in sonarqube instance name ${instanceKey}`, + ); + } + + response.send( + await sonarqubeInfoProvider.getFindings(componentKey, instanceKey), + ); + }) as RequestHandler); + + router.get('/instanceUrl', ((request, response) => { + let requestedInstanceKey = request.query.instanceKey; + if (requestedInstanceKey) { + logger.info( + `Retrieving sonarqube instance URL for key ${requestedInstanceKey}`, + ); + } else { + requestedInstanceKey = ''; + logger.info( + `Retrieving default sonarqube instance URL as parameter is inexistant, empty or malformed`, + ); + } response.send({ - analysisDate: '2022-10-22T04:55:23Z', - measures: [{ metric: 'coverage', value: '50' }], + instanceUrl: sonarqubeInfoProvider.getBaseUrl(requestedInstanceKey), }); - }); - router.get('/instanceUrl', (request, response) => { - logger.info(request.params); - response.send({ - instanceUrl: `https://instance.local?${encodeURI( - request.query.instanceKey as string, - )}`, - }); - }); + }) as RequestHandler); + router.use(errorHandler()); return router; } diff --git a/plugins/sonarqube-backend/src/service/standaloneServer.ts b/plugins/sonarqube-backend/src/service/standaloneServer.ts index 78f39b2680..06a8d4ffb2 100644 --- a/plugins/sonarqube-backend/src/service/standaloneServer.ts +++ b/plugins/sonarqube-backend/src/service/standaloneServer.ts @@ -14,10 +14,14 @@ * limitations under the License. */ -import { createServiceBuilder } from '@backstage/backend-common'; +import { + createServiceBuilder, + loadBackendConfig, +} from '@backstage/backend-common'; import { Server } from 'http'; import { Logger } from 'winston'; import { createRouter } from './router'; +import { DefaultSonarqubeInfoProvider } from './sonarqubeInfoProvider'; export interface ServerOptions { port: number; @@ -30,13 +34,15 @@ export async function startStandaloneServer( ): Promise { const logger = options.logger.child({ service: 'sonarqube-backend-backend' }); logger.debug('Starting application server...'); + const config = await loadBackendConfig({ logger, argv: process.argv }); const router = await createRouter({ logger, + sonarqubeInfoProvider: DefaultSonarqubeInfoProvider.fromConfig(config), }); let service = createServiceBuilder(module) .setPort(options.port) - .addRouter('/sonarqube-backend', router); + .addRouter('/sonarqube', router); if (options.enableCors) { service = service.enableCors({ origin: 'http://localhost:3000' }); } From 035ea31f2cc140333423c461f24e20f03bca6580 Mon Sep 17 00:00:00 2001 From: Neemys <36508659+Neemys@users.noreply.github.com> Date: Fri, 22 Jul 2022 14:37:50 +0200 Subject: [PATCH 013/144] Add api-report.md for plugin sonarqube-backend Signed-off-by: Neemys <36508659+Neemys@users.noreply.github.com> --- plugins/sonarqube-backend/api-report.md | 67 +++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 plugins/sonarqube-backend/api-report.md diff --git a/plugins/sonarqube-backend/api-report.md b/plugins/sonarqube-backend/api-report.md new file mode 100644 index 0000000000..c163ff3bc5 --- /dev/null +++ b/plugins/sonarqube-backend/api-report.md @@ -0,0 +1,67 @@ +## API Report File for "@backstage/plugin-sonarqube-backend" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { Config } from '@backstage/config'; +import express from 'express'; +import { Logger } from 'winston'; + +// @public +export function createRouter(options: RouterOptions): Promise; + +// @public +export class DefaultSonarqubeInfoProvider implements SonarqubeInfoProvider { + static fromConfig(config: Config): DefaultSonarqubeInfoProvider; + getBaseUrl(instanceName: string): string; + getFindings( + componentKey: string, + instanceName: string, + ): Promise; +} + +// @public +export interface Measure { + metric: string; + value: string; +} + +// @public +export interface RouterOptions { + logger: Logger; + sonarqubeInfoProvider: SonarqubeInfoProvider; +} + +// @public +export class SonarqubeConfig { + constructor(instances: SonarqubeInstanceConfig[]); + static fromConfig(config: Config): SonarqubeConfig; + getInstanceConfig(sonarqubeName?: string): SonarqubeInstanceConfig; + // (undocumented) + readonly instances: SonarqubeInstanceConfig[]; +} + +// @public +export interface SonarqubeFindings { + analysisDate: string; + measures: Measure[]; +} + +// @public +export interface SonarqubeInfoProvider { + getBaseUrl(instanceName: string): string; + getFindings( + componentKey: string, + instanceName: string, + ): Promise; +} + +// @public +export interface SonarqubeInstanceConfig { + apiKey: string; + baseUrl: string; + name: string; +} + +// (No @packageDocumentation comment for this package) +``` From f1768c82e13861d3f536cab34e026332bb922209 Mon Sep 17 00:00:00 2001 From: Neemys <36508659+Neemys@users.noreply.github.com> Date: Fri, 22 Jul 2022 14:39:35 +0200 Subject: [PATCH 014/144] Update package.json for plugin sonarqube-backend Set the plugin to non private and prefix the name with "@backstage/" Signed-off-by: Neemys <36508659+Neemys@users.noreply.github.com> --- plugins/sonarqube-backend/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/sonarqube-backend/package.json b/plugins/sonarqube-backend/package.json index ca2b98c10e..d8d21e86d1 100644 --- a/plugins/sonarqube-backend/package.json +++ b/plugins/sonarqube-backend/package.json @@ -1,10 +1,10 @@ { - "name": "plugin-sonarqube-backend", + "name": "@backstage/plugin-sonarqube-backend", "version": "0.0.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", - "private": true, + "private": false, "publishConfig": { "access": "public", "main": "dist/index.cjs.js", From ddd47ff7fba20f7cb431405da27c758a38a8ddbe Mon Sep 17 00:00:00 2001 From: Neemys <36508659+Neemys@users.noreply.github.com> Date: Fri, 22 Jul 2022 14:47:25 +0200 Subject: [PATCH 015/144] Fix typo in comment in sonarqube plugin Signed-off-by: Neemys <36508659+Neemys@users.noreply.github.com> --- plugins/sonarqube/src/components/useProjectKey.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/sonarqube/src/components/useProjectKey.ts b/plugins/sonarqube/src/components/useProjectKey.ts index b091ea597c..acf28c7802 100644 --- a/plugins/sonarqube/src/components/useProjectKey.ts +++ b/plugins/sonarqube/src/components/useProjectKey.ts @@ -30,7 +30,7 @@ export const isSonarQubeAvailable = (entity: Entity) => /** * Try to parse sonarqube information from an entity. * - * If part are all info are not found, they will default to an empty string + * If part or all info are not found, they will default to an empty string * * @param entity entity to find the sonarqube information from. * @return a ProjectInfo properly populated. From 648190c0b4da3e430d16d92b93037d2ba14c4a9d Mon Sep 17 00:00:00 2001 From: Neemys <36508659+Neemys@users.noreply.github.com> Date: Fri, 22 Jul 2022 16:45:27 +0200 Subject: [PATCH 016/144] Update plugin sonarqube-backend's README with proper information Signed-off-by: Neemys <36508659+Neemys@users.noreply.github.com> --- plugins/sonarqube-backend/README.md | 138 ++++++++++++++++++++++++++-- 1 file changed, 132 insertions(+), 6 deletions(-) diff --git a/plugins/sonarqube-backend/README.md b/plugins/sonarqube-backend/README.md index 0fad3b67f3..0db23ade6c 100644 --- a/plugins/sonarqube-backend/README.md +++ b/plugins/sonarqube-backend/README.md @@ -2,12 +2,138 @@ Welcome to the sonarqube-backend backend plugin! -_This plugin was created through the Backstage CLI_ +## Integrating into a backstage instance -## Getting started +This plugin needs to be added to an existing backstage instance. -Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn start` in the root directory, and then navigating to [/sonarqube-backend](http://localhost:3000/sonarqube-backend). +```bash +# From your Backstage root directory +yarn add --cwd packages/backend @backstage/plugin-sonarqube-backend +``` -You can also serve the plugin in isolation by running `yarn start` in the plugin directory. -This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads. -It is only meant for local development, and the setup for it can be found inside the [/dev](/dev) directory. +Typically, this means creating a `src/plugins/sonarqube.ts` file and adding a reference to it to `src/index.ts` in the backend package. + +### sonarqube.ts + +```typescript +import { + createRouter, + DefaultSonarqubeInfoProvider, +} from '@backstage/plugin-sonarqube-backend'; +import { Router } from 'express'; +import { PluginEnvironment } from '../types'; + +export default async function createPlugin( + env: PluginEnvironment, +): Promise { + return await createRouter({ + logger: env.logger, + sonarqubeInfoProvider: DefaultSonarqubeInfoProvider.fromConfig(env.config), + }); +} +``` + +### src/index.ts + +```diff +diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts +index 1942c36ad1..7fdc48ba24 100644 +--- a/packages/backend/src/index.ts ++++ b/packages/backend/src/index.ts +@@ -50,6 +50,7 @@ import scaffolder from './plugins/scaffolder'; + import proxy from './plugins/proxy'; + import search from './plugins/search'; + import techdocs from './plugins/techdocs'; ++import sonarqube from './plugins/sonarqube'; + import techInsights from './plugins/techInsights'; + import todo from './plugins/todo'; + import graphql from './plugins/graphql'; +@@ -133,6 +134,7 @@ async function main() { + createEnv('tech-insights'), + ); + const permissionEnv = useHotMemoize(module, () => createEnv('permission')); ++ const sonarqubeEnv = useHotMemoize(module, () => createEnv('sonarqube')); + + const apiRouter = Router(); + apiRouter.use('/catalog', await catalog(catalogEnv)); +@@ -152,6 +154,7 @@ async function main() { + apiRouter.use('/badges', await badges(badgesEnv)); + apiRouter.use('/jenkins', await jenkins(jenkinsEnv)); + apiRouter.use('/permission', await permission(permissionEnv)); ++ apiRouter.use('/sonarqube', await sonarqube(sonarqubeEnv)); + apiRouter.use(notFoundHandler()); + + const service = createServiceBuilder(module) + +``` + +This plugin must be provided with a `SonarqubeInfoProvider`, this is a strategy object for finding sonarqube instances in configuration and retrieving data from an instance. + +There is a standard one provided (`DefaultSonarqubeInfoProvider`), but the Integrator is free to build their own. + +### DefaultSonarqubeInfoProvider + +Allows configuration of either a single or multiple global Sonarqube instances and annotating entities with the instance name. This instance name in the entities is optional, if not provided the default instance in configuration will be used. That allow to keep configuration from before multiple instances capability to keep working without changes. + +#### Example - Single global instance + +##### Config + +```yaml +sonarqube: + baseUrl: https://sonarqube.example.com + apiKey: 123456789abcdef0123456789abcedf012 +``` + +##### Catalog + +```yaml +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage + annotations: + sonarqube.org/project-key: YOUR_INSTANCE_NAME/YOUR_PROJECT_KEY +``` + +#### Example - Multiple global instance + +The following will look for findings at `https://special-project-sonarqube.example.com` for the project of key `YOUR_PROJECT_KEY`. + +##### Config + +```yaml +sonarqube: + instances: + - name: default + baseUrl: https://default-sonarqube.example.com + apiKey: 123456789abcdef0123456789abcedf012 + - name: specialProject + baseUrl: https://special-project-sonarqube.example.com + apiKey: abcdef0123456789abcedf0123456789ab +``` + +##### Catalog + +```yaml +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage + annotations: + sonarqube.org/project-key: specialProject/YOUR_PROJECT_KEY +``` + +If the `specialProject/` part is omitted (or replaced with `default/`), the sonarqube instance of name `default` will be used. + +The following config is an equivalent (but less clear) version of the above: + +```yaml +sonarqube: + baseUrl: https://default-sonarqube.example.com + apiKey: 123456789abcdef0123456789abcedf012 + instances: + - name: specialProject + baseUrl: https://special-project-sonarqube.example.com + apiKey: abcdef0123456789abcedf0123456789ab +``` From 4bec71fe13ad5fadc7e1e839af3410d4e8062a55 Mon Sep 17 00:00:00 2001 From: Neemys <36508659+Neemys@users.noreply.github.com> Date: Fri, 22 Jul 2022 17:38:30 +0200 Subject: [PATCH 017/144] Update plugin sonarqube-backend's dependencies Signed-off-by: Neemys <36508659+Neemys@users.noreply.github.com> --- plugins/sonarqube-backend/package.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/sonarqube-backend/package.json b/plugins/sonarqube-backend/package.json index d8d21e86d1..22dbe1e637 100644 --- a/plugins/sonarqube-backend/package.json +++ b/plugins/sonarqube-backend/package.json @@ -23,20 +23,20 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/backend-common": "^0.13.6-next.1", + "@backstage/backend-common": "^0.14.1", "@backstage/config": "^1.0.1", "@types/express": "*", - "express": "^4.17.1", + "express": "^4.18.1", "express-promise-router": "^4.1.0", - "winston": "^3.2.1", "node-fetch": "^2.6.7", - "yn": "^4.0.0" + "winston": "^3.8.1", + "yn": "^5.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2-next.1", - "@types/supertest": "^2.0.8", - "supertest": "^4.0.2", - "msw": "^0.42.0" + "@backstage/cli": "^0.18.0", + "@types/supertest": "^2.0.12", + "msw": "^0.44.2", + "supertest": "^6.2.4" }, "files": [ "dist" From e2be9ab3a48aa0b23d1a3e58691053755dd8eb63 Mon Sep 17 00:00:00 2001 From: Neemys <36508659+Neemys@users.noreply.github.com> Date: Fri, 22 Jul 2022 17:44:50 +0200 Subject: [PATCH 018/144] Add plugin sonarqube-backend's changeset Signed-off-by: Neemys <36508659+Neemys@users.noreply.github.com> --- .changeset/eighty-radios-look.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/eighty-radios-look.md diff --git a/.changeset/eighty-radios-look.md b/.changeset/eighty-radios-look.md new file mode 100644 index 0000000000..de178c1111 --- /dev/null +++ b/.changeset/eighty-radios-look.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-sonarqube-backend': patch +--- + +Initial creation of the plugin From b2b62ab5b672304c3e3bfbd0e2b74c58adf860f4 Mon Sep 17 00:00:00 2001 From: Neemys <36508659+Neemys@users.noreply.github.com> Date: Fri, 22 Jul 2022 18:01:48 +0200 Subject: [PATCH 019/144] Correct usage of 'sonarqube' with 'Sonarqube' Also add 'Sonarqube' into vale vocab Signed-off-by: Neemys <36508659+Neemys@users.noreply.github.com> --- .changeset/forty-lobsters-guess.md | 2 +- .changeset/ten-roses-walk.md | 2 +- .github/vale/Vocab/Backstage/accept.txt | 1 + plugins/sonarqube-backend/README.md | 4 ++-- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.changeset/forty-lobsters-guess.md b/.changeset/forty-lobsters-guess.md index 50dd22627f..c7ab852e08 100644 --- a/.changeset/forty-lobsters-guess.md +++ b/.changeset/forty-lobsters-guess.md @@ -6,4 +6,4 @@ The whole proxy's `'/sonarqube':` key can be removed from your configuration files. -Then head to the sonarqube-backend plugin page to learn how to set-up the link to your sonarqube instances. +Then head to the sonarqube-backend plugin page to learn how to set-up the link to your Sonarqube instances. diff --git a/.changeset/ten-roses-walk.md b/.changeset/ten-roses-walk.md index 14d0819c38..87b711db2a 100644 --- a/.changeset/ten-roses-walk.md +++ b/.changeset/ten-roses-walk.md @@ -2,4 +2,4 @@ '@backstage/plugin-sonarqube': patch --- -Add ability to provide an optional sonarqube instance into the annotation in the `catalog-info.yaml` file +Add ability to provide an optional Sonarqube instance into the annotation in the `catalog-info.yaml` file diff --git a/.github/vale/Vocab/Backstage/accept.txt b/.github/vale/Vocab/Backstage/accept.txt index cd01425a5e..5324ce2b2a 100644 --- a/.github/vale/Vocab/Backstage/accept.txt +++ b/.github/vale/Vocab/Backstage/accept.txt @@ -283,6 +283,7 @@ shoutout siloed Sinon Snyk +Sonarqube sourcemaps sparklines Splunk diff --git a/plugins/sonarqube-backend/README.md b/plugins/sonarqube-backend/README.md index 0db23ade6c..ac3973a5c0 100644 --- a/plugins/sonarqube-backend/README.md +++ b/plugins/sonarqube-backend/README.md @@ -67,7 +67,7 @@ index 1942c36ad1..7fdc48ba24 100644 ``` -This plugin must be provided with a `SonarqubeInfoProvider`, this is a strategy object for finding sonarqube instances in configuration and retrieving data from an instance. +This plugin must be provided with a `SonarqubeInfoProvider`, this is a strategy object for finding Sonarqube instances in configuration and retrieving data from an instance. There is a standard one provided (`DefaultSonarqubeInfoProvider`), but the Integrator is free to build their own. @@ -124,7 +124,7 @@ metadata: sonarqube.org/project-key: specialProject/YOUR_PROJECT_KEY ``` -If the `specialProject/` part is omitted (or replaced with `default/`), the sonarqube instance of name `default` will be used. +If the `specialProject/` part is omitted (or replaced with `default/`), the Sonarqube instance of name `default` will be used. The following config is an equivalent (but less clear) version of the above: From f48950e34b14606b12964ed24fbdedde5d6b1ffd Mon Sep 17 00:00:00 2001 From: brentg-telus <50498366+brentg-telus@users.noreply.github.com> Date: Mon, 25 Jul 2022 13:00:53 -0400 Subject: [PATCH 020/144] feat: github discovery provider Signed-off-by: brentg-telus <50498366+brentg-telus@users.noreply.github.com> --- .changeset/odd-tomatoes-juggle.md | 9 + docs/integrations/github/discovery.md | 114 ++++++++ .../api-report.md | 21 ++ .../src/index.ts | 12 +- .../GithubDiscoveryProcessor.test.ts | 2 +- .../GithubDiscoveryProcessor.ts | 2 +- .../GithubMultiOrgReaderProcessor.ts | 2 +- .../GithubOrgReaderProcessor.test.ts | 0 .../GithubOrgReaderProcessor.ts | 2 +- .../providers/GitHubEntityProvider.test.ts | 185 ++++++++++++ .../src/providers/GitHubEntityProvider.ts | 271 ++++++++++++++++++ .../GitHubEntityProviderConfig.test.ts | 115 ++++++++ .../providers/GitHubEntityProviderConfig.ts | 90 ++++++ .../GitHubOrgEntityProvider.test.ts | 0 .../GitHubOrgEntityProvider.ts | 2 +- 15 files changed, 817 insertions(+), 10 deletions(-) create mode 100644 .changeset/odd-tomatoes-juggle.md rename plugins/catalog-backend-module-github/src/{ => processors}/GithubDiscoveryProcessor.test.ts (99%) rename plugins/catalog-backend-module-github/src/{ => processors}/GithubDiscoveryProcessor.ts (99%) rename plugins/catalog-backend-module-github/src/{ => processors}/GithubMultiOrgReaderProcessor.ts (99%) rename plugins/catalog-backend-module-github/src/{ => processors}/GithubOrgReaderProcessor.test.ts (100%) rename plugins/catalog-backend-module-github/src/{ => processors}/GithubOrgReaderProcessor.ts (99%) create mode 100644 plugins/catalog-backend-module-github/src/providers/GitHubEntityProvider.test.ts create mode 100644 plugins/catalog-backend-module-github/src/providers/GitHubEntityProvider.ts create mode 100644 plugins/catalog-backend-module-github/src/providers/GitHubEntityProviderConfig.test.ts create mode 100644 plugins/catalog-backend-module-github/src/providers/GitHubEntityProviderConfig.ts rename plugins/catalog-backend-module-github/src/{ => providers}/GitHubOrgEntityProvider.test.ts (100%) rename plugins/catalog-backend-module-github/src/{ => providers}/GitHubOrgEntityProvider.ts (99%) diff --git a/.changeset/odd-tomatoes-juggle.md b/.changeset/odd-tomatoes-juggle.md new file mode 100644 index 0000000000..336af17eb4 --- /dev/null +++ b/.changeset/odd-tomatoes-juggle.md @@ -0,0 +1,9 @@ +--- +'@backstage/plugin-catalog-backend-module-github': patch +--- + +Github Entity Provider functionality for adding entities to the catalog. + +This provider replaces the GithubDiscoveryProcessor functionality as providers offer more flexibility with scheduling ingestion, removing and preventing orphaned entities. + +More information can be found on the [GitHub Discovery](https://backstage.io/docs/integrations/github/discovery) page. diff --git a/docs/integrations/github/discovery.md b/docs/integrations/github/discovery.md index a0c3fed153..82abc25eca 100644 --- a/docs/integrations/github/discovery.md +++ b/docs/integrations/github/discovery.md @@ -6,6 +6,120 @@ sidebar_label: Discovery description: Automatically discovering catalog entities from repositories in a GitHub organization --- +## GitHub Provider + +The GitHub integration has a discovery provider for discovering catalog +entities within a GitHub organization. The provider will crawl the GitHub +organization and register entities matching the configured path. This can be +useful as an alternative to static locations or manually adding things to the +catalog. This is the prefered method for ingesting entities into the catalog. + +## Installation + +You will have to add the provider in the catalog initialization code of your +backend. They are not installed by default, therefore you have to add a +dependency on `@backstage/plugin-catalog-backend-module-github` to your backend +package + +```bash +# From your Backstage root directory +yarn add --cwd packages/backend @backstage/plugin-catalog-backend-module-github +``` + +And then add the entity provider to your catalog builder: + +```diff + // In packages/backend/src/plugins/catalog.ts ++ import { GitHubEntityProvider } from '@backstage/plugin-catalog-backend-module-github'; + + export default async function createPlugin( + env: PluginEnvironment, + ): Promise { + const builder = await CatalogBuilder.create(env); ++ builder.addEntityProvider( ++ GitHubEntityProvider.fromConfig(env.config, { ++ logger: env.logger, ++ schedule: env.scheduler.createScheduledTaskRunner({ ++ frequency: { minutes: 30 }, ++ timeout: { minutes: 3 }, ++ }), ++ }), ++ ); + + // [...] + } +``` + +## Configuration + +To use the discovery provider, you'll need a GitHub integration +[set up](locations.md) with either a [Personal Access Token](../../getting-started/configuration.md#setting-up-a-github-integration) or [GitHub Apps](./github-apps.md). + +Then you can add a github config to the catalog providers configuration: + +```yaml +catalog: + providers: + github: + # the provider ID can be any camelCase string + providerId: + organization: 'backstage' # string + catalogPath: '/catalog-info.yaml' # string + filters: + branch: 'main' # string + repository: '.*' # Regex + customProviderId: + organization: 'new-org' # string + catalogPath: '/custom/path/catalog-info.yaml' # string + filters: # optional filters + branch: 'develop' # optional string + repository: '.*' # optional Regex +``` + +This provider supports multiple organizations via unique provider IDs + +> **Note:** It is possible but certainly not recommended to skip the provider ID level. +> If you do so, `default` will be used as provider ID. + +- **catalogPath** _(optional)_: + Default: `/catalog-info.yaml`. + Path where to look for `catalog-info.yaml` files. + When started with `/`, it is an absolute path from the repo root. +- **filters** _(optional)_: + - **branch** _(optional)_: + String used to filter results based on the branch name. + - **repository** _(optional)_: + Regular expression used to filter results based on the repository name. +- **organization**: + Name of your organization account/workspace. + If you want to add multiple organizations, you need to add one provider config each. + +## GitHub API Rate Limits + +GitHub [rate limits](https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting) API requests to 5,000 per hour (or more for Enterprise +accounts). The default Backstage catalog backend refreshes data every 100 +seconds, which issues an API request for each discovered location. + +This means if you have more than ~140 catalog entities, you may get throttled by +rate limiting. You can change the refresh frequency of the catalog in your `packages/backend/src/plugins/catalog.ts` file: + +```typescript +schedule: env.scheduler.createScheduledTaskRunner({ + frequency: { minutes: 35 }, + timeout: { minutes: 30 }, +}), +``` + +More information about scheduling can be found on the [TaskScheduleDefinition](https://backstage.io/docs/reference/backend-tasks.taskscheduledefinition) page. + +Alternatively, or additionally, you can configure [github-apps](github-apps.md) authentication +which carries a much higher rate limit at GitHub. + +This is true for any method of adding GitHub entities to the catalog, but +especially easy to hit with automatic discovery. + +## GitHub Processor (To Be Deprecated) + The GitHub integration has a special discovery processor for discovering catalog entities within a GitHub organization. The processor will crawl the GitHub organization and register entities matching the configured path. This can be diff --git a/plugins/catalog-backend-module-github/api-report.md b/plugins/catalog-backend-module-github/api-report.md index e5fa2ea46a..62e64122bb 100644 --- a/plugins/catalog-backend-module-github/api-report.md +++ b/plugins/catalog-backend-module-github/api-report.md @@ -40,6 +40,27 @@ export class GithubDiscoveryProcessor implements CatalogProcessor { ): Promise; } +// @public +export class GitHubEntityProvider implements EntityProvider { + // (undocumented) + connect(connection: EntityProviderConnection): Promise; + // (undocumented) + static fromConfig( + config: Config, + options: GitHubEntityProviderOptions, + ): GitHubEntityProvider[]; + // (undocumented) + getProviderName(): string; + // (undocumented) + refresh(): Promise; +} + +// @public +export interface GitHubEntityProviderOptions { + logger: Logger; + schedule: TaskRunner; +} + // @public export type GithubMultiOrgConfig = Array<{ name: string; diff --git a/plugins/catalog-backend-module-github/src/index.ts b/plugins/catalog-backend-module-github/src/index.ts index 2f666e6547..81dc1727c8 100644 --- a/plugins/catalog-backend-module-github/src/index.ts +++ b/plugins/catalog-backend-module-github/src/index.ts @@ -20,9 +20,11 @@ * @packageDocumentation */ -export { GithubDiscoveryProcessor } from './GithubDiscoveryProcessor'; -export { GithubMultiOrgReaderProcessor } from './GithubMultiOrgReaderProcessor'; -export { GitHubOrgEntityProvider } from './GitHubOrgEntityProvider'; -export type { GitHubOrgEntityProviderOptions } from './GitHubOrgEntityProvider'; -export { GithubOrgReaderProcessor } from './GithubOrgReaderProcessor'; +export { GithubDiscoveryProcessor } from './processors/GithubDiscoveryProcessor'; +export { GithubMultiOrgReaderProcessor } from './processors/GithubMultiOrgReaderProcessor'; +export { GithubOrgReaderProcessor } from './processors/GithubOrgReaderProcessor'; +export { GitHubEntityProvider } from './providers/GitHubEntityProvider'; +export { GitHubOrgEntityProvider } from './providers/GitHubOrgEntityProvider'; +export type { GitHubOrgEntityProviderOptions } from './providers/GitHubOrgEntityProvider'; +export type { GitHubEntityProviderOptions } from './providers/GitHubEntityProvider'; export type { GithubMultiOrgConfig } from './lib'; diff --git a/plugins/catalog-backend-module-github/src/GithubDiscoveryProcessor.test.ts b/plugins/catalog-backend-module-github/src/processors/GithubDiscoveryProcessor.test.ts similarity index 99% rename from plugins/catalog-backend-module-github/src/GithubDiscoveryProcessor.test.ts rename to plugins/catalog-backend-module-github/src/processors/GithubDiscoveryProcessor.test.ts index b18e3baf75..aa6dc9229e 100644 --- a/plugins/catalog-backend-module-github/src/GithubDiscoveryProcessor.test.ts +++ b/plugins/catalog-backend-module-github/src/processors/GithubDiscoveryProcessor.test.ts @@ -22,7 +22,7 @@ import { } from '@backstage/integration'; import { LocationSpec } from '@backstage/plugin-catalog-backend'; import { GithubDiscoveryProcessor, parseUrl } from './GithubDiscoveryProcessor'; -import { getOrganizationRepositories } from './lib'; +import { getOrganizationRepositories } from '../lib'; jest.mock('./lib'); const mockGetOrganizationRepositories = diff --git a/plugins/catalog-backend-module-github/src/GithubDiscoveryProcessor.ts b/plugins/catalog-backend-module-github/src/processors/GithubDiscoveryProcessor.ts similarity index 99% rename from plugins/catalog-backend-module-github/src/GithubDiscoveryProcessor.ts rename to plugins/catalog-backend-module-github/src/processors/GithubDiscoveryProcessor.ts index 78a1bca169..97c77bf033 100644 --- a/plugins/catalog-backend-module-github/src/GithubDiscoveryProcessor.ts +++ b/plugins/catalog-backend-module-github/src/processors/GithubDiscoveryProcessor.ts @@ -29,7 +29,7 @@ import { } from '@backstage/plugin-catalog-backend'; import { graphql } from '@octokit/graphql'; import { Logger } from 'winston'; -import { getOrganizationRepositories } from './lib'; +import { getOrganizationRepositories } from '../lib'; /** * Extracts repositories out of a GitHub org. diff --git a/plugins/catalog-backend-module-github/src/GithubMultiOrgReaderProcessor.ts b/plugins/catalog-backend-module-github/src/processors/GithubMultiOrgReaderProcessor.ts similarity index 99% rename from plugins/catalog-backend-module-github/src/GithubMultiOrgReaderProcessor.ts rename to plugins/catalog-backend-module-github/src/processors/GithubMultiOrgReaderProcessor.ts index 321e9cc8f8..c5315ad166 100644 --- a/plugins/catalog-backend-module-github/src/GithubMultiOrgReaderProcessor.ts +++ b/plugins/catalog-backend-module-github/src/processors/GithubMultiOrgReaderProcessor.ts @@ -37,7 +37,7 @@ import { getOrganizationUsers, GithubMultiOrgConfig, readGithubMultiOrgConfig, -} from './lib'; +} from '../lib'; /** * Extracts teams and users out of a multiple GitHub orgs namespaced per org. diff --git a/plugins/catalog-backend-module-github/src/GithubOrgReaderProcessor.test.ts b/plugins/catalog-backend-module-github/src/processors/GithubOrgReaderProcessor.test.ts similarity index 100% rename from plugins/catalog-backend-module-github/src/GithubOrgReaderProcessor.test.ts rename to plugins/catalog-backend-module-github/src/processors/GithubOrgReaderProcessor.test.ts diff --git a/plugins/catalog-backend-module-github/src/GithubOrgReaderProcessor.ts b/plugins/catalog-backend-module-github/src/processors/GithubOrgReaderProcessor.ts similarity index 99% rename from plugins/catalog-backend-module-github/src/GithubOrgReaderProcessor.ts rename to plugins/catalog-backend-module-github/src/processors/GithubOrgReaderProcessor.ts index ca1dd96b3c..c6f2f5d0e2 100644 --- a/plugins/catalog-backend-module-github/src/GithubOrgReaderProcessor.ts +++ b/plugins/catalog-backend-module-github/src/processors/GithubOrgReaderProcessor.ts @@ -36,7 +36,7 @@ import { getOrganizationTeams, getOrganizationUsers, parseGitHubOrgUrl, -} from './lib'; +} from '../lib'; type GraphQL = typeof graphql; diff --git a/plugins/catalog-backend-module-github/src/providers/GitHubEntityProvider.test.ts b/plugins/catalog-backend-module-github/src/providers/GitHubEntityProvider.test.ts new file mode 100644 index 0000000000..f933053f4a --- /dev/null +++ b/plugins/catalog-backend-module-github/src/providers/GitHubEntityProvider.test.ts @@ -0,0 +1,185 @@ +/* + * 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 { getVoidLogger } from '@backstage/backend-common'; +import { TaskInvocationDefinition, TaskRunner } from '@backstage/backend-tasks'; +import { ConfigReader } from '@backstage/config'; +import { EntityProviderConnection } from '@backstage/plugin-catalog-backend'; +import { GitHubEntityProvider } from './GitHubEntityProvider'; +import * as helpers from '../lib/github'; + +class PersistingTaskRunner implements TaskRunner { + private tasks: TaskInvocationDefinition[] = []; + + getTasks() { + return this.tasks; + } + + run(task: TaskInvocationDefinition): Promise { + this.tasks.push(task); + return Promise.resolve(undefined); + } +} + +const logger = getVoidLogger(); + +describe('GitHubEntityProvider', () => { + afterEach(() => jest.resetAllMocks()); + + it('no provider config', () => { + const schedule = new PersistingTaskRunner(); + const config = new ConfigReader({}); + const providers = GitHubEntityProvider.fromConfig(config, { + logger, + schedule, + }); + + expect(providers).toHaveLength(0); + }); + + it('single simple provider config', () => { + const schedule = new PersistingTaskRunner(); + const config = new ConfigReader({ + catalog: { + providers: { + github: { + organization: 'test-org', + }, + }, + }, + }); + const providers = GitHubEntityProvider.fromConfig(config, { + logger, + schedule, + }); + + expect(providers).toHaveLength(1); + expect(providers[0].getProviderName()).toEqual('github-provider:default'); + }); + + it('multiple provider configs', () => { + const schedule = new PersistingTaskRunner(); + const config = new ConfigReader({ + catalog: { + providers: { + github: { + myProvider: { + organization: 'test-org1', + }, + anotherProvider: { + organization: 'test-org2', + }, + }, + }, + }, + }); + const providers = GitHubEntityProvider.fromConfig(config, { + logger, + schedule, + }); + + expect(providers).toHaveLength(2); + expect(providers[0].getProviderName()).toEqual( + 'github-provider:myProvider', + ); + expect(providers[1].getProviderName()).toEqual( + 'github-provider:anotherProvider', + ); + }); + + it.only('apply full update on scheduled execution', async () => { + const config = new ConfigReader({ + catalog: { + providers: { + github: { + myProvider: { + organization: 'test-org', + catalogPath: 'custom/path/catalog-custom.yaml', + filters: { + branch: 'main', + repository: 'test-.*', + }, + }, + }, + }, + }, + }); + const schedule = new PersistingTaskRunner(); + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + }; + + const provider = GitHubEntityProvider.fromConfig(config, { + logger, + schedule, + })[0]; + + const mockGetOrganizationRepositories = jest.spyOn( + helpers, + 'getOrganizationRepositories', + ); + + mockGetOrganizationRepositories.mockReturnValue( + Promise.resolve({ + repositories: [ + { + name: 'test-repo', + url: 'https://github.com/test-org/test-repo', + isArchived: false, + defaultBranchRef: { + name: 'main', + }, + }, + ], + }), + ); + + await provider.connect(entityProviderConnection); + + const taskDef = schedule.getTasks()[0]; + expect(taskDef.id).toEqual('github-provider:myProvider:refresh'); + await (taskDef.fn as () => Promise)(); + + const url = `https://github.com/test-org/test-repo/blob/main/catalog-custom.yaml`; + const expectedEntities = [ + { + entity: { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Location', + metadata: { + annotations: { + 'backstage.io/managed-by-location': `url:${url}`, + 'backstage.io/managed-by-origin-location': `url:${url}`, + }, + name: 'generated-21936a3d1e926b8bb3b00ac4398dc9a8dbb90b45', + }, + spec: { + presence: 'optional', + target: `${url}`, + type: 'url', + }, + }, + locationKey: 'github-provider:myProvider', + }, + ]; + + expect(entityProviderConnection.applyMutation).toBeCalledTimes(1); + expect(entityProviderConnection.applyMutation).toBeCalledWith({ + type: 'full', + entities: expectedEntities, + }); + }); +}); diff --git a/plugins/catalog-backend-module-github/src/providers/GitHubEntityProvider.ts b/plugins/catalog-backend-module-github/src/providers/GitHubEntityProvider.ts new file mode 100644 index 0000000000..5f228dff28 --- /dev/null +++ b/plugins/catalog-backend-module-github/src/providers/GitHubEntityProvider.ts @@ -0,0 +1,271 @@ +/* + * 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 { TaskRunner } from '@backstage/backend-tasks'; +import { Config } from '@backstage/config'; +import { + GithubCredentialsProvider, + ScmIntegrations, + GitHubIntegrationConfig, + GitHubIntegration, + SingleInstanceGithubCredentialsProvider, +} from '@backstage/integration'; +import { + EntityProvider, + EntityProviderConnection, + LocationSpec, + locationSpecToLocationEntity, +} from '@backstage/plugin-catalog-backend'; + +import { graphql } from '@octokit/graphql'; +import * as uuid from 'uuid'; +import { Logger } from 'winston'; +import { + readProviderConfigs, + GitHubEntityProviderConfig, +} from './GitHubEntityProviderConfig'; +import { getOrganizationRepositories, Repository } from '../lib/github'; + +/** + * Options for {@link GitHubEntityProvider}. + * + * @public + */ +export interface GitHubEntityProviderOptions { + /** + * A Scheduled Task Runner + * + * {@link @backstage/backend-tasks#PluginTaskScheduler.createScheduledTaskRunner} + * to enable automatic scheduling of tasks. + */ + schedule: TaskRunner; + + /** + * The logger to use. + */ + logger: Logger; +} + +/** + * Discovers catalog files located in [GitHub](https://github.com). + * The provider will search your GitHub account and register catalog files matching the configured path + * as Location entity and via following processing steps add all contained catalog entities. + * This can be useful as an alternative to static locations or manually adding things to the catalog. + * + * @public + */ +export class GitHubEntityProvider implements EntityProvider { + private readonly config: GitHubEntityProviderConfig; + private readonly logger: Logger; + private readonly integration: GitHubIntegrationConfig; + private readonly scheduleFn: () => Promise; + private connection?: EntityProviderConnection; + private readonly githubCredentialsProvider: GithubCredentialsProvider; + + static fromConfig( + config: Config, + options: GitHubEntityProviderOptions, + ): GitHubEntityProvider[] { + const integrations = ScmIntegrations.fromConfig(config); + const integration = integrations.github.byHost('github.com'); + + if (!integration) { + throw new Error( + `There is no GitHub config that matches github. Please add a configuration entry for it under integrations.github`, + ); + } + + return readProviderConfigs(config).map( + providerConfig => + new GitHubEntityProvider( + providerConfig, + integration, + options.logger, + options.schedule, + ), + ); + } + + private constructor( + config: GitHubEntityProviderConfig, + integration: GitHubIntegration, + logger: Logger, + schedule: TaskRunner, + ) { + this.config = config; + this.integration = integration.config; + this.logger = logger.child({ + target: this.getProviderName(), + }); + this.scheduleFn = this.createScheduleFn(schedule); + this.githubCredentialsProvider = + SingleInstanceGithubCredentialsProvider.create(integration.config); + this.scheduleFn = this.createScheduleFn(schedule); + } + + /** {@inheritdoc @backstage/plugin-catalog-backend#EntityProvider.getProviderName} */ + getProviderName(): string { + return `github-provider:${this.config.id}`; + } + + /** {@inheritdoc @backstage/plugin-catalog-backend#EntityProvider.connect} */ + async connect(connection: EntityProviderConnection): Promise { + this.connection = connection; + return await this.scheduleFn(); + } + + private createScheduleFn(schedule: TaskRunner): () => Promise { + return async () => { + const taskId = `${this.getProviderName()}:refresh`; + return schedule.run({ + id: taskId, + fn: async () => { + const logger = this.logger.child({ + taskId, + taskInstanceId: uuid.v4(), + }); + try { + await this.refresh(); + } catch (error) { + logger.error(error); + } + }, + }); + }; + } + + async refresh() { + if (!this.connection) { + throw new Error('Not initialized'); + } + + const targets = await this.findCatalogFiles(); + const matchingTargets = this.matchesFilters(targets); + const entities = matchingTargets + .map(repository => this.createLocationUrl(repository)) + .map(GitHubEntityProvider.toLocationSpec) + .map(location => { + return { + locationKey: this.getProviderName(), + entity: locationSpecToLocationEntity({ location }), + }; + }); + + await this.connection.applyMutation({ + type: 'full', + entities, + }); + + this.logger.info( + `Read ${targets.length} GitHub repositories (${entities.length} matching the pattern)`, + ); + } + + // go to the server and get all of the repositories + private async findCatalogFiles(): Promise { + const organization = this.config.organization; + const host = this.integration.host; + const orgUrl = `https://${host}/${organization}`; + + const { headers } = await this.githubCredentialsProvider.getCredentials({ + url: orgUrl, + }); + + const client = graphql.defaults({ + baseUrl: this.integration.apiBaseUrl, + headers, + }); + + const { repositories } = await getOrganizationRepositories( + client, + organization, + ); + + return repositories; + } + + private matchesFilters(repositories: Repository[]) { + const repositoryFilter = this.config.filters?.repository; + + const matchingRepositories = repositories.filter(r => { + return ( + !r.isArchived && + repositoryFilter?.test(r.name) && + r.defaultBranchRef?.name + ); + }); + return matchingRepositories; + } + + private createLocationUrl(repository: Repository): string { + const branch = + this.config.filters?.branch || repository.defaultBranchRef?.name || '-'; + const catalogFile = this.config.catalogPath.substring( + this.config.catalogPath.lastIndexOf('/') + 1, + ); + return `${repository.url}/blob/${branch}/${catalogFile}`; + } + + private static toLocationSpec(target: string): LocationSpec { + return { + type: 'url', + target: target, + presence: 'optional', + }; + } +} + +/* + * Helpers + */ + +export function parseUrl(urlString: string): { + org: string; + repoSearchPath: RegExp; + catalogPath: string; + branch: string; + host: string; +} { + const url = new URL(urlString); + const path = url.pathname.substr(1).split('/'); + + // /backstage/techdocs-*/blob/master/catalog-info.yaml + // can also be + // /backstage + if (path.length > 2 && path[0].length && path[1].length) { + return { + org: decodeURIComponent(path[0]), + repoSearchPath: escapeRegExp(decodeURIComponent(path[1])), + catalogPath: `/${decodeURIComponent(path.slice(4).join('/'))}`, + branch: decodeURIComponent(path[3]), + host: url.host, + }; + } else if (path.length === 1 && path[0].length) { + return { + org: decodeURIComponent(path[0]), + repoSearchPath: escapeRegExp('*'), + catalogPath: '/catalog-info.yaml', + branch: '-', + host: url.host, + }; + } + + throw new Error(`Failed to parse ${urlString}`); +} + +export function escapeRegExp(str: string): RegExp { + return new RegExp(`^${str.replace(/\*/g, '.*')}$`); +} diff --git a/plugins/catalog-backend-module-github/src/providers/GitHubEntityProviderConfig.test.ts b/plugins/catalog-backend-module-github/src/providers/GitHubEntityProviderConfig.test.ts new file mode 100644 index 0000000000..ba72dbf950 --- /dev/null +++ b/plugins/catalog-backend-module-github/src/providers/GitHubEntityProviderConfig.test.ts @@ -0,0 +1,115 @@ +/* + * 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 { ConfigReader } from '@backstage/config'; +import { readProviderConfigs } from './GitHubEntityProviderConfig'; + +describe('readProviderConfigs', () => { + afterEach(() => jest.resetAllMocks()); + + it('no provider config', () => { + const config = new ConfigReader({}); + const providerConfigs = readProviderConfigs(config); + + expect(providerConfigs).toHaveLength(0); + }); + + it('single simple provider config', () => { + const config = new ConfigReader({ + catalog: { + providers: { + github: { + organization: 'test-org', + }, + }, + }, + }); + const providerConfigs = readProviderConfigs(config); + + expect(providerConfigs).toHaveLength(1); + expect(providerConfigs[0].id).toEqual('default'); + expect(providerConfigs[0].organization).toEqual('test-org'); + }); + + it('multiple provider configs', () => { + const config = new ConfigReader({ + catalog: { + providers: { + github: { + providerOrganizationOnly: { + organization: 'test-org1', + }, + providerCustomCatalogPath: { + organization: 'test-org2', + catalogPath: 'custom/path/catalog-info.yaml', + }, + providerWithRepositoryFilter: { + organization: 'test-org3', + filters: { + repository: 'repository.*filter', + }, + }, + providerWithBranchFilter: { + organization: 'test-org4', + filters: { + branch: 'branch-name', + }, + }, + }, + }, + }, + }); + const providerConfigs = readProviderConfigs(config); + + expect(providerConfigs).toHaveLength(4); + expect(providerConfigs[0]).toEqual({ + id: 'providerOrganizationOnly', + organization: 'test-org1', + catalogPath: '/catalog-info.yaml', + filters: { + repository: undefined, + branch: undefined, + }, + }); + expect(providerConfigs[1]).toEqual({ + id: 'providerCustomCatalogPath', + organization: 'test-org2', + catalogPath: 'custom/path/catalog-info.yaml', + filters: { + repository: undefined, + branch: undefined, + }, + }); + expect(providerConfigs[2]).toEqual({ + id: 'providerWithRepositoryFilter', + organization: 'test-org3', // organization + catalogPath: '/catalog-info.yaml', // file + filters: { + repository: /^repository.*filter$/, // repo + branch: undefined, // branch + }, + }); + expect(providerConfigs[3]).toEqual({ + id: 'providerWithBranchFilter', + organization: 'test-org4', + catalogPath: '/catalog-info.yaml', + filters: { + repository: undefined, + branch: 'branch-name', + }, + }); + }); +}); diff --git a/plugins/catalog-backend-module-github/src/providers/GitHubEntityProviderConfig.ts b/plugins/catalog-backend-module-github/src/providers/GitHubEntityProviderConfig.ts new file mode 100644 index 0000000000..b5929c5300 --- /dev/null +++ b/plugins/catalog-backend-module-github/src/providers/GitHubEntityProviderConfig.ts @@ -0,0 +1,90 @@ +/* + * 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 { Config } from '@backstage/config'; + +const DEFAULT_CATALOG_PATH = '/catalog-info.yaml'; +const DEFAULT_PROVIDER_ID = 'default'; + +export type GitHubEntityProviderConfig = { + id: string; + catalogPath: string; + organization: string; + filters?: { + repository?: RegExp; + branch?: string; + }; +}; + +export function readProviderConfigs( + config: Config, +): GitHubEntityProviderConfig[] { + const providersConfig = config.getOptionalConfig('catalog.providers.github'); + if (!providersConfig) { + return []; + } + + if (providersConfig.has('organization')) { + // simple/single config variant + return [readProviderConfig(DEFAULT_PROVIDER_ID, providersConfig)]; + } + + return providersConfig.keys().map(id => { + const providerConfig = providersConfig.getConfig(id); + + return readProviderConfig(id, providerConfig); + }); +} + +function readProviderConfig( + id: string, + config: Config, +): GitHubEntityProviderConfig { + const organization = config.getString('organization'); + const catalogPath = + config.getOptionalString('catalogPath') ?? DEFAULT_CATALOG_PATH; + const repositoryPattern = config.getOptionalString('filters.repository'); + const branchPattern = config.getOptionalString('filters.branch'); + + return { + id, + catalogPath, + organization, + filters: { + repository: repositoryPattern + ? compileRegExp(repositoryPattern) + : undefined, + branch: branchPattern || undefined, + }, + }; +} +/** + * Compiles a RegExp while enforcing the pattern to contain + * the start-of-line and end-of-line anchors. + * + * @param pattern + */ +function compileRegExp(pattern: string): RegExp { + let fullLinePattern = pattern; + if (!fullLinePattern.startsWith('^')) { + fullLinePattern = `^${fullLinePattern}`; + } + if (!fullLinePattern.endsWith('$')) { + fullLinePattern = `${fullLinePattern}$`; + } + + return new RegExp(fullLinePattern); +} diff --git a/plugins/catalog-backend-module-github/src/GitHubOrgEntityProvider.test.ts b/plugins/catalog-backend-module-github/src/providers/GitHubOrgEntityProvider.test.ts similarity index 100% rename from plugins/catalog-backend-module-github/src/GitHubOrgEntityProvider.test.ts rename to plugins/catalog-backend-module-github/src/providers/GitHubOrgEntityProvider.test.ts diff --git a/plugins/catalog-backend-module-github/src/GitHubOrgEntityProvider.ts b/plugins/catalog-backend-module-github/src/providers/GitHubOrgEntityProvider.ts similarity index 99% rename from plugins/catalog-backend-module-github/src/GitHubOrgEntityProvider.ts rename to plugins/catalog-backend-module-github/src/providers/GitHubOrgEntityProvider.ts index e6cb413a6f..bb994c193c 100644 --- a/plugins/catalog-backend-module-github/src/GitHubOrgEntityProvider.ts +++ b/plugins/catalog-backend-module-github/src/providers/GitHubOrgEntityProvider.ts @@ -42,7 +42,7 @@ import { getOrganizationTeams, getOrganizationUsers, parseGitHubOrgUrl, -} from './lib'; +} from '../lib'; /** * Options for {@link GitHubOrgEntityProvider}. From 7a6007d808990814688b5f58759b34c70d77a06a Mon Sep 17 00:00:00 2001 From: brentg-telus <50498366+brentg-telus@users.noreply.github.com> Date: Mon, 25 Jul 2022 13:27:38 -0400 Subject: [PATCH 021/144] feat: github discovery provider Signed-off-by: brentg-telus <50498366+brentg-telus@users.noreply.github.com> --- .../src/processors/GithubDiscoveryProcessor.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/catalog-backend-module-github/src/processors/GithubDiscoveryProcessor.test.ts b/plugins/catalog-backend-module-github/src/processors/GithubDiscoveryProcessor.test.ts index aa6dc9229e..7ce6f3f9cf 100644 --- a/plugins/catalog-backend-module-github/src/processors/GithubDiscoveryProcessor.test.ts +++ b/plugins/catalog-backend-module-github/src/processors/GithubDiscoveryProcessor.test.ts @@ -24,7 +24,7 @@ import { LocationSpec } from '@backstage/plugin-catalog-backend'; import { GithubDiscoveryProcessor, parseUrl } from './GithubDiscoveryProcessor'; import { getOrganizationRepositories } from '../lib'; -jest.mock('./lib'); +jest.mock('../lib'); const mockGetOrganizationRepositories = getOrganizationRepositories as jest.MockedFunction< typeof getOrganizationRepositories From 9328f4b349332d9e580657c3475ea7699872af8c Mon Sep 17 00:00:00 2001 From: brentg-telus <50498366+brentg-telus@users.noreply.github.com> Date: Mon, 25 Jul 2022 13:34:54 -0400 Subject: [PATCH 022/144] feat: github discovery provider Signed-off-by: brentg-telus <50498366+brentg-telus@users.noreply.github.com> --- .../src/providers/GitHubEntityProvider.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/catalog-backend-module-github/src/providers/GitHubEntityProvider.test.ts b/plugins/catalog-backend-module-github/src/providers/GitHubEntityProvider.test.ts index f933053f4a..0bda258b6e 100644 --- a/plugins/catalog-backend-module-github/src/providers/GitHubEntityProvider.test.ts +++ b/plugins/catalog-backend-module-github/src/providers/GitHubEntityProvider.test.ts @@ -100,7 +100,7 @@ describe('GitHubEntityProvider', () => { ); }); - it.only('apply full update on scheduled execution', async () => { + it('apply full update on scheduled execution', async () => { const config = new ConfigReader({ catalog: { providers: { From ae09b7855161b0a70474e6134ef81ff9e9a9b141 Mon Sep 17 00:00:00 2001 From: brentg-telus <50498366+brentg-telus@users.noreply.github.com> Date: Mon, 25 Jul 2022 14:37:22 -0400 Subject: [PATCH 023/144] chore: requested update to docs Signed-off-by: brentg-telus <50498366+brentg-telus@users.noreply.github.com> --- docs/integrations/github/discovery.md | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/docs/integrations/github/discovery.md b/docs/integrations/github/discovery.md index 82abc25eca..dba0907492 100644 --- a/docs/integrations/github/discovery.md +++ b/docs/integrations/github/discovery.md @@ -19,7 +19,7 @@ catalog. This is the prefered method for ingesting entities into the catalog. You will have to add the provider in the catalog initialization code of your backend. They are not installed by default, therefore you have to add a dependency on `@backstage/plugin-catalog-backend-module-github` to your backend -package +package. ```bash # From your Backstage root directory @@ -76,31 +76,34 @@ catalog: repository: '.*' # optional Regex ``` -This provider supports multiple organizations via unique provider IDs +This provider supports multiple organizations via unique provider IDs. > **Note:** It is possible but certainly not recommended to skip the provider ID level. > If you do so, `default` will be used as provider ID. -- **catalogPath** _(optional)_: +``` +catalogPath (optional): Default: `/catalog-info.yaml`. Path where to look for `catalog-info.yaml` files. When started with `/`, it is an absolute path from the repo root. -- **filters** _(optional)_: - - **branch** _(optional)_: + +filters (optional): + - branch (optional): String used to filter results based on the branch name. - - **repository** _(optional)_: + - repository (optional): Regular expression used to filter results based on the repository name. -- **organization**: + +organization: Name of your organization account/workspace. If you want to add multiple organizations, you need to add one provider config each. +``` ## GitHub API Rate Limits GitHub [rate limits](https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting) API requests to 5,000 per hour (or more for Enterprise -accounts). The default Backstage catalog backend refreshes data every 100 -seconds, which issues an API request for each discovered location. +accounts). The snippet below refreshes the Backstage catalog data every 35 minutes, which issues an API request for each discovered location. -This means if you have more than ~140 catalog entities, you may get throttled by +If your requests are too frequent then you may get throttled by rate limiting. You can change the refresh frequency of the catalog in your `packages/backend/src/plugins/catalog.ts` file: ```typescript From 1c7e940b39053300f9dc689e9d24c603e1a7c8b3 Mon Sep 17 00:00:00 2001 From: brentg-telus <50498366+brentg-telus@users.noreply.github.com> Date: Tue, 26 Jul 2022 08:31:51 -0400 Subject: [PATCH 024/144] chore: requested update to docs Signed-off-by: brentg-telus <50498366+brentg-telus@users.noreply.github.com> --- docs/integrations/github/discovery.md | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/docs/integrations/github/discovery.md b/docs/integrations/github/discovery.md index dba0907492..3b49644613 100644 --- a/docs/integrations/github/discovery.md +++ b/docs/integrations/github/discovery.md @@ -81,22 +81,18 @@ This provider supports multiple organizations via unique provider IDs. > **Note:** It is possible but certainly not recommended to skip the provider ID level. > If you do so, `default` will be used as provider ID. -``` -catalogPath (optional): +- **`catalogPath`** _(optional)_: Default: `/catalog-info.yaml`. Path where to look for `catalog-info.yaml` files. When started with `/`, it is an absolute path from the repo root. - -filters (optional): - - branch (optional): +- **filters** _(optional)_: + - **branch** _(optional)_: String used to filter results based on the branch name. - - repository (optional): + - **repository** _(optional)_: Regular expression used to filter results based on the repository name. - -organization: +- **organization**: Name of your organization account/workspace. If you want to add multiple organizations, you need to add one provider config each. -``` ## GitHub API Rate Limits From ad35364e971bf21d26e7b8ec3d74a00323996268 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20Do=C4=9Fan?= <8117265+omerfarukdogan@users.noreply.github.com> Date: Wed, 27 Jul 2022 18:31:13 +0300 Subject: [PATCH 025/144] feat(techdocs): add edit button support for bitbucketServer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ömer Faruk Doğan <8117265+omerfarukdogan@users.noreply.github.com> --- .changeset/red-turtles-melt.md | 7 +++ packages/integration/src/ScmIntegrations.ts | 16 ++++++- .../BitbucketServerIntegration.test.ts | 47 +++++++++++++++---- .../BitbucketServerIntegration.ts | 21 ++++----- .../src/ReportIssue/ReportIssue.tsx | 7 ++- .../src/stages/generate/helpers.ts | 7 ++- 6 files changed, 77 insertions(+), 28 deletions(-) create mode 100644 .changeset/red-turtles-melt.md diff --git a/.changeset/red-turtles-melt.md b/.changeset/red-turtles-melt.md new file mode 100644 index 0000000000..436e69116c --- /dev/null +++ b/.changeset/red-turtles-melt.md @@ -0,0 +1,7 @@ +--- +'@backstage/integration': minor +'@backstage/plugin-techdocs-node': minor +'@backstage/plugin-techdocs-module-addons-contrib': patch +--- + +feat(techdocs): add edit button support for bitbucketServer diff --git a/packages/integration/src/ScmIntegrations.ts b/packages/integration/src/ScmIntegrations.ts index 3e712cc012..6d745dcf1c 100644 --- a/packages/integration/src/ScmIntegrations.ts +++ b/packages/integration/src/ScmIntegrations.ts @@ -113,9 +113,21 @@ export class ScmIntegrations implements ScmIntegrationRegistry { } byUrl(url: string | URL): ScmIntegration | undefined { - return Object.values(this.byType) + let candidates = Object.values(this.byType) .map(i => i.byUrl(url)) - .find(Boolean); + .filter(Boolean); + + // Do not return deprecated integrations if there are other options + if (candidates.length > 1) { + const filteredCandidates = candidates.filter( + x => !(x instanceof BitbucketIntegration), + ); + if (filteredCandidates.length !== 0) { + candidates = filteredCandidates; + } + } + + return candidates[0]; } byHost(host: string): ScmIntegration | undefined { diff --git a/packages/integration/src/bitbucketServer/BitbucketServerIntegration.test.ts b/packages/integration/src/bitbucketServer/BitbucketServerIntegration.test.ts index 24d7935e72..00b5e21316 100644 --- a/packages/integration/src/bitbucketServer/BitbucketServerIntegration.test.ts +++ b/packages/integration/src/bitbucketServer/BitbucketServerIntegration.test.ts @@ -44,31 +44,58 @@ describe('BitbucketServerIntegration', () => { expect(integration.title).toBe('h.com'); }); - it('resolves url line number correctly', () => { + it('resolves url', () => { const integration = new BitbucketServerIntegration({ host: 'h.com', } as any); expect( integration.resolveUrl({ - url: './a.yaml', - base: 'https://h.com/my-owner/my-project/src/master/README.md', - lineNumber: 14, + url: './README.md', + base: 'https://h.com/projects/my-project/repos/my-repo/browse/?at=master', }), - ).toBe('https://h.com/my-owner/my-project/src/master/a.yaml#a.yaml-14'); + ).toBe( + 'https://h.com/projects/my-project/repos/my-repo/browse/README.md?at=master', + ); }); - it('resolve edit URL', () => { + it('resolves url with line number', () => { + const integration = new BitbucketServerIntegration({ + host: 'h.com', + } as any); + + expect( + integration.resolveUrl({ + url: './README.md', + base: 'https://h.com/projects/my-project/repos/my-repo/browse/?at=master', + lineNumber: 14, + }), + ).toBe( + 'https://h.com/projects/my-project/repos/my-repo/browse/README.md?at=master#14', + ); + }); + + it('resolves edit url', () => { const integration = new BitbucketServerIntegration({ host: 'h.com', } as any); expect( integration.resolveEditUrl( - 'https://h.com/my-owner/my-project/src/master/README.md', + 'https://h.com/projects/my-project/repos/my-repo/browse/README.md', ), - ).toBe( - 'https://h.com/my-owner/my-project/src/master/README.md?mode=edit&spa=0&at=master', - ); + ).toBe('https://h.com/projects/my-project/repos/my-repo/browse/README.md'); + }); + + it('resolves edit url with query params', () => { + const integration = new BitbucketServerIntegration({ + host: 'h.com', + } as any); + + expect( + integration.resolveEditUrl( + 'https://h.com/projects/my-project/repos/my-repo/browse/README.md?at=master', + ), + ).toBe('https://h.com/projects/my-project/repos/my-repo/browse/README.md'); }); }); diff --git a/packages/integration/src/bitbucketServer/BitbucketServerIntegration.ts b/packages/integration/src/bitbucketServer/BitbucketServerIntegration.ts index 10055aeddc..01886e16bc 100644 --- a/packages/integration/src/bitbucketServer/BitbucketServerIntegration.ts +++ b/packages/integration/src/bitbucketServer/BitbucketServerIntegration.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import parseGitUrl from 'git-url-parse'; import { basicIntegrations, defaultScmResolveUrl } from '../helpers'; import { ScmIntegration, ScmIntegrationsFactory } from '../types'; import { @@ -63,12 +62,11 @@ export class BitbucketServerIntegration implements ScmIntegration { }): string { const resolved = defaultScmResolveUrl(options); - // Bitbucket Server line numbers use the syntax #example.txt-42, rather than #L42 + // Bitbucket Server line numbers use the syntax #42, rather than #L42 if (options.lineNumber) { const url = new URL(resolved); - const filename = url.pathname.split('/').slice(-1)[0]; - url.hash = `${filename}-${options.lineNumber}`; + url.hash = options.lineNumber.toString(); return url.toString(); } @@ -76,14 +74,11 @@ export class BitbucketServerIntegration implements ScmIntegration { } resolveEditUrl(url: string): string { - const urlData = parseGitUrl(url); - const editUrl = new URL(url); - - editUrl.searchParams.set('mode', 'edit'); - // TODO: Not sure what spa=0 does, at least bitbucket.org doesn't support it - // but this is taken over from the initial implementation. - editUrl.searchParams.set('spa', '0'); - editUrl.searchParams.set('at', urlData.ref); - return editUrl.toString(); + // Bitbucket Server doesn't support deep linking to edit mode, therefore there's nothing to do here. + // We just remove query parameters since they cause issues with TechDocs edit button. + if (url.includes('?')) { + return url.substring(0, url.indexOf('?')); + } + return url; } } diff --git a/plugins/techdocs-module-addons-contrib/src/ReportIssue/ReportIssue.tsx b/plugins/techdocs-module-addons-contrib/src/ReportIssue/ReportIssue.tsx index c8caa5ddbc..c81eacb1ee 100644 --- a/plugins/techdocs-module-addons-contrib/src/ReportIssue/ReportIssue.tsx +++ b/plugins/techdocs-module-addons-contrib/src/ReportIssue/ReportIssue.tsx @@ -118,7 +118,12 @@ export const ReportIssueAddon = ({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [selection, mainContent, feedbackContainer]); - if (!selection || !repository) return null; + if ( + !selection || + !repository || + !['github', 'gitlab'].includes(repository.type) + ) + return null; if (!feedbackContainer) { feedbackContainer = document.createElement('div'); diff --git a/plugins/techdocs-node/src/stages/generate/helpers.ts b/plugins/techdocs-node/src/stages/generate/helpers.ts index e1a79ecc19..50db0eb86a 100644 --- a/plugins/techdocs-node/src/stages/generate/helpers.ts +++ b/plugins/techdocs-node/src/stages/generate/helpers.ts @@ -101,9 +101,12 @@ export const getRepoUrlFromLocationAnnotation = ( if (locationType === 'url') { const integration = scmIntegrations.byUrl(target); - // We only support it for github and gitlab for now as the edit_uri + // We only support it for github, gitlab and bitbucketServer for now as the edit_uri // is not properly supported for others yet. - if (integration && ['github', 'gitlab'].includes(integration.type)) { + if ( + integration && + ['github', 'gitlab', 'bitbucketServer'].includes(integration.type) + ) { // handle the case where a user manually writes url:https://github.com/backstage/backstage i.e. without /blob/... const { filepathtype } = gitUrlParse(target); if (filepathtype === '') { From 8acb22205c3dcc84404c6de8d3eb15ed9d5a1d84 Mon Sep 17 00:00:00 2001 From: Crevil Date: Thu, 28 Jul 2022 08:01:29 +0200 Subject: [PATCH 026/144] Add navigation scroll to techdocs Currently the active navigation item might be hidden behind nested items or out of view on load. This change adds a techdocs transformer that scrolls any active item into view and expands any nested active items. Signed-off-by: Crevil --- .changeset/rich-readers-return.md | 5 ++ .../TechDocsReaderPageContent/dom.tsx | 2 + .../techdocs/src/reader/transformers/index.ts | 1 + .../transformers/scrollIntoNavigation.test.ts | 80 +++++++++++++++++++ .../transformers/scrollIntoNavigation.ts | 34 ++++++++ 5 files changed, 122 insertions(+) create mode 100644 .changeset/rich-readers-return.md create mode 100644 plugins/techdocs/src/reader/transformers/scrollIntoNavigation.test.ts create mode 100644 plugins/techdocs/src/reader/transformers/scrollIntoNavigation.ts diff --git a/.changeset/rich-readers-return.md b/.changeset/rich-readers-return.md new file mode 100644 index 0000000000..3c8f3d7b5a --- /dev/null +++ b/.changeset/rich-readers-return.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs': patch +--- + +Scroll techdocs navigation into focus and expand any nested navigation items. diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/dom.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/dom.tsx index 76b07c9d32..98bd6d867c 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/dom.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/dom.tsx @@ -41,6 +41,7 @@ import { rewriteDocLinks, simplifyMkdocsFooter, scrollIntoAnchor, + scrollIntoNavigation, transform as transformer, copyToClipboard, useSanitizerTransformer, @@ -166,6 +167,7 @@ export const useTechDocsReaderDom = ( async (transformedElement: Element) => transformer(transformedElement, [ scrollIntoAnchor(), + scrollIntoNavigation(), copyToClipboard(theme), addLinkClickListener({ baseUrl: window.location.origin, diff --git a/plugins/techdocs/src/reader/transformers/index.ts b/plugins/techdocs/src/reader/transformers/index.ts index dc3c43a584..ca17261572 100644 --- a/plugins/techdocs/src/reader/transformers/index.ts +++ b/plugins/techdocs/src/reader/transformers/index.ts @@ -26,4 +26,5 @@ export * from './removeMkdocsHeader'; export * from './simplifyMkdocsFooter'; export * from './onCssReady'; export * from './scrollIntoAnchor'; +export * from './scrollIntoNavigation'; export * from './transformer'; diff --git a/plugins/techdocs/src/reader/transformers/scrollIntoNavigation.test.ts b/plugins/techdocs/src/reader/transformers/scrollIntoNavigation.test.ts new file mode 100644 index 0000000000..ca8cf04b5e --- /dev/null +++ b/plugins/techdocs/src/reader/transformers/scrollIntoNavigation.test.ts @@ -0,0 +1,80 @@ +/* + * 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 { scrollIntoNavigation } from '.'; + +jest.useFakeTimers(); + +describe('scrollIntoNavigation', () => { + const transformer = scrollIntoNavigation(); + const dom = { querySelectorAll: jest.fn().mockReturnValue([]) }; + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('scroll to active navigation item', async () => { + const scrollNavIntoView1 = jest.fn(); + const scrollNavIntoView2 = jest.fn(); + + dom.querySelectorAll.mockReturnValue([ + { + scrollIntoView: scrollNavIntoView1, + querySelector: jest.fn(), + click: jest.fn(), + }, + { + scrollIntoView: scrollNavIntoView2, + querySelector: jest.fn(), + click: jest.fn(), + }, + ]); + + transformer(dom as unknown as Element); + jest.advanceTimersByTime(200); + + expect(dom.querySelectorAll).toHaveBeenCalledWith( + expect.stringMatching('li.md-nav__item--active'), + ); + expect(scrollNavIntoView1).not.toHaveBeenCalled(); + expect(scrollNavIntoView2).toHaveBeenCalledWith(); + }); + + it('expand active navigation items', async () => { + const navItemClick1 = jest.fn(); + const navItemClick2 = jest.fn(); + + dom.querySelectorAll.mockReturnValue([ + { + scrollIntoView: jest.fn(), + querySelector: jest.fn().mockReturnValue({ click: navItemClick1 }), + }, + { + scrollIntoView: jest.fn(), + querySelector: jest.fn().mockReturnValue({ click: navItemClick2 }), + }, + ]); + + transformer(dom as unknown as Element); + jest.advanceTimersByTime(200); + + expect(dom.querySelectorAll).toHaveBeenCalledWith( + expect.stringMatching('li.md-nav__item--active'), + ); + expect(navItemClick1).toHaveBeenCalledWith(); + expect(navItemClick2).toHaveBeenCalledWith(); + }); +}); diff --git a/plugins/techdocs/src/reader/transformers/scrollIntoNavigation.ts b/plugins/techdocs/src/reader/transformers/scrollIntoNavigation.ts new file mode 100644 index 0000000000..ff6901686a --- /dev/null +++ b/plugins/techdocs/src/reader/transformers/scrollIntoNavigation.ts @@ -0,0 +1,34 @@ +/* + * 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 type { Transformer } from './transformer'; + +export const scrollIntoNavigation = (): Transformer => { + return dom => { + setTimeout(() => { + const activeNavItems = dom?.querySelectorAll(`li.md-nav__item--active`); + if (activeNavItems.length !== 0) { + // expand all navigation items that are active + activeNavItems.forEach(activeNavItem => { + activeNavItem?.querySelector('input')?.click(); + }); + // scroll to the last active navigation item + activeNavItems[activeNavItems.length - 1].scrollIntoView(); + } + }, 200); + return dom; + }; +}; From c9c6bf39326e7c4168502c0f84a4abd17f69f91d Mon Sep 17 00:00:00 2001 From: Kamil Wolny Date: Thu, 28 Jul 2022 14:35:54 +0100 Subject: [PATCH 027/144] feat: github issues plugin mvp Signed-off-by: Kamil Wolny --- packages/app/package.json | 1 + packages/app/src/App.tsx | 2 + .../app/src/components/catalog/EntityPage.tsx | 18 + plugins/github-issues/.eslintrc.js | 1 + plugins/github-issues/README.md | 13 + plugins/github-issues/dev/index.tsx | 27 ++ plugins/github-issues/package.json | 60 +++ .../GitHubIssues/GitHubIssues.test.tsx | 49 +++ .../components/GitHubIssues/GitHubIssues.tsx | 150 +++++++ .../GitHubIssues/IssueCard/Assignees.tsx | 61 +++ .../GitHubIssues/IssueCard/CommentsCount.tsx | 40 ++ .../GitHubIssues/IssueCard/IssueCard.tsx | 93 +++++ .../GitHubIssues/IssueCard/index.ts | 16 + .../IssuesList/Filters/Filters.tsx | 64 +++ .../GitHubIssues/IssuesList/Filters/index.ts | 16 + .../GitHubIssues/IssuesList/IssuesList.tsx | 101 +++++ .../GitHubIssues/IssuesList/index.tsx | 16 + .../NoRepositoriesInfo/NoRepositoriesInfo.tsx | 27 ++ .../GitHubIssues/NoRepositoriesInfo/index.tsx | 16 + .../src/components/GitHubIssues/index.ts | 16 + .../GitHubIssuesCard/GitHubIssuesCard.tsx | 24 ++ .../src/components/GitHubIssuesCard/index.ts | 16 + .../GitHubIssuesPage/GitHubIssuesPage.tsx | 23 ++ .../src/components/GitHubIssuesPage/index.ts | 16 + .../src/hooks/useEntityGitHubRepositories.ts | 69 ++++ .../useGetIssuesBeRepoFromGitHub.test.tsx | 105 +++++ .../src/hooks/useGetIssuesByRepoFromGitHub.ts | 177 ++++++++ .../src/hooks/useGitHubIssues.ts | 21 + .../src/hooks/useOctokitGraphQL.ts | 47 +++ plugins/github-issues/src/index.ts | 20 + plugins/github-issues/src/plugin.test.ts | 22 + plugins/github-issues/src/plugin.ts | 48 +++ plugins/github-issues/src/routes.ts | 20 + plugins/github-issues/src/setupTests.ts | 17 + yarn.lock | 378 +++++++++++++++++- 35 files changed, 1770 insertions(+), 20 deletions(-) create mode 100644 plugins/github-issues/.eslintrc.js create mode 100644 plugins/github-issues/README.md create mode 100644 plugins/github-issues/dev/index.tsx create mode 100644 plugins/github-issues/package.json create mode 100644 plugins/github-issues/src/components/GitHubIssues/GitHubIssues.test.tsx create mode 100644 plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx create mode 100644 plugins/github-issues/src/components/GitHubIssues/IssueCard/Assignees.tsx create mode 100644 plugins/github-issues/src/components/GitHubIssues/IssueCard/CommentsCount.tsx create mode 100644 plugins/github-issues/src/components/GitHubIssues/IssueCard/IssueCard.tsx create mode 100644 plugins/github-issues/src/components/GitHubIssues/IssueCard/index.ts create mode 100644 plugins/github-issues/src/components/GitHubIssues/IssuesList/Filters/Filters.tsx create mode 100644 plugins/github-issues/src/components/GitHubIssues/IssuesList/Filters/index.ts create mode 100644 plugins/github-issues/src/components/GitHubIssues/IssuesList/IssuesList.tsx create mode 100644 plugins/github-issues/src/components/GitHubIssues/IssuesList/index.tsx create mode 100644 plugins/github-issues/src/components/GitHubIssues/NoRepositoriesInfo/NoRepositoriesInfo.tsx create mode 100644 plugins/github-issues/src/components/GitHubIssues/NoRepositoriesInfo/index.tsx create mode 100644 plugins/github-issues/src/components/GitHubIssues/index.ts create mode 100644 plugins/github-issues/src/components/GitHubIssuesCard/GitHubIssuesCard.tsx create mode 100644 plugins/github-issues/src/components/GitHubIssuesCard/index.ts create mode 100644 plugins/github-issues/src/components/GitHubIssuesPage/GitHubIssuesPage.tsx create mode 100644 plugins/github-issues/src/components/GitHubIssuesPage/index.ts create mode 100644 plugins/github-issues/src/hooks/useEntityGitHubRepositories.ts create mode 100644 plugins/github-issues/src/hooks/useGetIssuesBeRepoFromGitHub.test.tsx create mode 100644 plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts create mode 100644 plugins/github-issues/src/hooks/useGitHubIssues.ts create mode 100644 plugins/github-issues/src/hooks/useOctokitGraphQL.ts create mode 100644 plugins/github-issues/src/index.ts create mode 100644 plugins/github-issues/src/plugin.test.ts create mode 100644 plugins/github-issues/src/plugin.ts create mode 100644 plugins/github-issues/src/routes.ts create mode 100644 plugins/github-issues/src/setupTests.ts diff --git a/packages/app/package.json b/packages/app/package.json index 738dbc2246..d1ab52a6a8 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -33,6 +33,7 @@ "@backstage/plugin-gcalendar": "^0.3.4-next.0", "@backstage/plugin-gcp-projects": "^0.3.27-next.0", "@backstage/plugin-github-actions": "^0.5.8-next.0", + "@backstage/plugin-github-issues": "^0.0.0", "@backstage/plugin-gocd": "^0.1.14-next.0", "@backstage/plugin-graphiql": "^0.2.40-next.0", "@backstage/plugin-home": "^0.4.24-next.0", diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index 289af8d40f..bc1d86b650 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -100,6 +100,7 @@ import { techDocsPage } from './components/techdocs/TechDocsPage'; import { ApacheAirflowPage } from '@backstage/plugin-apache-airflow'; import { PermissionedRoute } from '@backstage/plugin-permission-react'; import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common'; +import { GitHubIssuesPage } from '@backstage/plugin-github-issues'; const app = createApp({ apis, @@ -241,6 +242,7 @@ const routes = ( } /> } /> + } /> ); diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx index 288196266e..166157a2bc 100644 --- a/packages/app/src/components/catalog/EntityPage.tsx +++ b/packages/app/src/components/catalog/EntityPage.tsx @@ -150,6 +150,11 @@ import { ReportIssue, } from '@backstage/plugin-techdocs-module-addons-contrib'; +import { + GitHubIssuesCard, + GitHubIssuesPage, +} from '@backstage/plugin-github-issues'; + const customEntityFilterKind = ['Component', 'API', 'System']; const EntityLayoutWrapper = (props: { children?: ReactNode }) => { @@ -325,6 +330,10 @@ const overviewContent = ( + + + + @@ -624,6 +633,9 @@ const userPage = ( entityFilterKind={customEntityFilterKind} /> + + + @@ -646,8 +658,14 @@ const groupPage = ( + + + + + + ); diff --git a/plugins/github-issues/.eslintrc.js b/plugins/github-issues/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/github-issues/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/github-issues/README.md b/plugins/github-issues/README.md new file mode 100644 index 0000000000..65757bef00 --- /dev/null +++ b/plugins/github-issues/README.md @@ -0,0 +1,13 @@ +# github-issues + +Welcome to the github-issues plugin! + +_This plugin was created through the Backstage CLI_ + +## Getting started + +Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn start` in the root directory, and then navigating to [/github-issues](http://localhost:3000/github-issues). + +You can also serve the plugin in isolation by running `yarn start` in the plugin directory. +This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads. +It is only meant for local development, and the setup for it can be found inside the [/dev](./dev) directory. diff --git a/plugins/github-issues/dev/index.tsx b/plugins/github-issues/dev/index.tsx new file mode 100644 index 0000000000..4de5a78b2f --- /dev/null +++ b/plugins/github-issues/dev/index.tsx @@ -0,0 +1,27 @@ +/* + * 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 { createDevApp } from '@backstage/dev-utils'; +import { gitHubIssuesPlugin, GitHubIssuesPage } from '../src/plugin'; + +createDevApp() + .registerPlugin(gitHubIssuesPlugin) + .addPage({ + element: , + title: 'Root Page', + path: '/github-issues', + }) + .render(); diff --git a/plugins/github-issues/package.json b/plugins/github-issues/package.json new file mode 100644 index 0000000000..ab2f7b914e --- /dev/null +++ b/plugins/github-issues/package.json @@ -0,0 +1,60 @@ +{ + "name": "@backstage/plugin-github-issues", + "version": "0.0.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "main": "dist/index.esm.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "frontend-plugin" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "prettier": "@spotify/prettier-config", + "dependencies": { + "@backstage/catalog-model": "^1.0.3", + "@backstage/core-components": "^0.9.5", + "@backstage/core-plugin-api": "^1.0.3", + "@backstage/integration": "^1.2.1", + "@backstage/plugin-catalog-react": "^1.1.1", + "@backstage/theme": "^0.2.15", + "@material-ui/core": "^4.12.4", + "@material-ui/icons": "^4.9.1", + "@material-ui/lab": "^4.0.0-alpha.61", + "@octokit/rest": "^18.12.0", + "luxon": "^2.4.0", + "react-use": "^17.2.4" + }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, + "devDependencies": { + "@backstage/cli": "^0.17.2", + "@backstage/core-app-api": "^1.0.3", + "@backstage/dev-utils": "^1.0.3", + "@backstage/test-utils": "^1.1.1", + "@spotify/prettier-config": "^13.0.1", + "@testing-library/jest-dom": "^5.10.1", + "@testing-library/react": "^12.1.3", + "@testing-library/user-event": "^14.0.0", + "@types/jest": "*", + "@types/node": "*", + "cross-fetch": "^3.1.5", + "msw": "^0.42.0", + "prettier": "^2.7.1" + }, + "files": [ + "dist" + ] +} 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..ebb9c78f19 --- /dev/null +++ b/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.test.tsx @@ -0,0 +1,49 @@ +/* + * 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 { GitHubIssues } from './GitHubIssues'; +import { ThemeProvider } from '@material-ui/core'; +import { lightTheme } from '@backstage/theme'; +import { rest } from 'msw'; +import { setupServer } from 'msw/node'; +import { + setupRequestMockHandlers, + renderInTestApp, +} from '@backstage/test-utils'; + +// test for repo duplicates + +describe('GitHubIssues', () => { + const server = setupServer(); + // Enable sane handlers for network requests + setupRequestMockHandlers(server); + + // setup mock response + beforeEach(() => { + server.use( + rest.get('/*', (_, res, ctx) => res(ctx.status(200), ctx.json({}))), + ); + }); + + it('should render', async () => { + const rendered = await renderInTestApp( + + + , + ); + expect(rendered.getByText('Welcome to github-issues!')).toBeInTheDocument(); + }); +}); diff --git a/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx b/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx new file mode 100644 index 0000000000..da31869000 --- /dev/null +++ b/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx @@ -0,0 +1,150 @@ +/* + * 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 { Box, IconButton, Typography } from '@material-ui/core'; +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 { IssueList } from './IssuesList'; +import { NoRepositoriesInfo } from './NoRepositoriesInfo'; + +export type PluginMode = 'page' | 'card'; + +export type Props = { + mode: PluginMode; + itemsPerPage?: number; + itemsPerRepo?: number; +}; + +export const GitHubIssues = ({ + itemsPerPage = 10, + itemsPerRepo = 40, +}: Props) => { + const [isLoading, setIsLoading] = React.useState(true); + const [activeFilter, setActiveFilter] = React.useState>([]); + + const [issuesByRepository, setIssuesByRepository] = + React.useState>(); + + const { repositories } = useEntityGitHubRepositories(); + const getIssues = useGetIssuesByRepoFromGitHub(); + + const filters = React.useMemo( + () => + issuesByRepository + ? Object.keys(issuesByRepository) + .filter(repo => issuesByRepository[repo].issues.totalCount > 0) + .map(repo => ({ + label: `${repo} (${issuesByRepository[repo].issues.totalCount})`, + value: repo, + })) + : [], + [issuesByRepository], + ); + + const totalIssuesInGitHub = React.useMemo( + () => + issuesByRepository + ? Object.values(issuesByRepository).reduce( + (acc, { issues: { totalCount } }) => acc + totalCount, + 0, + ) + : 0, + [issuesByRepository], + ); + + const filteredRepos = React.useMemo( + () => + issuesByRepository && activeFilter.length + ? activeFilter.reduce( + (acc, val) => ({ + [val]: issuesByRepository[val], + ...acc, + }), + {}, + ) + : issuesByRepository, + [issuesByRepository, activeFilter], + ); + + const issues = React.useMemo( + () => + filteredRepos + ? Object.values(filteredRepos) + .map(({ issues: { edges } }) => edges) + .flat() + .sort((a, b) => { + if (a.node.updatedAt > b.node.updatedAt) { + return -1; + } else if (b.node.updatedAt > a.node.updatedAt) { + return 1; + } + return 0; + }) + : [], + [filteredRepos], + ); + + 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]); + + if (!repositories.length) { + return ; + } + + return ( + + Open GitHub Issues + + + + + } + > + {isLoading && } + + + + ); +}; diff --git a/plugins/github-issues/src/components/GitHubIssues/IssueCard/Assignees.tsx b/plugins/github-issues/src/components/GitHubIssues/IssueCard/Assignees.tsx new file mode 100644 index 0000000000..e6abdbb6fe --- /dev/null +++ b/plugins/github-issues/src/components/GitHubIssues/IssueCard/Assignees.tsx @@ -0,0 +1,61 @@ +/* + * 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, { FunctionComponent } from 'react'; +import { Typography, Box, Avatar, makeStyles } from '@material-ui/core'; + +type Props = { + name?: string; + avatar?: string; +}; + +const useStyles = makeStyles(theme => ({ + small: { + width: theme.spacing(4), + height: theme.spacing(4), + marginLeft: theme.spacing(1), + }, + noAssignees: { + height: theme.spacing(4), + }, +})); + +export const Assignees: FunctionComponent = (props: Props) => { + const { name, avatar } = props; + const classes = useStyles(); + + // todo: many assignees -> NUM assignees + stock images on each other + return name ? ( + + + {name} + + + + ) : ( + + + No assignees + + + ); +}; + +export default Assignees; diff --git a/plugins/github-issues/src/components/GitHubIssues/IssueCard/CommentsCount.tsx b/plugins/github-issues/src/components/GitHubIssues/IssueCard/CommentsCount.tsx new file mode 100644 index 0000000000..d3e7f355e0 --- /dev/null +++ b/plugins/github-issues/src/components/GitHubIssues/IssueCard/CommentsCount.tsx @@ -0,0 +1,40 @@ +/* + * 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, { FunctionComponent } from 'react'; +import { ChatIcon } from '@backstage/core-components'; +import { Box, Badge } from '@material-ui/core'; + +type Props = { + commentsCount: number; +}; + +export const CommentsCount: FunctionComponent = (props: Props) => { + const { commentsCount } = props; + + return ( + + + + + + ); +}; diff --git a/plugins/github-issues/src/components/GitHubIssues/IssueCard/IssueCard.tsx b/plugins/github-issues/src/components/GitHubIssues/IssueCard/IssueCard.tsx new file mode 100644 index 0000000000..73010d50c9 --- /dev/null +++ b/plugins/github-issues/src/components/GitHubIssues/IssueCard/IssueCard.tsx @@ -0,0 +1,93 @@ +/* + * 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, { FunctionComponent } from 'react'; +import { DateTime } from 'luxon'; + +import { Box, Paper, Typography, CardActionArea } from '@material-ui/core'; +import Assignees from './Assignees'; +import { CommentsCount } from './CommentsCount'; + +import Divider from '@material-ui/core/Divider'; + +type Props = { + title: string; + createdAt: string; + updatedAt?: string; + url: string; + authorName: string; + assigneeName?: string; + assigneeAvatar?: string; + authorAvatar?: string; + repositoryName: string; + commentsCount: number; + even: boolean; +}; + +const getElapsedTime = (isoDate: string) => + DateTime.fromISO(isoDate).toRelative(); + +export const IssueCard: FunctionComponent = (props: Props) => { + const { + title, + createdAt, + updatedAt, + url, + assigneeName, + assigneeAvatar, + authorName, + repositoryName, + commentsCount, + } = props; + + return ( + + + + + + + {repositoryName} + + + + + + {title} + + + + + + + Created at: {getElapsedTime(createdAt)} by{' '} + {authorName} + + {updatedAt && ( + + Last update at: {getElapsedTime(updatedAt)} + + )} + + {commentsCount > 0 && ( + + )} + + + + + + ); +}; diff --git a/plugins/github-issues/src/components/GitHubIssues/IssueCard/index.ts b/plugins/github-issues/src/components/GitHubIssues/IssueCard/index.ts new file mode 100644 index 0000000000..5c60abf6ab --- /dev/null +++ b/plugins/github-issues/src/components/GitHubIssues/IssueCard/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 { IssueCard } from './IssueCard'; diff --git a/plugins/github-issues/src/components/GitHubIssues/IssuesList/Filters/Filters.tsx b/plugins/github-issues/src/components/GitHubIssues/IssuesList/Filters/Filters.tsx new file mode 100644 index 0000000000..7f654dd9e5 --- /dev/null +++ b/plugins/github-issues/src/components/GitHubIssues/IssuesList/Filters/Filters.tsx @@ -0,0 +1,64 @@ +/* + * 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 { Select } from '@backstage/core-components'; +import { SelectedItems } from '@backstage/core-components'; +import { makeStyles, Box } from '@material-ui/core'; + +export type FilterItem = { + label: string; + value: string; +}; + +type Props = { + items: Array; + totalIssuesInGitHub: number; + onChange: (active: Array) => void; +}; + +const useStyles = makeStyles(theme => ({ + filters: { + margin: theme.spacing(0, 0, 2, 0), + '& > div': { + width: '600px', + '& > div': { + maxWidth: '600px', + }, + }, + }, +})); + +const checkSelectedItems: ( + onChange: (active: Array) => void, +) => (active: SelectedItems) => void = onChange => active => { + return onChange(active as Array); +}; + +export const Filters = ({ items, totalIssuesInGitHub, onChange }: Props) => { + const css = useStyles(); + + return ( + + + + *Repositories with more Issues in GitHub than available to view in + Backstage. To view them go to GitHub. + ); }; diff --git a/plugins/github-issues/src/components/GitHubIssues/IssuesList/IssuesList.tsx b/plugins/github-issues/src/components/GitHubIssues/IssuesList/IssuesList.tsx index 152a888785..34ccab597d 100644 --- a/plugins/github-issues/src/components/GitHubIssues/IssuesList/IssuesList.tsx +++ b/plugins/github-issues/src/components/GitHubIssues/IssuesList/IssuesList.tsx @@ -19,29 +19,86 @@ import { Box } from '@material-ui/core'; import { Pagination } from '@material-ui/lab'; import { IssueCard } from '../IssueCard'; -import { Issue } from '../../../hooks/useGetIssuesByRepoFromGitHub'; -import { Filters, FilterItem } from './Filters'; +import { RepoIssues } from '../../../hooks/useGetIssuesByRepoFromGitHub'; +import { Filters } from './Filters'; export type PluginMode = 'page' | 'card'; export type Props = { itemsPerPage?: number; - issues: Array<{ - node: Issue; - }>; - filters: Array; - totalIssuesInGitHub: number; - setActiveFilter: (active: Array) => void; + issuesByRepository?: Record; }; -export const IssueList = ({ - itemsPerPage = 10, - issues, - filters, - setActiveFilter, - totalIssuesInGitHub, -}: Props) => { +const getIssuesCountForFilterLabel = ( + totalIssues: number, + issuesAvailable: number, +) => + `(${totalIssues} ${totalIssues === 1 ? 'Issue' : `Issues`})${ + issuesAvailable < totalIssues ? '*' : '' + }`; + +export const IssueList = ({ itemsPerPage = 10, issuesByRepository }: Props) => { const [currentPage, setCurrentPage] = React.useState(1); + const [activeFilter, setActiveFilter] = React.useState>([]); + + const filters = React.useMemo( + () => + issuesByRepository + ? Object.keys(issuesByRepository) + .filter(repo => issuesByRepository[repo].issues.totalCount > 0) + .map(repo => ({ + label: `${repo} ${getIssuesCountForFilterLabel( + issuesByRepository[repo].issues.totalCount, + issuesByRepository[repo].issues.edges.length, + )}`, + value: repo, + })) + : [], + [issuesByRepository], + ); + + const totalIssuesInGitHub = React.useMemo( + () => + issuesByRepository + ? Object.values(issuesByRepository).reduce( + (acc, { issues: { totalCount } }) => acc + totalCount, + 0, + ) + : 0, + [issuesByRepository], + ); + + const filteredRepos = React.useMemo( + () => + issuesByRepository && activeFilter.length + ? activeFilter.reduce( + (acc, val) => ({ + [val]: issuesByRepository[val], + ...acc, + }), + {}, + ) + : issuesByRepository, + [issuesByRepository, activeFilter], + ); + + const issues = React.useMemo( + () => + filteredRepos + ? Object.values(filteredRepos) + .map(({ issues: { edges } }) => edges) + .flat() + .sort((a, b) => { + if (a.node.updatedAt > b.node.updatedAt) { + return -1; + } else if (b.node.updatedAt > a.node.updatedAt) { + return 1; + } + return 0; + }) + : [], + [filteredRepos], + ); const displayIssues = issues.slice( (currentPage - 1) * itemsPerPage, @@ -50,11 +107,17 @@ export const IssueList = ({ return ( - + {issues.length > 0 && ( + + )} {displayIssues.length > 0 ? ( displayIssues.map( @@ -88,7 +151,7 @@ export const IssueList = ({ ), ) ) : ( -

No issues 🚀

+

Hurray! No Issues 🚀

)} {issues.length / itemsPerPage > 1 ? ( { const Helper = () => { const getIssues = useGetIssuesByRepoFromGitHub(); - getIssues(['mrwolny/yo-yo', 'mrwolny/yoyo'], 10); + getIssues(['mrwolny/yo-yo', 'mrwolny/yoyo', 'mrwolny/yo.yo'], 10); return
; }; render(); - expect(mockGraphQLQuery).toHaveBeenCalled(); + expect(mockGraphQLQuery).toHaveBeenCalledTimes(1); expect(mockGraphQLQuery).toHaveBeenCalledWith( '\n' + ' \n' + @@ -46,7 +46,6 @@ describe('useGetIssuesBeRepoFromGitHub', () => { ' ) {\n' + ' totalCount\n' + ' edges {\n' + - ' cursor\n' + ' node {\n' + ' assignees(first: 10) {\n' + ' edges {\n' + @@ -64,7 +63,6 @@ describe('useGetIssuesBeRepoFromGitHub', () => { ' repository {\n' + ' nameWithOwner\n' + ' }\n' + - ' body\n' + ' title\n' + ' url\n' + ' participants {\n' + @@ -90,6 +88,10 @@ describe('useGetIssuesBeRepoFromGitHub', () => { ' 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 c75bd495ec..271cd6c741 100644 --- a/plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts +++ b/plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts @@ -36,13 +36,11 @@ type IssueAuthor = { }; export type Issue = { - cursor: string; assignees: EdgesWithNodes; author: IssueAuthor; repository: { nameWithOwner: string; }; - body: string; title: string; url: string; participants: { @@ -80,7 +78,6 @@ const createQuery = ( ) { totalCount edges { - cursor node { assignees(first: 10) { edges { @@ -98,7 +95,6 @@ const createQuery = ( repository { nameWithOwner } - body title url participants { diff --git a/plugins/github-issues/src/hooks/useGitHubIssues.ts b/plugins/github-issues/src/hooks/useGitHubIssues.ts deleted file mode 100644 index ffe3ca20f1..0000000000 --- a/plugins/github-issues/src/hooks/useGitHubIssues.ts +++ /dev/null @@ -1,21 +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 { Issue } from './useGetIssuesByRepoFromGitHub'; - -export type GitHubIssues = { - getIssues: (repo?: string) => Array; - getIssuesTotalCountByRepo: () => Record; -}; From f9445b8d7b41996e655dae898c7eed21f19e3196 Mon Sep 17 00:00:00 2001 From: Kamil Wolny Date: Fri, 29 Jul 2022 14:51:32 +0100 Subject: [PATCH 080/144] feat: api report added Signed-off-by: Kamil Wolny --- plugins/github-issues/api-report.md | 34 +++++++++++++++++++++++++++++ plugins/github-issues/src/plugin.ts | 3 +++ 2 files changed, 37 insertions(+) create mode 100644 plugins/github-issues/api-report.md diff --git a/plugins/github-issues/api-report.md b/plugins/github-issues/api-report.md new file mode 100644 index 0000000000..5e6f75460d --- /dev/null +++ b/plugins/github-issues/api-report.md @@ -0,0 +1,34 @@ +## API Report File for "@backstage/plugin-github-issues" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +/// + +import { BackstagePlugin } from '@backstage/core-plugin-api'; +import { FunctionComponent } from 'react'; +import { RouteRef } from '@backstage/core-plugin-api'; + +// @public (undocumented) +export const GitHubIssuesCard: FunctionComponent<{ + itemsPerPage?: number | undefined; + itemsPerRepo?: number | undefined; +}>; + +// @public (undocumented) +export const GitHubIssuesPage: FunctionComponent<{ + itemsPerPage?: number | undefined; + itemsPerRepo?: number | undefined; +}>; + +// @public (undocumented) +export const gitHubIssuesPlugin: BackstagePlugin< + { + root: RouteRef; + }, + {}, + {} +>; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/github-issues/src/plugin.ts b/plugins/github-issues/src/plugin.ts index 60bae268c5..c5bf1cdbce 100644 --- a/plugins/github-issues/src/plugin.ts +++ b/plugins/github-issues/src/plugin.ts @@ -21,6 +21,7 @@ import { import { rootRouteRef } from './routes'; +/** @public */ export const gitHubIssuesPlugin = createPlugin({ id: 'github-issues', routes: { @@ -28,6 +29,7 @@ export const gitHubIssuesPlugin = createPlugin({ }, }); +/** @public */ export const GitHubIssuesCard = gitHubIssuesPlugin.provide( createComponentExtension({ name: 'GitHubIssuesCard', @@ -38,6 +40,7 @@ export const GitHubIssuesCard = gitHubIssuesPlugin.provide( }), ); +/** @public */ export const GitHubIssuesPage = gitHubIssuesPlugin.provide( createRoutableExtension({ name: 'GitHubIssuesPage', From 34f8a7acb395562b78db6f50eb12816f6dea2135 Mon Sep 17 00:00:00 2001 From: Kamil Wolny Date: Fri, 29 Jul 2022 15:27:25 +0100 Subject: [PATCH 081/144] feat: docs Signed-off-by: Kamil Wolny --- plugins/github-issues/README.md | 66 +++++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 8 deletions(-) diff --git a/plugins/github-issues/README.md b/plugins/github-issues/README.md index 65757bef00..eeb93ab27b 100644 --- a/plugins/github-issues/README.md +++ b/plugins/github-issues/README.md @@ -1,13 +1,63 @@ -# github-issues +# GitHub Issues plugin -Welcome to the github-issues plugin! +Welcome to the GitHub Issues plugin! -_This plugin was created through the Backstage CLI_ +Based on the [well-known GitHub slug annotation](https://backstage.io/docs/features/software-catalog/well-known-annotations#githubcomproject-slug) associated with the Entity, it renders the list of Open issues in GitHub. -## Getting started +The plugin is designed to work with four Entity kinds, and it behaves a bit differently depending on that kind: -Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn start` in the root directory, and then navigating to [/github-issues](http://localhost:3000/github-issues). +- Kind: Group/User: plugin renders issues from all repositories for which the Entity is the owner. +- Kind: API/Component: plugin renders issues from only one repository assigned to the Entity -You can also serve the plugin in isolation by running `yarn start` in the plugin directory. -This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads. -It is only meant for local development, and the setup for it can be found inside the [/dev](./dev) directory. +**Issues are sorted from the recently updated DESC order (the plugin might not render all issues from a single repo next to each other).** + +## Prerequisites + +- [GitHub Authentication Provider](https://backstage.io/docs/auth/github/provider) + +## Usage + +Install the plugin by running the following command **from your Backstage root directory** + +`yarn --cwd packages/app add @backstage/plugin-github-issues` + +After installation, the plugin can be used as a Card or as a Page. + +```typescript +import { + GitHubIssuesCard, + GitHubIssuesPage, +} from '@backstage/plugin-github-issues'; + +// To use as a page Plugin needs to be wrapped in EntityLayout.Route +const RenderGitHubIssuesPage = () => ( + + + + + + + +); + +// To use as a card and make it render correctly please place it inside appropriate Grid elements +const RenderGitHubIssuesCard = () => ( + + + + + + + + + +); +``` + +## Configuration + +Both `GitHubIssuesPage` and `GitHubIssuesCard` provide default configuration. It is ready to use out of the box. +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 From ecabc7a35ed457831763762d47184bd93a8272c4 Mon Sep 17 00:00:00 2001 From: Kamil Wolny Date: Fri, 29 Jul 2022 15:32:48 +0100 Subject: [PATCH 082/144] feat: removed local changes to package/app Signed-off-by: Kamil Wolny --- packages/app/package.json | 1 - packages/app/src/App.tsx | 2 -- .../app/src/components/catalog/EntityPage.tsx | 18 ------------------ 3 files changed, 21 deletions(-) diff --git a/packages/app/package.json b/packages/app/package.json index d1ab52a6a8..738dbc2246 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -33,7 +33,6 @@ "@backstage/plugin-gcalendar": "^0.3.4-next.0", "@backstage/plugin-gcp-projects": "^0.3.27-next.0", "@backstage/plugin-github-actions": "^0.5.8-next.0", - "@backstage/plugin-github-issues": "^0.0.0", "@backstage/plugin-gocd": "^0.1.14-next.0", "@backstage/plugin-graphiql": "^0.2.40-next.0", "@backstage/plugin-home": "^0.4.24-next.0", diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index bc1d86b650..289af8d40f 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -100,7 +100,6 @@ import { techDocsPage } from './components/techdocs/TechDocsPage'; import { ApacheAirflowPage } from '@backstage/plugin-apache-airflow'; import { PermissionedRoute } from '@backstage/plugin-permission-react'; import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common'; -import { GitHubIssuesPage } from '@backstage/plugin-github-issues'; const app = createApp({ apis, @@ -242,7 +241,6 @@ const routes = ( } /> } /> - } /> ); diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx index 166157a2bc..288196266e 100644 --- a/packages/app/src/components/catalog/EntityPage.tsx +++ b/packages/app/src/components/catalog/EntityPage.tsx @@ -150,11 +150,6 @@ import { ReportIssue, } from '@backstage/plugin-techdocs-module-addons-contrib'; -import { - GitHubIssuesCard, - GitHubIssuesPage, -} from '@backstage/plugin-github-issues'; - const customEntityFilterKind = ['Component', 'API', 'System']; const EntityLayoutWrapper = (props: { children?: ReactNode }) => { @@ -330,10 +325,6 @@ const overviewContent = ( - - - - @@ -633,9 +624,6 @@ const userPage = ( entityFilterKind={customEntityFilterKind} /> - - - @@ -658,14 +646,8 @@ const groupPage = ( - - - - - - ); From 658e22b1a86fe57576ddccf559ddc526939a07e1 Mon Sep 17 00:00:00 2001 From: Iswariya Manivannan Date: Fri, 29 Jul 2022 13:50:01 +0200 Subject: [PATCH 083/144] docs: Remove markdown version constraint for mkdocs-techdocs-core Signed-off-by: Iswariya Manivannan --- docs/features/techdocs/getting-started.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/docs/features/techdocs/getting-started.md b/docs/features/techdocs/getting-started.md index f8bf98c0e0..c2070e7840 100644 --- a/docs/features/techdocs/getting-started.md +++ b/docs/features/techdocs/getting-started.md @@ -278,10 +278,7 @@ Note: We recommend Python version 3.7 or higher. > Caveat: Please install the `mkdocs-techdocs-core` package after all other > Python packages. The order is important to make sure we get correct version of -> some of the dependencies. For example, we want `Markdown` version to be -> [3.2.2](https://github.com/backstage/backstage/blob/f9f70c225548017b6a14daea75b00fbd399c11eb/packages/techdocs-container/techdocs-core/requirements.txt#L11). -> You can also explicitly install `Markdown==3.2.2` after installing all other -> Python packages. +> some of the dependencies. ## Running Backstage locally From 42d301b43c6ea9f0c129a1d877570edc5835b967 Mon Sep 17 00:00:00 2001 From: Kamil Wolny Date: Fri, 29 Jul 2022 16:07:37 +0100 Subject: [PATCH 084/144] fix: add missing react types + fixed typo Signed-off-by: Kamil Wolny --- plugins/github-issues/package.json | 1 + .../GitHubIssues/IssuesList/Filters/Filters.tsx | 2 +- yarn.lock | 14 +++++++++++--- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/plugins/github-issues/package.json b/plugins/github-issues/package.json index f1ee17b2a3..f32ccc039e 100644 --- a/plugins/github-issues/package.json +++ b/plugins/github-issues/package.json @@ -50,6 +50,7 @@ "@testing-library/user-event": "^14.0.0", "@types/jest": "*", "@types/node": "*", + "@types/react": "^18.0.15", "cross-fetch": "^3.1.5", "msw": "^0.42.0", "prettier": "^2.7.1" diff --git a/plugins/github-issues/src/components/GitHubIssues/IssuesList/Filters/Filters.tsx b/plugins/github-issues/src/components/GitHubIssues/IssuesList/Filters/Filters.tsx index 9a6ceb103f..eab1d8f57b 100644 --- a/plugins/github-issues/src/components/GitHubIssues/IssuesList/Filters/Filters.tsx +++ b/plugins/github-issues/src/components/GitHubIssues/IssuesList/Filters/Filters.tsx @@ -60,7 +60,7 @@ export const Filters = ({ items, onChange, placeholder }: Props) => { onChange={checkSelectedItems(onChange)} /> - *Repositories with more Issues in GitHub than available to view in + *Repositories with more Issues on GitHub than available to view in Backstage. To view them go to GitHub. diff --git a/yarn.lock b/yarn.lock index 28ba459975..a7a5d687cf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7432,7 +7432,7 @@ resolved "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA== -"@types/react-dom@*", "@types/react-dom@<18.0.0", "@types/react-dom@^17": +"@types/react-dom@*", "@types/react-dom@<18.0.0": version "17.0.17" resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.17.tgz#2e3743277a793a96a99f1bf87614598289da68a1" integrity sha512-VjnqEmqGnasQKV0CWLevqMTXBYG9GbwuE6x3VetERLh0cq2LTptFE73MrQi2S7GkKXCf2GgwItB/melLnxfnsg== @@ -7507,6 +7507,15 @@ "@types/scheduler" "*" csstype "^3.0.2" +"@types/react@^18.0.15": + version "18.0.15" + resolved "https://registry.npmjs.org/@types/react/-/react-18.0.15.tgz#d355644c26832dc27f3e6cbf0c4f4603fc4ab7fe" + integrity sha512-iz3BtLuIYH1uWdsv6wXYdhozhqj20oD4/Hk2DNXIn1kFsmp9x8d9QB6FnPhfkbhd2PgEONt9Q1x/ebkwjfFLow== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + "@types/recharts@^1.8.14", "@types/recharts@^1.8.15": version "1.8.23" resolved "https://registry.npmjs.org/@types/recharts/-/recharts-1.8.23.tgz#eeb6c52c6b2b916e9383bd5cf8fb5fd941c9c6fe" @@ -13160,7 +13169,6 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: "@backstage/plugin-gcalendar" "^0.3.4-next.0" "@backstage/plugin-gcp-projects" "^0.3.27-next.0" "@backstage/plugin-github-actions" "^0.5.8-next.0" - "@backstage/plugin-github-issues" "^0.0.0" "@backstage/plugin-gocd" "^0.1.14-next.0" "@backstage/plugin-graphiql" "^0.2.40-next.0" "@backstage/plugin-home" "^0.4.24-next.0" @@ -26700,7 +26708,7 @@ ws@^7.3.1, ws@^7.4.6: resolved "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz#9e0ac77ee50af70d58326ecff7e85eb3fa375e67" integrity sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A== -ws@^8.0.0, ws@^8.3.0: +ws@^8.3.0: version "8.8.1" resolved "https://registry.npmjs.org/ws/-/ws-8.8.1.tgz#5dbad0feb7ade8ecc99b830c1d77c913d4955ff0" integrity sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA== From 88dae32a7e93d6e2f674a85e74c34378a419b9f7 Mon Sep 17 00:00:00 2001 From: Neemys <36508659+Neemys@users.noreply.github.com> Date: Fri, 29 Jul 2022 17:22:35 +0200 Subject: [PATCH 085/144] Take into account PR comments on `sonarqube-backend` plugin's `router.ts` Simplify some code and change response method call to be `json` instead of plain `send`. Signed-off-by: Neemys <36508659+Neemys@users.noreply.github.com> --- .../sonarqube-backend/src/service/router.ts | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/plugins/sonarqube-backend/src/service/router.ts b/plugins/sonarqube-backend/src/service/router.ts index c0a9cb88d1..d6f5da7691 100644 --- a/plugins/sonarqube-backend/src/service/router.ts +++ b/plugins/sonarqube-backend/src/service/router.ts @@ -15,13 +15,10 @@ */ import { errorHandler } from '@backstage/backend-common'; -import express, { RequestHandler } from 'express'; +import express from 'express'; import Router from 'express-promise-router'; import { Logger } from 'winston'; -import { - SonarqubeFindings, - SonarqubeInfoProvider, -} from './sonarqubeInfoProvider'; +import { SonarqubeInfoProvider } from './sonarqubeInfoProvider'; import { InputError } from '../../../../packages/errors'; /** @@ -55,9 +52,9 @@ export async function createRouter( const router = Router(); router.use(express.json()); - router.get('/findings', (async (request, response) => { - const componentKey = request.query.componentKey; - let instanceKey = request.query.instanceKey; + router.get('/findings', async (request, response) => { + const componentKey = request.query.componentKey as string; + let instanceKey = request.query.instanceKey as string; if (!componentKey) throw new InputError('ComponentKey must be provided as a single string.'); @@ -73,13 +70,13 @@ export async function createRouter( ); } - response.send( + response.json( await sonarqubeInfoProvider.getFindings(componentKey, instanceKey), ); - }) as RequestHandler); + }); - router.get('/instanceUrl', ((request, response) => { - let requestedInstanceKey = request.query.instanceKey; + router.get('/instanceUrl', (request, response) => { + let requestedInstanceKey = request.query.instanceKey as string; if (requestedInstanceKey) { logger.info( `Retrieving sonarqube instance URL for key ${requestedInstanceKey}`, @@ -90,12 +87,13 @@ export async function createRouter( `Retrieving default sonarqube instance URL as parameter is inexistant, empty or malformed`, ); } - response.send({ - instanceUrl: sonarqubeInfoProvider.getBaseUrl({ - instanceName: requestedInstanceKey, - }).baseUrl, + const { baseUrl } = sonarqubeInfoProvider.getBaseUrl({ + instanceName: requestedInstanceKey, }); - }) as RequestHandler); + response.json({ + instanceUrl: baseUrl, + }); + }); router.use(errorHandler()); return router; From 043fb69c3d2b32dfa38ab00bdea4d412bbb155c6 Mon Sep 17 00:00:00 2001 From: Kamil Wolny Date: Fri, 29 Jul 2022 16:46:19 +0100 Subject: [PATCH 086/144] fix: @types/react as dependecy in plugins/github-issues Signed-off-by: Kamil Wolny --- plugins/github-issues/package.json | 2 +- yarn.lock | 13 ++----------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/plugins/github-issues/package.json b/plugins/github-issues/package.json index f32ccc039e..861a67ffa2 100644 --- a/plugins/github-issues/package.json +++ b/plugins/github-issues/package.json @@ -33,6 +33,7 @@ "@material-ui/icons": "^4.9.1", "@material-ui/lab": "^4.0.0-alpha.61", "@octokit/rest": "^18.12.0", + "@types/react": "^16.13.1 || ^17.0.0", "luxon": "^2.4.0", "react-use": "^17.2.4" }, @@ -50,7 +51,6 @@ "@testing-library/user-event": "^14.0.0", "@types/jest": "*", "@types/node": "*", - "@types/react": "^18.0.15", "cross-fetch": "^3.1.5", "msw": "^0.42.0", "prettier": "^2.7.1" diff --git a/yarn.lock b/yarn.lock index a7a5d687cf..44409c647b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7432,7 +7432,7 @@ resolved "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA== -"@types/react-dom@*", "@types/react-dom@<18.0.0": +"@types/react-dom@*", "@types/react-dom@<18.0.0", "@types/react-dom@^17": version "17.0.17" resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.17.tgz#2e3743277a793a96a99f1bf87614598289da68a1" integrity sha512-VjnqEmqGnasQKV0CWLevqMTXBYG9GbwuE6x3VetERLh0cq2LTptFE73MrQi2S7GkKXCf2GgwItB/melLnxfnsg== @@ -7507,15 +7507,6 @@ "@types/scheduler" "*" csstype "^3.0.2" -"@types/react@^18.0.15": - version "18.0.15" - resolved "https://registry.npmjs.org/@types/react/-/react-18.0.15.tgz#d355644c26832dc27f3e6cbf0c4f4603fc4ab7fe" - integrity sha512-iz3BtLuIYH1uWdsv6wXYdhozhqj20oD4/Hk2DNXIn1kFsmp9x8d9QB6FnPhfkbhd2PgEONt9Q1x/ebkwjfFLow== - dependencies: - "@types/prop-types" "*" - "@types/scheduler" "*" - csstype "^3.0.2" - "@types/recharts@^1.8.14", "@types/recharts@^1.8.15": version "1.8.23" resolved "https://registry.npmjs.org/@types/recharts/-/recharts-1.8.23.tgz#eeb6c52c6b2b916e9383bd5cf8fb5fd941c9c6fe" @@ -26708,7 +26699,7 @@ ws@^7.3.1, ws@^7.4.6: resolved "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz#9e0ac77ee50af70d58326ecff7e85eb3fa375e67" integrity sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A== -ws@^8.3.0: +ws@^8.0.0, ws@^8.3.0: version "8.8.1" resolved "https://registry.npmjs.org/ws/-/ws-8.8.1.tgz#5dbad0feb7ade8ecc99b830c1d77c913d4955ff0" integrity sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA== From e7a5a0498456e506e4e10ea3e4d0f11f5d80cc3a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 29 Jul 2022 15:46:42 +0000 Subject: [PATCH 087/144] fix(deps): update dependency @roadiehq/backstage-plugin-buildkite to v2.0.5 Signed-off-by: Renovate Bot --- yarn.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/yarn.lock b/yarn.lock index fe03c06949..7588c24433 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6035,12 +6035,12 @@ integrity sha512-8UiDeDbjCImFSfOegGu13otQ7OdP9FOYpcLjeouppnhs+MPeIEAtYS+jCcBKmi3reyTagC15/KVSRhde1wS1vg== "@roadiehq/backstage-plugin-buildkite@^2.0.0": - version "2.0.4" - resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-buildkite/-/backstage-plugin-buildkite-2.0.4.tgz#cd72fd35a9f8b6bb1c2ccd3c13d2aece2ecaf86e" - integrity sha512-bOrqKO9MmRB5jgue+S8WEmJk83h6g4EdGp2qmirVODQddL03gtFNgMTauQkKAV7T8N+C948xDcgdL3pjvLYJdA== + version "2.0.5" + resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-buildkite/-/backstage-plugin-buildkite-2.0.5.tgz#540679bd1dbb4cadf654e3d939cc9cbe4cf6e2e5" + integrity sha512-zMTlBzjEHdydWSddCt+Mr+2wjbMWn2f/AgBTXfYvaGDTY1fCmEFQ3gOL2fHd7UHk635AE/DKuGLL8gyEvLbqjg== dependencies: "@backstage/catalog-model" "^1.0.0" - "@backstage/core-components" "^0.9.0" + "@backstage/core-components" "^0.10.0" "@backstage/core-plugin-api" "^1.0.0" "@backstage/plugin-catalog-react" "^1.0.0" "@backstage/theme" "^0.2.6" From d1cf60891fdc7f5df905adce41e804869e1faa0d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 29 Jul 2022 15:47:30 +0000 Subject: [PATCH 088/144] fix(deps): update dependency @roadiehq/backstage-plugin-github-insights to v2.0.2 Signed-off-by: Renovate Bot --- yarn.lock | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/yarn.lock b/yarn.lock index fe03c06949..7458040db7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6054,12 +6054,12 @@ react-use "^17.2.4" "@roadiehq/backstage-plugin-github-insights@^2.0.0": - version "2.0.1" - resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-github-insights/-/backstage-plugin-github-insights-2.0.1.tgz#b0cccdd5cfe1c94055ad372087a1daba9ec72bb4" - integrity sha512-Kq3JdzSIpLV0Ka6GqX7Ok2QW/s6w18l0Kyec+OtQ+/1dz8AeG7UoYwUtBI/+sTd+gveTHAonwi9xINYbcIvQhQ== + version "2.0.2" + resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-github-insights/-/backstage-plugin-github-insights-2.0.2.tgz#d6a953123f8a60be5df5b32583c5c2b22d18f8bb" + integrity sha512-3f+iTuAqINdolxrOjAS2XR2JDv7v2BALfAnr/EuCXfIS5qbJqn6IpktC1FcS0HHV1hmI/y+fyI3V5/69RjNBnQ== dependencies: "@backstage/catalog-model" "^1.0.0" - "@backstage/core-components" "^0.9.0" + "@backstage/core-components" "^0.10.0" "@backstage/core-plugin-api" "^1.0.0" "@backstage/integration-react" "^1.0.0" "@backstage/plugin-catalog-react" "^1.0.0" @@ -6068,7 +6068,6 @@ "@material-ui/core" "^4.11.0" "@material-ui/icons" "^4.9.1" "@material-ui/lab" "4.0.0-alpha.45" - "@octokit/request-error" "^2.1.0" "@octokit/rest" "^18.5.3" "@octokit/types" "^6.14.2" history "^5.0.0" From e614c09280e479b63781d17005eccfe4ce9658d5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 29 Jul 2022 16:33:58 +0000 Subject: [PATCH 089/144] fix(deps): update dependency @roadiehq/backstage-plugin-github-pull-requests to v2.2.2 Signed-off-by: Renovate Bot --- yarn.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/yarn.lock b/yarn.lock index 7588c24433..72062c92fb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6078,12 +6078,12 @@ zustand "3.6.9" "@roadiehq/backstage-plugin-github-pull-requests@^2.0.0": - version "2.2.1" - resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-github-pull-requests/-/backstage-plugin-github-pull-requests-2.2.1.tgz#a50ca71c70fb16283bd65427688c3c5e9425dec7" - integrity sha512-oMLe1ew8hee9LfV5Pdw25sV1XdoMxpq/ZKZWWtZTS0iCudgWleslkdj20preF8FPuHQjkr1xAtnDdnMWvejtxQ== + version "2.2.2" + resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-github-pull-requests/-/backstage-plugin-github-pull-requests-2.2.2.tgz#b58568bdfbf08dcf0d4d45e2fd1d080875627439" + integrity sha512-klMqFfiSQMVg2PxrEU7v7UulkwuTiGBjQQnfHKuwpsziGiJoN4XtEZW/VdIEc4wHbBN8BA4CRJ1127V9up1dnQ== dependencies: "@backstage/catalog-model" "^1.0.0" - "@backstage/core-components" "^0.9.0" + "@backstage/core-components" "^0.10.0" "@backstage/core-plugin-api" "^1.0.0" "@backstage/plugin-catalog-react" "^1.0.0" "@backstage/plugin-home" "^0.4.19" From 0175a7da43f8d757530c7e751437312c6656c80d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 29 Jul 2022 16:34:46 +0000 Subject: [PATCH 090/144] fix(deps): update dependency @roadiehq/backstage-plugin-travis-ci to v2.0.2 Signed-off-by: Renovate Bot --- yarn.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/yarn.lock b/yarn.lock index 7588c24433..b473732c4f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6102,12 +6102,12 @@ react-use "^17.2.4" "@roadiehq/backstage-plugin-travis-ci@^2.0.0": - version "2.0.1" - resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-travis-ci/-/backstage-plugin-travis-ci-2.0.1.tgz#0d706d3a31b123cd2e76b6d7fd849ae8cb97e786" - integrity sha512-Qay8Ad+heMEyW5QPi2I4C7ky3NUYhgE7FF+pV77ES21zyytCcTHQIkYHJd0FrR6WpedtNSegfcRj61VSZfbRKA== + version "2.0.2" + resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-travis-ci/-/backstage-plugin-travis-ci-2.0.2.tgz#9a7aca54a6728bf836c5f51e22fd1a397801c9e0" + integrity sha512-fIevPreKE16nEuJzg5WPN3xI+z8EaotXwqCpWk7GR/8UjLSB5bt7wAwaMsQdywvmK21rBLAmKBlSn5x0TfYoLQ== dependencies: "@backstage/catalog-model" "^1.0.0" - "@backstage/core-components" "^0.9.0" + "@backstage/core-components" "^0.10.0" "@backstage/core-plugin-api" "^1.0.0" "@backstage/plugin-catalog-react" "^1.0.0" "@backstage/theme" "^0.2.9" From ec07a46aa39e87821ae0a73cbedd8ce101aab0e8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 29 Jul 2022 17:40:24 +0000 Subject: [PATCH 091/144] chore(deps): update dependency @types/express-serve-static-core to v4.17.30 Signed-off-by: Renovate Bot --- yarn.lock | 63 +------------------------------------------------------ 1 file changed, 1 insertion(+), 62 deletions(-) diff --git a/yarn.lock b/yarn.lock index 916921f374..38ace74f20 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2072,52 +2072,7 @@ zen-observable "^0.8.15" zod "^3.11.6" -"@backstage/core-components@^0.9.0": - version "0.9.5" - resolved "https://registry.npmjs.org/@backstage/core-components/-/core-components-0.9.5.tgz#5a0b34867aaee0549bfa67b39a69c09588fa3c7a" - integrity sha512-kfAdN70idiEqHeH9ZQryn6C0RxJEKiRc/7srYIz0CVV88zJfc0nmZ5C/S10Gkht2xWfm95tTSw2P1vEYIBbfxg== - dependencies: - "@backstage/config" "^1.0.1" - "@backstage/core-plugin-api" "^1.0.3" - "@backstage/errors" "^1.0.0" - "@backstage/theme" "^0.2.15" - "@backstage/version-bridge" "^1.0.1" - "@material-table/core" "^3.1.0" - "@material-ui/core" "^4.12.2" - "@material-ui/icons" "^4.9.1" - "@material-ui/lab" "4.0.0-alpha.57" - "@react-hookz/web" "^14.0.0" - "@types/react-sparklines" "^1.7.0" - "@types/react-text-truncate" "^0.14.0" - ansi-regex "^6.0.1" - classnames "^2.2.6" - d3-selection "^3.0.0" - d3-shape "^3.0.0" - d3-zoom "^3.0.0" - dagre "^0.8.5" - history "^5.0.0" - immer "^9.0.1" - lodash "^4.17.21" - pluralize "^8.0.0" - prop-types "^15.7.2" - qs "^6.9.4" - rc-progress "3.3.3" - react-helmet "6.1.0" - react-hook-form "^7.12.2" - react-markdown "^8.0.0" - react-router "6.0.0-beta.0" - react-router-dom "6.0.0-beta.0" - react-sparklines "^1.7.0" - react-syntax-highlighter "^15.4.5" - react-text-truncate "^0.19.0" - react-use "^17.3.2" - react-virtualized-auto-sizer "^1.0.6" - react-window "^1.8.6" - remark-gfm "^3.0.1" - zen-observable "^0.8.15" - zod "^3.11.6" - -"@backstage/core-plugin-api@^1.0.0", "@backstage/core-plugin-api@^1.0.3", "@backstage/core-plugin-api@^1.0.4": +"@backstage/core-plugin-api@^1.0.0", "@backstage/core-plugin-api@^1.0.4": version "1.0.4" resolved "https://registry.npmjs.org/@backstage/core-plugin-api/-/core-plugin-api-1.0.4.tgz#0dbe80be1d298273df0299ef69baa18522d9a808" integrity sha512-fMMpjqW2RjwclnHUJsSyPCTguplflQYEWv7wsk7IoanEkWx39pensi8OsdIBawXrOixXEnI47dgxtVMOQUxOKA== @@ -6000,13 +5955,6 @@ resolved "https://registry.npmjs.org/@react-hookz/deep-equal/-/deep-equal-1.0.2.tgz#4e8bdeda027379dcf8b62a42e5f75f0351b11b35" integrity sha512-cM5kPFb6EFH5q52WzRxfRX9+8g5kq78McWOYs6e1seo+nK6NpfLupT5uOCIJp37jU8ayd4Su8ni3HRFTN2C2kg== -"@react-hookz/web@^14.0.0": - version "14.7.1" - resolved "https://registry.npmjs.org/@react-hookz/web/-/web-14.7.1.tgz#5e39e6fc21331cc4ae95f36e8135ad763e6c29fb" - integrity sha512-kU1CccZDXvQ9G4vcCCpX3mDQqYKkuLXGFOtPMgmbZ9KrvkEduMRH4JqSVXp1nI/bGI1GJ0KAWm4UEb1x5eDGAg== - dependencies: - "@react-hookz/deep-equal" "^1.0.2" - "@react-hookz/web@^15.0.0": version "15.0.1" resolved "https://registry.npmjs.org/@react-hookz/web/-/web-15.0.1.tgz#a6e5460dd16e54ccc0b899e1eed4ae29e871060f" @@ -22098,15 +22046,6 @@ raw-body@2.5.1, raw-body@^2.4.1: iconv-lite "0.4.24" unpipe "1.0.0" -rc-progress@3.3.3: - version "3.3.3" - resolved "https://registry.npmjs.org/rc-progress/-/rc-progress-3.3.3.tgz#eb9bffbacab1534f2542f9f6861ce772254362b1" - integrity sha512-MDVNVHzGanYtRy2KKraEaWeZLri2ZHWIRyaE1a9MQ2MuJ09m+Wxj5cfcaoaR6z5iRpHpA59YeUxAlpML8N4PJw== - dependencies: - "@babel/runtime" "^7.10.1" - classnames "^2.2.6" - rc-util "^5.16.1" - rc-progress@3.4.0: version "3.4.0" resolved "https://registry.npmjs.org/rc-progress/-/rc-progress-3.4.0.tgz#80a33c25c9675f5836ba25a87cd8dc310aad72b1" From 35f344f6adc02ec8bf586dc9763feaaf68e350ac Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 29 Jul 2022 17:41:19 +0000 Subject: [PATCH 092/144] fix(deps): update dependency @graphql-tools/schema to v8.5.1 Signed-off-by: Renovate Bot --- yarn.lock | 63 +------------------------------------------------------ 1 file changed, 1 insertion(+), 62 deletions(-) diff --git a/yarn.lock b/yarn.lock index 916921f374..38ace74f20 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2072,52 +2072,7 @@ zen-observable "^0.8.15" zod "^3.11.6" -"@backstage/core-components@^0.9.0": - version "0.9.5" - resolved "https://registry.npmjs.org/@backstage/core-components/-/core-components-0.9.5.tgz#5a0b34867aaee0549bfa67b39a69c09588fa3c7a" - integrity sha512-kfAdN70idiEqHeH9ZQryn6C0RxJEKiRc/7srYIz0CVV88zJfc0nmZ5C/S10Gkht2xWfm95tTSw2P1vEYIBbfxg== - dependencies: - "@backstage/config" "^1.0.1" - "@backstage/core-plugin-api" "^1.0.3" - "@backstage/errors" "^1.0.0" - "@backstage/theme" "^0.2.15" - "@backstage/version-bridge" "^1.0.1" - "@material-table/core" "^3.1.0" - "@material-ui/core" "^4.12.2" - "@material-ui/icons" "^4.9.1" - "@material-ui/lab" "4.0.0-alpha.57" - "@react-hookz/web" "^14.0.0" - "@types/react-sparklines" "^1.7.0" - "@types/react-text-truncate" "^0.14.0" - ansi-regex "^6.0.1" - classnames "^2.2.6" - d3-selection "^3.0.0" - d3-shape "^3.0.0" - d3-zoom "^3.0.0" - dagre "^0.8.5" - history "^5.0.0" - immer "^9.0.1" - lodash "^4.17.21" - pluralize "^8.0.0" - prop-types "^15.7.2" - qs "^6.9.4" - rc-progress "3.3.3" - react-helmet "6.1.0" - react-hook-form "^7.12.2" - react-markdown "^8.0.0" - react-router "6.0.0-beta.0" - react-router-dom "6.0.0-beta.0" - react-sparklines "^1.7.0" - react-syntax-highlighter "^15.4.5" - react-text-truncate "^0.19.0" - react-use "^17.3.2" - react-virtualized-auto-sizer "^1.0.6" - react-window "^1.8.6" - remark-gfm "^3.0.1" - zen-observable "^0.8.15" - zod "^3.11.6" - -"@backstage/core-plugin-api@^1.0.0", "@backstage/core-plugin-api@^1.0.3", "@backstage/core-plugin-api@^1.0.4": +"@backstage/core-plugin-api@^1.0.0", "@backstage/core-plugin-api@^1.0.4": version "1.0.4" resolved "https://registry.npmjs.org/@backstage/core-plugin-api/-/core-plugin-api-1.0.4.tgz#0dbe80be1d298273df0299ef69baa18522d9a808" integrity sha512-fMMpjqW2RjwclnHUJsSyPCTguplflQYEWv7wsk7IoanEkWx39pensi8OsdIBawXrOixXEnI47dgxtVMOQUxOKA== @@ -6000,13 +5955,6 @@ resolved "https://registry.npmjs.org/@react-hookz/deep-equal/-/deep-equal-1.0.2.tgz#4e8bdeda027379dcf8b62a42e5f75f0351b11b35" integrity sha512-cM5kPFb6EFH5q52WzRxfRX9+8g5kq78McWOYs6e1seo+nK6NpfLupT5uOCIJp37jU8ayd4Su8ni3HRFTN2C2kg== -"@react-hookz/web@^14.0.0": - version "14.7.1" - resolved "https://registry.npmjs.org/@react-hookz/web/-/web-14.7.1.tgz#5e39e6fc21331cc4ae95f36e8135ad763e6c29fb" - integrity sha512-kU1CccZDXvQ9G4vcCCpX3mDQqYKkuLXGFOtPMgmbZ9KrvkEduMRH4JqSVXp1nI/bGI1GJ0KAWm4UEb1x5eDGAg== - dependencies: - "@react-hookz/deep-equal" "^1.0.2" - "@react-hookz/web@^15.0.0": version "15.0.1" resolved "https://registry.npmjs.org/@react-hookz/web/-/web-15.0.1.tgz#a6e5460dd16e54ccc0b899e1eed4ae29e871060f" @@ -22098,15 +22046,6 @@ raw-body@2.5.1, raw-body@^2.4.1: iconv-lite "0.4.24" unpipe "1.0.0" -rc-progress@3.3.3: - version "3.3.3" - resolved "https://registry.npmjs.org/rc-progress/-/rc-progress-3.3.3.tgz#eb9bffbacab1534f2542f9f6861ce772254362b1" - integrity sha512-MDVNVHzGanYtRy2KKraEaWeZLri2ZHWIRyaE1a9MQ2MuJ09m+Wxj5cfcaoaR6z5iRpHpA59YeUxAlpML8N4PJw== - dependencies: - "@babel/runtime" "^7.10.1" - classnames "^2.2.6" - rc-util "^5.16.1" - rc-progress@3.4.0: version "3.4.0" resolved "https://registry.npmjs.org/rc-progress/-/rc-progress-3.4.0.tgz#80a33c25c9675f5836ba25a87cd8dc310aad72b1" From 26bccf92689682cf849ecafdaa680ddc02719510 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 29 Jul 2022 18:34:14 +0000 Subject: [PATCH 093/144] fix(deps): update dependency core-js to v3.24.1 Signed-off-by: Renovate Bot --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 38ace74f20..94c027c1a4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11015,9 +11015,9 @@ core-js@^2.4.0, core-js@^2.5.0, core-js@^2.6.10: integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== core-js@^3.4.1, core-js@^3.6.5: - version "3.24.0" - resolved "https://registry.npmjs.org/core-js/-/core-js-3.24.0.tgz#4928d4e99c593a234eb1a1f9abd3122b04d3ac57" - integrity sha512-IeOyT8A6iK37Ep4kZDD423mpi6JfPRoPUdQwEWYiGolvn4o6j2diaRzNfDfpTdu3a5qMbrGUzKUpYpRY8jXCkQ== + version "3.24.1" + resolved "https://registry.npmjs.org/core-js/-/core-js-3.24.1.tgz#cf7724d41724154010a6576b7b57d94c5d66e64f" + integrity sha512-0QTBSYSUZ6Gq21utGzkfITDylE8jWC9Ne1D2MrhvlsZBI1x39OdDIVbzSqtgMndIy6BlHxBXpMGqzZmnztg2rg== core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" From e8cf4701e6c5dad40c9d3b1c563e28e1def30d8e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 29 Jul 2022 19:25:25 +0000 Subject: [PATCH 094/144] fix(deps): update dependency aws-sdk to v2.1185.0 Signed-off-by: Renovate Bot --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 94c027c1a4..23059ddcae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9062,9 +9062,9 @@ aws-sdk-mock@^5.2.1: traverse "^0.6.6" aws-sdk@^2.1122.0, aws-sdk@^2.814.0, aws-sdk@^2.840.0, aws-sdk@^2.948.0: - version "2.1184.0" - resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1184.0.tgz#6f800815382284825a3f03422410eaf3cefcac68" - integrity sha512-g4UQgc8+Ljk2e6xJYwBSQrDJ8BmQ/E3nHLw9ITEJKC1hgK8DLy77PUielA0ptscoKz5ySCSSGbMjR1B1HgThKQ== + version "2.1185.0" + resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1185.0.tgz#157c6a900a9449cb36b37493337cae418e01210d" + integrity sha512-viFlYC6RAKOqBRM4gIB4rE80KMFNVvEkQpNmpd3PqCOemGPETDxCVHS0oqZ26qM278sZVHt+oAjPy5HmZasskg== dependencies: buffer "4.9.2" events "1.1.1" From c51d970410311dc32250241db855901249b4ac3c Mon Sep 17 00:00:00 2001 From: Jamie Klassen Date: Fri, 29 Jul 2022 15:38:32 -0400 Subject: [PATCH 095/144] clarify caData field The code in `@kubernetes/client-node` will decode this value, as seen here: https://github.com/kubernetes-client/javascript/blob/2b6813f99a85605f691973d6bc43f291ac072fc7/src/config.ts#L518-L520 I have seen a casual reader insert the multi-line raw contents of a PEM file in this field, so it seems worth mentioning the extra layer of encoding explicitly. Signed-off-by: Jamie Klassen --- docs/features/kubernetes/configuration.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/features/kubernetes/configuration.md b/docs/features/kubernetes/configuration.md index c3559585f7..dc541c5c50 100644 --- a/docs/features/kubernetes/configuration.md +++ b/docs/features/kubernetes/configuration.md @@ -236,10 +236,12 @@ kubernetes: ##### `clusters.\*.caData` (optional) -PEM-encoded certificate authority certificates. +Base64-encoded certificate authority bundle in PEM format. The Kubernetes client +will verify that TLS certificate presented by the API server is signed by this +CA. -This values could be obtained via inspecting the Kubernetes config file (usually -at `~/.kube/config`) under `clusters.cluster.certificate-authority-data`. For +This value could be obtained via inspecting the kubeconfig file (usually +at `~/.kube/config`) under `clusters[*].cluster.certificate-authority-data`. For GKE, execute the following command to obtain the value ``` From 0ec2aeea70245fe609bc986e93acaaa43e0e8f6a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 29 Jul 2022 22:40:39 +0000 Subject: [PATCH 096/144] fix(deps): update dependency yeoman-environment to v3.10.0 Signed-off-by: Renovate Bot --- yarn.lock | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 23059ddcae..2806f3fc9d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16305,6 +16305,11 @@ isarray@2.0.1: resolved "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4= +isbinaryfile@^4.0.10: + version "4.0.10" + resolved "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz#0c5b5e30c2557a2f06febd37b7322946aaee42b3" + integrity sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw== + isbinaryfile@^4.0.8: version "4.0.8" resolved "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.8.tgz#5d34b94865bd4946633ecc78a026fc76c5b11fcf" @@ -27051,9 +27056,9 @@ yeast@0.1.2: integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk= yeoman-environment@^3.9.1: - version "3.9.1" - resolved "https://registry.npmjs.org/yeoman-environment/-/yeoman-environment-3.9.1.tgz#21912bdee4b1d302a5c25a7d31338fa092ea7116" - integrity sha512-IdRnbQt/DSOSnao0oD9c+or1X2UrL+fx9eC0O7Lq/MGZV68nhv9k77MqG+hEAySPSlyCpocVlhfQwV62hczk5Q== + version "3.10.0" + resolved "https://registry.npmjs.org/yeoman-environment/-/yeoman-environment-3.10.0.tgz#d8c56571b68d16b4af8abfb950f83acc503eed77" + integrity sha512-sYtSxBK9daq21QjoskJTHKLQ1xEsRPURkmFV/aM8HS8ZlQVzwx57Rz1zCs8EGPhK4vqsmTE8H92Gp1jg1fT3EA== dependencies: "@npmcli/arborist" "^4.0.4" are-we-there-yet "^2.0.0" @@ -27073,6 +27078,7 @@ yeoman-environment@^3.9.1: grouped-queue "^2.0.0" inquirer "^8.0.0" is-scoped "^2.1.0" + isbinaryfile "^4.0.10" lodash "^4.17.10" log-symbols "^4.0.0" mem-fs "^1.2.0 || ^2.0.0" From a03914237ead04dc22550fdbb74a02b140bc9550 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 30 Jul 2022 01:53:13 +0000 Subject: [PATCH 097/144] fix(deps): update dependency eslint-plugin-jest to v26.7.0 Signed-off-by: Renovate Bot --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 2806f3fc9d..a43c8ffeb2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12906,9 +12906,9 @@ eslint-plugin-import@^2.25.4: tsconfig-paths "^3.14.1" eslint-plugin-jest@^26.1.2: - version "26.6.0" - resolved "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-26.6.0.tgz#546804fa42da75d7d58d4d3b278d5186abd3f6c0" - integrity sha512-f8n46/97ZFdU4KqeQYqO8AEVGIhHWvkpgNBWHH3jrM28/y8llnbf3IjfIKv6p2pZIMinK1PCqbbROxs9Eud02Q== + version "26.7.0" + resolved "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-26.7.0.tgz#41d405ac9143e1284a3401282db47ed459436778" + integrity sha512-/YNitdfG3o3cC6juZziAdkk6nfJt01jXVfj4AgaYVLs7bupHzRDL5K+eipdzhDXtQsiqaX1TzfwSuRlEgeln1A== dependencies: "@typescript-eslint/utils" "^5.10.0" From 4274051839bc9fc616cd0cb27118f097e6ff7766 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 30 Jul 2022 18:06:24 +0000 Subject: [PATCH 098/144] chore(deps): update dependency @graphql-codegen/cli to v2.11.3 Signed-off-by: Renovate Bot --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index a43c8ffeb2..85e483a12c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2790,9 +2790,9 @@ meros "^1.1.4" "@graphql-codegen/cli@^2.3.1": - version "2.11.2" - resolved "https://registry.npmjs.org/@graphql-codegen/cli/-/cli-2.11.2.tgz#f502d0e9e19305acffca5f07789dde8d4e0fa656" - integrity sha512-dt70+et0QFmhL3krrlYWcsp7T6pvChEQ1vEGoNn46Rn53velGDwP546DtSPpHJmajY/eJ11CueoI0J/3o0/BTA== + version "2.11.3" + resolved "https://registry.npmjs.org/@graphql-codegen/cli/-/cli-2.11.3.tgz#6cb0fd6da0773957b531cccf7459303a23ee1c05" + integrity sha512-C1d88Kx0a0PF1tOR00UIZjHq5aWNNcw5fM2k08rOY9O5b4sU7kEb+YbGKP6EExTtJnYb49fePLKVvrIv1ejDFg== dependencies: "@graphql-codegen/core" "2.6.0" "@graphql-codegen/plugin-helpers" "^2.6.1" From 0123765ceddb0a791130f9b445def79db005e014 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 30 Jul 2022 22:11:36 +0000 Subject: [PATCH 099/144] chore(deps): update dependency @types/node to v16.11.47 Signed-off-by: Renovate Bot --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index a43c8ffeb2..2072f255d8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7343,9 +7343,9 @@ integrity sha512-qjd88DrCxupx/kJD5yQgZdcYKZKSIGBVDIBE1/LTGcNm3d2Np/jxojkdePDdfnBHJc5W7vSMpbJ1aB7p/Py69A== "@types/node@^16.0.0", "@types/node@^16.11.26", "@types/node@^16.9.2": - version "16.11.46" - resolved "https://registry.npmjs.org/@types/node/-/node-16.11.46.tgz#26047602eefa47b36759d9ebb1b55ad08ce97a73" - integrity sha512-x+sfpb2dMrhCQPL4NAGs64Z9hh0t72aP0dg+PuZidmPr/0Gj5ELQTjD/t46dq3DF/8ZvSHOaIyDIbAsdPshyVQ== + version "16.11.47" + resolved "https://registry.npmjs.org/@types/node/-/node-16.11.47.tgz#efa9e3e0f72e7aa6a138055dace7437a83d9f91c" + integrity sha512-fpP+jk2zJ4VW66+wAMFoBJlx1bxmBKx4DUFf68UHgdGCOuyUTDlLWqsaNPJh7xhNDykyJ9eIzAygilP/4WoN8g== "@types/normalize-package-data@^2.4.0": version "2.4.1" From f6c2c4847d97578242de25a522d4373ffc6b3885 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 04:44:40 +0000 Subject: [PATCH 100/144] fix(deps): update dependency dockerode to v3.3.3 Signed-off-by: Renovate Bot --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index a43c8ffeb2..2c2dfa4e93 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12185,9 +12185,9 @@ docker-modem@^3.0.0: ssh2 "^1.4.0" dockerode@^3.3.1: - version "3.3.2" - resolved "https://registry.npmjs.org/dockerode/-/dockerode-3.3.2.tgz#f3545700d2f7f86141b58843a755eeb21e38d5cd" - integrity sha512-oXN+1XVH2TeyE0Jj9Ci6Fim8ZIDxyqeJrkx9qhEOaRiA+nhLihKfd3M2L+Aqrj5C2ObPw8RVN2zPWvvk0x2dwg== + version "3.3.3" + resolved "https://registry.npmjs.org/dockerode/-/dockerode-3.3.3.tgz#7504db10d23866c6f267e7b0b7b4a75fc2203e8d" + integrity sha512-lvKV6/NGf2/CYLt5V4c0fd6Fl9XZSCo1Z2HBT9ioKrKLMB2o+gA62Uza8RROpzGvYv57KJx2dKu+ZwSpB//OIA== dependencies: docker-modem "^3.0.0" tar-fs "~2.0.1" From 9e5e0c97a60680f86794b43cc67f878df1fa9c4b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 04:46:17 +0000 Subject: [PATCH 101/144] fix(deps): update dependency eslint to v8.21.0 Signed-off-by: Renovate Bot --- yarn.lock | 41 ++++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/yarn.lock b/yarn.lock index a43c8ffeb2..722669fd90 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3390,15 +3390,20 @@ object-assign "^4.1.1" scheduler "^0.20.2" -"@humanwhocodes/config-array@^0.9.2": - version "0.9.2" - resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.2.tgz#68be55c737023009dfc5fe245d51181bb6476914" - integrity sha512-UXOuFCGcwciWckOpmfKDq/GyhlTf9pN/BzG//x8p8zTOFEcGuA68ANXheFS0AGvy3qgZqLBUkMs7hqzqCKOVwA== +"@humanwhocodes/config-array@^0.10.4": + version "0.10.4" + resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz#01e7366e57d2ad104feea63e72248f22015c520c" + integrity sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw== dependencies: "@humanwhocodes/object-schema" "^1.2.1" debug "^4.1.1" minimatch "^3.0.4" +"@humanwhocodes/gitignore-to-minimatch@^1.0.2": + version "1.0.2" + resolved "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz#316b0a63b91c10e53f242efb4ace5c3b34e8728d" + integrity sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA== + "@humanwhocodes/object-schema@^1.2.1": version "1.2.1" resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" @@ -8384,6 +8389,11 @@ acorn@^8.2.4, acorn@^8.4.1, acorn@^8.5.0, acorn@^8.7.0, acorn@^8.7.1: resolved "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== +acorn@^8.8.0: + version "8.8.0" + resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8" + integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== + add-stream@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa" @@ -13023,12 +13033,13 @@ eslint-webpack-plugin@^3.1.1: schema-utils "^4.0.0" eslint@^8.6.0: - version "8.20.0" - resolved "https://registry.npmjs.org/eslint/-/eslint-8.20.0.tgz#048ac56aa18529967da8354a478be4ec0a2bc81b" - integrity sha512-d4ixhz5SKCa1D6SCPrivP7yYVi7nyD6A4vs6HIAul9ujBzcEmZVM3/0NN/yu5nKhmO1wjp5xQ46iRfmDGlOviA== + version "8.21.0" + resolved "https://registry.npmjs.org/eslint/-/eslint-8.21.0.tgz#1940a68d7e0573cef6f50037addee295ff9be9ef" + integrity sha512-/XJ1+Qurf1T9G2M5IHrsjp+xrGT73RZf23xA1z5wB1ZzzEAWSZKvRwhWxTFp1rvkvCfwcvAUNAP31bhKTTGfDA== dependencies: "@eslint/eslintrc" "^1.3.0" - "@humanwhocodes/config-array" "^0.9.2" + "@humanwhocodes/config-array" "^0.10.4" + "@humanwhocodes/gitignore-to-minimatch" "^1.0.2" ajv "^6.10.0" chalk "^4.0.0" cross-spawn "^7.0.2" @@ -13038,14 +13049,17 @@ eslint@^8.6.0: eslint-scope "^7.1.1" eslint-utils "^3.0.0" eslint-visitor-keys "^3.3.0" - espree "^9.3.2" + espree "^9.3.3" esquery "^1.4.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" file-entry-cache "^6.0.1" + find-up "^5.0.0" functional-red-black-tree "^1.0.1" glob-parent "^6.0.1" globals "^13.15.0" + globby "^11.1.0" + grapheme-splitter "^1.0.4" ignore "^5.2.0" import-fresh "^3.0.0" imurmurhash "^0.1.4" @@ -13077,6 +13091,15 @@ espree@^9.3.2: acorn-jsx "^5.3.2" eslint-visitor-keys "^3.3.0" +espree@^9.3.3: + version "9.3.3" + resolved "https://registry.npmjs.org/espree/-/espree-9.3.3.tgz#2dd37c4162bb05f433ad3c1a52ddf8a49dc08e9d" + integrity sha512-ORs1Rt/uQTqUKjDdGCyrtYxbazf5umATSf/K4qxjmZHORR6HJk+2s/2Pqe+Kk49HHINC/xNIrGfgh8sZcll0ng== + dependencies: + acorn "^8.8.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.3.0" + esprima@^4.0.0, esprima@^4.0.1, esprima@~4.0.0: version "4.0.1" resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" From 1b2d1ff431ab8c917a6dc378cd748ce4e1a5a781 Mon Sep 17 00:00:00 2001 From: Neemys <36508659+Neemys@users.noreply.github.com> Date: Mon, 1 Aug 2022 10:42:43 +0200 Subject: [PATCH 102/144] Make instanceName an optional parameter in plugin `sonarqube-backend` APIs Signed-off-by: Neemys <36508659+Neemys@users.noreply.github.com> --- plugins/sonarqube-backend/api-report.md | 8 ++-- .../src/service/router.test.ts | 16 +++++++- .../sonarqube-backend/src/service/router.ts | 37 +++++++------------ .../src/service/sonarqubeInfoProvider.test.ts | 13 +++++++ .../src/service/sonarqubeInfoProvider.ts | 23 +++++++----- 5 files changed, 58 insertions(+), 39 deletions(-) diff --git a/plugins/sonarqube-backend/api-report.md b/plugins/sonarqube-backend/api-report.md index b4f1ad4589..8f0c672c6c 100644 --- a/plugins/sonarqube-backend/api-report.md +++ b/plugins/sonarqube-backend/api-report.md @@ -13,12 +13,12 @@ export function createRouter(options: RouterOptions): Promise; // @public export class DefaultSonarqubeInfoProvider implements SonarqubeInfoProvider { static fromConfig(config: Config): DefaultSonarqubeInfoProvider; - getBaseUrl({ instanceName }: { instanceName: string }): { + getBaseUrl({ instanceName }?: { instanceName?: string }): { baseUrl: string; }; getFindings( componentKey: string, - instanceName: string, + instanceName?: string, ): Promise; } @@ -45,12 +45,12 @@ export interface SonarqubeFindings { // @public export interface SonarqubeInfoProvider { - getBaseUrl({ instanceName }: { instanceName: string }): { + getBaseUrl({ instanceName }?: { instanceName?: string }): { baseUrl: string; }; getFindings( componentKey: string, - instanceName: string, + instanceName?: string, ): Promise; } diff --git a/plugins/sonarqube-backend/src/service/router.test.ts b/plugins/sonarqube-backend/src/service/router.test.ts index 719db6787e..e082215abc 100644 --- a/plugins/sonarqube-backend/src/service/router.test.ts +++ b/plugins/sonarqube-backend/src/service/router.test.ts @@ -83,7 +83,7 @@ describe('createRouter', () => { expect(response.status).toEqual(400); }); - it('use an empty string as instance name when instance key not provided', async () => { + it('use the value as instance name when instance key not provided', async () => { const measures = { analysisDate: '2021-04-08', measures: [{ metric: 'vulnerabilities', value: '54' }], @@ -94,11 +94,12 @@ describe('createRouter', () => { .get('/findings') .query({ componentKey: DUMMY_COMPONENT_KEY, + instanceKey: undefined, }) .send(); expect(getFindingsMock).toBeCalledTimes(1); - expect(getFindingsMock).toBeCalledWith(DUMMY_COMPONENT_KEY, ''); + expect(getFindingsMock).toBeCalledWith(DUMMY_COMPONENT_KEY, undefined); expect(response.status).toEqual(200); expect(response.body).toEqual(measures); }); @@ -121,5 +122,16 @@ describe('createRouter', () => { expect(response.status).toEqual(200); expect(response.body).toEqual({ instanceUrl: DUMMY_INSTANCE_URL }); }); + + it('query default instance when instanceKey not provided', async () => { + getBaseUrlMock.mockReturnValue({ baseUrl: DUMMY_INSTANCE_URL }); + const response = await request(app).get('/instanceUrl').send(); + expect(getBaseUrlMock).toBeCalledTimes(1); + expect(getBaseUrlMock).toBeCalledWith({ + instanceName: undefined, + }); + expect(response.status).toEqual(200); + expect(response.body).toEqual({ instanceUrl: DUMMY_INSTANCE_URL }); + }); }); }); diff --git a/plugins/sonarqube-backend/src/service/router.ts b/plugins/sonarqube-backend/src/service/router.ts index d6f5da7691..674045121f 100644 --- a/plugins/sonarqube-backend/src/service/router.ts +++ b/plugins/sonarqube-backend/src/service/router.ts @@ -54,21 +54,16 @@ export async function createRouter( router.use(express.json()); router.get('/findings', async (request, response) => { const componentKey = request.query.componentKey as string; - let instanceKey = request.query.instanceKey as string; + const instanceKey = request.query.instanceKey as string; if (!componentKey) throw new InputError('ComponentKey must be provided as a single string.'); - if (!instanceKey) { - instanceKey = ''; - logger.info( - `Retrieving findings for component ${componentKey} in default sonarqube instance`, - ); - } else { - logger.info( - `Retrieving findings for component ${componentKey} in sonarqube instance name ${instanceKey}`, - ); - } + logger.info( + instanceKey + ? `Retrieving findings for component ${componentKey} in sonarqube instance name ${instanceKey}` + : `Retrieving findings for component ${componentKey} in default sonarqube instance`, + ); response.json( await sonarqubeInfoProvider.getFindings(componentKey, instanceKey), @@ -76,19 +71,15 @@ export async function createRouter( }); router.get('/instanceUrl', (request, response) => { - let requestedInstanceKey = request.query.instanceKey as string; - if (requestedInstanceKey) { - logger.info( - `Retrieving sonarqube instance URL for key ${requestedInstanceKey}`, - ); - } else { - requestedInstanceKey = ''; - logger.info( - `Retrieving default sonarqube instance URL as parameter is inexistant, empty or malformed`, - ); - } + const instanceKey = request.query.instanceKey as string; + + logger.info( + instanceKey + ? `Retrieving sonarqube instance URL for key ${instanceKey}` + : `Retrieving default sonarqube instance URL as instanceKey is not provided`, + ); const { baseUrl } = sonarqubeInfoProvider.getBaseUrl({ - instanceName: requestedInstanceKey, + instanceName: instanceKey, }); response.json({ instanceUrl: baseUrl, diff --git a/plugins/sonarqube-backend/src/service/sonarqubeInfoProvider.test.ts b/plugins/sonarqube-backend/src/service/sonarqubeInfoProvider.test.ts index 774fdca238..f7298888fe 100644 --- a/plugins/sonarqube-backend/src/service/sonarqubeInfoProvider.test.ts +++ b/plugins/sonarqube-backend/src/service/sonarqubeInfoProvider.test.ts @@ -229,6 +229,19 @@ describe('DefaultSonarqubeInfoProvider', () => { } describe('getBaseUrl', () => { + it('Provide base url for default from simple config and non provided instanceName', async () => { + const provider = configureProvider({ + sonarqube: { + baseUrl: 'https://sonarqube.example.com', + apiKey: '123456789abcdef0123456789abcedf012', + }, + }); + + expect(provider.getBaseUrl()).toEqual({ + baseUrl: 'https://sonarqube.example.com', + }); + }); + it('Provide base url for default from simple config and empty string', async () => { const provider = configureProvider({ sonarqube: { diff --git a/plugins/sonarqube-backend/src/service/sonarqubeInfoProvider.ts b/plugins/sonarqube-backend/src/service/sonarqubeInfoProvider.ts index 6f75171f65..f03593b012 100644 --- a/plugins/sonarqube-backend/src/service/sonarqubeInfoProvider.ts +++ b/plugins/sonarqube-backend/src/service/sonarqubeInfoProvider.ts @@ -23,18 +23,21 @@ import fetch from 'node-fetch'; */ export interface SonarqubeInfoProvider { /** - * Get the sonarqube URL in configuration from a provided name. + * Get the sonarqube URL in configuration from a provided instanceName. * - * If name is omitted, default sonarqube instance is queried in config + * If instanceName is omitted, default sonarqube instance is queried in config * * @param instanceName - Name of the sonarqube instance to get the info from * @returns the url of the instance */ - getBaseUrl({ instanceName }: { instanceName: string }): { baseUrl: string }; + getBaseUrl({ instanceName }?: { instanceName?: string }): { baseUrl: string }; /** * Query the sonarqube instance corresponding to the instanceName to get all * measures for the component of key componentKey. + * + * If instanceName is omitted, default sonarqube instance is queried in config + * * @param componentKey - component key of the project we want to get measure from. * @param instanceName - name of the instance (in config) where the project is hosted. * @returns All measures with the analysis date. Will return undefined if we @@ -42,7 +45,7 @@ export interface SonarqubeInfoProvider { */ getFindings( componentKey: string, - instanceName: string, + instanceName?: string, ): Promise; } @@ -295,8 +298,10 @@ export class DefaultSonarqubeInfoProvider implements SonarqubeInfoProvider { * {@inheritDoc SonarqubeInfoProvider.getBaseUrl} * @throws Error If configuration can't be retrieved. */ - getBaseUrl({ instanceName }: { instanceName: string }): { baseUrl: string } { - const instanceConfig = this.config.getInstanceConfig(instanceName ?? ''); + getBaseUrl({ instanceName }: { instanceName?: string } = {}): { + baseUrl: string; + } { + const instanceConfig = this.config.getInstanceConfig(instanceName); return { baseUrl: instanceConfig.baseUrl }; } @@ -306,11 +311,9 @@ export class DefaultSonarqubeInfoProvider implements SonarqubeInfoProvider { */ async getFindings( componentKey: string, - instanceName: string, + instanceName?: string, ): Promise { - const { baseUrl, apiKey } = this.config.getInstanceConfig( - instanceName ?? '', - ); + const { baseUrl, apiKey } = this.config.getInstanceConfig(instanceName); // get component info to retrieve analysis date const component = From b90d81c65ba747386cf8e3558b05547d0d314bd0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 09:23:45 +0000 Subject: [PATCH 103/144] fix(deps): update dependency @roadiehq/backstage-plugin-github-pull-requests to v2.2.3 Signed-off-by: Renovate Bot --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index d907bab571..d99d336004 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6030,9 +6030,9 @@ zustand "3.6.9" "@roadiehq/backstage-plugin-github-pull-requests@^2.0.0": - version "2.2.2" - resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-github-pull-requests/-/backstage-plugin-github-pull-requests-2.2.2.tgz#b58568bdfbf08dcf0d4d45e2fd1d080875627439" - integrity sha512-klMqFfiSQMVg2PxrEU7v7UulkwuTiGBjQQnfHKuwpsziGiJoN4XtEZW/VdIEc4wHbBN8BA4CRJ1127V9up1dnQ== + version "2.2.3" + resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-github-pull-requests/-/backstage-plugin-github-pull-requests-2.2.3.tgz#8a5f5c18f0d0196c3fb5b350598293f2e441c9cd" + integrity sha512-ClZc4gLSsE+e+C6tpXJFJ2bXSo28UdlEACKzVK/w1H63XnyebsJHNu8uJJbdZL7GImHM3P9HjkXhSjj01g6HUg== dependencies: "@backstage/catalog-model" "^1.0.0" "@backstage/core-components" "^0.10.0" From 92103db5373b8219df7d064a6352906529b7c9ee Mon Sep 17 00:00:00 2001 From: Joon Park Date: Mon, 1 Aug 2022 11:07:05 +0100 Subject: [PATCH 104/144] Aggregate catalog permissions (#12832) As a follow up to https://github.com/backstage/backstage/pull/11695, the catalog permissions will now be aggregated and made available on the `/.well-known/backstage/permissions/metadata/` endpoint. Signed-off-by: Joon Park --- .changeset/lovely-walls-brush.md | 5 +++++ .../catalog-backend/src/service/CatalogBuilder.ts | 6 +++++- plugins/catalog-common/api-report.md | 6 ++++++ plugins/catalog-common/src/index.ts | 1 + plugins/catalog-common/src/permissions.ts | 14 ++++++++++++++ 5 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 .changeset/lovely-walls-brush.md diff --git a/.changeset/lovely-walls-brush.md b/.changeset/lovely-walls-brush.md new file mode 100644 index 0000000000..8834673d3b --- /dev/null +++ b/.changeset/lovely-walls-brush.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-common': patch +--- + +Export aggregated list of all catalog permissions diff --git a/plugins/catalog-backend/src/service/CatalogBuilder.ts b/plugins/catalog-backend/src/service/CatalogBuilder.ts index a9ba5bbb23..e9e35301c3 100644 --- a/plugins/catalog-backend/src/service/CatalogBuilder.ts +++ b/plugins/catalog-backend/src/service/CatalogBuilder.ts @@ -91,7 +91,10 @@ import { } from '@backstage/plugin-permission-node'; import { AuthorizedEntitiesCatalog } from './AuthorizedEntitiesCatalog'; import { basicEntityFilter } from './request/basicEntityFilter'; -import { RESOURCE_TYPE_CATALOG_ENTITY } from '@backstage/plugin-catalog-common'; +import { + catalogPermissions, + RESOURCE_TYPE_CATALOG_ENTITY, +} from '@backstage/plugin-catalog-common'; import { AuthorizedLocationService } from './AuthorizedLocationService'; /** @public */ @@ -435,6 +438,7 @@ export class CatalogBuilder { entitiesByRef[stringifyEntityRef(parseEntityRef(resourceRef))], ); }, + permissions: catalogPermissions, rules: this.permissionRules, }); const stitcher = new Stitcher(dbClient, logger); diff --git a/plugins/catalog-common/api-report.md b/plugins/catalog-common/api-report.md index ab540d446b..b7eaf99d8b 100644 --- a/plugins/catalog-common/api-report.md +++ b/plugins/catalog-common/api-report.md @@ -49,6 +49,12 @@ export const catalogLocationDeletePermission: BasicPermission; // @alpha export const catalogLocationReadPermission: BasicPermission; +// @alpha +export const catalogPermissions: ( + | BasicPermission + | ResourcePermission<'catalog-entity'> +)[]; + // @alpha export const RESOURCE_TYPE_CATALOG_ENTITY = 'catalog-entity'; ``` diff --git a/plugins/catalog-common/src/index.ts b/plugins/catalog-common/src/index.ts index dfa90c448b..614948e56c 100644 --- a/plugins/catalog-common/src/index.ts +++ b/plugins/catalog-common/src/index.ts @@ -30,6 +30,7 @@ export { catalogLocationReadPermission, catalogLocationCreatePermission, catalogLocationDeletePermission, + catalogPermissions, } from './permissions'; export type { CatalogEntityPermission } from './permissions'; diff --git a/plugins/catalog-common/src/permissions.ts b/plugins/catalog-common/src/permissions.ts index aa95e8c00f..615f02a7fb 100644 --- a/plugins/catalog-common/src/permissions.ts +++ b/plugins/catalog-common/src/permissions.ts @@ -129,3 +129,17 @@ export const catalogLocationDeletePermission = createPermission({ action: 'delete', }, }); + +/** + * List of all catalog permissions. + * @alpha + */ +export const catalogPermissions = [ + catalogEntityReadPermission, + catalogEntityCreatePermission, + catalogEntityDeletePermission, + catalogEntityRefreshPermission, + catalogLocationReadPermission, + catalogLocationCreatePermission, + catalogLocationDeletePermission, +]; From 23abde02b63e9dda7197c6f1c70f9ac4e1e09939 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Mon, 1 Aug 2022 13:12:21 +0200 Subject: [PATCH 105/144] chore(techdocs-node): bump techdocs container image Signed-off-by: Camila Belo --- plugins/techdocs-node/src/stages/generate/techdocs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/techdocs-node/src/stages/generate/techdocs.ts b/plugins/techdocs-node/src/stages/generate/techdocs.ts index e3debab526..d80449d58c 100644 --- a/plugins/techdocs-node/src/stages/generate/techdocs.ts +++ b/plugins/techdocs-node/src/stages/generate/techdocs.ts @@ -53,7 +53,7 @@ export class TechdocsGenerator implements GeneratorBase { * The default docker image (and version) used to generate content. Public * and static so that techdocs-node consumers can use the same version. */ - public static readonly defaultDockerImage = 'spotify/techdocs:v1.0.3'; + public static readonly defaultDockerImage = 'spotify/techdocs:v1.1.0'; private readonly logger: Logger; private readonly containerRunner: ContainerRunner; private readonly options: GeneratorConfig; From e7d8ef03d37419ec7036fc5588fe6d2267519d59 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Mon, 1 Aug 2022 13:21:25 +0200 Subject: [PATCH 106/144] chore(techdocs-node): update api reports Signed-off-by: Camila Belo --- plugins/techdocs-node/api-report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/techdocs-node/api-report.md b/plugins/techdocs-node/api-report.md index cc9bc8eb51..0ac8c3eaae 100644 --- a/plugins/techdocs-node/api-report.md +++ b/plugins/techdocs-node/api-report.md @@ -217,7 +217,7 @@ export class TechdocsGenerator implements GeneratorBase { config: Config; scmIntegrations: ScmIntegrationRegistry; }); - static readonly defaultDockerImage = 'spotify/techdocs:v1.0.3'; + static readonly defaultDockerImage = 'spotify/techdocs:v1.1.0'; static fromConfig( config: Config, options: GeneratorOptions, From f83334461139a3aa4d3fcb40656c1d5f4d3abe34 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Mon, 1 Aug 2022 13:31:48 +0200 Subject: [PATCH 107/144] chore: add changeset file Signed-off-by: Camila Belo --- .changeset/techdocs-eagles-stare.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/techdocs-eagles-stare.md diff --git a/.changeset/techdocs-eagles-stare.md b/.changeset/techdocs-eagles-stare.md new file mode 100644 index 0000000000..cf8bda4024 --- /dev/null +++ b/.changeset/techdocs-eagles-stare.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs-node': patch +--- + +Bump default `TechDocs` image to `v1.1.0`, see the release [here](https://github.com/backstage/techdocs-container/releases/tag/v1.1.0). From 6b7214547f86f7d15b69ea72fa794d2b7c1b5869 Mon Sep 17 00:00:00 2001 From: Neemys <36508659+Neemys@users.noreply.github.com> Date: Mon, 1 Aug 2022 16:42:05 +0200 Subject: [PATCH 108/144] Make plugin `sonarqube-backend` APIs use object as parameters To be easily modified in the future Signed-off-by: Neemys <36508659+Neemys@users.noreply.github.com> --- .../src/service/sonarqubeInfoProvider.test.ts | 42 ++++++++++++++----- .../src/service/sonarqubeInfoProvider.ts | 34 ++++++++++----- 2 files changed, 55 insertions(+), 21 deletions(-) diff --git a/plugins/sonarqube-backend/src/service/sonarqubeInfoProvider.test.ts b/plugins/sonarqube-backend/src/service/sonarqubeInfoProvider.test.ts index f7298888fe..e617324555 100644 --- a/plugins/sonarqube-backend/src/service/sonarqubeInfoProvider.test.ts +++ b/plugins/sonarqube-backend/src/service/sonarqubeInfoProvider.test.ts @@ -173,7 +173,7 @@ describe('SonarqubeConfig', () => { }, ]); - expect(config.getInstanceConfig('default')).toEqual({ + expect(config.getInstanceConfig({ sonarqubeName: 'default' })).toEqual({ name: 'default', baseUrl: 'https://sonarqube.example.com', apiKey: '123456789abcdef0123456789abcedf012', @@ -190,7 +190,7 @@ describe('SonarqubeConfig', () => { }, ]); - expect(config.getInstanceConfig('other')).toEqual({ + expect(config.getInstanceConfig({ sonarqubeName: 'other' })).toEqual({ name: 'other', baseUrl: 'https://sonarqube-other.example.com', apiKey: '123456789abcdef0123456789abcedf012', @@ -206,7 +206,9 @@ describe('SonarqubeConfig', () => { }, ]); - expect(() => config.getInstanceConfig('default')).toThrowError(Error); + expect(() => + config.getInstanceConfig({ sonarqubeName: 'default' }), + ).toThrowError(Error); }); it('Throw an error if named instance could not be found', async () => { @@ -214,7 +216,9 @@ describe('SonarqubeConfig', () => { DUMMY_SIMPLE_OBJECT_FOR_DEFAULT_SONARQUBE_CONFIG, ]); - expect(() => config.getInstanceConfig('other')).toThrowError(Error); + expect(() => + config.getInstanceConfig({ sonarqubeName: 'other' }), + ).toThrowError(Error); }); }); }); @@ -385,7 +389,10 @@ describe('DefaultSonarqubeInfoProvider', () => { setupHandlers(); const provider = configureProvider(DUMMY_SIMPLE_CONFIG_FOR_PROVIDER); expect( - await provider.getFindings(DUMMY_COMPONENT_KEY, 'default'), + await provider.getFindings({ + componentKey: DUMMY_COMPONENT_KEY, + instanceName: 'default', + }), ).toEqual({ analysisDate: DUMMY_ANALYSIS_DATE, measures: [ @@ -414,7 +421,10 @@ describe('DefaultSonarqubeInfoProvider', () => { }, }); expect( - await provider.getFindings(DUMMY_COMPONENT_KEY, 'default'), + await provider.getFindings({ + componentKey: DUMMY_COMPONENT_KEY, + instanceName: 'default', + }), ).toBeUndefined(); }); it('Provide undefined as finding if component API answer incorrectly', async () => { @@ -434,7 +444,10 @@ describe('DefaultSonarqubeInfoProvider', () => { const provider = configureProvider(DUMMY_SIMPLE_CONFIG_FOR_PROVIDER); expect( - await provider.getFindings(DUMMY_COMPONENT_KEY, 'default'), + await provider.getFindings({ + componentKey: DUMMY_COMPONENT_KEY, + instanceName: 'default', + }), ).toBeUndefined(); }); it('Provide findings when metrics API uses pages', async () => { @@ -462,7 +475,10 @@ describe('DefaultSonarqubeInfoProvider', () => { const provider = configureProvider(DUMMY_SIMPLE_CONFIG_FOR_PROVIDER); expect( - await provider.getFindings(DUMMY_COMPONENT_KEY, 'default'), + await provider.getFindings({ + componentKey: DUMMY_COMPONENT_KEY, + instanceName: 'default', + }), ).toEqual({ analysisDate: DUMMY_ANALYSIS_DATE, measures: [ @@ -489,7 +505,10 @@ describe('DefaultSonarqubeInfoProvider', () => { const provider = configureProvider(DUMMY_SIMPLE_CONFIG_FOR_PROVIDER); expect( - await provider.getFindings(DUMMY_COMPONENT_KEY, 'default'), + await provider.getFindings({ + componentKey: DUMMY_COMPONENT_KEY, + instanceName: 'default', + }), ).toBeUndefined(); }); @@ -509,7 +528,10 @@ describe('DefaultSonarqubeInfoProvider', () => { const provider = configureProvider(DUMMY_SIMPLE_CONFIG_FOR_PROVIDER); expect( - await provider.getFindings(DUMMY_COMPONENT_KEY, 'default'), + await provider.getFindings({ + componentKey: DUMMY_COMPONENT_KEY, + instanceName: 'default', + }), ).toEqual({ analysisDate: DUMMY_ANALYSIS_DATE, measures: [], diff --git a/plugins/sonarqube-backend/src/service/sonarqubeInfoProvider.ts b/plugins/sonarqube-backend/src/service/sonarqubeInfoProvider.ts index f03593b012..7027738d2c 100644 --- a/plugins/sonarqube-backend/src/service/sonarqubeInfoProvider.ts +++ b/plugins/sonarqube-backend/src/service/sonarqubeInfoProvider.ts @@ -43,10 +43,13 @@ export interface SonarqubeInfoProvider { * @returns All measures with the analysis date. Will return undefined if we * can't provide the full response */ - getFindings( - componentKey: string, - instanceName?: string, - ): Promise; + getFindings({ + componentKey, + instanceName, + }: { + componentKey: string; + instanceName?: string; + }): Promise; } /** @@ -182,7 +185,9 @@ export class SonarqubeConfig { * @returns The requested Sonarqube instance. * @throws Error when no default config could be found or the requested name couldn't be found in config. */ - getInstanceConfig(sonarqubeName?: string): SonarqubeInstanceConfig { + getInstanceConfig({ + sonarqubeName, + }: { sonarqubeName?: string } = {}): SonarqubeInstanceConfig { const DEFAULT_SONARQUBE_NAME = 'default'; if (!sonarqubeName || sonarqubeName === DEFAULT_SONARQUBE_NAME) { @@ -301,7 +306,9 @@ export class DefaultSonarqubeInfoProvider implements SonarqubeInfoProvider { getBaseUrl({ instanceName }: { instanceName?: string } = {}): { baseUrl: string; } { - const instanceConfig = this.config.getInstanceConfig(instanceName); + const instanceConfig = this.config.getInstanceConfig({ + sonarqubeName: instanceName, + }); return { baseUrl: instanceConfig.baseUrl }; } @@ -309,11 +316,16 @@ export class DefaultSonarqubeInfoProvider implements SonarqubeInfoProvider { * {@inheritDoc SonarqubeInfoProvider.getFindings} * @throws Error If configuration can't be retrieved. */ - async getFindings( - componentKey: string, - instanceName?: string, - ): Promise { - const { baseUrl, apiKey } = this.config.getInstanceConfig(instanceName); + async getFindings({ + componentKey, + instanceName, + }: { + componentKey: string; + instanceName?: string; + }): Promise { + const { baseUrl, apiKey } = this.config.getInstanceConfig({ + sonarqubeName: instanceName, + }); // get component info to retrieve analysis date const component = From 063ca9713772d28704ebafd8d5c9b832f720d269 Mon Sep 17 00:00:00 2001 From: Neemys <36508659+Neemys@users.noreply.github.com> Date: Mon, 1 Aug 2022 16:54:24 +0200 Subject: [PATCH 109/144] Change behavior of method `useProjectInfo` in plugin `sonarqube` Will now return undefined instead of empty string. To be consistent with how the rest of the API works. Also provide unit test for this method and the other one in the same file `isSonarQubeAvailable` Signed-off-by: Neemys <36508659+Neemys@users.noreply.github.com> --- .../SonarQubeCard/SonarQubeCard.tsx | 6 +- .../src/components/useProjectKey.test.ts | 100 ++++++++++++++++++ .../sonarqube/src/components/useProjectKey.ts | 10 +- 3 files changed, 110 insertions(+), 6 deletions(-) create mode 100644 plugins/sonarqube/src/components/useProjectKey.test.ts diff --git a/plugins/sonarqube/src/components/SonarQubeCard/SonarQubeCard.tsx b/plugins/sonarqube/src/components/SonarQubeCard/SonarQubeCard.tsx index d8aaec04f2..af91bc5469 100644 --- a/plugins/sonarqube/src/components/SonarQubeCard/SonarQubeCard.tsx +++ b/plugins/sonarqube/src/components/SonarQubeCard/SonarQubeCard.tsx @@ -98,7 +98,11 @@ export const SonarQubeCard = ({ const { projectKey: projectTitle, projectInstance } = useProjectInfo(entity); const { value, loading } = useAsync( - async () => sonarQubeApi.getFindingSummary(projectTitle, projectInstance), + async () => + sonarQubeApi.getFindingSummary({ + componentKey: projectTitle, + projectInstance: projectInstance, + }), [sonarQubeApi, projectTitle], ); diff --git a/plugins/sonarqube/src/components/useProjectKey.test.ts b/plugins/sonarqube/src/components/useProjectKey.test.ts new file mode 100644 index 0000000000..be83c236df --- /dev/null +++ b/plugins/sonarqube/src/components/useProjectKey.test.ts @@ -0,0 +1,100 @@ +/* + * 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 { + isSonarQubeAvailable, + SONARQUBE_PROJECT_INSTANCE_SEPARATOR, + SONARQUBE_PROJECT_KEY_ANNOTATION, + useProjectInfo, +} from './useProjectKey'; +import { Entity } from '../../../../packages/catalog-model'; + +const createDummyEntity = (sonarqubeAnnotationValue: string): Entity => { + return { + apiVersion: '', + kind: '', + metadata: { + name: 'dummy', + annotations: { + [SONARQUBE_PROJECT_KEY_ANNOTATION]: sonarqubeAnnotationValue, + }, + }, + }; +}; + +describe('isSonarQubeAvailable', () => { + it('returns true if sonarqube annotation defined', () => { + const entity = createDummyEntity('dummy'); + expect(isSonarQubeAvailable(entity)).toBe(true); + }); + it('returns false if sonarqube annotation empty', () => { + const entity = createDummyEntity(''); + expect(isSonarQubeAvailable(entity)).toBe(false); + }); + it('returns false if sonarqube annotation not defined', () => { + const entity = { + apiVersion: '', + kind: '', + metadata: { + name: 'dummy', + annotations: {}, + }, + }; + expect(isSonarQubeAvailable(entity)).toBe(false); + }); +}); + +describe('useProjectInfo', () => { + const DUMMY_INSTANCE = 'dummyInstance'; + const DUMMY_KEY = 'dummyKey'; + it('parse annotation with key and instance', () => { + const entity = createDummyEntity( + DUMMY_INSTANCE + SONARQUBE_PROJECT_INSTANCE_SEPARATOR + DUMMY_KEY, + ); + expect(useProjectInfo(entity)).toEqual({ + projectInstance: DUMMY_INSTANCE, + projectKey: DUMMY_KEY, + }); + }); + // compatibility with previous mono-instance sonarqube config + it('parse annotation with only key', () => { + const entity = createDummyEntity(DUMMY_KEY); + expect(useProjectInfo(entity)).toEqual({ + projectInstance: undefined, + projectKey: DUMMY_KEY, + }); + }); + it('handle empty annotation', () => { + const entity = createDummyEntity(''); + expect(useProjectInfo(entity)).toEqual({ + projectInstance: undefined, + projectKey: undefined, + }); + }); + it('handle non-existent annotation', () => { + const entity = { + apiVersion: '', + kind: '', + metadata: { + name: 'dummy', + annotations: {}, + }, + }; + expect(useProjectInfo(entity)).toEqual({ + projectInstance: undefined, + projectKey: undefined, + }); + }); +}); diff --git a/plugins/sonarqube/src/components/useProjectKey.ts b/plugins/sonarqube/src/components/useProjectKey.ts index fbe12b5b5d..7a5a428f49 100644 --- a/plugins/sonarqube/src/components/useProjectKey.ts +++ b/plugins/sonarqube/src/components/useProjectKey.ts @@ -25,7 +25,7 @@ export const isSonarQubeAvailable = (entity: Entity) => /** * Try to parse sonarqube information from an entity. * - * If part or all info are not found, they will default to an empty string + * If part or all info are not found, they will default to undefined * * @param entity entity to find the sonarqube information from. * @return a ProjectInfo properly populated. @@ -33,11 +33,11 @@ export const isSonarQubeAvailable = (entity: Entity) => export const useProjectInfo = ( entity: Entity, ): { - projectInstance: string; - projectKey: string; + projectInstance: string | undefined; + projectKey: string | undefined; } => { - let projectInstance = ''; - let projectKey = ''; + let projectInstance = undefined; + let projectKey = undefined; const annotation = entity?.metadata.annotations?.[SONARQUBE_PROJECT_KEY_ANNOTATION]; if (annotation) { From e598739487d641e673563c725e7b68eb8cc311f8 Mon Sep 17 00:00:00 2001 From: Neemys <36508659+Neemys@users.noreply.github.com> Date: Mon, 1 Aug 2022 17:06:57 +0200 Subject: [PATCH 110/144] Modify plugin `sonarqube`'s APIs to take object as parameter to make the API more easy to extend. Signed-off-by: Neemys <36508659+Neemys@users.noreply.github.com> --- plugins/sonarqube/src/api/SonarQubeApi.ts | 11 +++++++---- .../sonarqube/src/api/SonarQubeClient.test.ts | 17 +++++++++++++---- plugins/sonarqube/src/api/SonarQubeClient.ts | 11 +++++++---- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/plugins/sonarqube/src/api/SonarQubeApi.ts b/plugins/sonarqube/src/api/SonarQubeApi.ts index 2232a00d9f..271f1d8e8e 100644 --- a/plugins/sonarqube/src/api/SonarQubeApi.ts +++ b/plugins/sonarqube/src/api/SonarQubeApi.ts @@ -38,8 +38,11 @@ export const sonarQubeApiRef = createApiRef({ }); export type SonarQubeApi = { - getFindingSummary( - projectInstance?: string, - componentKey?: string, - ): Promise; + getFindingSummary({ + componentKey, + projectInstance, + }: { + componentKey?: string; + projectInstance?: string; + }): Promise; }; diff --git a/plugins/sonarqube/src/api/SonarQubeClient.test.ts b/plugins/sonarqube/src/api/SonarQubeClient.test.ts index 87137ea93f..dc5d7f077e 100644 --- a/plugins/sonarqube/src/api/SonarQubeClient.test.ts +++ b/plugins/sonarqube/src/api/SonarQubeClient.test.ts @@ -124,7 +124,9 @@ describe('SonarQubeClient', () => { identityApi: identityApiAuthenticated, }); - const summary = await client.getFindingSummary('our:service'); + const summary = await client.getFindingSummary({ + componentKey: 'our:service', + }); expect(summary).toEqual( expect.objectContaining({ lastAnalysis: '2020-01-01T00:00:00Z', @@ -199,7 +201,10 @@ describe('SonarQubeClient', () => { identityApi: identityApiAuthenticated, }); - const summary = await client.getFindingSummary('our:service', 'custom'); + const summary = await client.getFindingSummary({ + componentKey: 'our:service', + projectInstance: 'custom', + }); expect(summary).toEqual( expect.objectContaining({ @@ -241,7 +246,9 @@ describe('SonarQubeClient', () => { discoveryApi, identityApi: identityApiAuthenticated, }); - const summary = await client.getFindingSummary('our:service'); + const summary = await client.getFindingSummary({ + componentKey: 'our:service', + }); expect(summary?.lastAnalysis).toBe('2020-01-01T00:00:00Z'); }); @@ -267,7 +274,9 @@ describe('SonarQubeClient', () => { discoveryApi, identityApi: identityApiGuest, }); - const summary = await client.getFindingSummary('our:service'); + const summary = await client.getFindingSummary({ + componentKey: 'our:service', + }); expect(summary?.lastAnalysis).toBe('2020-01-01T00:00:00Z'); }); diff --git a/plugins/sonarqube/src/api/SonarQubeClient.ts b/plugins/sonarqube/src/api/SonarQubeClient.ts index 59182d917f..9ec40e8420 100644 --- a/plugins/sonarqube/src/api/SonarQubeClient.ts +++ b/plugins/sonarqube/src/api/SonarQubeClient.ts @@ -56,10 +56,13 @@ export class SonarQubeClient implements SonarQubeApi { return undefined; } - async getFindingSummary( - componentKey?: string, - projectInstance?: string, - ): Promise { + async getFindingSummary({ + componentKey, + projectInstance, + }: { + componentKey?: string; + projectInstance?: string; + } = {}): Promise { if (!componentKey) { return undefined; } From 65f3172896fc9effb20d6c11e215e73169ab7a7d Mon Sep 17 00:00:00 2001 From: Neemys <36508659+Neemys@users.noreply.github.com> Date: Mon, 1 Aug 2022 17:27:52 +0200 Subject: [PATCH 111/144] Fix forgotten use of recent API change in `sonarqube-backend` plugin Signed-off-by: Neemys <36508659+Neemys@users.noreply.github.com> --- plugins/sonarqube-backend/src/service/router.test.ts | 7 ++++++- plugins/sonarqube-backend/src/service/router.ts | 5 ++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/plugins/sonarqube-backend/src/service/router.test.ts b/plugins/sonarqube-backend/src/service/router.test.ts index e082215abc..6b42e745be 100644 --- a/plugins/sonarqube-backend/src/service/router.test.ts +++ b/plugins/sonarqube-backend/src/service/router.test.ts @@ -29,7 +29,12 @@ describe('createRouter', () => { > = jest.fn(); const getFindingsMock: jest.Mock< Promise, - [string, string] + [ + { + componentKey: string; + instanceName: string; + }, + ] > = jest.fn(); beforeAll(async () => { diff --git a/plugins/sonarqube-backend/src/service/router.ts b/plugins/sonarqube-backend/src/service/router.ts index 674045121f..45cdcb64c3 100644 --- a/plugins/sonarqube-backend/src/service/router.ts +++ b/plugins/sonarqube-backend/src/service/router.ts @@ -66,7 +66,10 @@ export async function createRouter( ); response.json( - await sonarqubeInfoProvider.getFindings(componentKey, instanceKey), + await sonarqubeInfoProvider.getFindings({ + componentKey, + instanceName: instanceKey, + }), ); }); From 4c9193c384e407d50008be8ce30bf65cd629173a Mon Sep 17 00:00:00 2001 From: Neemys <36508659+Neemys@users.noreply.github.com> Date: Mon, 1 Aug 2022 17:37:24 +0200 Subject: [PATCH 112/144] Fix more forgotten use of recent API change in `sonarqube-backend` plugin Signed-off-by: Neemys <36508659+Neemys@users.noreply.github.com> --- .../sonarqube-backend/src/service/router.test.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/plugins/sonarqube-backend/src/service/router.test.ts b/plugins/sonarqube-backend/src/service/router.test.ts index 6b42e745be..426066d897 100644 --- a/plugins/sonarqube-backend/src/service/router.test.ts +++ b/plugins/sonarqube-backend/src/service/router.test.ts @@ -70,10 +70,10 @@ describe('createRouter', () => { }) .send(); expect(getFindingsMock).toBeCalledTimes(1); - expect(getFindingsMock).toBeCalledWith( - DUMMY_COMPONENT_KEY, - DUMMY_INSTANCE_KEY, - ); + expect(getFindingsMock).toBeCalledWith({ + componentKey: DUMMY_COMPONENT_KEY, + instanceName: DUMMY_INSTANCE_KEY, + }); expect(response.status).toEqual(200); expect(response.body).toEqual(measures); }); @@ -104,7 +104,10 @@ describe('createRouter', () => { .send(); expect(getFindingsMock).toBeCalledTimes(1); - expect(getFindingsMock).toBeCalledWith(DUMMY_COMPONENT_KEY, undefined); + expect(getFindingsMock).toBeCalledWith({ + componentKey: DUMMY_COMPONENT_KEY, + instanceName: undefined, + }); expect(response.status).toEqual(200); expect(response.body).toEqual(measures); }); From 1abe0a2333c4551926a0839222ef3dd086b94418 Mon Sep 17 00:00:00 2001 From: Crevil Date: Mon, 1 Aug 2022 17:37:33 +0200 Subject: [PATCH 113/144] Support already expanded navigation Signed-off-by: Crevil --- .../transformers/scrollIntoNavigation.test.ts | 82 +- .../transformers/scrollIntoNavigation.ts | 10 +- .../fixtures/mkdocs-expanded-index.ts | 1577 +++++++++++++++++ plugins/techdocs/src/test-utils/index.ts | 2 + 4 files changed, 1629 insertions(+), 42 deletions(-) create mode 100644 plugins/techdocs/src/test-utils/fixtures/mkdocs-expanded-index.ts diff --git a/plugins/techdocs/src/reader/transformers/scrollIntoNavigation.test.ts b/plugins/techdocs/src/reader/transformers/scrollIntoNavigation.test.ts index ca8cf04b5e..965f2d4771 100644 --- a/plugins/techdocs/src/reader/transformers/scrollIntoNavigation.test.ts +++ b/plugins/techdocs/src/reader/transformers/scrollIntoNavigation.test.ts @@ -15,66 +15,70 @@ */ import { scrollIntoNavigation } from '.'; +import { createTestShadowDom, FIXTURES } from '../../test-utils'; jest.useFakeTimers(); describe('scrollIntoNavigation', () => { - const transformer = scrollIntoNavigation(); - const dom = { querySelectorAll: jest.fn().mockReturnValue([]) }; - afterEach(() => { jest.clearAllMocks(); }); it('scroll to active navigation item', async () => { - const scrollNavIntoView1 = jest.fn(); - const scrollNavIntoView2 = jest.fn(); + await createTestShadowDom(FIXTURES.FIXTURE_STANDARD_PAGE, { + preTransformers: [], + postTransformers: [scrollIntoNavigation()], + }); - dom.querySelectorAll.mockReturnValue([ - { - scrollIntoView: scrollNavIntoView1, - querySelector: jest.fn(), - click: jest.fn(), - }, - { - scrollIntoView: scrollNavIntoView2, - querySelector: jest.fn(), - click: jest.fn(), - }, - ]); + // jsdom does not implement scrollIntoView so we attach a function to the + // prototype to be able to test the expected behaviour. + const scrollNavIntoView = jest.fn(); + window.HTMLElement.prototype.scrollIntoView = scrollNavIntoView; - transformer(dom as unknown as Element); jest.advanceTimersByTime(200); - expect(dom.querySelectorAll).toHaveBeenCalledWith( - expect.stringMatching('li.md-nav__item--active'), - ); - expect(scrollNavIntoView1).not.toHaveBeenCalled(); - expect(scrollNavIntoView2).toHaveBeenCalledWith(); + expect(scrollNavIntoView).toHaveBeenCalledWith(); }); it('expand active navigation items', async () => { - const navItemClick1 = jest.fn(); - const navItemClick2 = jest.fn(); - - dom.querySelectorAll.mockReturnValue([ + const shadowDom = await createTestShadowDom( + FIXTURES.FIXTURE_STANDARD_PAGE, { - scrollIntoView: jest.fn(), - querySelector: jest.fn().mockReturnValue({ click: navItemClick1 }), + preTransformers: [], + postTransformers: [scrollIntoNavigation()], }, - { - scrollIntoView: jest.fn(), - querySelector: jest.fn().mockReturnValue({ click: navItemClick2 }), - }, - ]); + ); + + // jsdom does not implement scrollIntoView so we attach an empty function to + // support the behaviour. + window.HTMLElement.prototype.scrollIntoView = () => {}; + + const click = jest.fn(); + shadowDom.addEventListener('click', click); - transformer(dom as unknown as Element); jest.advanceTimersByTime(200); - expect(dom.querySelectorAll).toHaveBeenCalledWith( - expect.stringMatching('li.md-nav__item--active'), + expect(click).toHaveBeenCalled(); + }); + + it('does not expand already expanded active navigation items', async () => { + const shadowDom = await createTestShadowDom( + FIXTURES.FIXTURE_STANDARD_PAGE_EXPANDED_NAVIGATION, + { + preTransformers: [], + postTransformers: [scrollIntoNavigation()], + }, ); - expect(navItemClick1).toHaveBeenCalledWith(); - expect(navItemClick2).toHaveBeenCalledWith(); + + // jsdom does not implement scrollIntoView so we attach an empty function to + // support the behaviour. + window.HTMLElement.prototype.scrollIntoView = () => {}; + + const click = jest.fn(); + shadowDom.addEventListener('click', click); + + jest.advanceTimersByTime(200); + + expect(click).not.toHaveBeenCalled(); }); }); diff --git a/plugins/techdocs/src/reader/transformers/scrollIntoNavigation.ts b/plugins/techdocs/src/reader/transformers/scrollIntoNavigation.ts index ff6901686a..1e17d08835 100644 --- a/plugins/techdocs/src/reader/transformers/scrollIntoNavigation.ts +++ b/plugins/techdocs/src/reader/transformers/scrollIntoNavigation.ts @@ -23,10 +23,14 @@ export const scrollIntoNavigation = (): Transformer => { if (activeNavItems.length !== 0) { // expand all navigation items that are active activeNavItems.forEach(activeNavItem => { - activeNavItem?.querySelector('input')?.click(); + const input = activeNavItem?.querySelector('input'); + if (input && !input?.checked) { + input.click(); + } }); - // scroll to the last active navigation item - activeNavItems[activeNavItems.length - 1].scrollIntoView(); + + const lastItem = activeNavItems[activeNavItems.length - 1]; + lastItem.scrollIntoView(); } }, 200); return dom; diff --git a/plugins/techdocs/src/test-utils/fixtures/mkdocs-expanded-index.ts b/plugins/techdocs/src/test-utils/fixtures/mkdocs-expanded-index.ts new file mode 100644 index 0000000000..1d607fd8b4 --- /dev/null +++ b/plugins/techdocs/src/test-utils/fixtures/mkdocs-expanded-index.ts @@ -0,0 +1,1577 @@ +/* + * Copyright 2020 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 default ` + + + + + + + + + + + + + + + MkDocs + + + + + + + + + + + + + + + + +
+ +
+ +
+ +
+
+
+
+
+
+ +
+
+
+ + + +
+
+

+ MkDocs +

+

Project documentation with Markdown.

+
+

+ Overview +

+

+ MkDocs is a fast, simple and + downright gorgeous static site generator that's + geared towards building project documentation. Documentation + source files are written in Markdown, and configured with a + single YAML configuration file. Start by reading the + introduction below, then check the User Guide for more info. +

+

+ Host anywhere +

+

+ MkDocs builds completely static HTML sites that you can host on + GitHub pages, Amazon S3, or + anywhere else you + choose. +

+

+ Great themes available +

+

+ There's a stack of good looking + themes available for + MkDocs. Choose between the built in themes: + mkdocs and + readthedocs, select one of the 3rd party themes listed on the + MkDocs Themes + wiki page, or + build your own. +

+

+ Preview your site as you work +

+

+ The built-in dev-server allows you to preview your documentation + as you're writing it. It will even auto-reload and refresh your + browser whenever you save your changes. +

+

+ Easy to customize +

+

+ Get your project documentation looking just the way you want it + by customizing the + theme and/or + installing some plugins. +

+
+

+ Installation +

+

+ Install with a Package Manager +

+

+ If you have and use a package manager (such as + apt-get, + dnf, homebrew, + yum, + chocolatey, etc.) to + install packages on your system, then you may want to search for + a "MkDocs" package and, if a recent version is available, + install it with your package manager (check your system's + documentation for details). That's it, you're done! Skip down to + Getting Started. +

+

+ If your package manager does not have a recent "MkDocs" package, + you can still use your package manager to install "Python" and + "pip". Then you can use pip to + install MkDocs. +

+

+ Manual Installation +

+

+ In order to manually install MkDocs you'll need + Python installed on your + system, as well as the Python package manager, + pip. You can check if you have these already installed from the + command line: +

+
+
$ python --version
+Python 3.8.2
+$ pip --version
+pip 20.0.2 from /usr/local/lib/python3.8/site-packages/pip (python 3.8)
+
+
+ +

+ MkDocs supports Python versions 3.5, 3.6, 3.7, 3.8, and pypy3. +

+

+ Installing Python +

+

+ Install Python by + downloading an installer appropriate for your system from + python.org and + running it. +

+
+

Note

+

+ If you are installing Python on Windows, be sure to check the + box to have Python added to your PATH if the installer offers + such an option (it's normally off by default). +

+

+ Add Python to PATH +

+
+

+ Installing pip +

+

+ If you're using a recent version of Python, the Python package + manager, + pip, is most likely installed by default. However, you may need to + upgrade pip to the lasted version: +

+
+
pip install --upgrade pip
+
+
+ +

+ If you need to install + pip + for the first time, download + get-pip.py. + Then run the following command to install it: +

+
+
python get-pip.py
+
+
+ +

+ Installing MkDocs +

+

Install the mkdocs package using pip:

+
+
pip install mkdocs
+
+
+ +

+ You should now have the mkdocs command installed on + your system. Run mkdocs --version to check that + everything worked okay. +

+
+
$ mkdocs --version
+mkdocs, version 0.15.3
+
+
+ +
+

Note

+

+ If you would like manpages installed for MkDocs, the + click-man + tool can generate and install them for you. Simply run the + following two commands: +

+ + + + + +
+
+
+1
+2
+
+
+
+
pip install click-man
+click-man --target path/to/man/pages mkdocs
+
+
+
+ +

+ See the + click-man documentation + for an explanation of why manpages are not automatically + generated and installed by pip. +

+
+
+

Note

+

+ If you are using Windows, some of the above commands may not + work out-of-the-box. +

+

+ A quick solution may be to preface every Python command with + python -m like this: +

+ + + + + +
+
+
+1
+2
+
+
+
+
python -m pip install mkdocs
+python -m mkdocs
+
+
+
+ +

+ For a more permanent solution, you may need to edit your + PATH environment variable to include the + Scripts directory of your Python installation. + Recent versions of Python include a script to do this for you. + Navigate to your Python installation directory (for example + C:\Python38\), open the Tools, then + Scripts folder, and run the + win_add2path.py file by double clicking on it. + Alternatively, you can + download + the script and run it (python win_add2path.py). +

+
+
+

+ Getting Started +

+

Getting started is super easy.

+
+
mkdocs new my-project
+cd my-project
+
+
+ +

+ Take a moment to review the initial project that has been + created for you. +

+

+ The initial MkDocs layout +

+

+ There's a single configuration file named + mkdocs.yml, and a folder named + docs that will contain your documentation source + files. Right now the docs folder just contains a + single documentation page, named index.md. +

+

+ MkDocs comes with a built-in dev-server that lets you preview + your documentation as you work on it. Make sure you're in the + same directory as the mkdocs.yml configuration + file, and then start the server by running the + mkdocs serve command: +

+
+
$ mkdocs serve
+INFO    -  Building documentation...
+INFO    -  Cleaning site directory
+[I 160402 15:50:43 server:271] Serving on http://127.0.0.1:8000
+[I 160402 15:50:43 handlers:58] Start watching changes
+[I 160402 15:50:43 handlers:60] Start detecting changes
+
+
+ +

+ Open up http://127.0.0.1:8000/ in your browser, and + you'll see the default home page being displayed: +

+

+ The MkDocs live server +

+

+ The dev-server also supports auto-reloading, and will rebuild + your documentation whenever anything in the configuration file, + documentation directory, or theme directory changes. +

+

+ Open the docs/index.md document in your text editor + of choice, change the initial heading to MkLorum, + and save your changes. Your browser will auto-reload and you + should see your updated documentation immediately. +

+

+ Now try editing the configuration file: mkdocs.yml. + Change the + site_name + setting to MkLorum and save the file. +

+
+
site_name: MkLorum
+
+
+ +

+ Your browser should immediately reload, and you'll see your new + site name take effect. +

+

The site_name setting

+

+ Adding pages +

+

Now add a second page to your documentation:

+
+
curl 'https://jaspervdj.be/lorem-markdownum/markdown.txt' > docs/about.md
+
+
+ +

+ As our documentation site will include some navigation headers, + you may want to edit the configuration file and add some + information about the order, title, and nesting of each page in + the navigation header by adding a + nav + setting: +

+
+
site_name: MkLorum
+nav:
+    - Home: index.md
+    - About: about.md
+
+
+ +

+ Save your changes and you'll now see a navigation bar with + Home and About items on the left as + well as Search, Previous, and + Next items on the right. +

+

Screenshot

+

+ Try the menu items and navigate back and forth between pages. + Then click on Search. A search dialog will appear, + allowing you to search for any text on any page. Notice that the + search results include every occurrence of the search term on + the site and links directly to the section of the page in which + the search term appears. You get all of that with no effort or + configuration on your part! +

+

Screenshot

+

+ Theming our documentation +

+

+ Now change the configuration file to alter how the documentation + is displayed by changing the theme. Edit the + mkdocs.yml file and add a + theme + setting: +

+
+
site_name: MkLorum
+nav:
+    - Home: index.md
+    - About: about.md
+theme: readthedocs
+
+
+ +

+ Save your changes, and you'll see the ReadTheDocs theme being + used. +

+

Screenshot

+

+ Changing the Favicon Icon +

+

+ By default, MkDocs uses the + MkDocs favicon icon. To use a + different icon, create an img subdirectory in your + docs_dir and copy your custom + favicon.ico file to that directory. MkDocs will + automatically detect and use that file as your favicon icon. +

+

+ Building the site +

+

+ That's looking good. You're ready to deploy the first pass of + your MkLorum documentation. First build the + documentation: +

+
+
mkdocs build
+
+
+ +

+ This will create a new directory, named site. Take + a look inside the directory: +

+
+
$ ls site
+about  fonts  index.html  license  search.html
+css    img    js          mkdocs   sitemap.xml
+
+
+ +

+ Notice that your source documentation has been output as two + HTML files named index.html and + about/index.html. You also have various other media + that's been copied into the site directory as part + of the documentation theme. You even have a + sitemap.xml file and + mkdocs/search_index.json. +

+

+ If you're using source code control such as git you + probably don't want to check your documentation builds into the + repository. Add a line containing site/ to your + .gitignore file. +

+
+
echo "site/" >> .gitignore
+
+
+ +

+ If you're using another source code control tool you'll want to + check its documentation on how to ignore specific directories. +

+

+ After some time, files may be removed from the documentation but + they will still reside in the site directory. To + remove those stale files, just run mkdocs with the + --clean switch. +

+
+
mkdocs build --clean
+
+
+ +

+ Other Commands and Options +

+

+ There are various other commands and options available. For a + complete list of commands, use the --help flag: +

+
+
mkdocs --help
+
+
+ +

+ To view a list of options available on a given command, use the + --help flag with that command. For example, to get + a list of all options available for the + build command run the following: +

+
+
mkdocs build --help
+
+
+ +

+ Deploying +

+

+ The documentation site that you just built only uses static + files so you'll be able to host it from pretty much anywhere. + GitHub project pages + and + Amazon S3 + may be good hosting options, depending upon your needs. Upload + the contents of the entire site directory to + wherever you're hosting your website from and you're done. For + specific instructions on a number of common hosts, see the + Deploying your Docs + page. +

+

+ Getting help +

+

+ To get help with MkDocs, please use the + discussion group, + GitHub issues + or the MkDocs IRC channel #mkdocs on freenode. +

+
+
+
+
+ + +
+ + + + + + + + +`; diff --git a/plugins/techdocs/src/test-utils/index.ts b/plugins/techdocs/src/test-utils/index.ts index 584934f732..3ed7161f01 100644 --- a/plugins/techdocs/src/test-utils/index.ts +++ b/plugins/techdocs/src/test-utils/index.ts @@ -15,9 +15,11 @@ */ import FIXTURE_STANDARD_PAGE from './fixtures/mkdocs-index'; +import FIXTURE_STANDARD_PAGE_EXPANDED_NAVIGATION from './fixtures/mkdocs-expanded-index'; export const FIXTURES = { FIXTURE_STANDARD_PAGE, + FIXTURE_STANDARD_PAGE_EXPANDED_NAVIGATION, }; export * from './shadowDom'; From e69f40594514a2b0c6f4351d33a372b0377cccab Mon Sep 17 00:00:00 2001 From: Crevil Date: Mon, 1 Aug 2022 17:40:19 +0200 Subject: [PATCH 114/144] Simplify code to be more readable Signed-off-by: Crevil --- .../src/reader/transformers/scrollIntoNavigation.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/techdocs/src/reader/transformers/scrollIntoNavigation.ts b/plugins/techdocs/src/reader/transformers/scrollIntoNavigation.ts index 1e17d08835..e8d6161404 100644 --- a/plugins/techdocs/src/reader/transformers/scrollIntoNavigation.ts +++ b/plugins/techdocs/src/reader/transformers/scrollIntoNavigation.ts @@ -23,9 +23,9 @@ export const scrollIntoNavigation = (): Transformer => { if (activeNavItems.length !== 0) { // expand all navigation items that are active activeNavItems.forEach(activeNavItem => { - const input = activeNavItem?.querySelector('input'); - if (input && !input?.checked) { - input.click(); + const checkbox = activeNavItem?.querySelector('input'); + if (!checkbox?.checked) { + checkbox?.click(); } }); From ead23df325a7759cefad70d2bc5884f635d1c6ba Mon Sep 17 00:00:00 2001 From: Neemys <36508659+Neemys@users.noreply.github.com> Date: Mon, 1 Aug 2022 17:49:15 +0200 Subject: [PATCH 115/144] Update api-report.md in `sonarqube-backend` plugin Signed-off-by: Neemys <36508659+Neemys@users.noreply.github.com> --- plugins/sonarqube-backend/api-report.md | 28 +++++++++++++++++-------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/plugins/sonarqube-backend/api-report.md b/plugins/sonarqube-backend/api-report.md index 8f0c672c6c..f4c48cadce 100644 --- a/plugins/sonarqube-backend/api-report.md +++ b/plugins/sonarqube-backend/api-report.md @@ -16,10 +16,13 @@ export class DefaultSonarqubeInfoProvider implements SonarqubeInfoProvider { getBaseUrl({ instanceName }?: { instanceName?: string }): { baseUrl: string; }; - getFindings( - componentKey: string, - instanceName?: string, - ): Promise; + getFindings({ + componentKey, + instanceName, + }: { + componentKey: string; + instanceName?: string; + }): Promise; } // @public @@ -32,7 +35,11 @@ export interface RouterOptions { export class SonarqubeConfig { constructor(instances: SonarqubeInstanceConfig[]); static fromConfig(config: Config): SonarqubeConfig; - getInstanceConfig(sonarqubeName?: string): SonarqubeInstanceConfig; + getInstanceConfig({ + sonarqubeName, + }?: { + sonarqubeName?: string; + }): SonarqubeInstanceConfig; // (undocumented) readonly instances: SonarqubeInstanceConfig[]; } @@ -48,10 +55,13 @@ export interface SonarqubeInfoProvider { getBaseUrl({ instanceName }?: { instanceName?: string }): { baseUrl: string; }; - getFindings( - componentKey: string, - instanceName?: string, - ): Promise; + getFindings({ + componentKey, + instanceName, + }: { + componentKey: string; + instanceName?: string; + }): Promise; } // @public From 156d4194f38481a395de11a7fffb717f425b8203 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 19:52:01 +0000 Subject: [PATCH 116/144] fix(deps): update dependency @google-cloud/storage to v6.3.0 Signed-off-by: Renovate Bot --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 75f810e611..0902fb1880 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2742,9 +2742,9 @@ integrity sha512-91ArYvRgXWb73YvEOBMmOcJc0bDRs5yiVHnqkwoG0f3nm7nZuipllz6e7BvFESBvjkDTBC0zMD8QxedUwNLc1A== "@google-cloud/storage@^6.0.0": - version "6.2.3" - resolved "https://registry.npmjs.org/@google-cloud/storage/-/storage-6.2.3.tgz#e3dae8708488cf2e0e4fbf0488083d9d279ee097" - integrity sha512-UJqn3Ln8wFBPLuwBaNu3PlhzQDL3EKKfP1+3mzLRQhcFqgpBSMPLDgAXxc6e9S0l0kqsi4GOuAA7fA+l/VAMjQ== + version "6.3.0" + resolved "https://registry.npmjs.org/@google-cloud/storage/-/storage-6.3.0.tgz#0a9765416b659f54477da6611d9c12b914c04a61" + integrity sha512-Ah4wl9cWUEW+2lAqHsKauaLlPmbtdOdQkvJE6BFwmTSZhywYVtVHLcEpf5F+/GmmNTnirFGNdE7UjgbyOxcnRg== dependencies: "@google-cloud/paginator" "^3.0.7" "@google-cloud/projectify" "^3.0.0" From 85cfe5979ef8ce41f7dc2e28db11247066471035 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 19:52:54 +0000 Subject: [PATCH 117/144] fix(deps): update dependency aws-sdk to v2.1186.0 Signed-off-by: Renovate Bot --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 75f810e611..973848d82d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9072,9 +9072,9 @@ aws-sdk-mock@^5.2.1: traverse "^0.6.6" aws-sdk@^2.1122.0, aws-sdk@^2.814.0, aws-sdk@^2.840.0, aws-sdk@^2.948.0: - version "2.1185.0" - resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1185.0.tgz#157c6a900a9449cb36b37493337cae418e01210d" - integrity sha512-viFlYC6RAKOqBRM4gIB4rE80KMFNVvEkQpNmpd3PqCOemGPETDxCVHS0oqZ26qM278sZVHt+oAjPy5HmZasskg== + version "2.1186.0" + resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1186.0.tgz#f08fc5f1f53defa1fff83177621947dc0ca8d29b" + integrity sha512-3yDWwNWgbSH9tRVyan0PlRU938Po9QH+06XHwRNwAa/6bixYl4L48c6YgpfxBpwl0IvcCCTivD7ZqshndwishQ== dependencies: buffer "4.9.2" events "1.1.1" From e9a47dd5d4d33cd9bc6464723ad6f2490bd273a4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 20:44:15 +0000 Subject: [PATCH 118/144] fix(deps): update typescript-eslint monorepo to v5.32.0 Signed-off-by: Renovate Bot --- yarn.lock | 90 +++++++++++++++++++++++++++---------------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/yarn.lock b/yarn.lock index 20a7bb07e0..66a83a0039 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7940,13 +7940,13 @@ integrity sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw== "@typescript-eslint/eslint-plugin@^5.9.0": - version "5.31.0" - resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.31.0.tgz#cae1967b1e569e6171bbc6bec2afa4e0c8efccfe" - integrity sha512-VKW4JPHzG5yhYQrQ1AzXgVgX8ZAJEvCz0QI6mLRX4tf7rnFfh5D8SKm0Pq6w5PyNfAWJk6sv313+nEt3ohWMBQ== + version "5.32.0" + resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.32.0.tgz#e27e38cffa4a61226327c874a7be965e9a861624" + integrity sha512-CHLuz5Uz7bHP2WgVlvoZGhf0BvFakBJKAD/43Ty0emn4wXWv5k01ND0C0fHcl/Im8Td2y/7h44E9pca9qAu2ew== dependencies: - "@typescript-eslint/scope-manager" "5.31.0" - "@typescript-eslint/type-utils" "5.31.0" - "@typescript-eslint/utils" "5.31.0" + "@typescript-eslint/scope-manager" "5.32.0" + "@typescript-eslint/type-utils" "5.32.0" + "@typescript-eslint/utils" "5.32.0" debug "^4.3.4" functional-red-black-tree "^1.0.1" ignore "^5.2.0" @@ -7967,13 +7967,13 @@ eslint-utils "^3.0.0" "@typescript-eslint/parser@^5.9.0": - version "5.31.0" - resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.31.0.tgz#7f42d7dcc68a0a6d80a0f3d9a65063aee7bb8d2c" - integrity sha512-UStjQiZ9OFTFReTrN+iGrC6O/ko9LVDhreEK5S3edmXgR396JGq7CoX2TWIptqt/ESzU2iRKXAHfSF2WJFcWHw== + version "5.32.0" + resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.32.0.tgz#1de243443bc6186fb153b9e395b842e46877ca5d" + integrity sha512-IxRtsehdGV9GFQ35IGm5oKKR2OGcazUoiNBxhRV160iF9FoyuXxjY+rIqs1gfnd+4eL98OjeGnMpE7RF/NBb3A== dependencies: - "@typescript-eslint/scope-manager" "5.31.0" - "@typescript-eslint/types" "5.31.0" - "@typescript-eslint/typescript-estree" "5.31.0" + "@typescript-eslint/scope-manager" "5.32.0" + "@typescript-eslint/types" "5.32.0" + "@typescript-eslint/typescript-estree" "5.32.0" debug "^4.3.4" "@typescript-eslint/scope-manager@5.20.0": @@ -7984,13 +7984,13 @@ "@typescript-eslint/types" "5.20.0" "@typescript-eslint/visitor-keys" "5.20.0" -"@typescript-eslint/scope-manager@5.31.0": - version "5.31.0" - resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.31.0.tgz#f47a794ba84d9b818ab7f8f44fff55a61016c606" - integrity sha512-8jfEzBYDBG88rcXFxajdVavGxb5/XKXyvWgvD8Qix3EEJLCFIdVloJw+r9ww0wbyNLOTYyBsR+4ALNGdlalLLg== +"@typescript-eslint/scope-manager@5.32.0": + version "5.32.0" + resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.32.0.tgz#763386e963a8def470580cc36cf9228864190b95" + integrity sha512-KyAE+tUON0D7tNz92p1uetRqVJiiAkeluvwvZOqBmW9z2XApmk5WSMV9FrzOroAcVxJZB3GfUwVKr98Dr/OjOg== dependencies: - "@typescript-eslint/types" "5.31.0" - "@typescript-eslint/visitor-keys" "5.31.0" + "@typescript-eslint/types" "5.32.0" + "@typescript-eslint/visitor-keys" "5.32.0" "@typescript-eslint/scope-manager@5.9.0": version "5.9.0" @@ -8000,12 +8000,12 @@ "@typescript-eslint/types" "5.9.0" "@typescript-eslint/visitor-keys" "5.9.0" -"@typescript-eslint/type-utils@5.31.0": - version "5.31.0" - resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.31.0.tgz#70a0b7201360b5adbddb0c36080495aa08f6f3d9" - integrity sha512-7ZYqFbvEvYXFn9ax02GsPcEOmuWNg+14HIf4q+oUuLnMbpJ6eHAivCg7tZMVwzrIuzX3QCeAOqKoyMZCv5xe+w== +"@typescript-eslint/type-utils@5.32.0": + version "5.32.0" + resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.32.0.tgz#45a14506fe3fb908600b4cef2f70778f7b5cdc79" + integrity sha512-0gSsIhFDduBz3QcHJIp3qRCvVYbqzHg8D6bHFsDMrm0rURYDj+skBK2zmYebdCp+4nrd9VWd13egvhYFJj/wZg== dependencies: - "@typescript-eslint/utils" "5.31.0" + "@typescript-eslint/utils" "5.32.0" debug "^4.3.4" tsutils "^3.21.0" @@ -8014,10 +8014,10 @@ resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.20.0.tgz#fa39c3c2aa786568302318f1cb51fcf64258c20c" integrity sha512-+d8wprF9GyvPwtoB4CxBAR/s0rpP25XKgnOvMf/gMXYDvlUC3rPFHupdTQ/ow9vn7UDe5rX02ovGYQbv/IUCbg== -"@typescript-eslint/types@5.31.0": - version "5.31.0" - resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.31.0.tgz#7aa389122b64b18e473c1672fb3b8310e5f07a9a" - integrity sha512-/f/rMaEseux+I4wmR6mfpM2wvtNZb1p9hAV77hWfuKc3pmaANp5dLAZSiE3/8oXTYTt3uV9KW5yZKJsMievp6g== +"@typescript-eslint/types@5.32.0": + version "5.32.0" + resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.32.0.tgz#484273021eeeae87ddb288f39586ef5efeb6dcd8" + integrity sha512-EBUKs68DOcT/EjGfzywp+f8wG9Zw6gj6BjWu7KV/IYllqKJFPlZlLSYw/PTvVyiRw50t6wVbgv4p9uE2h6sZrQ== "@typescript-eslint/types@5.9.0": version "5.9.0" @@ -8037,13 +8037,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@5.31.0": - version "5.31.0" - resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.31.0.tgz#eb92970c9d6e3946690d50c346fb9b1d745ee882" - integrity sha512-3S625TMcARX71wBc2qubHaoUwMEn+l9TCsaIzYI/ET31Xm2c9YQ+zhGgpydjorwQO9pLfR/6peTzS/0G3J/hDw== +"@typescript-eslint/typescript-estree@5.32.0": + version "5.32.0" + resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.32.0.tgz#282943f34babf07a4afa7b0ff347a8e7b6030d12" + integrity sha512-ZVAUkvPk3ITGtCLU5J4atCw9RTxK+SRc6hXqLtllC2sGSeMFWN+YwbiJR9CFrSFJ3w4SJfcWtDwNb/DmUIHdhg== dependencies: - "@typescript-eslint/types" "5.31.0" - "@typescript-eslint/visitor-keys" "5.31.0" + "@typescript-eslint/types" "5.32.0" + "@typescript-eslint/visitor-keys" "5.32.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" @@ -8063,15 +8063,15 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/utils@5.31.0": - version "5.31.0" - resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.31.0.tgz#e146fa00dca948bfe547d665b2138a2dc1b79acd" - integrity sha512-kcVPdQS6VIpVTQ7QnGNKMFtdJdvnStkqS5LeALr4rcwx11G6OWb2HB17NMPnlRHvaZP38hL9iK8DdE9Fne7NYg== +"@typescript-eslint/utils@5.32.0": + version "5.32.0" + resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.32.0.tgz#eccb6b672b94516f1afc6508d05173c45924840c" + integrity sha512-W7lYIAI5Zlc5K082dGR27Fczjb3Q57ECcXefKU/f0ajM5ToM0P+N9NmJWip8GmGu/g6QISNT+K6KYB+iSHjXCQ== dependencies: "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.31.0" - "@typescript-eslint/types" "5.31.0" - "@typescript-eslint/typescript-estree" "5.31.0" + "@typescript-eslint/scope-manager" "5.32.0" + "@typescript-eslint/types" "5.32.0" + "@typescript-eslint/typescript-estree" "5.32.0" eslint-scope "^5.1.1" eslint-utils "^3.0.0" @@ -8095,12 +8095,12 @@ "@typescript-eslint/types" "5.20.0" eslint-visitor-keys "^3.0.0" -"@typescript-eslint/visitor-keys@5.31.0": - version "5.31.0" - resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.31.0.tgz#b0eca264df01ce85dceb76aebff3784629258f54" - integrity sha512-ZK0jVxSjS4gnPirpVjXHz7mgdOsZUHzNYSfTw2yPa3agfbt9YfqaBiBZFSSxeBWnpWkzCxTfUpnzA3Vily/CSg== +"@typescript-eslint/visitor-keys@5.32.0": + version "5.32.0" + resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.32.0.tgz#b9715d0b11fdb5dd10fd0c42ff13987470525394" + integrity sha512-S54xOHZgfThiZ38/ZGTgB2rqx51CMJ5MCfVT2IplK4Q7hgzGfe0nLzLCcenDnc/cSjP568hdeKfeDcBgqNHD/g== dependencies: - "@typescript-eslint/types" "5.31.0" + "@typescript-eslint/types" "5.32.0" eslint-visitor-keys "^3.3.0" "@typescript-eslint/visitor-keys@5.9.0": From ff3d0e67799753e7a97ef43298f383ae491a7598 Mon Sep 17 00:00:00 2001 From: Kamil Wolny Date: Mon, 1 Aug 2022 22:51:25 +0100 Subject: [PATCH 119/144] feat: renamed react props to include components name + removed redundant default export Signed-off-by: Kamil Wolny --- .../components/GitHubIssues/GitHubIssues.tsx | 7 ++----- .../GitHubIssues/IssueCard/Assignees.tsx | 8 +++----- .../GitHubIssues/IssueCard/CommentsCount.tsx | 6 +++--- .../GitHubIssues/IssueCard/IssueCard.tsx | 8 ++++---- .../GitHubIssues/IssuesList/Filters/Filters.tsx | 17 ++++++++--------- .../GitHubIssues/IssuesList/IssuesList.tsx | 11 +++++++---- 6 files changed, 27 insertions(+), 30 deletions(-) diff --git a/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx b/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx index 1e50ececbf..e873028060 100644 --- a/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx +++ b/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx @@ -28,10 +28,7 @@ import { import { IssueList } from './IssuesList'; import { NoRepositoriesInfo } from './NoRepositoriesInfo'; -export type PluginMode = 'page' | 'card'; - -export type Props = { - mode: PluginMode; +export type GitHubIssuesProps = { itemsPerPage?: number; itemsPerRepo?: number; }; @@ -39,7 +36,7 @@ export type Props = { export const GitHubIssues = ({ itemsPerPage = 10, itemsPerRepo = 40, -}: Props) => { +}: GitHubIssuesProps) => { const [isLoading, setIsLoading] = React.useState(true); const [issuesByRepository, setIssuesByRepository] = diff --git a/plugins/github-issues/src/components/GitHubIssues/IssueCard/Assignees.tsx b/plugins/github-issues/src/components/GitHubIssues/IssueCard/Assignees.tsx index e6abdbb6fe..173c8d9439 100644 --- a/plugins/github-issues/src/components/GitHubIssues/IssueCard/Assignees.tsx +++ b/plugins/github-issues/src/components/GitHubIssues/IssueCard/Assignees.tsx @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React, { FunctionComponent } from 'react'; +import React from 'react'; import { Typography, Box, Avatar, makeStyles } from '@material-ui/core'; -type Props = { +type AssigneesProps = { name?: string; avatar?: string; }; @@ -32,7 +32,7 @@ const useStyles = makeStyles(theme => ({ }, })); -export const Assignees: FunctionComponent = (props: Props) => { +export const Assignees = (props: AssigneesProps) => { const { name, avatar } = props; const classes = useStyles(); @@ -57,5 +57,3 @@ export const Assignees: FunctionComponent = (props: Props) => { ); }; - -export default Assignees; diff --git a/plugins/github-issues/src/components/GitHubIssues/IssueCard/CommentsCount.tsx b/plugins/github-issues/src/components/GitHubIssues/IssueCard/CommentsCount.tsx index d3e7f355e0..80a365cbbb 100644 --- a/plugins/github-issues/src/components/GitHubIssues/IssueCard/CommentsCount.tsx +++ b/plugins/github-issues/src/components/GitHubIssues/IssueCard/CommentsCount.tsx @@ -13,15 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React, { FunctionComponent } from 'react'; +import React from 'react'; import { ChatIcon } from '@backstage/core-components'; import { Box, Badge } from '@material-ui/core'; -type Props = { +type CommentsCountProps = { commentsCount: number; }; -export const CommentsCount: FunctionComponent = (props: Props) => { +export const CommentsCount = (props: CommentsCountProps) => { const { commentsCount } = props; return ( diff --git a/plugins/github-issues/src/components/GitHubIssues/IssueCard/IssueCard.tsx b/plugins/github-issues/src/components/GitHubIssues/IssueCard/IssueCard.tsx index 5b0abe79b3..95658fb343 100644 --- a/plugins/github-issues/src/components/GitHubIssues/IssueCard/IssueCard.tsx +++ b/plugins/github-issues/src/components/GitHubIssues/IssueCard/IssueCard.tsx @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React, { FunctionComponent } from 'react'; +import React from 'react'; import { DateTime } from 'luxon'; import { @@ -23,12 +23,12 @@ import { CardActionArea, Link, } from '@material-ui/core'; -import Assignees from './Assignees'; +import { Assignees } from './Assignees'; import { CommentsCount } from './CommentsCount'; import Divider from '@material-ui/core/Divider'; -type Props = { +type IssueCardProps = { title: string; createdAt: string; updatedAt?: string; @@ -45,7 +45,7 @@ type Props = { const getElapsedTime = (isoDate: string) => DateTime.fromISO(isoDate).toRelative(); -export const IssueCard: FunctionComponent = (props: Props) => { +export const IssueCard = (props: IssueCardProps) => { const { title, createdAt, diff --git a/plugins/github-issues/src/components/GitHubIssues/IssuesList/Filters/Filters.tsx b/plugins/github-issues/src/components/GitHubIssues/IssuesList/Filters/Filters.tsx index eab1d8f57b..de071ab5bb 100644 --- a/plugins/github-issues/src/components/GitHubIssues/IssuesList/Filters/Filters.tsx +++ b/plugins/github-issues/src/components/GitHubIssues/IssuesList/Filters/Filters.tsx @@ -14,16 +14,11 @@ * limitations under the License. */ import React from 'react'; -import { Select, SelectedItems } from '@backstage/core-components'; +import { Select, SelectedItems, SelectItem } from '@backstage/core-components'; import { makeStyles, Box, Typography } from '@material-ui/core'; -export type FilterItem = { - label: string; - value: string; -}; - -type Props = { - items: Array; +type RepositoryFiltersProps = { + items: Array; totalIssuesInGitHub: number; placeholder: string; onChange: (active: Array) => void; @@ -47,7 +42,11 @@ const checkSelectedItems: ( return onChange(active as Array); }; -export const Filters = ({ items, onChange, placeholder }: Props) => { +export const RepositoryFilters = ({ + items, + onChange, + placeholder, +}: RepositoryFiltersProps) => { const css = useStyles(); return ( diff --git a/plugins/github-issues/src/components/GitHubIssues/IssuesList/IssuesList.tsx b/plugins/github-issues/src/components/GitHubIssues/IssuesList/IssuesList.tsx index 34ccab597d..f279294928 100644 --- a/plugins/github-issues/src/components/GitHubIssues/IssuesList/IssuesList.tsx +++ b/plugins/github-issues/src/components/GitHubIssues/IssuesList/IssuesList.tsx @@ -20,11 +20,11 @@ import { Pagination } from '@material-ui/lab'; import { IssueCard } from '../IssueCard'; import { RepoIssues } from '../../../hooks/useGetIssuesByRepoFromGitHub'; -import { Filters } from './Filters'; +import { RepositoryFilters } from './Filters'; export type PluginMode = 'page' | 'card'; -export type Props = { +export type IssueListProps = { itemsPerPage?: number; issuesByRepository?: Record; }; @@ -37,7 +37,10 @@ const getIssuesCountForFilterLabel = ( issuesAvailable < totalIssues ? '*' : '' }`; -export const IssueList = ({ itemsPerPage = 10, issuesByRepository }: Props) => { +export const IssueList = ({ + itemsPerPage = 10, + issuesByRepository, +}: IssueListProps) => { const [currentPage, setCurrentPage] = React.useState(1); const [activeFilter, setActiveFilter] = React.useState>([]); @@ -108,7 +111,7 @@ export const IssueList = ({ itemsPerPage = 10, issuesByRepository }: Props) => { return ( {issues.length > 0 && ( - Date: Mon, 1 Aug 2022 22:52:42 +0100 Subject: [PATCH 120/144] feat: export the same github component as card and as a page Signed-off-by: Kamil Wolny --- .../GitHubIssuesCard/GitHubIssuesCard.tsx | 24 ------------------- .../src/components/GitHubIssuesCard/index.ts | 16 ------------- .../GitHubIssuesPage/GitHubIssuesPage.tsx | 23 ------------------ .../src/components/GitHubIssuesPage/index.ts | 16 ------------- plugins/github-issues/src/plugin.ts | 5 ++-- 5 files changed, 2 insertions(+), 82 deletions(-) delete mode 100644 plugins/github-issues/src/components/GitHubIssuesCard/GitHubIssuesCard.tsx delete mode 100644 plugins/github-issues/src/components/GitHubIssuesCard/index.ts delete mode 100644 plugins/github-issues/src/components/GitHubIssuesPage/GitHubIssuesPage.tsx delete mode 100644 plugins/github-issues/src/components/GitHubIssuesPage/index.ts diff --git a/plugins/github-issues/src/components/GitHubIssuesCard/GitHubIssuesCard.tsx b/plugins/github-issues/src/components/GitHubIssuesCard/GitHubIssuesCard.tsx deleted file mode 100644 index 2db4cabb21..0000000000 --- a/plugins/github-issues/src/components/GitHubIssuesCard/GitHubIssuesCard.tsx +++ /dev/null @@ -1,24 +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 React, { FunctionComponent } from 'react'; - -import { GitHubIssues, Props as GitHubIssuesProps } from '../GitHubIssues'; - -type Props = Omit; - -export const GitHubIssuesCard: FunctionComponent = props => { - return ; -}; diff --git a/plugins/github-issues/src/components/GitHubIssuesCard/index.ts b/plugins/github-issues/src/components/GitHubIssuesCard/index.ts deleted file mode 100644 index c300af125c..0000000000 --- a/plugins/github-issues/src/components/GitHubIssuesCard/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 './GitHubIssuesCard'; diff --git a/plugins/github-issues/src/components/GitHubIssuesPage/GitHubIssuesPage.tsx b/plugins/github-issues/src/components/GitHubIssuesPage/GitHubIssuesPage.tsx deleted file mode 100644 index 0c9bf4d08e..0000000000 --- a/plugins/github-issues/src/components/GitHubIssuesPage/GitHubIssuesPage.tsx +++ /dev/null @@ -1,23 +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 React, { FunctionComponent } from 'react'; -import { GitHubIssues, Props as GitHubIssuesProps } from '../GitHubIssues'; - -type Props = Omit; - -export const GitHubIssuesPage: FunctionComponent = props => { - return ; -}; diff --git a/plugins/github-issues/src/components/GitHubIssuesPage/index.ts b/plugins/github-issues/src/components/GitHubIssuesPage/index.ts deleted file mode 100644 index 83f7f4eb87..0000000000 --- a/plugins/github-issues/src/components/GitHubIssuesPage/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 './GitHubIssuesPage'; diff --git a/plugins/github-issues/src/plugin.ts b/plugins/github-issues/src/plugin.ts index c5bf1cdbce..ece3fd09a2 100644 --- a/plugins/github-issues/src/plugin.ts +++ b/plugins/github-issues/src/plugin.ts @@ -34,8 +34,7 @@ export const GitHubIssuesCard = gitHubIssuesPlugin.provide( createComponentExtension({ name: 'GitHubIssuesCard', component: { - lazy: () => - import('./components/GitHubIssuesCard').then(m => m.GitHubIssuesCard), + lazy: () => import('./components/GitHubIssues').then(m => m.GitHubIssues), }, }), ); @@ -45,7 +44,7 @@ export const GitHubIssuesPage = gitHubIssuesPlugin.provide( createRoutableExtension({ name: 'GitHubIssuesPage', component: () => - import('./components/GitHubIssuesPage').then(m => m.GitHubIssuesPage), + import('./components/GitHubIssues').then(m => m.GitHubIssues), mountPoint: rootRouteRef, }), ); From 5b8aa801f772fd542fa2dd4fadc5b4c7786a8de9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 2 Aug 2022 01:50:57 +0000 Subject: [PATCH 121/144] chore(deps): update dependency @types/tar to v6.1.2 Signed-off-by: Renovate Bot --- yarn.lock | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/yarn.lock b/yarn.lock index 66a83a0039..6ced0266ee 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7781,12 +7781,12 @@ "@types/node" "*" "@types/tar@^6.1.1": - version "6.1.1" - resolved "https://registry.npmjs.org/@types/tar/-/tar-6.1.1.tgz#ab341ec1f149d7eb2a4f4ded56ff85f0d4fe7cb5" - integrity sha512-8mto3YZfVpqB1CHMaYz1TUYIQfZFbh/QbEq5Hsn6D0ilCfqRVCdalmc89B7vi3jhl9UYIk+dWDABShNfOkv5HA== + version "6.1.2" + resolved "https://registry.npmjs.org/@types/tar/-/tar-6.1.2.tgz#e60108a7d1b08cc91bf2faf1286cc08fdad48bbe" + integrity sha512-bnX3RRm70/n1WMwmevdOAeDU4YP7f5JSubgnuU+yrO+xQQjwDboJj3u2NTJI5ngCQhXihqVVAH5h5J8YpdpEvg== dependencies: - "@types/minipass" "*" "@types/node" "*" + minipass "^3.3.5" "@types/tern@*": version "0.23.4" @@ -19261,6 +19261,13 @@ minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3, minipass@^3. dependencies: yallist "^4.0.0" +minipass@^3.3.5: + version "3.3.5" + resolved "https://registry.npmjs.org/minipass/-/minipass-3.3.5.tgz#6da7e53a48db8a856eeb9153d85b230a2119e819" + integrity sha512-rQ/p+KfKBkeNwo04U15i+hOwoVBVmekmm/HcfTkTN2t9pbQKCMm4eN5gFeqgrrSp/kH/7BYYhTIHOxGqzbBPaA== + dependencies: + yallist "^4.0.0" + minizlib@^2.0.0, minizlib@^2.1.1, minizlib@^2.1.2: version "2.1.2" resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" From 8b03fb7800d3bedaa21268bb64dca31e8c66368a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 2 Aug 2022 05:12:13 +0000 Subject: [PATCH 122/144] fix(deps): update dependency sucrase to v3.25.0 Signed-off-by: Renovate Bot --- storybook/yarn.lock | 6 +++--- yarn.lock | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/storybook/yarn.lock b/storybook/yarn.lock index f603d5ba1a..bec1d7019f 100644 --- a/storybook/yarn.lock +++ b/storybook/yarn.lock @@ -7783,9 +7783,9 @@ style-to-object@0.3.0, style-to-object@^0.3.0: inline-style-parser "0.1.1" sucrase@^3.21.0: - version "3.24.0" - resolved "https://registry.npmjs.org/sucrase/-/sucrase-3.24.0.tgz#66a8f2cc845bc441706ce5f3056de283289067b6" - integrity sha512-SevqflhW356TKEyWjFHg2e5f3eH+5rzmsMJxrVMDvZIEHh/goYrpzDGA6APEj4ME9MdGm8oNgIzi1eF3c3dDQA== + version "3.25.0" + resolved "https://registry.npmjs.org/sucrase/-/sucrase-3.25.0.tgz#6dffa34e614b3347877507a4380cc4f022b7b7aa" + integrity sha512-WxTtwEYXSmZArPGStGBicyRsg5TBEFhT5b7N+tF+zauImP0Acy+CoUK0/byJ8JNPK/5lbpWIVuFagI4+0l85QQ== dependencies: commander "^4.0.0" glob "7.1.6" diff --git a/yarn.lock b/yarn.lock index 66a83a0039..1a52a2cdaa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -24761,9 +24761,9 @@ subscriptions-transport-ws@^0.11.0: ws "^5.2.0 || ^6.0.0 || ^7.0.0" sucrase@^3.18.0, sucrase@^3.20.2: - version "3.24.0" - resolved "https://registry.npmjs.org/sucrase/-/sucrase-3.24.0.tgz#66a8f2cc845bc441706ce5f3056de283289067b6" - integrity sha512-SevqflhW356TKEyWjFHg2e5f3eH+5rzmsMJxrVMDvZIEHh/goYrpzDGA6APEj4ME9MdGm8oNgIzi1eF3c3dDQA== + version "3.25.0" + resolved "https://registry.npmjs.org/sucrase/-/sucrase-3.25.0.tgz#6dffa34e614b3347877507a4380cc4f022b7b7aa" + integrity sha512-WxTtwEYXSmZArPGStGBicyRsg5TBEFhT5b7N+tF+zauImP0Acy+CoUK0/byJ8JNPK/5lbpWIVuFagI4+0l85QQ== dependencies: commander "^4.0.0" glob "7.1.6" From f762386d482c45f11d780f1d085f5f53ad083c1c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 2 Aug 2022 08:43:23 +0000 Subject: [PATCH 123/144] Version Packages (next) --- .changeset/create-app-1659429685.md | 5 + .changeset/pre.json | 22 +- docs/releases/v1.5.0-next.1-changelog.md | 274 ++++++++++++++++++ package.json | 2 +- packages/app/CHANGELOG.md | 17 ++ packages/app/package.json | 24 +- packages/backend-common/CHANGELOG.md | 8 + packages/backend-common/package.json | 4 +- packages/core-components/CHANGELOG.md | 6 + packages/core-components/package.json | 2 +- packages/create-app/CHANGELOG.md | 6 + packages/create-app/package.json | 2 +- packages/integration/CHANGELOG.md | 12 + packages/integration/package.json | 2 +- packages/techdocs-cli/CHANGELOG.md | 8 + packages/techdocs-cli/package.json | 6 +- plugins/airbrake/package.json | 2 +- plugins/allure/package.json | 2 +- plugins/analytics-module-ga/package.json | 2 +- plugins/apache-airflow/package.json | 2 +- plugins/api-docs/CHANGELOG.md | 10 + plugins/api-docs/package.json | 8 +- plugins/azure-devops/package.json | 2 +- plugins/badges/package.json | 2 +- plugins/bazaar/package.json | 2 +- plugins/bitrise/package.json | 2 +- .../CHANGELOG.md | 15 + .../package.json | 8 +- plugins/catalog-backend/CHANGELOG.md | 13 + plugins/catalog-backend/package.json | 8 +- plugins/catalog-common/CHANGELOG.md | 6 + plugins/catalog-common/package.json | 2 +- plugins/catalog-graph/package.json | 2 +- plugins/catalog-import/package.json | 2 +- plugins/catalog-react/CHANGELOG.md | 9 + plugins/catalog-react/package.json | 10 +- plugins/catalog/CHANGELOG.md | 13 + plugins/catalog/package.json | 8 +- plugins/circleci/package.json | 2 +- plugins/cloudbuild/package.json | 2 +- plugins/code-climate/package.json | 2 +- plugins/code-coverage/package.json | 2 +- plugins/config-schema/package.json | 2 +- plugins/cost-insights/package.json | 2 +- plugins/example-todo-list/package.json | 2 +- plugins/explore/package.json | 2 +- plugins/firehydrant/package.json | 2 +- plugins/fossa/package.json | 2 +- plugins/gcp-projects/package.json | 2 +- plugins/git-release-manager/package.json | 2 +- plugins/github-actions/package.json | 2 +- plugins/github-deployments/package.json | 2 +- .../github-pull-requests-board/package.json | 2 +- plugins/gitops-profiles/package.json | 2 +- plugins/gocd/package.json | 2 +- plugins/graphiql/package.json | 2 +- plugins/home/CHANGELOG.md | 9 + plugins/home/package.json | 6 +- plugins/ilert/package.json | 2 +- plugins/jenkins-backend/CHANGELOG.md | 8 + plugins/jenkins-backend/package.json | 6 +- plugins/jenkins-common/CHANGELOG.md | 7 + plugins/jenkins-common/package.json | 4 +- plugins/jenkins/CHANGELOG.md | 9 + plugins/jenkins/package.json | 8 +- plugins/kafka/package.json | 4 +- plugins/kubernetes/CHANGELOG.md | 9 + plugins/kubernetes/package.json | 6 +- plugins/lighthouse/package.json | 2 +- plugins/newrelic-dashboard/package.json | 2 +- plugins/newrelic/package.json | 2 +- plugins/org/package.json | 4 +- plugins/pagerduty/package.json | 2 +- plugins/periskop/package.json | 2 +- plugins/rollbar/package.json | 2 +- plugins/scaffolder-backend/CHANGELOG.md | 13 + plugins/scaffolder-backend/package.json | 8 +- plugins/scaffolder/CHANGELOG.md | 14 + plugins/scaffolder/package.json | 12 +- plugins/search/package.json | 2 +- plugins/sentry/package.json | 2 +- plugins/shortcuts/package.json | 2 +- plugins/sonarqube-backend/CHANGELOG.md | 12 + plugins/sonarqube-backend/package.json | 4 +- plugins/sonarqube/CHANGELOG.md | 17 ++ plugins/sonarqube/package.json | 6 +- plugins/splunk-on-call/package.json | 2 +- plugins/stack-overflow/package.json | 2 +- plugins/tech-insights/package.json | 2 +- plugins/tech-radar/package.json | 2 +- plugins/techdocs-backend/CHANGELOG.md | 10 + plugins/techdocs-backend/package.json | 10 +- .../CHANGELOG.md | 10 + .../package.json | 8 +- plugins/techdocs-node/CHANGELOG.md | 13 + plugins/techdocs-node/package.json | 6 +- plugins/techdocs-react/CHANGELOG.md | 9 + plugins/techdocs-react/package.json | 4 +- plugins/techdocs/CHANGELOG.md | 11 + plugins/techdocs/package.json | 10 +- plugins/todo/package.json | 2 +- plugins/user-settings/package.json | 2 +- plugins/xcmetrics/package.json | 2 +- yarn.lock | 40 ++- 104 files changed, 739 insertions(+), 158 deletions(-) create mode 100644 .changeset/create-app-1659429685.md create mode 100644 docs/releases/v1.5.0-next.1-changelog.md create mode 100644 plugins/sonarqube-backend/CHANGELOG.md diff --git a/.changeset/create-app-1659429685.md b/.changeset/create-app-1659429685.md new file mode 100644 index 0000000000..b50d431d4b --- /dev/null +++ b/.changeset/create-app-1659429685.md @@ -0,0 +1,5 @@ +--- +'@backstage/create-app': patch +--- + +Bumped create-app version. diff --git a/.changeset/pre.json b/.changeset/pre.json index 6af2afaf45..f20db5bacb 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -165,34 +165,54 @@ "@backstage/plugin-vault": "0.1.1", "@backstage/plugin-vault-backend": "0.2.0", "@backstage/plugin-xcmetrics": "0.2.27", - "@internal/plugin-catalog-customized": "0.0.0" + "@internal/plugin-catalog-customized": "0.0.0", + "@backstage/plugin-sonarqube-backend": "0.0.0" }, "changesets": [ + "big-mirrors-play", "calm-clocks-drum", "create-app-1658824524", + "create-app-1659429685", + "dull-owls-grab", "dull-pumas-hope", "dull-starfishes-chew", + "eighty-radios-look", + "empty-apple-pie", + "empty-apples-tie", "famous-bikes-brush", "fast-panthers-fold", "few-berries-deny", + "forty-lobsters-guess", "fresh-hounds-argue", "friendly-sheep-flash", + "itchy-mice-kiss", "khaki-meals-hammer", + "little-laws-heal", "loud-panthers-arrive", + "lovely-walls-brush", + "mean-ants-hang", "metal-points-itch", "mighty-penguins-tap", "modern-shrimps-wave", "nine-mails-crash", "odd-adults-smash", + "odd-tomatoes-juggle", "olive-tips-camp", "pretty-gifts-do", "purple-apricots-build", + "red-turtles-melt", "renovate-15030f1", "renovate-5b7b62b", + "renovate-5ba3a71", + "rotten-moles-give", "short-trains-roll", "silver-poets-push", "strange-crabs-confess", + "strange-moles-design", + "techdocs-eagles-stare", + "ten-roses-walk", "thick-readers-invite", + "twenty-humans-visit", "violet-mayflies-mix", "violet-trees-play" ] diff --git a/docs/releases/v1.5.0-next.1-changelog.md b/docs/releases/v1.5.0-next.1-changelog.md new file mode 100644 index 0000000000..deedd1dc44 --- /dev/null +++ b/docs/releases/v1.5.0-next.1-changelog.md @@ -0,0 +1,274 @@ +# Release v1.5.0-next.1 + +## @backstage/integration@1.3.0-next.1 + +### Minor Changes + +- ad35364e97: feat(techdocs): add edit button support for bitbucketServer + +### Patch Changes + +- 1f27d83933: Fixed bug in getGitLabFileFetchUrl where a target whose path did not contain the + `/-/` scope would result in a fetch URL that did not support + private-token-based authentication. + +## @backstage/plugin-catalog@1.5.0-next.1 + +### Minor Changes + +- fe94398418: Allow changing the subtitle of the `CatalogTable` component + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/plugin-catalog-common@1.0.5-next.0 + - @backstage/plugin-catalog-react@1.1.3-next.1 + +## @backstage/plugin-scaffolder@1.5.0-next.1 + +### Minor Changes + +- c4b452e16a: Starting the implementation of the Wizard page for the `next` scaffolder plugin + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/plugin-catalog-common@1.0.5-next.0 + - @backstage/integration@1.3.0-next.1 + - @backstage/plugin-catalog-react@1.1.3-next.1 + +## @backstage/plugin-scaffolder-backend@1.5.0-next.1 + +### Minor Changes + +- c4b452e16a: Starting the implementation of the Wizard page for the `next` scaffolder plugin + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.15.0-next.1 + - @backstage/integration@1.3.0-next.1 + - @backstage/plugin-catalog-backend@1.3.1-next.1 + +## @backstage/plugin-sonarqube@0.4.0-next.1 + +### Minor Changes + +- 619b515172: **BREAKING** This plugin now call the `sonarqube-backend` plugin instead of relying on the proxy plugin + + The whole proxy's `'/sonarqube':` key can be removed from your configuration files. + + Then head to the [README in sonarqube-backend plugin page](https://github.com/backstage/backstage/tree/master/plugins/sonarqube-backend/README.md) to learn how to set-up the link to your Sonarqube instances. + +### Patch Changes + +- f9c310a439: Add ability to provide an optional Sonarqube instance into the annotation in the `catalog-info.yaml` file +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/plugin-catalog-react@1.1.3-next.1 + +## @backstage/plugin-sonarqube-backend@0.1.0-next.0 + +### Minor Changes + +- e2be9ab3a4: Initial creation of the plugin + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.15.0-next.1 + +## @backstage/plugin-techdocs-node@1.3.0-next.1 + +### Minor Changes + +- ad35364e97: feat(techdocs): add edit button support for bitbucketServer + +### Patch Changes + +- f833344611: Bump default `TechDocs` image to `v1.1.0`, see the release [here](https://github.com/backstage/techdocs-container/releases/tag/v1.1.0). +- Updated dependencies + - @backstage/backend-common@0.15.0-next.1 + - @backstage/integration@1.3.0-next.1 + +## @backstage/backend-common@0.15.0-next.1 + +### Patch Changes + +- 1732a18a7a: Exported `redactLogLine` function to be able to use it in custom loggers and renamed it to `redactWinstonLogLine`. +- Updated dependencies + - @backstage/integration@1.3.0-next.1 + +## @backstage/core-components@0.10.1-next.1 + +### Patch Changes + +- a22af3edc8: Adding a `className` prop to the `MarkdownContent` component + +## @backstage/create-app@0.4.30-next.1 + +### Patch Changes + +- Bumped create-app version. + +## @techdocs/cli@1.1.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.15.0-next.1 + - @backstage/plugin-techdocs-node@1.3.0-next.1 + +## @backstage/plugin-api-docs@0.8.8-next.1 + +### Patch Changes + +- dae12c71cf: Updated dependency `@asyncapi/react-component` to `1.0.0-next.40`. +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/plugin-catalog@1.5.0-next.1 + - @backstage/plugin-catalog-react@1.1.3-next.1 + +## @backstage/plugin-catalog-backend@1.3.1-next.1 + +### Patch Changes + +- e3d3018531: Fix issue for conditional decisions based on properties stored as arrays, like tags. + + Before this change, having a permission policy returning conditional decisions based on metadata like tags, such like `createCatalogConditionalDecision(permission, catalogConditions.hasMetadata('tags', 'java'),)`, was producing wrong results. The issue occurred when authorizing entities already loaded from the database, for example when authorizing `catalogEntityDeletePermission`. + +- Updated dependencies + - @backstage/plugin-catalog-common@1.0.5-next.0 + - @backstage/backend-common@0.15.0-next.1 + - @backstage/integration@1.3.0-next.1 + +## @backstage/plugin-catalog-backend-module-github@0.1.6-next.1 + +### Patch Changes + +- f48950e34b: Github Entity Provider functionality for adding entities to the catalog. + + This provider replaces the GithubDiscoveryProcessor functionality as providers offer more flexibility with scheduling ingestion, removing and preventing orphaned entities. + + More information can be found on the [GitHub Discovery](https://backstage.io/docs/integrations/github/discovery) page. + +- Updated dependencies + - @backstage/backend-common@0.15.0-next.1 + - @backstage/integration@1.3.0-next.1 + - @backstage/plugin-catalog-backend@1.3.1-next.1 + +## @backstage/plugin-catalog-common@1.0.5-next.0 + +### Patch Changes + +- 92103db537: Export aggregated list of all catalog permissions + +## @backstage/plugin-catalog-react@1.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/plugin-catalog-common@1.0.5-next.0 + - @backstage/integration@1.3.0-next.1 + +## @backstage/plugin-home@0.4.24-next.1 + +### Patch Changes + +- df7b9158b8: Add wrap-around for the listing of tools to prevent increasing width with name length. +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/plugin-catalog-react@1.1.3-next.1 + +## @backstage/plugin-jenkins@0.7.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/plugin-catalog-react@1.1.3-next.1 + - @backstage/plugin-jenkins-common@0.1.7-next.0 + +## @backstage/plugin-jenkins-backend@0.1.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.15.0-next.1 + - @backstage/plugin-jenkins-common@0.1.7-next.0 + +## @backstage/plugin-jenkins-common@0.1.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-common@1.0.5-next.0 + +## @backstage/plugin-kubernetes@0.7.1-next.1 + +### Patch Changes + +- 860ed68343: Fixed bug in CronJobsAccordions component that causes an error when cronjobs use a kubernetes alias, such as `@hourly` or `@daily` instead of standard cron syntax. +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/plugin-catalog-react@1.1.3-next.1 + +## @backstage/plugin-techdocs@1.3.1-next.1 + +### Patch Changes + +- b86ed4d990: Add highlight to active navigation item and navigation parents. +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/integration@1.3.0-next.1 + - @backstage/plugin-techdocs-react@1.0.3-next.1 + - @backstage/plugin-catalog-react@1.1.3-next.1 + +## @backstage/plugin-techdocs-backend@1.2.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-common@1.0.5-next.0 + - @backstage/backend-common@0.15.0-next.1 + - @backstage/integration@1.3.0-next.1 + - @backstage/plugin-techdocs-node@1.3.0-next.1 + +## @backstage/plugin-techdocs-module-addons-contrib@1.0.3-next.1 + +### Patch Changes + +- ad35364e97: feat(techdocs): add edit button support for bitbucketServer +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/integration@1.3.0-next.1 + - @backstage/plugin-techdocs-react@1.0.3-next.1 + +## @backstage/plugin-techdocs-react@1.0.3-next.1 + +### Patch Changes + +- 29d6cf0147: Add `toLowerEntityRefMaybe()` helper function for handling `techdocs.legacyUseCaseSensitiveTripletPaths` flag. + Pass modified `entityRef` to `TechDocsReaderPageContext` to handle the `techdocs.legacyUseCaseSensitiveTripletPaths` flag. +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + +## example-app@0.2.74-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes@0.7.1-next.1 + - @backstage/plugin-home@0.4.24-next.1 + - @backstage/core-components@0.10.1-next.1 + - @backstage/plugin-scaffolder@1.5.0-next.1 + - @backstage/plugin-techdocs@1.3.1-next.1 + - @backstage/plugin-catalog-common@1.0.5-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.0.3-next.1 + - @backstage/plugin-api-docs@0.8.8-next.1 + - @backstage/plugin-techdocs-react@1.0.3-next.1 + - @backstage/plugin-catalog-react@1.1.3-next.1 + - @backstage/plugin-jenkins@0.7.7-next.1 diff --git a/package.json b/package.json index 8c8c643879..23e847f49f 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "@types/react": "^17", "@types/react-dom": "^17" }, - "version": "1.5.0-next.0", + "version": "1.5.0-next.1", "dependencies": { "@manypkg/get-packages": "^1.1.3", "@microsoft/api-documenter": "^7.17.11", diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md index 2f4c0e7bff..002ea41927 100644 --- a/packages/app/CHANGELOG.md +++ b/packages/app/CHANGELOG.md @@ -1,5 +1,22 @@ # example-app +## 0.2.74-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes@0.7.1-next.1 + - @backstage/plugin-home@0.4.24-next.1 + - @backstage/core-components@0.10.1-next.1 + - @backstage/plugin-scaffolder@1.5.0-next.1 + - @backstage/plugin-techdocs@1.3.1-next.1 + - @backstage/plugin-catalog-common@1.0.5-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.0.3-next.1 + - @backstage/plugin-api-docs@0.8.8-next.1 + - @backstage/plugin-techdocs-react@1.0.3-next.1 + - @backstage/plugin-catalog-react@1.1.3-next.1 + - @backstage/plugin-jenkins@0.7.7-next.1 + ## 0.2.74-next.0 ### Patch Changes diff --git a/packages/app/package.json b/packages/app/package.json index 738dbc2246..8fdbce600d 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "example-app", - "version": "0.2.74-next.0", + "version": "0.2.74-next.1", "private": true, "backstage": { "role": "frontend" @@ -12,18 +12,18 @@ "@backstage/cli": "^0.18.1-next.0", "@backstage/config": "^1.0.1", "@backstage/core-app-api": "^1.0.5-next.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/integration-react": "^1.1.3-next.0", "@backstage/plugin-airbrake": "^0.3.8-next.0", - "@backstage/plugin-api-docs": "^0.8.8-next.0", + "@backstage/plugin-api-docs": "^0.8.8-next.1", "@backstage/plugin-azure-devops": "^0.1.24-next.0", "@backstage/plugin-apache-airflow": "^0.2.1-next.0", "@backstage/plugin-badges": "^0.2.32-next.0", - "@backstage/plugin-catalog-common": "^1.0.4", + "@backstage/plugin-catalog-common": "^1.0.5-next.0", "@backstage/plugin-catalog-graph": "^0.2.20-next.0", "@backstage/plugin-catalog-import": "^0.8.11-next.0", - "@backstage/plugin-catalog-react": "^1.1.3-next.0", + "@backstage/plugin-catalog-react": "^1.1.3-next.1", "@backstage/plugin-circleci": "^0.3.8-next.0", "@backstage/plugin-cloudbuild": "^0.3.8-next.0", "@backstage/plugin-code-coverage": "^0.2.1-next.0", @@ -35,10 +35,10 @@ "@backstage/plugin-github-actions": "^0.5.8-next.0", "@backstage/plugin-gocd": "^0.1.14-next.0", "@backstage/plugin-graphiql": "^0.2.40-next.0", - "@backstage/plugin-home": "^0.4.24-next.0", - "@backstage/plugin-jenkins": "^0.7.7-next.0", + "@backstage/plugin-home": "^0.4.24-next.1", + "@backstage/plugin-jenkins": "^0.7.7-next.1", "@backstage/plugin-kafka": "^0.3.8-next.0", - "@backstage/plugin-kubernetes": "^0.7.1-next.0", + "@backstage/plugin-kubernetes": "^0.7.1-next.1", "@backstage/plugin-lighthouse": "^0.3.8-next.0", "@backstage/plugin-newrelic": "^0.3.26-next.0", "@backstage/plugin-newrelic-dashboard": "^0.2.1-next.0", @@ -46,7 +46,7 @@ "@backstage/plugin-pagerduty": "0.5.1-next.0", "@backstage/plugin-permission-react": "^0.4.4-next.0", "@backstage/plugin-rollbar": "^0.4.8-next.0", - "@backstage/plugin-scaffolder": "^1.4.1-next.0", + "@backstage/plugin-scaffolder": "^1.5.0-next.1", "@backstage/plugin-search": "^1.0.1-next.0", "@backstage/plugin-search-common": "^1.0.0", "@backstage/plugin-search-react": "^1.0.1-next.0", @@ -55,9 +55,9 @@ "@backstage/plugin-stack-overflow": "^0.1.4-next.0", "@backstage/plugin-tech-insights": "^0.2.4-next.0", "@backstage/plugin-tech-radar": "^0.5.15-next.0", - "@backstage/plugin-techdocs": "^1.3.1-next.0", - "@backstage/plugin-techdocs-module-addons-contrib": "^1.0.3-next.0", - "@backstage/plugin-techdocs-react": "^1.0.3-next.0", + "@backstage/plugin-techdocs": "^1.3.1-next.1", + "@backstage/plugin-techdocs-module-addons-contrib": "^1.0.3-next.1", + "@backstage/plugin-techdocs-react": "^1.0.3-next.1", "@backstage/plugin-todo": "^0.2.10-next.0", "@backstage/plugin-user-settings": "^0.4.7-next.0", "@backstage/theme": "^0.2.16", diff --git a/packages/backend-common/CHANGELOG.md b/packages/backend-common/CHANGELOG.md index 790bb0eedd..e712a96470 100644 --- a/packages/backend-common/CHANGELOG.md +++ b/packages/backend-common/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/backend-common +## 0.15.0-next.1 + +### Patch Changes + +- 1732a18a7a: Exported `redactLogLine` function to be able to use it in custom loggers and renamed it to `redactWinstonLogLine`. +- Updated dependencies + - @backstage/integration@1.3.0-next.1 + ## 0.15.0-next.0 ### Minor Changes diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index 7a0d492638..1e89cf13df 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-common", "description": "Common functionality library for Backstage backends", - "version": "0.15.0-next.0", + "version": "0.15.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "private": false, @@ -38,7 +38,7 @@ "@backstage/config": "^1.0.1", "@backstage/config-loader": "^1.1.3", "@backstage/errors": "^1.1.0", - "@backstage/integration": "^1.3.0-next.0", + "@backstage/integration": "^1.3.0-next.1", "@backstage/types": "^1.0.0", "@google-cloud/storage": "^6.0.0", "@keyv/redis": "^2.2.3", diff --git a/packages/core-components/CHANGELOG.md b/packages/core-components/CHANGELOG.md index 8edd7e8242..35dd20153d 100644 --- a/packages/core-components/CHANGELOG.md +++ b/packages/core-components/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/core-components +## 0.10.1-next.1 + +### Patch Changes + +- a22af3edc8: Adding a `className` prop to the `MarkdownContent` component + ## 0.10.1-next.0 ### Patch Changes diff --git a/packages/core-components/package.json b/packages/core-components/package.json index 5a67fa32c3..e8aae8d2fa 100644 --- a/packages/core-components/package.json +++ b/packages/core-components/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core-components", "description": "Core components used by Backstage plugins and apps", - "version": "0.10.1-next.0", + "version": "0.10.1-next.1", "private": false, "publishConfig": { "access": "public", diff --git a/packages/create-app/CHANGELOG.md b/packages/create-app/CHANGELOG.md index adbd0c50fd..d3180a9332 100644 --- a/packages/create-app/CHANGELOG.md +++ b/packages/create-app/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/create-app +## 0.4.30-next.1 + +### Patch Changes + +- Bumped create-app version. + ## 0.4.30-next.0 ### Patch Changes diff --git a/packages/create-app/package.json b/packages/create-app/package.json index 3182e2e83a..8b5daf3030 100644 --- a/packages/create-app/package.json +++ b/packages/create-app/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/create-app", "description": "A CLI that helps you create your own Backstage app", - "version": "0.4.30-next.0", + "version": "0.4.30-next.1", "private": false, "publishConfig": { "access": "public" diff --git a/packages/integration/CHANGELOG.md b/packages/integration/CHANGELOG.md index e2487eb1fb..ad2a32a713 100644 --- a/packages/integration/CHANGELOG.md +++ b/packages/integration/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/integration +## 1.3.0-next.1 + +### Minor Changes + +- ad35364e97: feat(techdocs): add edit button support for bitbucketServer + +### Patch Changes + +- 1f27d83933: Fixed bug in getGitLabFileFetchUrl where a target whose path did not contain the + `/-/` scope would result in a fetch URL that did not support + private-token-based authentication. + ## 1.3.0-next.0 ### Minor Changes diff --git a/packages/integration/package.json b/packages/integration/package.json index ade3399415..30eed36ae4 100644 --- a/packages/integration/package.json +++ b/packages/integration/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/integration", "description": "Helpers for managing integrations towards external systems", - "version": "1.3.0-next.0", + "version": "1.3.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/techdocs-cli/CHANGELOG.md b/packages/techdocs-cli/CHANGELOG.md index fe5db6db4c..feda80db73 100644 --- a/packages/techdocs-cli/CHANGELOG.md +++ b/packages/techdocs-cli/CHANGELOG.md @@ -1,5 +1,13 @@ # @techdocs/cli +## 1.1.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.15.0-next.1 + - @backstage/plugin-techdocs-node@1.3.0-next.1 + ## 1.1.4-next.0 ### Patch Changes diff --git a/packages/techdocs-cli/package.json b/packages/techdocs-cli/package.json index 14e09515ea..c47270ed70 100644 --- a/packages/techdocs-cli/package.json +++ b/packages/techdocs-cli/package.json @@ -1,7 +1,7 @@ { "name": "@techdocs/cli", "description": "Utility CLI for managing TechDocs sites in Backstage.", - "version": "1.1.4-next.0", + "version": "1.1.4-next.1", "private": false, "publishConfig": { "access": "public" @@ -62,11 +62,11 @@ "ext": "ts" }, "dependencies": { - "@backstage/backend-common": "^0.15.0-next.0", + "@backstage/backend-common": "^0.15.0-next.1", "@backstage/catalog-model": "^1.1.0", "@backstage/cli-common": "^0.1.9", "@backstage/config": "^1.0.1", - "@backstage/plugin-techdocs-node": "^1.2.1-next.0", + "@backstage/plugin-techdocs-node": "^1.3.0-next.1", "@types/dockerode": "^3.3.0", "commander": "^9.1.0", "dockerode": "^3.3.1", diff --git a/plugins/airbrake/package.json b/plugins/airbrake/package.json index 25e36a0a35..b4744d0f80 100644 --- a/plugins/airbrake/package.json +++ b/plugins/airbrake/package.json @@ -24,7 +24,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/dev-utils": "^1.0.5-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", diff --git a/plugins/allure/package.json b/plugins/allure/package.json index 77c175f12d..cf32d42566 100644 --- a/plugins/allure/package.json +++ b/plugins/allure/package.json @@ -26,7 +26,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", "@backstage/theme": "^0.2.16", diff --git a/plugins/analytics-module-ga/package.json b/plugins/analytics-module-ga/package.json index 300402bc83..99c159b474 100644 --- a/plugins/analytics-module-ga/package.json +++ b/plugins/analytics-module-ga/package.json @@ -25,7 +25,7 @@ }, "dependencies": { "@backstage/config": "^1.0.1", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/theme": "^0.2.16", "@material-ui/core": "^4.12.2", diff --git a/plugins/apache-airflow/package.json b/plugins/apache-airflow/package.json index 29448beef5..9b72ec0b20 100644 --- a/plugins/apache-airflow/package.json +++ b/plugins/apache-airflow/package.json @@ -23,7 +23,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", diff --git a/plugins/api-docs/CHANGELOG.md b/plugins/api-docs/CHANGELOG.md index ca61827a0a..fbde937344 100644 --- a/plugins/api-docs/CHANGELOG.md +++ b/plugins/api-docs/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-api-docs +## 0.8.8-next.1 + +### Patch Changes + +- dae12c71cf: Updated dependency `@asyncapi/react-component` to `1.0.0-next.40`. +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/plugin-catalog@1.5.0-next.1 + - @backstage/plugin-catalog-react@1.1.3-next.1 + ## 0.8.8-next.0 ### Patch Changes diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index 5c0f3dfce5..bac0fd8e39 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-api-docs", "description": "A Backstage plugin that helps represent API entities in the frontend", - "version": "0.8.8-next.0", + "version": "0.8.8-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,10 +35,10 @@ "dependencies": { "@asyncapi/react-component": "1.0.0-next.40", "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", - "@backstage/plugin-catalog": "^1.5.0-next.0", - "@backstage/plugin-catalog-react": "^1.1.3-next.0", + "@backstage/plugin-catalog": "^1.5.0-next.1", + "@backstage/plugin-catalog-react": "^1.1.3-next.1", "@backstage/theme": "^0.2.16", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", diff --git a/plugins/azure-devops/package.json b/plugins/azure-devops/package.json index bf782919a0..c0f4f89354 100644 --- a/plugins/azure-devops/package.json +++ b/plugins/azure-devops/package.json @@ -31,7 +31,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", "@backstage/plugin-azure-devops-common": "^0.2.4", diff --git a/plugins/badges/package.json b/plugins/badges/package.json index d7b6bd6489..4c93e4474a 100644 --- a/plugins/badges/package.json +++ b/plugins/badges/package.json @@ -31,7 +31,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", diff --git a/plugins/bazaar/package.json b/plugins/bazaar/package.json index d08ca17676..9ddb42d9e8 100644 --- a/plugins/bazaar/package.json +++ b/plugins/bazaar/package.json @@ -27,7 +27,7 @@ "@backstage/catalog-client": "^1.0.4", "@backstage/catalog-model": "^1.1.0", "@backstage/cli": "^0.18.1-next.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/plugin-catalog": "^1.5.0-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", diff --git a/plugins/bitrise/package.json b/plugins/bitrise/package.json index 0517a594f8..f6e2b5bebf 100644 --- a/plugins/bitrise/package.json +++ b/plugins/bitrise/package.json @@ -25,7 +25,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", "@backstage/theme": "^0.2.16", diff --git a/plugins/catalog-backend-module-github/CHANGELOG.md b/plugins/catalog-backend-module-github/CHANGELOG.md index aabee0b1eb..7403016bf1 100644 --- a/plugins/catalog-backend-module-github/CHANGELOG.md +++ b/plugins/catalog-backend-module-github/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-catalog-backend-module-github +## 0.1.6-next.1 + +### Patch Changes + +- f48950e34b: Github Entity Provider functionality for adding entities to the catalog. + + This provider replaces the GithubDiscoveryProcessor functionality as providers offer more flexibility with scheduling ingestion, removing and preventing orphaned entities. + + More information can be found on the [GitHub Discovery](https://backstage.io/docs/integrations/github/discovery) page. + +- Updated dependencies + - @backstage/backend-common@0.15.0-next.1 + - @backstage/integration@1.3.0-next.1 + - @backstage/plugin-catalog-backend@1.3.1-next.1 + ## 0.1.6-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-github/package.json b/plugins/catalog-backend-module-github/package.json index ed45d98b73..53ef808262 100644 --- a/plugins/catalog-backend-module-github/package.json +++ b/plugins/catalog-backend-module-github/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-github", "description": "A Backstage catalog backend module that helps integrate towards GitHub", - "version": "0.1.6-next.0", + "version": "0.1.6-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,13 +33,13 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/backend-common": "^0.15.0-next.0", + "@backstage/backend-common": "^0.15.0-next.1", "@backstage/backend-tasks": "^0.3.4-next.0", "@backstage/catalog-model": "^1.1.0", "@backstage/config": "^1.0.1", "@backstage/errors": "^1.1.0", - "@backstage/integration": "^1.3.0-next.0", - "@backstage/plugin-catalog-backend": "^1.3.1-next.0", + "@backstage/integration": "^1.3.0-next.1", + "@backstage/plugin-catalog-backend": "^1.3.1-next.1", "@backstage/types": "^1.0.0", "@octokit/graphql": "^5.0.0", "lodash": "^4.17.21", diff --git a/plugins/catalog-backend/CHANGELOG.md b/plugins/catalog-backend/CHANGELOG.md index 287ab75267..f7a42d0bf5 100644 --- a/plugins/catalog-backend/CHANGELOG.md +++ b/plugins/catalog-backend/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-backend +## 1.3.1-next.1 + +### Patch Changes + +- e3d3018531: Fix issue for conditional decisions based on properties stored as arrays, like tags. + + Before this change, having a permission policy returning conditional decisions based on metadata like tags, such like `createCatalogConditionalDecision(permission, catalogConditions.hasMetadata('tags', 'java'),)`, was producing wrong results. The issue occurred when authorizing entities already loaded from the database, for example when authorizing `catalogEntityDeletePermission`. + +- Updated dependencies + - @backstage/plugin-catalog-common@1.0.5-next.0 + - @backstage/backend-common@0.15.0-next.1 + - @backstage/integration@1.3.0-next.1 + ## 1.3.1-next.0 ### Patch Changes diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index fbc9dabf85..63ef5bc397 100644 --- a/plugins/catalog-backend/package.json +++ b/plugins/catalog-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend", "description": "The Backstage backend plugin that provides the Backstage catalog", - "version": "1.3.1-next.0", + "version": "1.3.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -36,13 +36,13 @@ "dependencies": { "@backstage/backend-plugin-api": "^0.1.1-next.0", "@backstage/plugin-catalog-node": "^1.0.1-next.0", - "@backstage/backend-common": "^0.15.0-next.0", + "@backstage/backend-common": "^0.15.0-next.1", "@backstage/catalog-client": "^1.0.4", "@backstage/catalog-model": "^1.1.0", "@backstage/config": "^1.0.1", "@backstage/errors": "^1.1.0", - "@backstage/integration": "^1.3.0-next.0", - "@backstage/plugin-catalog-common": "^1.0.4", + "@backstage/integration": "^1.3.0-next.1", + "@backstage/plugin-catalog-common": "^1.0.5-next.0", "@backstage/plugin-permission-common": "^0.6.3", "@backstage/plugin-permission-node": "^0.6.4-next.0", "@backstage/plugin-scaffolder-common": "^1.1.2", diff --git a/plugins/catalog-common/CHANGELOG.md b/plugins/catalog-common/CHANGELOG.md index 05830979e5..b05ac57b9f 100644 --- a/plugins/catalog-common/CHANGELOG.md +++ b/plugins/catalog-common/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/plugin-catalog-common +## 1.0.5-next.0 + +### Patch Changes + +- 92103db537: Export aggregated list of all catalog permissions + ## 1.0.4 ### Patch Changes diff --git a/plugins/catalog-common/package.json b/plugins/catalog-common/package.json index 329db25c75..f3cfa2d236 100644 --- a/plugins/catalog-common/package.json +++ b/plugins/catalog-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-common", "description": "Common functionalities for the catalog plugin", - "version": "1.0.4", + "version": "1.0.5-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json index e444c84713..a46d8b5ec3 100644 --- a/plugins/catalog-graph/package.json +++ b/plugins/catalog-graph/package.json @@ -26,7 +26,7 @@ "dependencies": { "@backstage/catalog-client": "^1.0.4", "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", "@backstage/theme": "^0.2.16", diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index d44b9aaa67..61e2ecc2a6 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -37,7 +37,7 @@ "@backstage/catalog-client": "^1.0.4", "@backstage/catalog-model": "^1.1.0", "@backstage/config": "^1.0.1", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", "@backstage/integration": "^1.3.0-next.0", diff --git a/plugins/catalog-react/CHANGELOG.md b/plugins/catalog-react/CHANGELOG.md index 51ef8b15a0..f9a6b39e96 100644 --- a/plugins/catalog-react/CHANGELOG.md +++ b/plugins/catalog-react/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-catalog-react +## 1.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/plugin-catalog-common@1.0.5-next.0 + - @backstage/integration@1.3.0-next.1 + ## 1.1.3-next.0 ### Patch Changes diff --git a/plugins/catalog-react/package.json b/plugins/catalog-react/package.json index 8bc5f1dfd0..b5ebf51c78 100644 --- a/plugins/catalog-react/package.json +++ b/plugins/catalog-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-react", "description": "A frontend library that helps other Backstage plugins interact with the catalog", - "version": "1.1.3-next.0", + "version": "1.1.3-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -36,11 +36,11 @@ "dependencies": { "@backstage/catalog-client": "^1.0.4", "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", - "@backstage/integration": "^1.3.0-next.0", - "@backstage/plugin-catalog-common": "^1.0.4", + "@backstage/integration": "^1.3.0-next.1", + "@backstage/plugin-catalog-common": "^1.0.5-next.0", "@backstage/plugin-permission-common": "^0.6.3", "@backstage/plugin-permission-react": "^0.4.4-next.0", "@backstage/theme": "^0.2.16", @@ -65,7 +65,7 @@ "devDependencies": { "@backstage/cli": "^0.18.1-next.0", "@backstage/core-app-api": "^1.0.5-next.0", - "@backstage/plugin-catalog-common": "^1.0.4", + "@backstage/plugin-catalog-common": "^1.0.5-next.0", "@backstage/plugin-scaffolder-common": "^1.1.2", "@backstage/test-utils": "^1.1.3-next.0", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/catalog/CHANGELOG.md b/plugins/catalog/CHANGELOG.md index e1583cb69e..ac7c8bb06f 100644 --- a/plugins/catalog/CHANGELOG.md +++ b/plugins/catalog/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog +## 1.5.0-next.1 + +### Minor Changes + +- fe94398418: Allow changing the subtitle of the `CatalogTable` component + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/plugin-catalog-common@1.0.5-next.0 + - @backstage/plugin-catalog-react@1.1.3-next.1 + ## 1.5.0-next.0 ### Minor Changes diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index 7bf2c9d5ec..04d9b98701 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog", "description": "The Backstage plugin for browsing the Backstage catalog", - "version": "1.5.0-next.0", + "version": "1.5.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -36,12 +36,12 @@ "dependencies": { "@backstage/catalog-client": "^1.0.4", "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", "@backstage/integration-react": "^1.1.3-next.0", - "@backstage/plugin-catalog-common": "^1.0.4", - "@backstage/plugin-catalog-react": "^1.1.3-next.0", + "@backstage/plugin-catalog-common": "^1.0.5-next.0", + "@backstage/plugin-catalog-react": "^1.1.3-next.1", "@backstage/plugin-search-common": "^1.0.0", "@backstage/plugin-search-react": "^1.0.1-next.0", "@backstage/theme": "^0.2.16", diff --git a/plugins/circleci/package.json b/plugins/circleci/package.json index 8810aca917..a4add36d06 100644 --- a/plugins/circleci/package.json +++ b/plugins/circleci/package.json @@ -36,7 +36,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", "@backstage/theme": "^0.2.16", diff --git a/plugins/cloudbuild/package.json b/plugins/cloudbuild/package.json index 8107d4c411..d6ffd896a1 100644 --- a/plugins/cloudbuild/package.json +++ b/plugins/cloudbuild/package.json @@ -35,7 +35,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", "@backstage/theme": "^0.2.16", diff --git a/plugins/code-climate/package.json b/plugins/code-climate/package.json index 5e1313a8f8..53c2d0f9e0 100644 --- a/plugins/code-climate/package.json +++ b/plugins/code-climate/package.json @@ -24,7 +24,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", "@backstage/theme": "^0.2.16", diff --git a/plugins/code-coverage/package.json b/plugins/code-coverage/package.json index d6e67ae320..d5adc75d4f 100644 --- a/plugins/code-coverage/package.json +++ b/plugins/code-coverage/package.json @@ -26,7 +26,7 @@ "dependencies": { "@backstage/catalog-model": "^1.1.0", "@backstage/config": "^1.0.1", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", diff --git a/plugins/config-schema/package.json b/plugins/config-schema/package.json index 80fdaf693c..9a04af2abf 100644 --- a/plugins/config-schema/package.json +++ b/plugins/config-schema/package.json @@ -25,7 +25,7 @@ }, "dependencies": { "@backstage/config": "^1.0.1", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", "@backstage/theme": "^0.2.16", diff --git a/plugins/cost-insights/package.json b/plugins/cost-insights/package.json index 980b916e31..dadf992c5d 100644 --- a/plugins/cost-insights/package.json +++ b/plugins/cost-insights/package.json @@ -36,7 +36,7 @@ "dependencies": { "@backstage/catalog-model": "^1.1.0", "@backstage/config": "^1.0.1", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/plugin-cost-insights-common": "^0.1.0", "@backstage/theme": "^0.2.16", diff --git a/plugins/example-todo-list/package.json b/plugins/example-todo-list/package.json index e767c59cd4..4fdaf42140 100644 --- a/plugins/example-todo-list/package.json +++ b/plugins/example-todo-list/package.json @@ -24,7 +24,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/theme": "^0.2.16", "@material-ui/core": "^4.12.2", diff --git a/plugins/explore/package.json b/plugins/explore/package.json index 209a22ff39..9d10bb182c 100644 --- a/plugins/explore/package.json +++ b/plugins/explore/package.json @@ -35,7 +35,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", "@backstage/plugin-explore-react": "^0.0.20-next.0", diff --git a/plugins/firehydrant/package.json b/plugins/firehydrant/package.json index 100ed11839..4cfaa1be32 100644 --- a/plugins/firehydrant/package.json +++ b/plugins/firehydrant/package.json @@ -25,7 +25,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", "@backstage/theme": "^0.2.16", diff --git a/plugins/fossa/package.json b/plugins/fossa/package.json index b24f02fa71..e0946d30a3 100644 --- a/plugins/fossa/package.json +++ b/plugins/fossa/package.json @@ -36,7 +36,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", diff --git a/plugins/gcp-projects/package.json b/plugins/gcp-projects/package.json index 3f78ea6609..824fbd80ed 100644 --- a/plugins/gcp-projects/package.json +++ b/plugins/gcp-projects/package.json @@ -34,7 +34,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/theme": "^0.2.16", "@material-ui/core": "^4.12.2", diff --git a/plugins/git-release-manager/package.json b/plugins/git-release-manager/package.json index fb357a2944..83710dc5e1 100644 --- a/plugins/git-release-manager/package.json +++ b/plugins/git-release-manager/package.json @@ -24,7 +24,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/integration": "^1.3.0-next.0", "@backstage/theme": "^0.2.16", diff --git a/plugins/github-actions/package.json b/plugins/github-actions/package.json index a589741d33..57a4789f3e 100644 --- a/plugins/github-actions/package.json +++ b/plugins/github-actions/package.json @@ -37,7 +37,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/integration": "^1.3.0-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", diff --git a/plugins/github-deployments/package.json b/plugins/github-deployments/package.json index 75b7fcbb92..504b65fff4 100644 --- a/plugins/github-deployments/package.json +++ b/plugins/github-deployments/package.json @@ -25,7 +25,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", "@backstage/integration": "^1.3.0-next.0", diff --git a/plugins/github-pull-requests-board/package.json b/plugins/github-pull-requests-board/package.json index ee48ebc9fe..ba19ccf68b 100644 --- a/plugins/github-pull-requests-board/package.json +++ b/plugins/github-pull-requests-board/package.json @@ -36,7 +36,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/integration": "^1.3.0-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", diff --git a/plugins/gitops-profiles/package.json b/plugins/gitops-profiles/package.json index 630c4ded07..19cd4fdeab 100644 --- a/plugins/gitops-profiles/package.json +++ b/plugins/gitops-profiles/package.json @@ -35,7 +35,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/theme": "^0.2.16", "@material-ui/core": "^4.12.2", diff --git a/plugins/gocd/package.json b/plugins/gocd/package.json index ecc8d8a4d0..e36653daf4 100644 --- a/plugins/gocd/package.json +++ b/plugins/gocd/package.json @@ -32,7 +32,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", diff --git a/plugins/graphiql/package.json b/plugins/graphiql/package.json index 5d0c221ed5..1938ef108e 100644 --- a/plugins/graphiql/package.json +++ b/plugins/graphiql/package.json @@ -34,7 +34,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/theme": "^0.2.16", "@material-ui/core": "^4.12.2", diff --git a/plugins/home/CHANGELOG.md b/plugins/home/CHANGELOG.md index 69b215106a..6c25055568 100644 --- a/plugins/home/CHANGELOG.md +++ b/plugins/home/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-home +## 0.4.24-next.1 + +### Patch Changes + +- df7b9158b8: Add wrap-around for the listing of tools to prevent increasing width with name length. +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/plugin-catalog-react@1.1.3-next.1 + ## 0.4.24-next.0 ### Patch Changes diff --git a/plugins/home/package.json b/plugins/home/package.json index f11a7d33fb..dbace1bcf6 100644 --- a/plugins/home/package.json +++ b/plugins/home/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-home", "description": "A Backstage plugin that helps you build a home page", - "version": "0.4.24-next.0", + "version": "0.4.24-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -36,9 +36,9 @@ "dependencies": { "@backstage/catalog-model": "^1.1.0", "@backstage/config": "^1.0.1", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", - "@backstage/plugin-catalog-react": "^1.1.3-next.0", + "@backstage/plugin-catalog-react": "^1.1.3-next.1", "@backstage/plugin-stack-overflow": "^0.1.4-next.0", "@backstage/theme": "^0.2.16", "@material-ui/core": "^4.12.2", diff --git a/plugins/ilert/package.json b/plugins/ilert/package.json index 9b73003de7..f1e03ad8ae 100644 --- a/plugins/ilert/package.json +++ b/plugins/ilert/package.json @@ -25,7 +25,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", diff --git a/plugins/jenkins-backend/CHANGELOG.md b/plugins/jenkins-backend/CHANGELOG.md index f1c6ed84e9..46430334b1 100644 --- a/plugins/jenkins-backend/CHANGELOG.md +++ b/plugins/jenkins-backend/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-jenkins-backend +## 0.1.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.15.0-next.1 + - @backstage/plugin-jenkins-common@0.1.7-next.0 + ## 0.1.25-next.0 ### Patch Changes diff --git a/plugins/jenkins-backend/package.json b/plugins/jenkins-backend/package.json index 4877a73093..c49e4a66cd 100644 --- a/plugins/jenkins-backend/package.json +++ b/plugins/jenkins-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-jenkins-backend", "description": "A Backstage backend plugin that integrates towards Jenkins", - "version": "0.1.25-next.0", + "version": "0.1.25-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -25,13 +25,13 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.15.0-next.0", + "@backstage/backend-common": "^0.15.0-next.1", "@backstage/catalog-client": "^1.0.4", "@backstage/catalog-model": "^1.1.0", "@backstage/config": "^1.0.1", "@backstage/errors": "^1.1.0", "@backstage/plugin-auth-node": "^0.2.4-next.0", - "@backstage/plugin-jenkins-common": "^0.1.6", + "@backstage/plugin-jenkins-common": "^0.1.7-next.0", "@backstage/plugin-permission-common": "^0.6.3", "@types/express": "^4.17.6", "express": "^4.17.1", diff --git a/plugins/jenkins-common/CHANGELOG.md b/plugins/jenkins-common/CHANGELOG.md index 0ccf0659bf..befb804c0c 100644 --- a/plugins/jenkins-common/CHANGELOG.md +++ b/plugins/jenkins-common/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-jenkins-common +## 0.1.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-common@1.0.5-next.0 + ## 0.1.6 ### Patch Changes diff --git a/plugins/jenkins-common/package.json b/plugins/jenkins-common/package.json index 75a4c60b35..e207f8e298 100644 --- a/plugins/jenkins-common/package.json +++ b/plugins/jenkins-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-jenkins-common", - "version": "0.1.6", + "version": "0.1.7-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,7 +22,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/plugin-catalog-common": "^1.0.4", + "@backstage/plugin-catalog-common": "^1.0.5-next.0", "@backstage/plugin-permission-common": "^0.6.3" }, "devDependencies": { diff --git a/plugins/jenkins/CHANGELOG.md b/plugins/jenkins/CHANGELOG.md index bee2b3ca63..245dc67b92 100644 --- a/plugins/jenkins/CHANGELOG.md +++ b/plugins/jenkins/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-jenkins +## 0.7.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/plugin-catalog-react@1.1.3-next.1 + - @backstage/plugin-jenkins-common@0.1.7-next.0 + ## 0.7.7-next.0 ### Patch Changes diff --git a/plugins/jenkins/package.json b/plugins/jenkins/package.json index a3f0b2b533..6ff8f60c16 100644 --- a/plugins/jenkins/package.json +++ b/plugins/jenkins/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-jenkins", "description": "A Backstage plugin that integrates towards Jenkins", - "version": "0.7.7-next.0", + "version": "0.7.7-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -36,11 +36,11 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", - "@backstage/plugin-catalog-react": "^1.1.3-next.0", - "@backstage/plugin-jenkins-common": "^0.1.6", + "@backstage/plugin-catalog-react": "^1.1.3-next.1", + "@backstage/plugin-jenkins-common": "^0.1.7-next.0", "@backstage/theme": "^0.2.16", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", diff --git a/plugins/kafka/package.json b/plugins/kafka/package.json index 68c05a0a4c..9beedf324a 100644 --- a/plugins/kafka/package.json +++ b/plugins/kafka/package.json @@ -26,11 +26,11 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/config": "^1.0.1", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", "@backstage/theme": "^0.2.16", - "@backstage/config": "^1.0.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", diff --git a/plugins/kubernetes/CHANGELOG.md b/plugins/kubernetes/CHANGELOG.md index 0784be7f50..736395425d 100644 --- a/plugins/kubernetes/CHANGELOG.md +++ b/plugins/kubernetes/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-kubernetes +## 0.7.1-next.1 + +### Patch Changes + +- 860ed68343: Fixed bug in CronJobsAccordions component that causes an error when cronjobs use a kubernetes alias, such as `@hourly` or `@daily` instead of standard cron syntax. +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/plugin-catalog-react@1.1.3-next.1 + ## 0.7.1-next.0 ### Patch Changes diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index c46b56809c..efcb553d9b 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes", "description": "A Backstage plugin that integrates towards Kubernetes", - "version": "0.7.1-next.0", + "version": "0.7.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -36,9 +36,9 @@ "dependencies": { "@backstage/catalog-model": "^1.1.0", "@backstage/config": "^1.0.1", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", - "@backstage/plugin-catalog-react": "^1.1.3-next.0", + "@backstage/plugin-catalog-react": "^1.1.3-next.1", "@backstage/plugin-kubernetes-common": "^0.4.0", "@backstage/theme": "^0.2.16", "@kubernetes/client-node": "^0.17.0", diff --git a/plugins/lighthouse/package.json b/plugins/lighthouse/package.json index eae133af16..89ba839759 100644 --- a/plugins/lighthouse/package.json +++ b/plugins/lighthouse/package.json @@ -37,7 +37,7 @@ "dependencies": { "@backstage/catalog-model": "^1.1.0", "@backstage/config": "^1.0.1", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", "@backstage/theme": "^0.2.16", diff --git a/plugins/newrelic-dashboard/package.json b/plugins/newrelic-dashboard/package.json index 7c977ad733..645e1eec5a 100644 --- a/plugins/newrelic-dashboard/package.json +++ b/plugins/newrelic-dashboard/package.json @@ -24,7 +24,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", diff --git a/plugins/newrelic/package.json b/plugins/newrelic/package.json index 32d6397940..1103a1290b 100644 --- a/plugins/newrelic/package.json +++ b/plugins/newrelic/package.json @@ -35,7 +35,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/theme": "^0.2.16", "@material-ui/core": "^4.12.2", diff --git a/plugins/org/package.json b/plugins/org/package.json index 49b0d78821..44459af351 100644 --- a/plugins/org/package.json +++ b/plugins/org/package.json @@ -30,16 +30,16 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", "@backstage/theme": "^0.2.16", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", + "p-limit": "^3.1.0", "pluralize": "^8.0.0", "qs": "^6.10.1", - "p-limit": "^3.1.0", "react-router": "6.0.0-beta.0", "react-router-dom": "6.0.0-beta.0", "react-use": "^17.2.4" diff --git a/plugins/pagerduty/package.json b/plugins/pagerduty/package.json index ae4819b5e6..9842bdee62 100644 --- a/plugins/pagerduty/package.json +++ b/plugins/pagerduty/package.json @@ -35,7 +35,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", diff --git a/plugins/periskop/package.json b/plugins/periskop/package.json index 9e9f94bda9..132074afff 100644 --- a/plugins/periskop/package.json +++ b/plugins/periskop/package.json @@ -26,7 +26,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", diff --git a/plugins/rollbar/package.json b/plugins/rollbar/package.json index e343d841af..b8211cd17f 100644 --- a/plugins/rollbar/package.json +++ b/plugins/rollbar/package.json @@ -36,7 +36,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", "@backstage/theme": "^0.2.16", diff --git a/plugins/scaffolder-backend/CHANGELOG.md b/plugins/scaffolder-backend/CHANGELOG.md index e2c5b51281..07cb50bd5f 100644 --- a/plugins/scaffolder-backend/CHANGELOG.md +++ b/plugins/scaffolder-backend/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-scaffolder-backend +## 1.5.0-next.1 + +### Minor Changes + +- c4b452e16a: Starting the implementation of the Wizard page for the `next` scaffolder plugin + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.15.0-next.1 + - @backstage/integration@1.3.0-next.1 + - @backstage/plugin-catalog-backend@1.3.1-next.1 + ## 1.5.0-next.0 ### Minor Changes diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index 7c2b2b4401..27a22f99cf 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend", "description": "The Backstage backend plugin that helps you create new things", - "version": "1.5.0-next.0", + "version": "1.5.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,13 +35,13 @@ "build:assets": "node scripts/build-nunjucks.js" }, "dependencies": { - "@backstage/backend-common": "^0.15.0-next.0", + "@backstage/backend-common": "^0.15.0-next.1", "@backstage/catalog-client": "^1.0.4", "@backstage/catalog-model": "^1.1.0", "@backstage/config": "^1.0.1", "@backstage/errors": "^1.1.0", - "@backstage/integration": "^1.3.0-next.0", - "@backstage/plugin-catalog-backend": "^1.3.1-next.0", + "@backstage/integration": "^1.3.0-next.1", + "@backstage/plugin-catalog-backend": "^1.3.1-next.1", "@backstage/plugin-scaffolder-common": "^1.1.2", "@backstage/backend-plugin-api": "^0.1.1-next.0", "@backstage/plugin-catalog-node": "^1.0.1-next.0", diff --git a/plugins/scaffolder/CHANGELOG.md b/plugins/scaffolder/CHANGELOG.md index a1f7c1a68d..d69a811811 100644 --- a/plugins/scaffolder/CHANGELOG.md +++ b/plugins/scaffolder/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-scaffolder +## 1.5.0-next.1 + +### Minor Changes + +- c4b452e16a: Starting the implementation of the Wizard page for the `next` scaffolder plugin + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/plugin-catalog-common@1.0.5-next.0 + - @backstage/integration@1.3.0-next.1 + - @backstage/plugin-catalog-react@1.1.3-next.1 + ## 1.4.1-next.0 ### Patch Changes diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index ca54750dd0..2c2c667c65 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder", "description": "The Backstage plugin that helps you create new things", - "version": "1.4.1-next.0", + "version": "1.5.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -38,13 +38,13 @@ "@backstage/catalog-client": "^1.0.4", "@backstage/catalog-model": "^1.1.0", "@backstage/config": "^1.0.1", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", - "@backstage/integration": "^1.3.0-next.0", + "@backstage/integration": "^1.3.0-next.1", "@backstage/integration-react": "^1.1.3-next.0", - "@backstage/plugin-catalog-common": "^1.0.4", - "@backstage/plugin-catalog-react": "^1.1.3-next.0", + "@backstage/plugin-catalog-common": "^1.0.5-next.0", + "@backstage/plugin-catalog-react": "^1.1.3-next.1", "@backstage/plugin-permission-react": "^0.4.4-next.0", "@backstage/plugin-scaffolder-common": "^1.1.2", "@backstage/theme": "^0.2.16", @@ -83,7 +83,7 @@ "@backstage/cli": "^0.18.1-next.0", "@backstage/core-app-api": "^1.0.5-next.0", "@backstage/dev-utils": "^1.0.5-next.0", - "@backstage/plugin-catalog": "^1.5.0-next.0", + "@backstage/plugin-catalog": "^1.5.0-next.1", "@backstage/test-utils": "^1.1.3-next.0", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", diff --git a/plugins/search/package.json b/plugins/search/package.json index 994d9c3f1f..db3bd9e16d 100644 --- a/plugins/search/package.json +++ b/plugins/search/package.json @@ -35,7 +35,7 @@ "dependencies": { "@backstage/catalog-model": "^1.1.0", "@backstage/config": "^1.0.1", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", diff --git a/plugins/sentry/package.json b/plugins/sentry/package.json index 2f7243dead..c36019b179 100644 --- a/plugins/sentry/package.json +++ b/plugins/sentry/package.json @@ -36,7 +36,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", "@backstage/theme": "^0.2.16", diff --git a/plugins/shortcuts/package.json b/plugins/shortcuts/package.json index 6ff802fd22..b8b2a8c442 100644 --- a/plugins/shortcuts/package.json +++ b/plugins/shortcuts/package.json @@ -24,7 +24,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/theme": "^0.2.16", "@backstage/types": "^1.0.0", diff --git a/plugins/sonarqube-backend/CHANGELOG.md b/plugins/sonarqube-backend/CHANGELOG.md new file mode 100644 index 0000000000..167224e5d5 --- /dev/null +++ b/plugins/sonarqube-backend/CHANGELOG.md @@ -0,0 +1,12 @@ +# @backstage/plugin-sonarqube-backend + +## 0.1.0-next.0 + +### Minor Changes + +- e2be9ab3a4: Initial creation of the plugin + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.15.0-next.1 diff --git a/plugins/sonarqube-backend/package.json b/plugins/sonarqube-backend/package.json index 5d3b8f852e..e4d87147b3 100644 --- a/plugins/sonarqube-backend/package.json +++ b/plugins/sonarqube-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-sonarqube-backend", - "version": "0.0.0", + "version": "0.1.0-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,7 +23,7 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/backend-common": "^0.15.0-next.0", + "@backstage/backend-common": "^0.15.0-next.1", "@backstage/config": "^1.0.1", "@types/express": "*", "express": "^4.18.1", diff --git a/plugins/sonarqube/CHANGELOG.md b/plugins/sonarqube/CHANGELOG.md index 8f2f86fc1a..94bb723bcb 100644 --- a/plugins/sonarqube/CHANGELOG.md +++ b/plugins/sonarqube/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-sonarqube +## 0.4.0-next.1 + +### Minor Changes + +- 619b515172: **BREAKING** This plugin now call the `sonarqube-backend` plugin instead of relying on the proxy plugin + + The whole proxy's `'/sonarqube':` key can be removed from your configuration files. + + Then head to the [README in sonarqube-backend plugin page](https://github.com/backstage/backstage/tree/master/plugins/sonarqube-backend/README.md) to learn how to set-up the link to your Sonarqube instances. + +### Patch Changes + +- f9c310a439: Add ability to provide an optional Sonarqube instance into the annotation in the `catalog-info.yaml` file +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/plugin-catalog-react@1.1.3-next.1 + ## 0.3.8-next.0 ### Patch Changes diff --git a/plugins/sonarqube/package.json b/plugins/sonarqube/package.json index c5c27d800a..4d53258bdf 100644 --- a/plugins/sonarqube/package.json +++ b/plugins/sonarqube/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-sonarqube", "description": "", - "version": "0.3.8-next.0", + "version": "0.4.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -37,9 +37,9 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", - "@backstage/plugin-catalog-react": "^1.1.3-next.0", + "@backstage/plugin-catalog-react": "^1.1.3-next.1", "@backstage/theme": "^0.2.16", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", diff --git a/plugins/splunk-on-call/package.json b/plugins/splunk-on-call/package.json index 63b4ddf1e2..f8d588bac0 100644 --- a/plugins/splunk-on-call/package.json +++ b/plugins/splunk-on-call/package.json @@ -35,7 +35,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", "@backstage/theme": "^0.2.16", diff --git a/plugins/stack-overflow/package.json b/plugins/stack-overflow/package.json index 8c896fb602..4ca025c346 100644 --- a/plugins/stack-overflow/package.json +++ b/plugins/stack-overflow/package.json @@ -24,7 +24,7 @@ }, "dependencies": { "@backstage/config": "^1.0.1", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/plugin-home": "^0.4.24-next.0", "@backstage/plugin-search-common": "^1.0.0", diff --git a/plugins/tech-insights/package.json b/plugins/tech-insights/package.json index bf6c21fcdf..5660ff8118 100644 --- a/plugins/tech-insights/package.json +++ b/plugins/tech-insights/package.json @@ -29,7 +29,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", diff --git a/plugins/tech-radar/package.json b/plugins/tech-radar/package.json index 1c73979600..5b05ba3313 100644 --- a/plugins/tech-radar/package.json +++ b/plugins/tech-radar/package.json @@ -34,7 +34,7 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/theme": "^0.2.16", "@material-ui/core": "^4.12.2", diff --git a/plugins/techdocs-backend/CHANGELOG.md b/plugins/techdocs-backend/CHANGELOG.md index 56b01d5bf0..944926f841 100644 --- a/plugins/techdocs-backend/CHANGELOG.md +++ b/plugins/techdocs-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-techdocs-backend +## 1.2.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-common@1.0.5-next.0 + - @backstage/backend-common@0.15.0-next.1 + - @backstage/integration@1.3.0-next.1 + - @backstage/plugin-techdocs-node@1.3.0-next.1 + ## 1.2.1-next.0 ### Patch Changes diff --git a/plugins/techdocs-backend/package.json b/plugins/techdocs-backend/package.json index 6b724686c9..eea1837301 100644 --- a/plugins/techdocs-backend/package.json +++ b/plugins/techdocs-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs-backend", "description": "The Backstage backend plugin that renders technical documentation for your components", - "version": "1.2.1-next.0", + "version": "1.2.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,16 +34,16 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.15.0-next.0", + "@backstage/backend-common": "^0.15.0-next.1", "@backstage/catalog-client": "^1.0.4", "@backstage/catalog-model": "^1.1.0", "@backstage/config": "^1.0.1", "@backstage/errors": "^1.1.0", - "@backstage/integration": "^1.3.0-next.0", - "@backstage/plugin-catalog-common": "^1.0.4", + "@backstage/integration": "^1.3.0-next.1", + "@backstage/plugin-catalog-common": "^1.0.5-next.0", "@backstage/plugin-permission-common": "^0.6.3", "@backstage/plugin-search-common": "^1.0.0", - "@backstage/plugin-techdocs-node": "^1.2.1-next.0", + "@backstage/plugin-techdocs-node": "^1.3.0-next.1", "@types/express": "^4.17.6", "dockerode": "^3.3.1", "express": "^4.17.1", diff --git a/plugins/techdocs-module-addons-contrib/CHANGELOG.md b/plugins/techdocs-module-addons-contrib/CHANGELOG.md index a7756a3221..929c851751 100644 --- a/plugins/techdocs-module-addons-contrib/CHANGELOG.md +++ b/plugins/techdocs-module-addons-contrib/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-techdocs-module-addons-contrib +## 1.0.3-next.1 + +### Patch Changes + +- ad35364e97: feat(techdocs): add edit button support for bitbucketServer +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/integration@1.3.0-next.1 + - @backstage/plugin-techdocs-react@1.0.3-next.1 + ## 1.0.3-next.0 ### Patch Changes diff --git a/plugins/techdocs-module-addons-contrib/package.json b/plugins/techdocs-module-addons-contrib/package.json index 635037bb81..61a2b11ea8 100644 --- a/plugins/techdocs-module-addons-contrib/package.json +++ b/plugins/techdocs-module-addons-contrib/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs-module-addons-contrib", "description": "Plugin module for contributed TechDocs Addons", - "version": "1.0.3-next.0", + "version": "1.0.3-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,11 +34,11 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", - "@backstage/integration": "^1.3.0-next.0", + "@backstage/integration": "^1.3.0-next.1", "@backstage/integration-react": "^1.1.3-next.0", - "@backstage/plugin-techdocs-react": "^1.0.3-next.0", + "@backstage/plugin-techdocs-react": "^1.0.3-next.1", "@backstage/theme": "^0.2.16", "@material-ui/core": "^4.9.13", "@material-ui/icons": "^4.9.1", diff --git a/plugins/techdocs-node/CHANGELOG.md b/plugins/techdocs-node/CHANGELOG.md index 4405c103af..4f8356a87c 100644 --- a/plugins/techdocs-node/CHANGELOG.md +++ b/plugins/techdocs-node/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-techdocs-node +## 1.3.0-next.1 + +### Minor Changes + +- ad35364e97: feat(techdocs): add edit button support for bitbucketServer + +### Patch Changes + +- f833344611: Bump default `TechDocs` image to `v1.1.0`, see the release [here](https://github.com/backstage/techdocs-container/releases/tag/v1.1.0). +- Updated dependencies + - @backstage/backend-common@0.15.0-next.1 + - @backstage/integration@1.3.0-next.1 + ## 1.2.1-next.0 ### Patch Changes diff --git a/plugins/techdocs-node/package.json b/plugins/techdocs-node/package.json index 9f61fa54a0..643ac95be2 100644 --- a/plugins/techdocs-node/package.json +++ b/plugins/techdocs-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs-node", "description": "Common node.js functionalities for TechDocs, to be shared between techdocs-backend plugin and techdocs-cli", - "version": "1.2.1-next.0", + "version": "1.3.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "private": false, @@ -42,11 +42,11 @@ "dependencies": { "@azure/identity": "^2.0.1", "@azure/storage-blob": "^12.5.0", - "@backstage/backend-common": "^0.15.0-next.0", + "@backstage/backend-common": "^0.15.0-next.1", "@backstage/catalog-model": "^1.1.0", "@backstage/config": "^1.0.1", "@backstage/errors": "^1.1.0", - "@backstage/integration": "^1.3.0-next.0", + "@backstage/integration": "^1.3.0-next.1", "@backstage/plugin-search-common": "^1.0.0", "@google-cloud/storage": "^6.0.0", "@trendyol-js/openstack-swift-sdk": "^0.0.5", diff --git a/plugins/techdocs-react/CHANGELOG.md b/plugins/techdocs-react/CHANGELOG.md index f11f3a6ae3..e70f55ac8a 100644 --- a/plugins/techdocs-react/CHANGELOG.md +++ b/plugins/techdocs-react/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-techdocs-react +## 1.0.3-next.1 + +### Patch Changes + +- 29d6cf0147: Add `toLowerEntityRefMaybe()` helper function for handling `techdocs.legacyUseCaseSensitiveTripletPaths` flag. + Pass modified `entityRef` to `TechDocsReaderPageContext` to handle the `techdocs.legacyUseCaseSensitiveTripletPaths` flag. +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + ## 1.0.3-next.0 ### Patch Changes diff --git a/plugins/techdocs-react/package.json b/plugins/techdocs-react/package.json index 75821eac88..a6dbfa85d7 100644 --- a/plugins/techdocs-react/package.json +++ b/plugins/techdocs-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs-react", "description": "Shared frontend utilities for TechDocs and Addons", - "version": "1.0.3-next.0", + "version": "1.0.3-next.1", "private": false, "publishConfig": { "access": "public", @@ -37,7 +37,7 @@ "dependencies": { "@backstage/catalog-model": "^1.1.0", "@backstage/config": "^1.0.1", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/version-bridge": "^1.0.1", "@material-ui/core": "^4.12.2", diff --git a/plugins/techdocs/CHANGELOG.md b/plugins/techdocs/CHANGELOG.md index bbc5b31139..8d5c5a8d2e 100644 --- a/plugins/techdocs/CHANGELOG.md +++ b/plugins/techdocs/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-techdocs +## 1.3.1-next.1 + +### Patch Changes + +- b86ed4d990: Add highlight to active navigation item and navigation parents. +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/integration@1.3.0-next.1 + - @backstage/plugin-techdocs-react@1.0.3-next.1 + - @backstage/plugin-catalog-react@1.1.3-next.1 + ## 1.3.1-next.0 ### Patch Changes diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index 1cf6dd7bd8..fe1ad97bbf 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs", "description": "The Backstage plugin that renders technical documentation for your components", - "version": "1.3.1-next.0", + "version": "1.3.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -37,15 +37,15 @@ "dependencies": { "@backstage/catalog-model": "^1.1.0", "@backstage/config": "^1.0.1", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", - "@backstage/integration": "^1.3.0-next.0", + "@backstage/integration": "^1.3.0-next.1", "@backstage/integration-react": "^1.1.3-next.0", - "@backstage/plugin-catalog-react": "^1.1.3-next.0", + "@backstage/plugin-catalog-react": "^1.1.3-next.1", "@backstage/plugin-search-common": "^1.0.0", "@backstage/plugin-search-react": "^1.0.1-next.0", - "@backstage/plugin-techdocs-react": "^1.0.3-next.0", + "@backstage/plugin-techdocs-react": "^1.0.3-next.1", "@backstage/theme": "^0.2.16", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", diff --git a/plugins/todo/package.json b/plugins/todo/package.json index 6e1d555ab0..a025c3c136 100644 --- a/plugins/todo/package.json +++ b/plugins/todo/package.json @@ -31,7 +31,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index 2a16a80332..05ceb6f5f5 100644 --- a/plugins/user-settings/package.json +++ b/plugins/user-settings/package.json @@ -34,7 +34,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/theme": "^0.2.16", "@material-ui/core": "^4.12.2", diff --git a/plugins/xcmetrics/package.json b/plugins/xcmetrics/package.json index 2dbc98a290..68b8c834eb 100644 --- a/plugins/xcmetrics/package.json +++ b/plugins/xcmetrics/package.json @@ -24,7 +24,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", "@backstage/theme": "^0.2.16", diff --git a/yarn.lock b/yarn.lock index 2fc42e810b..919c41fcc7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2114,6 +2114,14 @@ lodash "^4.17.21" luxon "^3.0.0" +"@backstage/plugin-catalog-common@^1.0.4": + version "1.0.4" + resolved "https://registry.npmjs.org/@backstage/plugin-catalog-common/-/plugin-catalog-common-1.0.4.tgz#94389cb6555eeaea2814d286744d951578ae9132" + integrity sha512-6+3pQMFOjvsswzaGZ1qqgkc2dnuQOFILDk4zmmc/bq35R4ICk48Pbw41gH0/YR7yupXPi3OwN4la50ECUELCqw== + dependencies: + "@backstage/plugin-permission-common" "^0.6.3" + "@backstage/plugin-search-common" "^1.0.0" + "@backstage/plugin-catalog-react@^1.0.0", "@backstage/plugin-catalog-react@^1.1.2": version "1.1.2" resolved "https://registry.npmjs.org/@backstage/plugin-catalog-react/-/plugin-catalog-react-1.1.2.tgz#253a99d9ced5d751f9d1fb3d278511d754aaed4e" @@ -7751,7 +7759,7 @@ "@types/cookiejar" "*" "@types/node" "*" -"@types/supertest@^2.0.8": +"@types/supertest@^2.0.12", "@types/supertest@^2.0.8": version "2.0.12" resolved "https://registry.npmjs.org/@types/supertest/-/supertest-2.0.12.tgz#ddb4a0568597c9aadff8dbec5b2e8fddbe8692fc" integrity sha512-X3HPWTwXRerBZS7Mo1k6vMVR1Z6zmJcDVn5O/31whe0tnjE4te6ZJSJGq1RiqHPjzPdMTfjCFogDJmwng9xHaQ== @@ -13216,25 +13224,25 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: safe-buffer "^5.1.1" "example-app@link:packages/app": - version "0.2.74-next.0" + version "0.2.74-next.1" dependencies: "@backstage/app-defaults" "^1.0.5-next.0" "@backstage/catalog-model" "^1.1.0" "@backstage/cli" "^0.18.1-next.0" "@backstage/config" "^1.0.1" "@backstage/core-app-api" "^1.0.5-next.0" - "@backstage/core-components" "^0.10.1-next.0" + "@backstage/core-components" "^0.10.1-next.1" "@backstage/core-plugin-api" "^1.0.5-next.0" "@backstage/integration-react" "^1.1.3-next.0" "@backstage/plugin-airbrake" "^0.3.8-next.0" "@backstage/plugin-apache-airflow" "^0.2.1-next.0" - "@backstage/plugin-api-docs" "^0.8.8-next.0" + "@backstage/plugin-api-docs" "^0.8.8-next.1" "@backstage/plugin-azure-devops" "^0.1.24-next.0" "@backstage/plugin-badges" "^0.2.32-next.0" - "@backstage/plugin-catalog-common" "^1.0.4" + "@backstage/plugin-catalog-common" "^1.0.5-next.0" "@backstage/plugin-catalog-graph" "^0.2.20-next.0" "@backstage/plugin-catalog-import" "^0.8.11-next.0" - "@backstage/plugin-catalog-react" "^1.1.3-next.0" + "@backstage/plugin-catalog-react" "^1.1.3-next.1" "@backstage/plugin-circleci" "^0.3.8-next.0" "@backstage/plugin-cloudbuild" "^0.3.8-next.0" "@backstage/plugin-code-coverage" "^0.2.1-next.0" @@ -13246,10 +13254,10 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: "@backstage/plugin-github-actions" "^0.5.8-next.0" "@backstage/plugin-gocd" "^0.1.14-next.0" "@backstage/plugin-graphiql" "^0.2.40-next.0" - "@backstage/plugin-home" "^0.4.24-next.0" - "@backstage/plugin-jenkins" "^0.7.7-next.0" + "@backstage/plugin-home" "^0.4.24-next.1" + "@backstage/plugin-jenkins" "^0.7.7-next.1" "@backstage/plugin-kafka" "^0.3.8-next.0" - "@backstage/plugin-kubernetes" "^0.7.1-next.0" + "@backstage/plugin-kubernetes" "^0.7.1-next.1" "@backstage/plugin-lighthouse" "^0.3.8-next.0" "@backstage/plugin-newrelic" "^0.3.26-next.0" "@backstage/plugin-newrelic-dashboard" "^0.2.1-next.0" @@ -13257,7 +13265,7 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: "@backstage/plugin-pagerduty" "0.5.1-next.0" "@backstage/plugin-permission-react" "^0.4.4-next.0" "@backstage/plugin-rollbar" "^0.4.8-next.0" - "@backstage/plugin-scaffolder" "^1.4.1-next.0" + "@backstage/plugin-scaffolder" "^1.5.0-next.1" "@backstage/plugin-search" "^1.0.1-next.0" "@backstage/plugin-search-common" "^1.0.0" "@backstage/plugin-search-react" "^1.0.1-next.0" @@ -13266,9 +13274,9 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: "@backstage/plugin-stack-overflow" "^0.1.4-next.0" "@backstage/plugin-tech-insights" "^0.2.4-next.0" "@backstage/plugin-tech-radar" "^0.5.15-next.0" - "@backstage/plugin-techdocs" "^1.3.1-next.0" - "@backstage/plugin-techdocs-module-addons-contrib" "^1.0.3-next.0" - "@backstage/plugin-techdocs-react" "^1.0.3-next.0" + "@backstage/plugin-techdocs" "^1.3.1-next.1" + "@backstage/plugin-techdocs-module-addons-contrib" "^1.0.3-next.1" + "@backstage/plugin-techdocs-react" "^1.0.3-next.1" "@backstage/plugin-todo" "^0.2.10-next.0" "@backstage/plugin-user-settings" "^0.4.7-next.0" "@backstage/theme" "^0.2.16" @@ -19427,7 +19435,7 @@ msw@^0.43.0: type-fest "^1.2.2" yargs "^17.3.1" -msw@^0.44.0: +msw@^0.44.0, msw@^0.44.2: version "0.44.2" resolved "https://registry.npmjs.org/msw/-/msw-0.44.2.tgz#00a901b6cc9d119fb30f794330d96dca6944afc2" integrity sha512-u8wjzzcMWouoZtuIShCwx4M3wFF5sBAV1f8K4a0WX8kiihFjzl89IKE1VYmTclLyMIwpOq8qQ1HTpuh2BFX/3A== @@ -24796,7 +24804,7 @@ superagent@^8.0.0: readable-stream "^3.6.0" semver "^7.3.7" -supertest@^6.1.3, supertest@^6.1.6: +supertest@^6.1.3, supertest@^6.1.6, supertest@^6.2.4: version "6.2.4" resolved "https://registry.npmjs.org/supertest/-/supertest-6.2.4.tgz#3dcebe42f7fd6f28dd7ac74c6cba881f7101b2f0" integrity sha512-M8xVnCNv+q2T2WXVzxDECvL2695Uv2uUj2O0utxsld/HRyJvOU8W9f1gvsYxSNU4wmIe0/L/ItnpU4iKq0emDA== @@ -26651,7 +26659,7 @@ winston-transport@^4.5.0: readable-stream "^3.6.0" triple-beam "^1.3.0" -winston@^3.2.1, winston@^3.7.2: +winston@^3.2.1, winston@^3.7.2, winston@^3.8.1: version "3.8.1" resolved "https://registry.npmjs.org/winston/-/winston-3.8.1.tgz#76f15b3478cde170b780234e0c4cf805c5a7fb57" integrity sha512-r+6YAiCR4uI3N8eQNOg8k3P3PqwAm20cLKlzVD9E66Ch39+LZC+VH1UKf9JemQj2B3QoUHfKD7Poewn0Pr3Y1w== From 4a4b9ad2de274fdf47178edba54da6d74d858c31 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Tue, 2 Aug 2022 11:51:33 +0200 Subject: [PATCH 124/144] Added project pattern for GitLab provider to be able to filter projects on more granular level. Signed-off-by: bnechyporenko --- plugins/catalog-backend-module-gitlab/src/lib/types.ts | 1 + .../src/providers/GitlabDiscoveryEntityProvider.ts | 4 ++++ .../catalog-backend-module-gitlab/src/providers/config.ts | 6 +++++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/plugins/catalog-backend-module-gitlab/src/lib/types.ts b/plugins/catalog-backend-module-gitlab/src/lib/types.ts index 69de9d28c7..8a3c33c8f2 100644 --- a/plugins/catalog-backend-module-gitlab/src/lib/types.ts +++ b/plugins/catalog-backend-module-gitlab/src/lib/types.ts @@ -35,4 +35,5 @@ export type GitlabProviderConfig = { id: string; branch: string; catalogFile: string; + projectPattern: RegExp; }; diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.ts index 36c3ee90be..ffb123edf7 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.ts @@ -147,6 +147,10 @@ export class GitlabDiscoveryEntityProvider implements EntityProvider { }; for await (const project of projects) { + if (!this.config.projectPattern.test(project.path_with_namespace ?? '')) { + continue; + } + res.scanned++; if (project.archived) { diff --git a/plugins/catalog-backend-module-gitlab/src/providers/config.ts b/plugins/catalog-backend-module-gitlab/src/providers/config.ts index d6ad28b2ca..a316ddc3c9 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/config.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/config.ts @@ -15,13 +15,14 @@ */ import { Config } from '@backstage/config'; -import { GitlabProviderConfig } from '../lib/types'; +import { GitlabProviderConfig } from '../lib'; /** * Extracts the gitlab config from a config object * * @public * + * @param id - The provider key * @param config - The config object to extract from */ function readGitlabConfig(id: string, config: Config): GitlabProviderConfig { @@ -30,6 +31,8 @@ function readGitlabConfig(id: string, config: Config): GitlabProviderConfig { const branch = config.getOptionalString('branch') ?? 'master'; const catalogFile = config.getOptionalString('entityFilename') ?? 'catalog-info.yaml'; + const projectPattern = + new RegExp(config.getString('projectPattern')) ?? /[\s\S]*/; return { id, @@ -37,6 +40,7 @@ function readGitlabConfig(id: string, config: Config): GitlabProviderConfig { branch, host, catalogFile, + projectPattern, }; } From 24979413a43493ff276862a29c23c078746522f5 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Tue, 2 Aug 2022 11:56:43 +0200 Subject: [PATCH 125/144] Added project pattern for GitLab provider to be able to filter projects on more granular level. Signed-off-by: bnechyporenko --- .changeset/cool-months-tickle.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .changeset/cool-months-tickle.md diff --git a/.changeset/cool-months-tickle.md b/.changeset/cool-months-tickle.md new file mode 100644 index 0000000000..a160b13bd0 --- /dev/null +++ b/.changeset/cool-months-tickle.md @@ -0,0 +1,17 @@ +--- +'@backstage/plugin-catalog-backend-module-gitlab': minor +--- + +Enhancing GitLab provider with filtering projects by pattern RegExp + +```yaml +providers: + gitlab: + stg: + host: gitlab.stg.company.io + branch: main + projectPattern: johndoe/ <== new option + entityFilename: template.yaml +``` + +With the abovementioned parameter you can filter projects, and keep only who belongs to the namespace "johndoe". From d51e5223d6c06838f7c17282bfc10c42f84e9597 Mon Sep 17 00:00:00 2001 From: Kamil Wolny Date: Tue, 2 Aug 2022 08:57:29 +0100 Subject: [PATCH 126/144] feat: updated api-report.md Signed-off-by: Kamil Wolny --- plugins/github-issues/api-report.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/plugins/github-issues/api-report.md b/plugins/github-issues/api-report.md index 5e6f75460d..6679fec610 100644 --- a/plugins/github-issues/api-report.md +++ b/plugins/github-issues/api-report.md @@ -6,20 +6,21 @@ /// import { BackstagePlugin } from '@backstage/core-plugin-api'; -import { FunctionComponent } from 'react'; import { RouteRef } from '@backstage/core-plugin-api'; +// Warning: (ae-forgotten-export) The symbol "GitHubIssuesProps" needs to be exported by the entry point index.d.ts +// // @public (undocumented) -export const GitHubIssuesCard: FunctionComponent<{ - itemsPerPage?: number | undefined; - itemsPerRepo?: number | undefined; -}>; +export const GitHubIssuesCard: ({ + itemsPerPage, + itemsPerRepo, +}: GitHubIssuesProps) => JSX.Element; // @public (undocumented) -export const GitHubIssuesPage: FunctionComponent<{ - itemsPerPage?: number | undefined; - itemsPerRepo?: number | undefined; -}>; +export const GitHubIssuesPage: ({ + itemsPerPage, + itemsPerRepo, +}: GitHubIssuesProps) => JSX.Element; // @public (undocumented) export const gitHubIssuesPlugin: BackstagePlugin< From ffd5e47fb5c6338aa0e6965d687d0028e0baabb5 Mon Sep 17 00:00:00 2001 From: Kamil Wolny Date: Tue, 2 Aug 2022 10:35:51 +0100 Subject: [PATCH 127/144] feat: pr review fixes + changeset Signed-off-by: Kamil Wolny --- .changeset/silver-carpets-grin.md | 5 ++ plugins/github-issues/api-report.md | 8 +- plugins/github-issues/package.json | 4 +- .../components/GitHubIssues/GitHubIssues.tsx | 10 ++- .../src/hooks/useOctokitGraphQL.ts | 2 +- plugins/github-issues/src/index.ts | 2 + yarn.lock | 78 +------------------ 7 files changed, 23 insertions(+), 86 deletions(-) create mode 100644 .changeset/silver-carpets-grin.md diff --git a/.changeset/silver-carpets-grin.md b/.changeset/silver-carpets-grin.md new file mode 100644 index 0000000000..9865393631 --- /dev/null +++ b/.changeset/silver-carpets-grin.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-github-issues': minor +--- + +New plugin for displaying GitHub Issues added diff --git a/plugins/github-issues/api-report.md b/plugins/github-issues/api-report.md index 6679fec610..8c77aaf674 100644 --- a/plugins/github-issues/api-report.md +++ b/plugins/github-issues/api-report.md @@ -8,8 +8,6 @@ import { BackstagePlugin } from '@backstage/core-plugin-api'; import { RouteRef } from '@backstage/core-plugin-api'; -// Warning: (ae-forgotten-export) The symbol "GitHubIssuesProps" needs to be exported by the entry point index.d.ts -// // @public (undocumented) export const GitHubIssuesCard: ({ itemsPerPage, @@ -31,5 +29,11 @@ export const gitHubIssuesPlugin: BackstagePlugin< {} >; +// @public (undocumented) +export type GitHubIssuesProps = { + itemsPerPage?: number; + itemsPerRepo?: number; +}; + // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/github-issues/package.json b/plugins/github-issues/package.json index 861a67ffa2..74f108cd94 100644 --- a/plugins/github-issues/package.json +++ b/plugins/github-issues/package.json @@ -32,9 +32,9 @@ "@material-ui/core": "^4.12.4", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "^4.0.0-alpha.61", - "@octokit/rest": "^18.12.0", "@types/react": "^16.13.1 || ^17.0.0", "luxon": "^2.4.0", + "octokit": "^2.0.4", "react-use": "^17.2.4" }, "peerDependencies": { @@ -52,7 +52,7 @@ "@types/jest": "*", "@types/node": "*", "cross-fetch": "^3.1.5", - "msw": "^0.42.0", + "msw": "^0.44.0", "prettier": "^2.7.1" }, "files": [ diff --git a/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx b/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx index e873028060..5380c8eb22 100644 --- a/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx +++ b/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx @@ -28,15 +28,17 @@ import { import { IssueList } from './IssuesList'; import { NoRepositoriesInfo } from './NoRepositoriesInfo'; +/** + * @public + */ export type GitHubIssuesProps = { itemsPerPage?: number; itemsPerRepo?: number; }; -export const GitHubIssues = ({ - itemsPerPage = 10, - itemsPerRepo = 40, -}: GitHubIssuesProps) => { +export const GitHubIssues = (props: GitHubIssuesProps) => { + const { itemsPerPage = 10, itemsPerRepo = 40 } = props; + const [isLoading, setIsLoading] = React.useState(true); const [issuesByRepository, setIssuesByRepository] = diff --git a/plugins/github-issues/src/hooks/useOctokitGraphQL.ts b/plugins/github-issues/src/hooks/useOctokitGraphQL.ts index e408360c53..6b783efd6f 100644 --- a/plugins/github-issues/src/hooks/useOctokitGraphQL.ts +++ b/plugins/github-issues/src/hooks/useOctokitGraphQL.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { Octokit } from '@octokit/rest'; +import { Octokit } from 'octokit'; import { useApi, githubAuthApiRef, diff --git a/plugins/github-issues/src/index.ts b/plugins/github-issues/src/index.ts index 7905d2fba2..5f6c248db7 100644 --- a/plugins/github-issues/src/index.ts +++ b/plugins/github-issues/src/index.ts @@ -18,3 +18,5 @@ export { GitHubIssuesPage, GitHubIssuesCard, } from './plugin'; + +export type { GitHubIssuesProps } from './components/GitHubIssues'; diff --git a/yarn.lock b/yarn.lock index 44409c647b..3b60557a67 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5431,19 +5431,6 @@ before-after-hook "^2.1.0" universal-user-agent "^6.0.0" -"@octokit/core@^3.5.1": - version "3.6.0" - resolved "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz#3376cb9f3008d9b3d110370d90e0a1fcd5fe6085" - integrity sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q== - dependencies: - "@octokit/auth-token" "^2.4.4" - "@octokit/graphql" "^4.5.8" - "@octokit/request" "^5.6.3" - "@octokit/request-error" "^2.0.5" - "@octokit/types" "^6.0.3" - before-after-hook "^2.2.0" - universal-user-agent "^6.0.0" - "@octokit/core@^4.0.0": version "4.0.2" resolved "https://registry.npmjs.org/@octokit/core/-/core-4.0.2.tgz#4eaf9c5fd39913b541c5e31a2b8fdc3cf50480bc" @@ -5560,11 +5547,6 @@ resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.2.0.tgz#b38d7fc3736d52a1e96b230c1ccd4a58a2f400a6" integrity sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA== -"@octokit/openapi-types@^12.11.0": - version "12.11.0" - resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.11.0.tgz#da5638d64f2b919bca89ce6602d059f1b52d3ef0" - integrity sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ== - "@octokit/openapi-types@^12.4.0": version "12.4.0" resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.4.0.tgz#fd8bf5db72bd566c5ba2cb76754512a9ebe66e71" @@ -5585,13 +5567,6 @@ resolved "https://registry.npmjs.org/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-6.0.1.tgz#e07896739618dab8da7d4077c658003775f95437" integrity sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw== -"@octokit/plugin-paginate-rest@^2.16.8": - version "2.21.3" - resolved "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz#7f12532797775640dbb8224da577da7dc210c87e" - integrity sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw== - dependencies: - "@octokit/types" "^6.40.0" - "@octokit/plugin-paginate-rest@^2.6.2": version "2.7.0" resolved "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.7.0.tgz#6bb7b043c246e0654119a6ec4e72a172c9e2c7f3" @@ -5624,14 +5599,6 @@ "@octokit/types" "^6.16.2" deprecation "^2.3.1" -"@octokit/plugin-rest-endpoint-methods@^5.12.0": - version "5.16.2" - resolved "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz#7ee8bf586df97dd6868cf68f641354e908c25342" - integrity sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw== - dependencies: - "@octokit/types" "^6.39.0" - deprecation "^2.3.1" - "@octokit/plugin-rest-endpoint-methods@^6.0.0": version "6.0.0" resolved "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-6.0.0.tgz#e4a55d83ec5a00e6b4d7a780f4ec9009095bff6f" @@ -5708,16 +5675,6 @@ "@octokit/plugin-request-log" "^1.0.2" "@octokit/plugin-rest-endpoint-methods" "5.3.1" -"@octokit/rest@^18.12.0": - version "18.12.0" - resolved "https://registry.npmjs.org/@octokit/rest/-/rest-18.12.0.tgz#f06bc4952fc87130308d810ca9d00e79f6988881" - integrity sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q== - dependencies: - "@octokit/core" "^3.5.1" - "@octokit/plugin-paginate-rest" "^2.16.8" - "@octokit/plugin-request-log" "^1.0.4" - "@octokit/plugin-rest-endpoint-methods" "^5.12.0" - "@octokit/rest@^19.0.3": version "19.0.3" resolved "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.3.tgz#b9a4e8dc8d53e030d611c053153ee6045f080f02" @@ -5763,13 +5720,6 @@ dependencies: "@octokit/openapi-types" "^12.7.0" -"@octokit/types@^6.40.0": - version "6.41.0" - resolved "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz#e58ef78d78596d2fb7df9c6259802464b5f84a04" - integrity sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg== - dependencies: - "@octokit/openapi-types" "^12.11.0" - "@octokit/webhooks-methods@^3.0.0": version "3.0.0" resolved "https://registry.npmjs.org/@octokit/webhooks-methods/-/webhooks-methods-3.0.0.tgz#4f4443605233f46abc5f85a857ba105095aa1181" @@ -19310,32 +19260,6 @@ msw@^0.39.2: type-fest "^1.2.2" yargs "^17.3.1" -msw@^0.42.0: - version "0.42.3" - resolved "https://registry.npmjs.org/msw/-/msw-0.42.3.tgz#150c475e2cb6d53c67503bd0e3f6251bfd075328" - integrity sha512-zrKBIGCDsNUCZLd3DLSeUtRruZ0riwJgORg9/bSDw3D0PTI8XUGAK3nC0LJA9g0rChGuKaWK/SwObA8wpFrz4g== - dependencies: - "@mswjs/cookies" "^0.2.0" - "@mswjs/interceptors" "^0.16.3" - "@open-draft/until" "^1.0.3" - "@types/cookie" "^0.4.1" - "@types/js-levenshtein" "^1.1.1" - chalk "4.1.1" - chokidar "^3.4.2" - cookie "^0.4.2" - graphql "^16.3.0" - headers-polyfill "^3.0.4" - inquirer "^8.2.0" - is-node-process "^1.0.1" - js-levenshtein "^1.1.6" - node-fetch "^2.6.7" - outvariant "^1.3.0" - path-to-regexp "^6.2.0" - statuses "^2.0.0" - strict-event-emitter "^0.2.0" - type-fest "^1.2.2" - yargs "^17.3.1" - msw@^0.43.0: version "0.43.1" resolved "https://registry.npmjs.org/msw/-/msw-0.43.1.tgz#57cb4af56f07442e8a6d14d76032a0ab41434256" @@ -20090,7 +20014,7 @@ octokit-plugin-create-pull-request@^3.10.0: dependencies: "@octokit/types" "^6.8.2" -octokit@^2.0.0: +octokit@^2.0.0, octokit@^2.0.4: version "2.0.4" resolved "https://registry.npmjs.org/octokit/-/octokit-2.0.4.tgz#cfd3adee6b775d3fa8cd8746590bed36127cc0a0" integrity sha512-9QvgYGzrSTGmr3koSGtbgeMgqYI20QI0Vv8Bk9y6phchk6L2aHFhcrUOIeNUPj1Z+KZnEBd6A/8faNpDFNfVjg== From 34504ab52b9d3efa5f97892ea75d59b73d6a5ce9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Brad=20Reed=20=F0=9F=98=8E?= Date: Tue, 2 Aug 2022 12:12:48 +0200 Subject: [PATCH 128/144] feat(kubernetes): add namespace to k8s error reporting table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Brad Reed 😎 --- .../src/components/ErrorReporting/ErrorReporting.tsx | 9 +++++++-- plugins/kubernetes/src/error-detection/common.ts | 2 ++ .../src/error-detection/error-detection.test.ts | 8 ++++++++ plugins/kubernetes/src/error-detection/types.ts | 1 + 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/plugins/kubernetes/src/components/ErrorReporting/ErrorReporting.tsx b/plugins/kubernetes/src/components/ErrorReporting/ErrorReporting.tsx index 62af1d9d14..0dbf889fab 100644 --- a/plugins/kubernetes/src/components/ErrorReporting/ErrorReporting.tsx +++ b/plugins/kubernetes/src/components/ErrorReporting/ErrorReporting.tsx @@ -26,12 +26,17 @@ type ErrorReportingProps = { const columns: TableColumn[] = [ { title: 'cluster', - width: '15%', + width: '10%', render: (detectedError: DetectedError) => detectedError.cluster, }, + { + title: 'namespace', + width: '10%', + render: (detectedError: DetectedError) => detectedError.namespace, + }, { title: 'kind', - width: '15%', + width: '10%', render: (detectedError: DetectedError) => detectedError.kind, }, { diff --git a/plugins/kubernetes/src/error-detection/common.ts b/plugins/kubernetes/src/error-detection/common.ts index ce7902110f..bc5fd2fc40 100644 --- a/plugins/kubernetes/src/error-detection/common.ts +++ b/plugins/kubernetes/src/error-detection/common.ts @@ -45,6 +45,7 @@ export const detectErrorsInObjects = ( const value = errors.get(dedupKey); const name = object.metadata?.name ?? 'unknown'; + const namespace = object.metadata?.namespace ?? 'unknown'; if (value !== undefined) { // This gets translated into the Chip "+5 others" @@ -60,6 +61,7 @@ export const detectErrorsInObjects = ( names: [name], message: message, severity: errorMapper.severity, + namespace, }); } } diff --git a/plugins/kubernetes/src/error-detection/error-detection.test.ts b/plugins/kubernetes/src/error-detection/error-detection.test.ts index ef64ff6a20..2c6373f32d 100644 --- a/plugins/kubernetes/src/error-detection/error-detection.test.ts +++ b/plugins/kubernetes/src/error-detection/error-detection.test.ts @@ -154,6 +154,7 @@ describe('detectErrors', () => { 'container=side-car restarted 38 times', ], names: ['dice-roller-canary-7d64cd756c-55rfq'], + namespace: 'default', severity: 4, }); @@ -165,6 +166,7 @@ describe('detectErrors', () => { 'containers with unready status: [side-car other-side-car]', ], names: ['dice-roller-canary-7d64cd756c-55rfq'], + namespace: 'default', severity: 5, }); @@ -176,6 +178,7 @@ describe('detectErrors', () => { 'back-off 5m0s restarting failed container=side-car pod=dice-roller-canary-7d64cd756c-55rfq_default(65ad28e3-5d51-4b4b-9bf8-4cb069803034)', ], names: ['dice-roller-canary-7d64cd756c-55rfq'], + namespace: 'default', severity: 6, }); @@ -187,6 +190,7 @@ describe('detectErrors', () => { 'container=side-car exited with error code (1)', ], names: ['dice-roller-canary-7d64cd756c-55rfq'], + namespace: 'default', severity: 4, }); }); @@ -210,6 +214,7 @@ describe('detectErrors', () => { 'containers with unready status: [nginx]', ], names: ['dice-roller-bad-cm-855bf85464-mg6xb'], + namespace: 'default', severity: 5, }); @@ -218,6 +223,7 @@ describe('detectErrors', () => { kind: 'Pod', message: ['configmap "some-cm" not found'], names: ['dice-roller-bad-cm-855bf85464-mg6xb'], + namespace: 'default', severity: 6, }); }); @@ -248,6 +254,7 @@ describe('detectErrors', () => { kind: 'Deployment', message: ['Deployment does not have minimum availability.'], names: ['dice-roller-canary'], + namespace: 'default', severity: 6, }); }); @@ -280,6 +287,7 @@ describe('detectErrors', () => { 'Current number of replicas (10) is equal to the configured max number of replicas (10)', ], names: ['dice-roller'], + namespace: 'default', severity: 8, }); }); diff --git a/plugins/kubernetes/src/error-detection/types.ts b/plugins/kubernetes/src/error-detection/types.ts index 871413d43e..5e35cef8b6 100644 --- a/plugins/kubernetes/src/error-detection/types.ts +++ b/plugins/kubernetes/src/error-detection/types.ts @@ -55,6 +55,7 @@ export type DetectedErrorsByCluster = Map; export interface DetectedError { severity: ErrorSeverity; cluster: string; + namespace: string; kind: ErrorDetectableKind; names: string[]; message: string[]; From f563b86a5b1fc76dc4875c6331de85e81e009cd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Brad=20Reed=20=F0=9F=98=8E?= Date: Tue, 2 Aug 2022 12:20:07 +0200 Subject: [PATCH 129/144] changeset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Brad Reed 😎 --- .changeset/flat-zebras-draw.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/flat-zebras-draw.md diff --git a/.changeset/flat-zebras-draw.md b/.changeset/flat-zebras-draw.md new file mode 100644 index 0000000000..338ee9ca27 --- /dev/null +++ b/.changeset/flat-zebras-draw.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-kubernetes': minor +--- + +Adds namespace column to Kubernetes error reporting table From 62aae9363a4dc82de17eb5d9705b0dadb411ac31 Mon Sep 17 00:00:00 2001 From: kielosz Date: Tue, 2 Aug 2022 12:43:48 +0200 Subject: [PATCH 130/144] Add names to Groups Signed-off-by: kielosz --- plugins/cost-insights-common/src/types/Group.ts | 1 + .../src/components/CostInsightsTabs/CostInsightsTabs.test.tsx | 3 ++- .../src/components/CostInsightsTabs/CostInsightsTabs.tsx | 2 +- plugins/cost-insights/src/example/client.ts | 3 ++- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/plugins/cost-insights-common/src/types/Group.ts b/plugins/cost-insights-common/src/types/Group.ts index b34cac083f..ad384abe7b 100644 --- a/plugins/cost-insights-common/src/types/Group.ts +++ b/plugins/cost-insights-common/src/types/Group.ts @@ -19,4 +19,5 @@ */ export type Group = { id: string; + name?: string; }; diff --git a/plugins/cost-insights/src/components/CostInsightsTabs/CostInsightsTabs.test.tsx b/plugins/cost-insights/src/components/CostInsightsTabs/CostInsightsTabs.test.tsx index 6da6286515..2e2131daff 100644 --- a/plugins/cost-insights/src/components/CostInsightsTabs/CostInsightsTabs.test.tsx +++ b/plugins/cost-insights/src/components/CostInsightsTabs/CostInsightsTabs.test.tsx @@ -32,6 +32,7 @@ const mockGroups: Group[] = [ }, { id: 'test-group-3', + name: 'Test Group 3', }, ]; @@ -76,7 +77,7 @@ describe('', () => { ); await userEvent.click(rendered.getByTestId('cost-insights-groups-tab')); mockGroups.forEach(group => - expect(rendered.getByText(group.id)).toBeInTheDocument(), + expect(rendered.getByText(group.name ?? group.id)).toBeInTheDocument(), ); }); }); diff --git a/plugins/cost-insights/src/components/CostInsightsTabs/CostInsightsTabs.tsx b/plugins/cost-insights/src/components/CostInsightsTabs/CostInsightsTabs.tsx index 3bb3f14214..935184ee55 100644 --- a/plugins/cost-insights/src/components/CostInsightsTabs/CostInsightsTabs.tsx +++ b/plugins/cost-insights/src/components/CostInsightsTabs/CostInsightsTabs.tsx @@ -100,7 +100,7 @@ export const CostInsightsTabs = ({ groups }: CostInsightsTabsProps) => { data-testid={g.id} onClick={updateGroupFilterAndCloseMenu(g)} > - {g.id} + {g.name ?? g.id} ))} diff --git a/plugins/cost-insights/src/example/client.ts b/plugins/cost-insights/src/example/client.ts index a7a2a0e22f..a6aadedd09 100644 --- a/plugins/cost-insights/src/example/client.ts +++ b/plugins/cost-insights/src/example/client.ts @@ -52,7 +52,8 @@ export class ExampleCostInsightsClient implements CostInsightsApi { async getUserGroups(userId: string): Promise { const groups: Group[] = await this.request({ userId }, [ - { id: 'pied-piper' }, + { id: 'group-a', name: 'Group A' }, + { id: 'group-b', name: 'Group B' }, ]); return groups; From daf4b33e34cbc9257f783a2a6e87f51919fb7bc2 Mon Sep 17 00:00:00 2001 From: kielosz Date: Tue, 2 Aug 2022 12:51:48 +0200 Subject: [PATCH 131/144] Add changeset Signed-off-by: kielosz --- .changeset/plenty-timers-flow.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/plenty-timers-flow.md diff --git a/.changeset/plenty-timers-flow.md b/.changeset/plenty-timers-flow.md new file mode 100644 index 0000000000..8a26c8068b --- /dev/null +++ b/.changeset/plenty-timers-flow.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-cost-insights': patch +'@backstage/plugin-cost-insights-common': patch +--- + +Add name property to Group From eae2f7c73224f1ed66bf856e4f4fa5f0a047a855 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Tue, 2 Aug 2022 13:02:04 +0200 Subject: [PATCH 132/144] Added project pattern for GitLab provider to be able to filter projects on more granular level. Signed-off-by: bnechyporenko --- .changeset/cool-months-tickle.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/cool-months-tickle.md b/.changeset/cool-months-tickle.md index a160b13bd0..41ee67db33 100644 --- a/.changeset/cool-months-tickle.md +++ b/.changeset/cool-months-tickle.md @@ -10,8 +10,8 @@ providers: stg: host: gitlab.stg.company.io branch: main - projectPattern: johndoe/ <== new option + projectPattern: john/ <== new option entityFilename: template.yaml ``` -With the abovementioned parameter you can filter projects, and keep only who belongs to the namespace "johndoe". +With the aforementioned parameter you can filter projects, and keep only who belongs to the namespace "john". From 440663a4fd484cd2ffe16ba097006e045063fadd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Brad=20Reed=20=F0=9F=98=8E?= Date: Tue, 2 Aug 2022 13:09:07 +0200 Subject: [PATCH 133/144] api-report MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Brad Reed 😎 --- plugins/kubernetes/api-report.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/kubernetes/api-report.md b/plugins/kubernetes/api-report.md index e85c9cbeca..ccb4dcae8d 100644 --- a/plugins/kubernetes/api-report.md +++ b/plugins/kubernetes/api-report.md @@ -109,6 +109,8 @@ export interface DetectedError { // (undocumented) names: string[]; // (undocumented) + namespace: string; + // (undocumented) severity: ErrorSeverity; } From 986fcb39d8dd2615ad39e26df9b4f0219854b62b Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Tue, 2 Aug 2022 13:10:38 +0200 Subject: [PATCH 134/144] Added project pattern for GitLab provider to be able to filter projects on more granular level. Signed-off-by: bnechyporenko --- .../catalog-backend-module-gitlab/src/providers/config.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/catalog-backend-module-gitlab/src/providers/config.ts b/plugins/catalog-backend-module-gitlab/src/providers/config.ts index a316ddc3c9..da2a7e0b8d 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/config.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/config.ts @@ -31,8 +31,9 @@ function readGitlabConfig(id: string, config: Config): GitlabProviderConfig { const branch = config.getOptionalString('branch') ?? 'master'; const catalogFile = config.getOptionalString('entityFilename') ?? 'catalog-info.yaml'; - const projectPattern = - new RegExp(config.getString('projectPattern')) ?? /[\s\S]*/; + const projectPattern = new RegExp( + config.getString('projectPattern') ?? /[\s\S]*/, + ); return { id, From 77e84d6ea4113d664cb45caa7967f645dcc2bd67 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Tue, 2 Aug 2022 13:18:03 +0200 Subject: [PATCH 135/144] Added project pattern for GitLab provider to be able to filter projects on more granular level. Signed-off-by: bnechyporenko --- .../catalog-backend-module-gitlab/src/providers/config.test.ts | 2 ++ plugins/catalog-backend-module-gitlab/src/providers/config.ts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/catalog-backend-module-gitlab/src/providers/config.test.ts b/plugins/catalog-backend-module-gitlab/src/providers/config.test.ts index 892ce5f25c..cb36e5166c 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/config.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/config.test.ts @@ -52,6 +52,7 @@ describe('config', () => { branch: 'master', host: 'host', catalogFile: 'catalog-info.yaml', + projectPattern: /[\s\S]*/, }), ); }); @@ -81,6 +82,7 @@ describe('config', () => { branch: 'not-master', host: 'host', catalogFile: 'custom-file.yaml', + projectPattern: /[\s\S]*/, }), ); }); diff --git a/plugins/catalog-backend-module-gitlab/src/providers/config.ts b/plugins/catalog-backend-module-gitlab/src/providers/config.ts index da2a7e0b8d..392922860f 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/config.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/config.ts @@ -32,7 +32,7 @@ function readGitlabConfig(id: string, config: Config): GitlabProviderConfig { const catalogFile = config.getOptionalString('entityFilename') ?? 'catalog-info.yaml'; const projectPattern = new RegExp( - config.getString('projectPattern') ?? /[\s\S]*/, + config.getOptionalString('projectPattern') ?? /[\s\S]*/, ); return { From b169ddac671abcb583dafc010792b47a4462e979 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Tue, 2 Aug 2022 13:23:12 +0200 Subject: [PATCH 136/144] Added project pattern for GitLab provider to be able to filter projects on more granular level. Signed-off-by: bnechyporenko --- docs/integrations/gitlab/discovery.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/integrations/gitlab/discovery.md b/docs/integrations/gitlab/discovery.md index aad73c8209..df5aadcab4 100644 --- a/docs/integrations/gitlab/discovery.md +++ b/docs/integrations/gitlab/discovery.md @@ -24,6 +24,7 @@ catalog: branch: main # Optional. Uses `master` as default group: example-group # Optional. Group and subgroup (if needed) to look for repositories. If not present the whole project will be scanned entityFilename: catalog-info.yaml # Optional. Defaults to `catalog-info.yaml` + projectPattern: /[\s\S]*/ # Optional. Filters found projects based on provided patter. Defaults to `/[\s\S]*/`, what means to not filter anything ``` As this provider is not one of the default providers, you will first need to install From c2dca67d24cd5b485e3be44ccf0dd7aac9bdec4c Mon Sep 17 00:00:00 2001 From: kielosz Date: Tue, 2 Aug 2022 13:40:39 +0200 Subject: [PATCH 137/144] Add api-report Signed-off-by: kielosz --- plugins/cost-insights-common/api-report.md | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/cost-insights-common/api-report.md b/plugins/cost-insights-common/api-report.md index a5f7045854..8d9e2d030d 100644 --- a/plugins/cost-insights-common/api-report.md +++ b/plugins/cost-insights-common/api-report.md @@ -44,6 +44,7 @@ export interface Entity { // @public (undocumented) export type Group = { id: string; + name?: string; }; // @public (undocumented) From 76b4026d032060b356b44aea6582c0c003a030af Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Tue, 2 Aug 2022 13:54:54 +0200 Subject: [PATCH 138/144] Added project pattern for GitLab provider to be able to filter projects on more granular level. Signed-off-by: bnechyporenko --- .../GitlabDiscoveryEntityProvider.test.ts | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.test.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.test.ts index dc70772d3d..d4a13cf81e 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.test.ts @@ -227,4 +227,113 @@ describe('GitlabDiscoveryEntityProvider', () => { entities: expectedEntities, }); }); + + it('should filter found projects based on a provided project pattern', async () => { + const config = new ConfigReader({ + integrations: { + gitlab: [ + { + host: 'test-gitlab', + apiBaseUrl: 'https://api.gitlab.example/api/v4', + token: '1234', + }, + ], + }, + catalog: { + providers: { + gitlab: { + 'test-id': { + host: 'test-gitlab', + projectPattern: 'john/', + }, + }, + }, + }, + }); + const schedule = new PersistingTaskRunner(); + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + }; + const provider = GitlabDiscoveryEntityProvider.fromConfig(config, { + logger, + schedule, + })[0]; + + server.use( + rest.get( + `https://api.gitlab.example/api/v4/projects`, + (_req, res, ctx) => { + const response = [ + { + id: 123, + default_branch: 'master', + archived: false, + last_activity_at: new Date().toString(), + web_url: 'https://api.gitlab.example/test-group/test-repo', + path_with_namespace: 'test-group/test-repo', + }, + { + id: 124, + default_branch: 'master', + archived: false, + last_activity_at: new Date().toString(), + web_url: 'https://api.gitlab.example/john/example', + path_with_namespace: 'john/example', + }, + ]; + return res(ctx.json(response)); + }, + ), + rest.head( + 'https://api.gitlab.example/api/v4/projects/test-group%2Ftest-repo/repository/files/catalog-info.yaml', + (req, res, ctx) => { + if (req.url.searchParams.get('ref') === 'master') { + return res(ctx.status(200)); + } + return res(ctx.status(404, 'Not Found')); + }, + ), + rest.head( + 'https://api.gitlab.example/api/v4/projects/john%2Fexample/repository/files/catalog-info.yaml', + (req, res, ctx) => { + if (req.url.searchParams.get('ref') === 'master') { + return res(ctx.status(200)); + } + return res(ctx.status(404, 'Not Found')); + }, + ), + ); + + await provider.connect(entityProviderConnection); + + await provider.refresh(logger); + + expect(entityProviderConnection.applyMutation).toBeCalledWith({ + type: 'full', + entities: [ + { + entity: { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Location', + metadata: { + annotations: { + 'backstage.io/managed-by-location': + 'url:https://api.gitlab.example/john/example/-/blob/master/catalog-info.yaml', + 'backstage.io/managed-by-origin-location': + 'url:https://api.gitlab.example/john/example/-/blob/master/catalog-info.yaml', + }, + name: 'generated-2045212e5b3e9e6bacf51cec709e362282e3cda9', + }, + spec: { + presence: 'optional', + target: + 'https://api.gitlab.example/john/example/-/blob/master/catalog-info.yaml', + type: 'url', + }, + }, + locationKey: 'GitlabDiscoveryEntityProvider:test-id', + }, + ], + }); + }); }); From 77f143585c84c8a155e7f2c0771a5ddaa5e1a38a Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Tue, 2 Aug 2022 14:53:13 +0200 Subject: [PATCH 139/144] Incorporated a feedback Signed-off-by: bnechyporenko --- .changeset/cool-months-tickle.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/cool-months-tickle.md b/.changeset/cool-months-tickle.md index 41ee67db33..3c3370216e 100644 --- a/.changeset/cool-months-tickle.md +++ b/.changeset/cool-months-tickle.md @@ -1,5 +1,5 @@ --- -'@backstage/plugin-catalog-backend-module-gitlab': minor +'@backstage/plugin-catalog-backend-module-gitlab': patch --- Enhancing GitLab provider with filtering projects by pattern RegExp From 4890dc302563cfeafdedbd36d43db26eb00cf2ba Mon Sep 17 00:00:00 2001 From: Ben Lambert Date: Tue, 2 Aug 2022 15:05:17 +0200 Subject: [PATCH 140/144] Comment the new option Just update the changeset description a little bit Signed-off-by: Ben Lambert --- .changeset/cool-months-tickle.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/cool-months-tickle.md b/.changeset/cool-months-tickle.md index 3c3370216e..281c74bab0 100644 --- a/.changeset/cool-months-tickle.md +++ b/.changeset/cool-months-tickle.md @@ -10,7 +10,7 @@ providers: stg: host: gitlab.stg.company.io branch: main - projectPattern: john/ <== new option + projectPattern: 'john/' # new option entityFilename: template.yaml ``` From 039999d2e898c3bf882d3e51202753c356bcc902 Mon Sep 17 00:00:00 2001 From: Brad Reed Date: Tue, 2 Aug 2022 15:30:46 +0200 Subject: [PATCH 141/144] Update .changeset/flat-zebras-draw.md Signed-off-by: Brad Reed --- .changeset/flat-zebras-draw.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/flat-zebras-draw.md b/.changeset/flat-zebras-draw.md index 338ee9ca27..ba82f156ef 100644 --- a/.changeset/flat-zebras-draw.md +++ b/.changeset/flat-zebras-draw.md @@ -1,5 +1,5 @@ --- -'@backstage/plugin-kubernetes': minor +'@backstage/plugin-kubernetes': patch --- Adds namespace column to Kubernetes error reporting table From e597fa5e8e88d9273241d7ee93b726a0b66b4709 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 2 Aug 2022 14:22:58 +0000 Subject: [PATCH 142/144] fix(deps): update dependency swagger-ui-react to v4.13.2 Signed-off-by: Renovate Bot --- yarn.lock | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/yarn.lock b/yarn.lock index 919c41fcc7..4d624b850e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1908,7 +1908,7 @@ pirates "^4.0.0" source-map-support "^0.5.16" -"@babel/runtime-corejs3@^7.10.2", "@babel/runtime-corejs3@^7.11.2", "@babel/runtime-corejs3@^7.16.8": +"@babel/runtime-corejs3@^7.10.2", "@babel/runtime-corejs3@^7.11.2": version "7.17.2" resolved "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.17.2.tgz#fdca2cd05fba63388babe85d349b6801b008fd13" integrity sha512-NcKtr2epxfIrNM4VOmPKO46TvDMCBhgi2CrSHaEarrz+Plk2K5r9QemmOFTGpZaoKnWoGH5MO+CzeRsih/Fcgg== @@ -1916,6 +1916,14 @@ core-js-pure "^3.20.2" regenerator-runtime "^0.13.4" +"@babel/runtime-corejs3@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.18.9.tgz#7bacecd1cb2dd694eacd32a91fcf7021c20770ae" + integrity sha512-qZEWeccZCrHA2Au4/X05QW5CMdm4VjUDCrGq5gf1ZDcM4hRqreKrtwAn7yci9zfgAS9apvnsFXiGBHBAxZdK9A== + dependencies: + core-js-pure "^3.20.2" + regenerator-runtime "^0.13.4" + "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.6", "@babel/runtime@^7.15.4", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.17.7" resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.7.tgz#a5f3328dc41ff39d803f311cfe17703418cf9825" @@ -12289,12 +12297,7 @@ domhandler@^4.0.0, domhandler@^4.2.0: dependencies: domelementtype "^2.2.0" -dompurify@=2.3.3: - version "2.3.3" - resolved "https://registry.npmjs.org/dompurify/-/dompurify-2.3.3.tgz#c1af3eb88be47324432964d8abc75cf4b98d634c" - integrity sha512-dqnqRkPMAjOZE0FogZ+ceJNM2dZ3V/yNOuFB7+39qpO93hHhfRpHw3heYQC7DPK9FqbQTfBKUJhiSfz4MvXYwg== - -dompurify@^2.2.7, dompurify@^2.2.9, dompurify@^2.3.6: +dompurify@=2.3.10, dompurify@^2.2.7, dompurify@^2.2.9, dompurify@^2.3.6: version "2.3.10" resolved "https://registry.npmjs.org/dompurify/-/dompurify-2.3.10.tgz#901f7390ffe16a91a5a556b94043314cd4850385" integrity sha512-o7Fg/AgC7p/XpKjf/+RC3Ok6k4St5F7Q6q6+Nnm3p2zGWioAY6dh0CbbuwOhH2UcSzKsdniE/YnE2/92JcsA+g== @@ -22146,13 +22149,13 @@ react-copy-to-clipboard@^5.0.4: copy-to-clipboard "^3.3.1" prop-types "^15.8.1" -react-debounce-input@=3.2.4: - version "3.2.4" - resolved "https://registry.npmjs.org/react-debounce-input/-/react-debounce-input-3.2.4.tgz#8204373a6498776536a2fcc7e467d054c3b729d4" - integrity sha512-fX70bNj0fLEYO2Zcvuh7eh9wOUQ29GIx6r8IxIJlc0i0mpUH++9ax0BhfAYfzndADli3RAMROrZQ014J01owrg== +react-debounce-input@=3.3.0: + version "3.3.0" + resolved "https://registry.npmjs.org/react-debounce-input/-/react-debounce-input-3.3.0.tgz#85e3ebcaa41f2016e50613134a1ec9fe3cdb422e" + integrity sha512-VEqkvs8JvY/IIZvh71Z0TC+mdbxERvYF33RcebnodlsUZ8RSgyKe2VWaHXv4+/8aoOgXLxWrdsYs2hDhcwbUgA== dependencies: lodash.debounce "^4" - prop-types "^15.7.2" + prop-types "^15.8.1" react-dev-utils@^12.0.0-next.60: version "12.0.1" @@ -24884,17 +24887,17 @@ swagger-client@^3.18.5: url "~0.11.0" swagger-ui-react@^4.11.1: - version "4.13.0" - resolved "https://registry.npmjs.org/swagger-ui-react/-/swagger-ui-react-4.13.0.tgz#da4192b9b2a761a1e761c268606741ba200e971d" - integrity sha512-SNAByPvnpFKXUnrH6+V2TjVrbilftyVLWK+7K73tBX3uRNAYv0hzNs5Q6xPIekq4iq7xRtuUhVA7Qxn9vK4C+w== + version "4.13.2" + resolved "https://registry.npmjs.org/swagger-ui-react/-/swagger-ui-react-4.13.2.tgz#dee4f42dae9ca8b9ac85e64a46fc12c694100a80" + integrity sha512-U3IarPb0Vyi5/bHb45Q8uWf/7fowPp3B+LeYF0VKB4xhgKNiaPypPHoSJW9oCse/lkFGd4ZKyqBOpYXCsWMcgA== dependencies: - "@babel/runtime-corejs3" "^7.16.8" + "@babel/runtime-corejs3" "^7.18.9" "@braintree/sanitize-url" "=6.0.0" base64-js "^1.5.1" classnames "^2.3.1" css.escape "1.5.1" deep-extend "0.6.0" - dompurify "=2.3.3" + dompurify "=2.3.10" ieee754 "^1.2.1" immutable "^3.x.x" js-file-download "^0.4.12" @@ -24904,7 +24907,7 @@ swagger-ui-react@^4.11.1: randexp "^0.5.3" randombytes "^2.1.0" react-copy-to-clipboard "5.0.4" - react-debounce-input "=3.2.4" + react-debounce-input "=3.3.0" react-immutable-proptypes "2.2.0" react-immutable-pure-component "^2.2.0" react-inspector "^5.1.1" From 0ef08ee6bf4038d49262466cd3477b9bea52981f Mon Sep 17 00:00:00 2001 From: Kamil Wolny Date: Tue, 2 Aug 2022 16:16:17 +0100 Subject: [PATCH 143/144] feat: updated api-reports Signed-off-by: Kamil Wolny --- plugins/github-issues/api-report.md | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/plugins/github-issues/api-report.md b/plugins/github-issues/api-report.md index 8c77aaf674..eb69fc8e8e 100644 --- a/plugins/github-issues/api-report.md +++ b/plugins/github-issues/api-report.md @@ -9,16 +9,10 @@ import { BackstagePlugin } from '@backstage/core-plugin-api'; import { RouteRef } from '@backstage/core-plugin-api'; // @public (undocumented) -export const GitHubIssuesCard: ({ - itemsPerPage, - itemsPerRepo, -}: GitHubIssuesProps) => JSX.Element; +export const GitHubIssuesCard: (props: GitHubIssuesProps) => JSX.Element; // @public (undocumented) -export const GitHubIssuesPage: ({ - itemsPerPage, - itemsPerRepo, -}: GitHubIssuesProps) => JSX.Element; +export const GitHubIssuesPage: (props: GitHubIssuesProps) => JSX.Element; // @public (undocumented) export const gitHubIssuesPlugin: BackstagePlugin< From 44ed5ed6a2c61670a62ecdcaa9c5ad98fe4336d5 Mon Sep 17 00:00:00 2001 From: Kamil Wolny Date: Tue, 2 Aug 2022 16:48:52 +0100 Subject: [PATCH 144/144] fix: move types to dev dependencies 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 74f108cd94..5435f81324 100644 --- a/plugins/github-issues/package.json +++ b/plugins/github-issues/package.json @@ -32,7 +32,6 @@ "@material-ui/core": "^4.12.4", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "^4.0.0-alpha.61", - "@types/react": "^16.13.1 || ^17.0.0", "luxon": "^2.4.0", "octokit": "^2.0.4", "react-use": "^17.2.4" @@ -51,6 +50,7 @@ "@testing-library/user-event": "^14.0.0", "@types/jest": "*", "@types/node": "*", + "@types/react": "^16.13.1 || ^17.0.0", "cross-fetch": "^3.1.5", "msw": "^0.44.0", "prettier": "^2.7.1"