From 19355928c004cc494a9e531c3afa310c0ad27585 Mon Sep 17 00:00:00 2001 From: Jussi Hallila Date: Tue, 12 Jan 2021 17:29:44 +0100 Subject: [PATCH 01/13] Modifies component registration to use existing file if present Creates additional check on catalog import form to check for an existing catalog-info.yaml file if repo URL put in. Registers an existing file instead of creating pull request in case catalog file is present. Defaults to the root-most catalog-info.yaml file if multiple defined in the repository. --- .../src/api/CatalogImportApi.ts | 5 ++ .../src/api/CatalogImportClient.test.ts | 64 +++++++++++++++++++ .../src/api/CatalogImportClient.ts | 48 ++++++++++++++ .../src/components/ImportComponentForm.tsx | 42 ++++++++---- .../src/components/ImportComponentPage.tsx | 5 +- .../catalog-import/src/util/useGithubRepos.ts | 39 ++++++++++- 6 files changed, 186 insertions(+), 17 deletions(-) create mode 100644 plugins/catalog-import/src/api/CatalogImportClient.test.ts diff --git a/plugins/catalog-import/src/api/CatalogImportApi.ts b/plugins/catalog-import/src/api/CatalogImportApi.ts index 99526a3eaa..5abb0e3e53 100644 --- a/plugins/catalog-import/src/api/CatalogImportApi.ts +++ b/plugins/catalog-import/src/api/CatalogImportApi.ts @@ -30,6 +30,11 @@ export interface CatalogImportApi { fileContent: string; githubIntegrationConfig: GitHubIntegrationConfig; }): Promise<{ link: string; location: string }>; + checkForExistingCatalogInfo(options: { + owner: string; + repo: string; + githubIntegrationConfig: GitHubIntegrationConfig; + }): Promise<{ exists: boolean; url?: string }>; createRepositoryLocation(options: { location: string }): Promise; generateEntityDefinitions(options: { repo: string; diff --git a/plugins/catalog-import/src/api/CatalogImportClient.test.ts b/plugins/catalog-import/src/api/CatalogImportClient.test.ts new file mode 100644 index 0000000000..0e0cf4b323 --- /dev/null +++ b/plugins/catalog-import/src/api/CatalogImportClient.test.ts @@ -0,0 +1,64 @@ +/* + * Copyright 2020 Spotify AB + * + * 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 { CatalogImportClient } from './CatalogImportClient'; + +jest.mock('@octokit/rest', () => ({ + Octokit: jest.fn().mockImplementation(() => { + return { + repos: { + get: () => + Promise.resolve({ + data: { + default_branch: 'main', + }, + }), + }, + search: { + code: () => + Promise.resolve({ + data: { + total_count: 2, + items: [ + { path: 'simple/path/catalog-info.yaml' }, + { path: 'co/mple/x/path/catalog-info.yaml' }, + { path: 'catalog-info.yaml' }, + ], + }, + }), + }, + }; + }), +})); + +describe('CatalogImportClient', () => { + describe('checkForExistingCatalogInfo', () => { + const cic = new CatalogImportClient({ + discoveryApi: { getBaseUrl: () => Promise.resolve('base') }, + githubAuthApi: { getAccessToken: (_, __) => Promise.resolve('token') }, + configApi: {} as any, + }); + it('should return the closest-to-root catalog-info from multiple responses', async () => { + const respo = await cic.checkForExistingCatalogInfo({ + owner: 'test-user', + repo: 'rest-repo', + githubIntegrationConfig: { host: 'https://github.com' }, + }); + expect(respo.exists).toBe(true); + expect(respo.url).toBe('blob/main/catalog-info.yaml'); + }); + }); +}); diff --git a/plugins/catalog-import/src/api/CatalogImportClient.ts b/plugins/catalog-import/src/api/CatalogImportClient.ts index 0e28042db3..af429f748a 100644 --- a/plugins/catalog-import/src/api/CatalogImportClient.ts +++ b/plugins/catalog-import/src/api/CatalogImportClient.ts @@ -91,6 +91,54 @@ export class CatalogImportClient implements CatalogImportApi { } } + async checkForExistingCatalogInfo({ + owner, + repo, + githubIntegrationConfig, + }: { + owner: string; + repo: string; + githubIntegrationConfig: GitHubIntegrationConfig; + }): Promise<{ exists: boolean; url?: string }> { + const token = await this.githubAuthApi.getAccessToken(['repo']); + const octo = new Octokit({ + auth: token, + baseUrl: githubIntegrationConfig.apiBaseUrl, + }); + const catalogFileName = 'catalog-info.yaml'; + const query = `repo:${owner}/${repo}+filename:${catalogFileName}`; + + const searchResult = await octo.search.code({ q: query }).catch(e => { + throw new Error( + formatHttpErrorMessage( + "Couldn't search repository for metadata file.", + e, + ), + ); + }); + const exists = searchResult.data.total_count > 0; + if (exists) { + const repoInformation = await octo.repos.get({ owner, repo }).catch(e => { + throw new Error(formatHttpErrorMessage("Couldn't fetch repo data", e)); + }); + const defaultBranch = repoInformation.data.default_branch; + + // Github search sorts returned values with 'best match' using 'multiple factors to boost the most relevant item', + // aka magic. + // Sorting to use the shortest item, closest to the repository root. + const catalogInfoItem = searchResult.data.items + .map(it => it.path) + .sort((a, b) => a.length - b.length)[0]; + return Promise.resolve({ + url: `blob/${defaultBranch}/${catalogInfoItem}`, + exists, + }); + } + return Promise.resolve({ + exists, + }); + } + async submitPrToRepo({ owner, repo, diff --git a/plugins/catalog-import/src/components/ImportComponentForm.tsx b/plugins/catalog-import/src/components/ImportComponentForm.tsx index dab5ccbea2..b7dc82c9b1 100644 --- a/plugins/catalog-import/src/components/ImportComponentForm.tsx +++ b/plugins/catalog-import/src/components/ImportComponentForm.tsx @@ -59,27 +59,45 @@ export const RegisterComponentForm = ({ nextStep, saveConfig }: Props) => { const isMounted = useMountedState(); const errorApi = useApi(errorApiRef); - const { generateEntityDefinitions } = useGithubRepos(); + const { + generateEntityDefinitions, + checkForExistingCatalogInfo, + } = useGithubRepos(); const onSubmit = async (formData: Record) => { const { componentLocation: target } = formData; - try { - if (!isMounted()) return; - const type = !parseGitUri(target).filepathtype ? 'repo' : 'file'; + async function saveCatalogFileConfig(target: string) { + const data = await catalogApi.addLocation({ target }); + saveConfig({ + type: 'file', + location: data.location.target, + config: data.entities, + }); + } - if (type === 'repo') { + async function trySaveRepositoryConfig(target: string) { + const existingCatalog = await checkForExistingCatalogInfo(target); + if (existingCatalog.exists) { + const targetUrl = target.endsWith('/') + ? `${target}${existingCatalog.url}` + : `${target}/${existingCatalog.url}`; + await saveCatalogFileConfig(targetUrl); + } else { saveConfig({ - type, + type: 'repo', location: target, config: await generateEntityDefinitions(target), }); + } + } + + try { + if (!isMounted()) return; + const type = !parseGitUri(target).filepathtype ? 'repo' : 'file'; + if (type === 'repo') { + await trySaveRepositoryConfig(target); } else { - const data = await catalogApi.addLocation({ target }); - saveConfig({ - type, - location: data.location.target, - config: data.entities, - }); + await saveCatalogFileConfig(target); } nextStep(); } catch (e) { diff --git a/plugins/catalog-import/src/components/ImportComponentPage.tsx b/plugins/catalog-import/src/components/ImportComponentPage.tsx index 9fdb465dd1..8b3b90003d 100644 --- a/plugins/catalog-import/src/components/ImportComponentPage.tsx +++ b/plugins/catalog-import/src/components/ImportComponentPage.tsx @@ -77,8 +77,9 @@ export const ImportComponentPage = ({ GitHub Repo - If you already have code in a GitHub repository, enter the full - URL to your repo and a new pull request with a sample Backstage + If you already have code in a GitHub repository without + Backstage metadata file set up for it, enter the full URL to + your repo and a new pull request with a sample Backstage metadata Entity File (catalog-info.yaml) will be opened for you. diff --git a/plugins/catalog-import/src/util/useGithubRepos.ts b/plugins/catalog-import/src/util/useGithubRepos.ts index 30e77e18a8..56cf101c35 100644 --- a/plugins/catalog-import/src/util/useGithubRepos.ts +++ b/plugins/catalog-import/src/util/useGithubRepos.ts @@ -28,12 +28,12 @@ export function useGithubRepos() { const api = useApi(catalogImportApiRef); const config = useApi(configApiRef); - const submitPrToRepo = async (selectedRepo: ConfigSpec) => { + const getGithubIntegrationConfig = (location: string) => { const { name: repoName, owner: ownerName, resource: hostname, - } = parseGitUri(selectedRepo.location); + } = parseGitUri(location); const configs = readGitHubIntegrationConfigs( config.getOptionalConfigArray('integrations.github') ?? [], @@ -41,9 +41,22 @@ export function useGithubRepos() { const githubIntegrationConfig = configs.find(v => v.host === hostname); if (!githubIntegrationConfig) { throw new Error( - `Unable to locate github-integration for repo-location: ${selectedRepo.location}`, + `Unable to locate github-integration for repo-location: ${location}`, ); } + return { + repoName, + ownerName, + githubIntegrationConfig, + }; + }; + + const submitPrToRepo = async (selectedRepo: ConfigSpec) => { + const { + repoName, + ownerName, + githubIntegrationConfig, + } = getGithubIntegrationConfig(selectedRepo.location); const submitPRResponse = await api .submitPrToRepo({ owner: ownerName, @@ -68,8 +81,28 @@ export function useGithubRepos() { return submitPRResponse; }; + const checkForExistingCatalogInfo = async (location: string) => { + const { + repoName, + ownerName, + githubIntegrationConfig, + } = getGithubIntegrationConfig(location); + return await api + .checkForExistingCatalogInfo({ + owner: ownerName, + repo: repoName, + githubIntegrationConfig, + }) + .catch(e => { + throw new Error( + `Failed to inspect repository for existing catalog-info.yaml:\n${e.message}`, + ); + }); + }; + return { submitPrToRepo, + checkForExistingCatalogInfo, generateEntityDefinitions: (repo: string) => api.generateEntityDefinitions({ repo }), addLocation: (location: string) => From 2b514d53234744d5ea067175778532028793b725 Mon Sep 17 00:00:00 2001 From: Jussi Hallila Date: Wed, 13 Jan 2021 14:21:50 +0100 Subject: [PATCH 02/13] Adding test setup for import page and first form Creating tests to check that correct action is proposed when user tries to add Github repos. --- .changeset/eleven-tables-tease.md | 5 + .../components/ImportComponentForm.test.tsx | 85 ++++++++ .../components/ImportComponentPage.test.tsx | 189 ++++++++++++++++++ .../mocks/analyze-location-POST-response.json | 22 ++ .../src/mocks/locations-POST-response.json | 39 ++++ plugins/catalog-import/src/setupTests.ts | 3 + 6 files changed, 343 insertions(+) create mode 100644 .changeset/eleven-tables-tease.md create mode 100644 plugins/catalog-import/src/components/ImportComponentForm.test.tsx create mode 100644 plugins/catalog-import/src/components/ImportComponentPage.test.tsx create mode 100644 plugins/catalog-import/src/mocks/analyze-location-POST-response.json create mode 100644 plugins/catalog-import/src/mocks/locations-POST-response.json diff --git a/.changeset/eleven-tables-tease.md b/.changeset/eleven-tables-tease.md new file mode 100644 index 0000000000..177211b4db --- /dev/null +++ b/.changeset/eleven-tables-tease.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-import': patch +--- + +Modifying import functionality to register existing catalog-info.yaml if one exists in given Github repository diff --git a/plugins/catalog-import/src/components/ImportComponentForm.test.tsx b/plugins/catalog-import/src/components/ImportComponentForm.test.tsx new file mode 100644 index 0000000000..dcacfcc76f --- /dev/null +++ b/plugins/catalog-import/src/components/ImportComponentForm.test.tsx @@ -0,0 +1,85 @@ +/* + * Copyright 2021 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { renderInTestApp } from '@backstage/test-utils'; +import { RegisterComponentForm } from './ImportComponentForm'; +import { + ApiProvider, + ApiRegistry, + DiscoveryApi, + errorApiRef, +} from '@backstage/core'; +import { catalogApiRef, CatalogClient } from '@backstage/plugin-catalog'; +import { catalogImportApiRef, CatalogImportClient } from '../api'; +import { fireEvent, waitFor, screen } from '@testing-library/react'; + +describe('', () => { + let apis: ApiRegistry; + + const mockErrorApi: jest.Mocked = { + post: jest.fn(), + error$: jest.fn(), + }; + + beforeEach(() => { + apis = ApiRegistry.from([ + [catalogApiRef, new CatalogClient({ discoveryApi: {} as DiscoveryApi })], + [ + catalogImportApiRef, + new CatalogImportClient({ + discoveryApi: { getBaseUrl: () => Promise.resolve('base') }, + githubAuthApi: { + getAccessToken: (_, __) => Promise.resolve('token'), + }, + configApi: {} as any, + }), + ], + [errorApiRef, mockErrorApi], + ]); + }); + + async function renderSUT( + nextStep: () => void = () => {}, + saveConfig: () => void = () => {}, + ) { + return await renderInTestApp( + + + , + ); + } + + it('Renders without exploding', async () => { + await renderSUT(); + expect( + screen.getByPlaceholderText('https://github.com/backstage/backstage'), + ).toBeInTheDocument(); + }); + + it('Should have basic URL validation for input', async () => { + await renderSUT(); + await waitFor(() => { + fireEvent.input( + screen.getByPlaceholderText('https://github.com/backstage/backstage'), + { target: { value: 'not a url' } }, + ); + }); + await waitFor(() => { + fireEvent.click(screen.getByText('Next')); + }); + expect(screen.getByText('Must start with https://.')).toBeInTheDocument(); + }); +}); diff --git a/plugins/catalog-import/src/components/ImportComponentPage.test.tsx b/plugins/catalog-import/src/components/ImportComponentPage.test.tsx new file mode 100644 index 0000000000..0e03a467e5 --- /dev/null +++ b/plugins/catalog-import/src/components/ImportComponentPage.test.tsx @@ -0,0 +1,189 @@ +/* + * Copyright 2021 Spotify AB + * + * 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 { msw, renderInTestApp } from '@backstage/test-utils'; +import { ImportComponentPage } from './ImportComponentPage'; +import { ApiProvider, ApiRegistry, errorApiRef } from '@backstage/core'; +import { catalogApiRef, CatalogClient } from '@backstage/plugin-catalog'; +import { catalogImportApiRef, CatalogImportClient } from '../api'; +import { fireEvent, screen, waitFor } from '@testing-library/react'; + +import { rest } from 'msw'; +import { setupServer } from 'msw/node'; + +let codeSearchMockResponse: () => Promise<{ + data: { + total_count: number; + items: Array<{ path: string }>; + }; +}>; + +jest.mock('@backstage/integration', () => ({ + readGitHubIntegrationConfigs: () => ({ + find: () => ({ + host: 'test.localhost', + owner: 'someuser', + }), + }), +})); + +jest.mock('@octokit/rest', () => ({ + Octokit: jest.fn().mockImplementation(() => { + return { + repos: { + get: () => + Promise.resolve({ + data: { + default_branch: 'main', + }, + }), + }, + search: { + code: codeSearchMockResponse, + }, + }; + }), +})); + +describe('', () => { + const server = setupServer(); + msw.setupDefaultHandlers(server); + + beforeEach(() => { + server.use( + rest.post('https://backend.localhost/locations', (_, res, ctx) => { + return res( + ctx.status(201), + ctx.json(require('../mocks/locations-POST-response.json')), + ); + }), + rest.post('https://backend.localhost/analyze-location', (_, res, ctx) => { + return res( + ctx.json(require('../mocks/analyze-location-POST-response.json')), + ); + }), + ); + }); + beforeAll(() => server.listen()); + afterEach(() => server.resetHandlers()); + afterAll(() => server.close()); + + let apis: ApiRegistry; + + const mockErrorApi: jest.Mocked = { + post: jest.fn(), + error$: jest.fn(), + }; + + beforeEach(() => { + const getBaseUrl = () => Promise.resolve('https://backend.localhost'); + apis = ApiRegistry.from([ + [ + catalogApiRef, + new CatalogClient({ + discoveryApi: { getBaseUrl }, + }), + ], + [ + catalogImportApiRef, + new CatalogImportClient({ + discoveryApi: { getBaseUrl }, + githubAuthApi: { + getAccessToken: (_, __) => Promise.resolve('token'), + }, + configApi: {} as any, + }), + ], + [errorApiRef, mockErrorApi], + ]); + }); + + async function renderSUT() { + return await renderInTestApp( + + + , + ); + } + + it('Should use found yaml file directly and not create a pull request if GitHub api returns one', async () => { + codeSearchMockResponse = () => + Promise.resolve({ + data: { + total_count: 3, + items: [ + { path: 'simple/path/catalog-info.yaml' }, + { path: 'co/mple/x/path/catalog-info.yaml' }, + { path: 'catalog-info.yaml' }, + ], + }, + }); + await renderSUT(); + await waitFor(() => { + fireEvent.input( + screen.getByPlaceholderText('https://github.com/backstage/backstage'), + { target: { value: 'https://test.localhost/someuser/somerepo' } }, + ); + }); + + fireEvent.click(screen.getByText('Next')); + await waitFor(() => { + expect( + screen.getByText( + 'https://test.localhost/someusername/somerepo/blob/master/src/catalog-info.yaml', + ), + ).toBeInTheDocument(); + + const pullReqText = screen.queryByText('pull request'); + expect(pullReqText).not.toBeInTheDocument(); + }); + }); + + it('Should indicate a pull request creation when no yaml file found in the repo', async () => { + codeSearchMockResponse = () => + Promise.resolve({ + data: { + total_count: 0, + items: [], + }, + }); + const { container } = await renderSUT(); + await waitFor(() => { + fireEvent.input( + screen.getByPlaceholderText('https://github.com/backstage/backstage'), + { target: { value: 'https://test.localhost/someuser/somerepo' } }, + ); + }); + + fireEvent.click(screen.getByText('Next')); + await waitFor(() => { + expect( + screen.getByText('https://test.localhost/someuser/somerepo'), + ).toBeInTheDocument(); + }); + const textNode = container + .querySelector('a[href="https://test.localhost/someuser/somerepo"]') + ?.closest('p'); + expect(textNode?.innerHTML).toContain( + 'Following config object will be submitted in a pull request to the repository', + ); + expect( + screen.queryByText( + 'https://test.localhost/someusername/somerepo/blob/master/src/catalog-info.yaml', + ), + ).not.toBeInTheDocument(); + }); +}); diff --git a/plugins/catalog-import/src/mocks/analyze-location-POST-response.json b/plugins/catalog-import/src/mocks/analyze-location-POST-response.json new file mode 100644 index 0000000000..eaadf1054a --- /dev/null +++ b/plugins/catalog-import/src/mocks/analyze-location-POST-response.json @@ -0,0 +1,22 @@ +{ + "existingEntityFiles": [], + "generateEntities": [ + { + "entity": { + "apiVersion": "backstage.io/v1alpha1", + "kind": "Component", + "metadata": { + "name": "somerepo", + "annotations": { + "github.com/project-slug": "someuser/somerepo" + } + }, + "spec": { + "type": "other", + "lifecycle": "unknown" + } + }, + "fields": [] + } + ] +} diff --git a/plugins/catalog-import/src/mocks/locations-POST-response.json b/plugins/catalog-import/src/mocks/locations-POST-response.json new file mode 100644 index 0000000000..20e4e1582c --- /dev/null +++ b/plugins/catalog-import/src/mocks/locations-POST-response.json @@ -0,0 +1,39 @@ +{ + "location": { + "id": "d4a64359-a709-4c91-a9de-0905a033bf22", + "type": "url", + "target": "https://test.localhost/someusername/somerepo/blob/master/src/catalog-info.yaml" + }, + "entities": [ + { + "metadata": { + "namespace": "default", + "annotations": { + "backstage.io/managed-by-location": "url:https://test.localhost/someusername/somerepo/blob/master/src/catalog-info.yaml", + "github.com/project-slug": "someusername/somerepo" + }, + "name": "somerepo", + "uid": "e992d5ee-7c70-4316-90cf-325f1a0a5146", + "etag": "YWE2M2Q5MzgtNjdkNi00N2QwLWJkZjYtNDM0MTMzMDI4Y2I0", + "generation": 1 + }, + "apiVersion": "backstage.io/v1alpha1", + "kind": "Component", + "spec": { + "type": "other", + "lifecycle": "unknown", + "owner": "unknown" + }, + "relations": [ + { + "target": { + "kind": "group", + "namespace": "default", + "name": "unknown" + }, + "type": "ownedBy" + } + ] + } + ] +} diff --git a/plugins/catalog-import/src/setupTests.ts b/plugins/catalog-import/src/setupTests.ts index 825bcd4115..fba7d7a957 100644 --- a/plugins/catalog-import/src/setupTests.ts +++ b/plugins/catalog-import/src/setupTests.ts @@ -15,3 +15,6 @@ */ import '@testing-library/jest-dom'; +import fetch from 'cross-fetch'; + +global.fetch = fetch; From 5805251b73c45138f9caf63abc016408705293c7 Mon Sep 17 00:00:00 2001 From: Jussi Hallila Date: Wed, 13 Jan 2021 15:50:00 +0100 Subject: [PATCH 03/13] Fix tests after changes from master. --- .../components/ImportComponentForm.test.tsx | 6 +++++- .../components/ImportComponentPage.test.tsx | 19 ++++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/plugins/catalog-import/src/components/ImportComponentForm.test.tsx b/plugins/catalog-import/src/components/ImportComponentForm.test.tsx index dcacfcc76f..91a5208bee 100644 --- a/plugins/catalog-import/src/components/ImportComponentForm.test.tsx +++ b/plugins/catalog-import/src/components/ImportComponentForm.test.tsx @@ -57,7 +57,11 @@ describe('', () => { ) { return await renderInTestApp( - + , ); } diff --git a/plugins/catalog-import/src/components/ImportComponentPage.test.tsx b/plugins/catalog-import/src/components/ImportComponentPage.test.tsx index 0e03a467e5..3f6f878b29 100644 --- a/plugins/catalog-import/src/components/ImportComponentPage.test.tsx +++ b/plugins/catalog-import/src/components/ImportComponentPage.test.tsx @@ -16,9 +16,15 @@ import React from 'react'; import { msw, renderInTestApp } from '@backstage/test-utils'; import { ImportComponentPage } from './ImportComponentPage'; -import { ApiProvider, ApiRegistry, errorApiRef } from '@backstage/core'; +import { + ApiProvider, + ApiRegistry, + configApiRef, + errorApiRef, +} from '@backstage/core'; import { catalogApiRef, CatalogClient } from '@backstage/plugin-catalog'; import { catalogImportApiRef, CatalogImportClient } from '../api'; + import { fireEvent, screen, waitFor } from '@testing-library/react'; import { rest } from 'msw'; @@ -107,6 +113,17 @@ describe('', () => { configApi: {} as any, }), ], + [ + configApiRef, + { + getOptional: () => 'Title', + getOptionalConfigArray: () => [], + has: () => true, + getConfig: () => ({ + has: () => true, + }), + }, + ], [errorApiRef, mockErrorApi], ]); }); From f5bd375bef2c4b76af015553d5564a11daea500a Mon Sep 17 00:00:00 2001 From: Jussi Hallila Date: Wed, 13 Jan 2021 16:04:39 +0100 Subject: [PATCH 04/13] Remove unneeded empty string. --- plugins/catalog-import/src/components/ImportComponentPage.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/catalog-import/src/components/ImportComponentPage.tsx b/plugins/catalog-import/src/components/ImportComponentPage.tsx index 60766ebaf2..e284e95456 100644 --- a/plugins/catalog-import/src/components/ImportComponentPage.tsx +++ b/plugins/catalog-import/src/components/ImportComponentPage.tsx @@ -107,7 +107,6 @@ export const ImportComponentPage = ({ {manifestGenerationAvailable(configApi) && ( - {' '} GitHub Repo If you already have code in a GitHub repository without From 8fcfd7b31668857e310afa761987a1c323044902 Mon Sep 17 00:00:00 2001 From: Jussi Hallila Date: Wed, 13 Jan 2021 16:36:50 +0100 Subject: [PATCH 05/13] Add logic to not contact GitHub on non-GitHub urls Wrap in tests. --- .../components/ImportComponentPage.test.tsx | 65 ++++++++++++++++--- .../src/mocks/locations-POST-response.json | 4 +- .../catalog-import/src/util/useGithubRepos.ts | 8 ++- 3 files changed, 66 insertions(+), 11 deletions(-) diff --git a/plugins/catalog-import/src/components/ImportComponentPage.test.tsx b/plugins/catalog-import/src/components/ImportComponentPage.test.tsx index 3f6f878b29..5c4b2e8538 100644 --- a/plugins/catalog-import/src/components/ImportComponentPage.test.tsx +++ b/plugins/catalog-import/src/components/ImportComponentPage.test.tsx @@ -64,6 +64,7 @@ jest.mock('@octokit/rest', () => ({ }), })); +const OUR_GITHUB_TEST_REPO = 'https://github.com/someuser/somerepo'; describe('', () => { const server = setupServer(); msw.setupDefaultHandlers(server); @@ -136,6 +137,56 @@ describe('', () => { ); } + it('Should not explode on non-Github URLs', async () => { + await renderSUT(); + await waitFor(() => { + fireEvent.input( + screen.getByPlaceholderText('https://github.com/backstage/backstage'), + { + target: { + value: 'https://test-git-provider.localhost/someuser/somerepo', + }, + }, + ); + }); + + fireEvent.click(screen.getByText('Next')); + await waitFor(() => { + const firstStepInput = screen.queryByPlaceholderText( + 'https://github.com/backstage/backstage', + ); + expect(firstStepInput).not.toBeInTheDocument(); + }); + }); + + it('Should offer direct file import from non-Github URLs', async () => { + await renderSUT(); + await waitFor(() => { + fireEvent.input( + screen.getByPlaceholderText('https://github.com/backstage/backstage'), + { + target: { + value: + 'https://test-git-provider.localhost/someuser/somerepo/catalog-info.yaml', + }, + }, + ); + }); + + fireEvent.click(screen.getByText('Next')); + await waitFor(() => { + const firstStepInput = screen.queryByPlaceholderText( + 'https://github.com/backstage/backstage', + ); + expect(firstStepInput).not.toBeInTheDocument(); + }); + expect( + screen.getByText( + 'https://test-git-provider.localhost/someuser/somerepo/catalog-info.yaml', + ), + ).toBeInTheDocument(); + }); + it('Should use found yaml file directly and not create a pull request if GitHub api returns one', async () => { codeSearchMockResponse = () => Promise.resolve({ @@ -152,7 +203,7 @@ describe('', () => { await waitFor(() => { fireEvent.input( screen.getByPlaceholderText('https://github.com/backstage/backstage'), - { target: { value: 'https://test.localhost/someuser/somerepo' } }, + { target: { value: OUR_GITHUB_TEST_REPO } }, ); }); @@ -160,7 +211,7 @@ describe('', () => { await waitFor(() => { expect( screen.getByText( - 'https://test.localhost/someusername/somerepo/blob/master/src/catalog-info.yaml', + 'https://github.com/someusername/somerepo/blob/master/src/catalog-info.yaml', ), ).toBeInTheDocument(); @@ -181,25 +232,23 @@ describe('', () => { await waitFor(() => { fireEvent.input( screen.getByPlaceholderText('https://github.com/backstage/backstage'), - { target: { value: 'https://test.localhost/someuser/somerepo' } }, + { target: { value: OUR_GITHUB_TEST_REPO } }, ); }); fireEvent.click(screen.getByText('Next')); await waitFor(() => { - expect( - screen.getByText('https://test.localhost/someuser/somerepo'), - ).toBeInTheDocument(); + expect(screen.getByText(OUR_GITHUB_TEST_REPO)).toBeInTheDocument(); }); const textNode = container - .querySelector('a[href="https://test.localhost/someuser/somerepo"]') + .querySelector('a[href="https://github.com/someuser/somerepo"]') ?.closest('p'); expect(textNode?.innerHTML).toContain( 'Following config object will be submitted in a pull request to the repository', ); expect( screen.queryByText( - 'https://test.localhost/someusername/somerepo/blob/master/src/catalog-info.yaml', + 'https://github.com/someusername/somerepo/blob/master/src/catalog-info.yaml', ), ).not.toBeInTheDocument(); }); diff --git a/plugins/catalog-import/src/mocks/locations-POST-response.json b/plugins/catalog-import/src/mocks/locations-POST-response.json index 20e4e1582c..c44a0f4d61 100644 --- a/plugins/catalog-import/src/mocks/locations-POST-response.json +++ b/plugins/catalog-import/src/mocks/locations-POST-response.json @@ -2,14 +2,14 @@ "location": { "id": "d4a64359-a709-4c91-a9de-0905a033bf22", "type": "url", - "target": "https://test.localhost/someusername/somerepo/blob/master/src/catalog-info.yaml" + "target": "https://github.com/someusername/somerepo/blob/master/src/catalog-info.yaml" }, "entities": [ { "metadata": { "namespace": "default", "annotations": { - "backstage.io/managed-by-location": "url:https://test.localhost/someusername/somerepo/blob/master/src/catalog-info.yaml", + "backstage.io/managed-by-location": "url:https://github.com/someusername/somerepo/blob/master/src/catalog-info.yaml", "github.com/project-slug": "someusername/somerepo" }, "name": "somerepo", diff --git a/plugins/catalog-import/src/util/useGithubRepos.ts b/plugins/catalog-import/src/util/useGithubRepos.ts index 56cf101c35..319457dfe8 100644 --- a/plugins/catalog-import/src/util/useGithubRepos.ts +++ b/plugins/catalog-import/src/util/useGithubRepos.ts @@ -81,7 +81,13 @@ export function useGithubRepos() { return submitPRResponse; }; - const checkForExistingCatalogInfo = async (location: string) => { + const checkForExistingCatalogInfo = async ( + location: string, + ): Promise<{ exists: boolean; url?: string }> => { + const { source } = parseGitUri(location); + if (source !== 'github.com') { + return Promise.resolve({ exists: false }); + } const { repoName, ownerName, From f8dd991767262247d60992e4445ce18b1cbfc6d1 Mon Sep 17 00:00:00 2001 From: Jussi Hallila Date: Wed, 13 Jan 2021 16:59:00 +0100 Subject: [PATCH 06/13] Stylize the spelling of GitHub --- .changeset/eleven-tables-tease.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/eleven-tables-tease.md b/.changeset/eleven-tables-tease.md index 177211b4db..3f95fbb9d2 100644 --- a/.changeset/eleven-tables-tease.md +++ b/.changeset/eleven-tables-tease.md @@ -2,4 +2,4 @@ '@backstage/plugin-catalog-import': patch --- -Modifying import functionality to register existing catalog-info.yaml if one exists in given Github repository +Modifying import functionality to register existing catalog-info.yaml if one exists in given GitHub repository From 62fa5496c1e350a6758ab502b3ffe5f4def44b3c Mon Sep 17 00:00:00 2001 From: Jussi Hallila Date: Mon, 18 Jan 2021 11:09:08 +0100 Subject: [PATCH 07/13] Address issues from code review --- .../src/api/CatalogImportClient.ts | 4 +-- .../components/ImportComponentPage.test.tsx | 20 +++++++++++--- .../catalog-import/src/util/useGithubRepos.ts | 26 +++++++++++-------- 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/plugins/catalog-import/src/api/CatalogImportClient.ts b/plugins/catalog-import/src/api/CatalogImportClient.ts index 706943a6aa..4ce25e8fc2 100644 --- a/plugins/catalog-import/src/api/CatalogImportClient.ts +++ b/plugins/catalog-import/src/api/CatalogImportClient.ts @@ -128,10 +128,10 @@ export class CatalogImportClient implements CatalogImportApi { const catalogInfoItem = searchResult.data.items .map(it => it.path) .sort((a, b) => a.length - b.length)[0]; - return Promise.resolve({ + return { url: `blob/${defaultBranch}/${catalogInfoItem}`, exists, - }); + }; } return Promise.resolve({ exists, diff --git a/plugins/catalog-import/src/components/ImportComponentPage.test.tsx b/plugins/catalog-import/src/components/ImportComponentPage.test.tsx index 5c4b2e8538..932f9aafa0 100644 --- a/plugins/catalog-import/src/components/ImportComponentPage.test.tsx +++ b/plugins/catalog-import/src/components/ImportComponentPage.test.tsx @@ -37,12 +37,14 @@ let codeSearchMockResponse: () => Promise<{ }; }>; +let findGithubConfigMockResponse = () => ({ + host: 'test.localhost', + owner: 'someuser', +}); + jest.mock('@backstage/integration', () => ({ readGitHubIntegrationConfigs: () => ({ - find: () => ({ - host: 'test.localhost', - owner: 'someuser', - }), + find: findGithubConfigMockResponse, }), })); @@ -138,6 +140,7 @@ describe('', () => { } it('Should not explode on non-Github URLs', async () => { + findGithubConfigMockResponse = () => undefined!!; await renderSUT(); await waitFor(() => { fireEvent.input( @@ -160,6 +163,7 @@ describe('', () => { }); it('Should offer direct file import from non-Github URLs', async () => { + findGithubConfigMockResponse = () => undefined!!; await renderSUT(); await waitFor(() => { fireEvent.input( @@ -188,6 +192,10 @@ describe('', () => { }); it('Should use found yaml file directly and not create a pull request if GitHub api returns one', async () => { + findGithubConfigMockResponse = () => ({ + host: 'test.localhost', + owner: 'someuser', + }); codeSearchMockResponse = () => Promise.resolve({ data: { @@ -221,6 +229,10 @@ describe('', () => { }); it('Should indicate a pull request creation when no yaml file found in the repo', async () => { + findGithubConfigMockResponse = () => ({ + host: 'test.localhost', + owner: 'someuser', + }); codeSearchMockResponse = () => Promise.resolve({ data: { diff --git a/plugins/catalog-import/src/util/useGithubRepos.ts b/plugins/catalog-import/src/util/useGithubRepos.ts index 319457dfe8..704ad974a5 100644 --- a/plugins/catalog-import/src/util/useGithubRepos.ts +++ b/plugins/catalog-import/src/util/useGithubRepos.ts @@ -22,7 +22,10 @@ import parseGitUri from 'git-url-parse'; // TODO: (O5ten) Refactor into a core API instead of direct usage like this // https://github.com/backstage/backstage/pull/3613#issuecomment-7408929430 -import { readGitHubIntegrationConfigs } from '@backstage/integration'; +import { + GitHubIntegrationConfig, + readGitHubIntegrationConfigs, +} from '@backstage/integration'; export function useGithubRepos() { const api = useApi(catalogImportApiRef); @@ -84,20 +87,21 @@ export function useGithubRepos() { const checkForExistingCatalogInfo = async ( location: string, ): Promise<{ exists: boolean; url?: string }> => { - const { source } = parseGitUri(location); - if (source !== 'github.com') { + let githubConfig: { + repoName: string; + ownerName: string; + githubIntegrationConfig: GitHubIntegrationConfig; + }; + try { + githubConfig = getGithubIntegrationConfig(location); + } catch (e) { return Promise.resolve({ exists: false }); } - const { - repoName, - ownerName, - githubIntegrationConfig, - } = getGithubIntegrationConfig(location); return await api .checkForExistingCatalogInfo({ - owner: ownerName, - repo: repoName, - githubIntegrationConfig, + owner: githubConfig.ownerName, + repo: githubConfig.repoName, + githubIntegrationConfig: githubConfig.githubIntegrationConfig, }) .catch(e => { throw new Error( From 70255c7fff4ec2e9b0654de52644d298a43017b2 Mon Sep 17 00:00:00 2001 From: Jussi Hallila Date: Mon, 18 Jan 2021 14:36:09 +0100 Subject: [PATCH 08/13] Address issues from code review. --- plugins/catalog-import/src/util/useGithubRepos.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/catalog-import/src/util/useGithubRepos.ts b/plugins/catalog-import/src/util/useGithubRepos.ts index 704ad974a5..db3ee9aa09 100644 --- a/plugins/catalog-import/src/util/useGithubRepos.ts +++ b/plugins/catalog-import/src/util/useGithubRepos.ts @@ -70,7 +70,7 @@ export function useGithubRepos() { githubIntegrationConfig, }) .catch(e => { - throw new Error(`Failed to submit PR to repo:\n${e.message}`); + throw new Error(`Failed to submit PR to repo: ${e.message}`); }); await api @@ -78,7 +78,7 @@ export function useGithubRepos() { location: submitPRResponse.location, }) .catch(e => { - throw new Error(`Failed to create repository location:\n${e.message}`); + throw new Error(`Failed to create repository location: ${e.message}`); }); return submitPRResponse; @@ -95,7 +95,7 @@ export function useGithubRepos() { try { githubConfig = getGithubIntegrationConfig(location); } catch (e) { - return Promise.resolve({ exists: false }); + return { exists: false }; } return await api .checkForExistingCatalogInfo({ @@ -105,7 +105,7 @@ export function useGithubRepos() { }) .catch(e => { throw new Error( - `Failed to inspect repository for existing catalog-info.yaml:\n${e.message}`, + `Failed to inspect repository for existing catalog-info.yaml: ${e.message}`, ); }); }; From 8fe334a7ebd938c6676d26e195b7c6f70819e6ef Mon Sep 17 00:00:00 2001 From: Jussi Hallila Date: Mon, 18 Jan 2021 16:40:11 +0100 Subject: [PATCH 09/13] Modify error messages based on PR comment. --- plugins/catalog-import/src/util/useGithubRepos.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/catalog-import/src/util/useGithubRepos.ts b/plugins/catalog-import/src/util/useGithubRepos.ts index db3ee9aa09..6c11ca1e8b 100644 --- a/plugins/catalog-import/src/util/useGithubRepos.ts +++ b/plugins/catalog-import/src/util/useGithubRepos.ts @@ -44,7 +44,7 @@ export function useGithubRepos() { const githubIntegrationConfig = configs.find(v => v.host === hostname); if (!githubIntegrationConfig) { throw new Error( - `Unable to locate github-integration for repo-location: ${location}`, + `Unable to locate github-integration for repo-location, ${location}`, ); } return { @@ -70,7 +70,7 @@ export function useGithubRepos() { githubIntegrationConfig, }) .catch(e => { - throw new Error(`Failed to submit PR to repo: ${e.message}`); + throw new Error(`Failed to submit PR to repo, ${e.message}`); }); await api @@ -78,7 +78,7 @@ export function useGithubRepos() { location: submitPRResponse.location, }) .catch(e => { - throw new Error(`Failed to create repository location: ${e.message}`); + throw new Error(`Failed to create repository location, ${e.message}`); }); return submitPRResponse; @@ -105,7 +105,7 @@ export function useGithubRepos() { }) .catch(e => { throw new Error( - `Failed to inspect repository for existing catalog-info.yaml: ${e.message}`, + `Failed to inspect repository for existing catalog-info.yaml, ${e.message}`, ); }); }; From 46a3fea2ba3cec45284fcd4c114800b8ef137f8f Mon Sep 17 00:00:00 2001 From: Jussi Hallila Date: Mon, 18 Jan 2021 19:37:50 +0100 Subject: [PATCH 10/13] Fixing erroneus test setup. --- plugins/catalog-import/package.json | 2 +- plugins/catalog-import/src/api/CatalogImportClient.ts | 5 ++--- plugins/catalog-import/src/setupTests.ts | 3 --- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index 5e601ad896..dfd5414ad1 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -39,6 +39,7 @@ "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", "@octokit/rest": "^18.0.12", + "cross-fetch": "^3.0.6", "git-url-parse": "^11.4.3", "react": "^16.13.1", "react-dom": "^16.13.1", @@ -57,7 +58,6 @@ "@testing-library/user-event": "^12.0.7", "@types/jest": "^26.0.7", "@types/node": "^12.0.0", - "cross-fetch": "^3.0.6", "msw": "^0.21.2" }, "files": [ diff --git a/plugins/catalog-import/src/api/CatalogImportClient.ts b/plugins/catalog-import/src/api/CatalogImportClient.ts index 4ce25e8fc2..385fecd1ab 100644 --- a/plugins/catalog-import/src/api/CatalogImportClient.ts +++ b/plugins/catalog-import/src/api/CatalogImportClient.ts @@ -19,6 +19,7 @@ import { DiscoveryApi, OAuthApi, ConfigApi } from '@backstage/core'; import { CatalogImportApi } from './CatalogImportApi'; import { PartialEntity } from '../util/types'; import { GitHubIntegrationConfig } from '@backstage/integration'; +import fetch from 'cross-fetch'; export class CatalogImportClient implements CatalogImportApi { private readonly discoveryApi: DiscoveryApi; @@ -133,9 +134,7 @@ export class CatalogImportClient implements CatalogImportApi { exists, }; } - return Promise.resolve({ - exists, - }); + return { exists }; } async submitPrToRepo({ diff --git a/plugins/catalog-import/src/setupTests.ts b/plugins/catalog-import/src/setupTests.ts index fba7d7a957..825bcd4115 100644 --- a/plugins/catalog-import/src/setupTests.ts +++ b/plugins/catalog-import/src/setupTests.ts @@ -15,6 +15,3 @@ */ import '@testing-library/jest-dom'; -import fetch from 'cross-fetch'; - -global.fetch = fetch; From 68adcb0c4219c34c5306d324238ba97188e307bc Mon Sep 17 00:00:00 2001 From: Jussi Hallila Date: Mon, 18 Jan 2021 20:09:13 +0100 Subject: [PATCH 11/13] Reorder package.json and rerun install for lockfile. --- plugins/catalog-import/package.json | 2 +- yarn.lock | 23 ++++++++++++++--------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index dfd5414ad1..5931d59a0a 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -32,8 +32,8 @@ "dependencies": { "@backstage/catalog-model": "^0.6.1", "@backstage/core": "^0.4.4", - "@backstage/plugin-catalog": "^0.2.11", "@backstage/integration": "^0.2.0", + "@backstage/plugin-catalog": "^0.2.11", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", diff --git a/yarn.lock b/yarn.lock index 6710c7e8e7..88938f86d6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2398,9 +2398,11 @@ to-fast-properties "^2.0.0" "@backstage/catalog-model@^0.2.0": - version "0.6.1" + version "0.2.0" + resolved "https://registry.npmjs.org/@backstage/catalog-model/-/catalog-model-0.2.0.tgz#e3fe2a4ddeb6a9b6ec480c80cb2b9c39cb245576" + integrity sha512-Y1ocdRpBlxK/VrJQjHlQd0bgADECd1B2NRjwd8ss46ibT5hwLvMOfD80+Fa7oPLu0ktJrH4lq0pNIIJIml48zA== dependencies: - "@backstage/config" "^0.1.2" + "@backstage/config" "^0.1.1" "@types/json-schema" "^7.0.5" "@types/yup" "^0.29.8" json-schema "^0.2.5" @@ -2409,9 +2411,11 @@ yup "^0.29.3" "@backstage/catalog-model@^0.3.0": - version "0.6.1" + version "0.3.1" + resolved "https://registry.npmjs.org/@backstage/catalog-model/-/catalog-model-0.3.1.tgz#45d08e2f333c9c566b2bf2629fd707fe989bb404" + integrity sha512-9XhV7c4rmVW+Yzj2PiwTQ7DsegWGB3C4ELsDRExuEVZONdqNcC02cyJtrt3fT5F31ZS3tHkB9bMUymFOBLqUSA== dependencies: - "@backstage/config" "^0.1.2" + "@backstage/config" "^0.1.1" "@types/json-schema" "^7.0.5" "@types/yup" "^0.29.8" json-schema "^0.2.5" @@ -2420,16 +2424,17 @@ yup "^0.29.3" "@backstage/core@^0.3.0": - version "0.4.4" + version "0.3.2" + resolved "https://registry.npmjs.org/@backstage/core/-/core-0.3.2.tgz#a8209126d5076cf4a8b9bd632fe4e5e2edb62916" + integrity sha512-i5d+Wh8js4qEWoAsPY5L7HVSWpumr1OhfF2dUCGYdyW6AMqVJPca6+n6zp1Rg2CO+J9norp44XAVVCbyhtUpig== dependencies: - "@backstage/config" "^0.1.2" - "@backstage/core-api" "^0.2.8" - "@backstage/theme" "^0.2.2" + "@backstage/config" "^0.1.1" + "@backstage/core-api" "^0.2.1" + "@backstage/theme" "^0.2.1" "@material-ui/core" "^4.11.0" "@material-ui/icons" "^4.9.1" "@material-ui/lab" "4.0.0-alpha.45" "@types/dagre" "^0.7.44" - "@types/prop-types" "^15.7.3" "@types/react" "^16.9" "@types/react-sparklines" "^1.7.0" classnames "^2.2.6" From b1c82487dd1cbbba95032bc4463aa2a6f358c551 Mon Sep 17 00:00:00 2001 From: Jussi Hallila Date: Mon, 18 Jan 2021 20:47:19 +0100 Subject: [PATCH 12/13] Update yarn lock. --- yarn.lock | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/yarn.lock b/yarn.lock index 88938f86d6..6710c7e8e7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2398,11 +2398,9 @@ to-fast-properties "^2.0.0" "@backstage/catalog-model@^0.2.0": - version "0.2.0" - resolved "https://registry.npmjs.org/@backstage/catalog-model/-/catalog-model-0.2.0.tgz#e3fe2a4ddeb6a9b6ec480c80cb2b9c39cb245576" - integrity sha512-Y1ocdRpBlxK/VrJQjHlQd0bgADECd1B2NRjwd8ss46ibT5hwLvMOfD80+Fa7oPLu0ktJrH4lq0pNIIJIml48zA== + version "0.6.1" dependencies: - "@backstage/config" "^0.1.1" + "@backstage/config" "^0.1.2" "@types/json-schema" "^7.0.5" "@types/yup" "^0.29.8" json-schema "^0.2.5" @@ -2411,11 +2409,9 @@ yup "^0.29.3" "@backstage/catalog-model@^0.3.0": - version "0.3.1" - resolved "https://registry.npmjs.org/@backstage/catalog-model/-/catalog-model-0.3.1.tgz#45d08e2f333c9c566b2bf2629fd707fe989bb404" - integrity sha512-9XhV7c4rmVW+Yzj2PiwTQ7DsegWGB3C4ELsDRExuEVZONdqNcC02cyJtrt3fT5F31ZS3tHkB9bMUymFOBLqUSA== + version "0.6.1" dependencies: - "@backstage/config" "^0.1.1" + "@backstage/config" "^0.1.2" "@types/json-schema" "^7.0.5" "@types/yup" "^0.29.8" json-schema "^0.2.5" @@ -2424,17 +2420,16 @@ yup "^0.29.3" "@backstage/core@^0.3.0": - version "0.3.2" - resolved "https://registry.npmjs.org/@backstage/core/-/core-0.3.2.tgz#a8209126d5076cf4a8b9bd632fe4e5e2edb62916" - integrity sha512-i5d+Wh8js4qEWoAsPY5L7HVSWpumr1OhfF2dUCGYdyW6AMqVJPca6+n6zp1Rg2CO+J9norp44XAVVCbyhtUpig== + version "0.4.4" dependencies: - "@backstage/config" "^0.1.1" - "@backstage/core-api" "^0.2.1" - "@backstage/theme" "^0.2.1" + "@backstage/config" "^0.1.2" + "@backstage/core-api" "^0.2.8" + "@backstage/theme" "^0.2.2" "@material-ui/core" "^4.11.0" "@material-ui/icons" "^4.9.1" "@material-ui/lab" "4.0.0-alpha.45" "@types/dagre" "^0.7.44" + "@types/prop-types" "^15.7.3" "@types/react" "^16.9" "@types/react-sparklines" "^1.7.0" classnames "^2.2.6" From f4cfdc648e4a6a634829b31b4a8095c9ce952114 Mon Sep 17 00:00:00 2001 From: Jussi Hallila Date: Tue, 19 Jan 2021 18:40:35 +0100 Subject: [PATCH 13/13] Modify fetch usage in tests to conform templates --- plugins/catalog-import/package.json | 2 +- plugins/catalog-import/src/api/CatalogImportClient.ts | 1 - plugins/catalog-import/src/setupTests.ts | 1 + 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index 5931d59a0a..c4e8d918d1 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -39,7 +39,6 @@ "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", "@octokit/rest": "^18.0.12", - "cross-fetch": "^3.0.6", "git-url-parse": "^11.4.3", "react": "^16.13.1", "react-dom": "^16.13.1", @@ -58,6 +57,7 @@ "@testing-library/user-event": "^12.0.7", "@types/jest": "^26.0.7", "@types/node": "^12.0.0", + "cross-fetch": "^3.0.6", "msw": "^0.21.2" }, "files": [ diff --git a/plugins/catalog-import/src/api/CatalogImportClient.ts b/plugins/catalog-import/src/api/CatalogImportClient.ts index 385fecd1ab..d1509c2105 100644 --- a/plugins/catalog-import/src/api/CatalogImportClient.ts +++ b/plugins/catalog-import/src/api/CatalogImportClient.ts @@ -19,7 +19,6 @@ import { DiscoveryApi, OAuthApi, ConfigApi } from '@backstage/core'; import { CatalogImportApi } from './CatalogImportApi'; import { PartialEntity } from '../util/types'; import { GitHubIntegrationConfig } from '@backstage/integration'; -import fetch from 'cross-fetch'; export class CatalogImportClient implements CatalogImportApi { private readonly discoveryApi: DiscoveryApi; diff --git a/plugins/catalog-import/src/setupTests.ts b/plugins/catalog-import/src/setupTests.ts index 825bcd4115..aea2220869 100644 --- a/plugins/catalog-import/src/setupTests.ts +++ b/plugins/catalog-import/src/setupTests.ts @@ -15,3 +15,4 @@ */ import '@testing-library/jest-dom'; +import 'cross-fetch/polyfill';