diff --git a/plugins/catalog-import/src/api/CatalogImportClient.test.ts b/plugins/catalog-import/src/api/CatalogImportClient.test.ts index 202a7aba85..fa63825af1 100644 --- a/plugins/catalog-import/src/api/CatalogImportClient.test.ts +++ b/plugins/catalog-import/src/api/CatalogImportClient.test.ts @@ -396,6 +396,84 @@ describe('CatalogImportClient', () => { ], }); }); + + it('should find location with custom catalog filename', async () => { + const repositoryUrl = 'https://github.com/acme-corp/our-awesome-api'; + const entityFilename = 'anvil.yaml'; + + catalogImportClient = new CatalogImportClient({ + discoveryApi, + scmAuthApi, + scmIntegrationsApi, + identityApi, + catalogApi, + configApi: new ConfigReader({ + catalog: { + import: { + entityFilename, + }, + }, + }), + }); + + (new Octokit().search.code as any as jest.Mock).mockImplementationOnce( + async params => ({ + data: { + total_count: 1, + items: [{ path: params.q.split('+filename:').slice(-1)[0] }], + }, + }), + ); + + catalogApi.addLocation.mockImplementation(async ({ type, target }) => ({ + location: { + id: 'id-0', + type: type ?? 'url', + target, + }, + entities: [ + { + apiVersion: '1', + kind: 'Location', + metadata: { + name: 'my-entity', + namespace: 'my-namespace', + }, + }, + { + apiVersion: '1', + kind: 'Component', + metadata: { + name: 'my-entity', + namespace: 'my-namespace', + }, + }, + ], + })); + + await expect( + catalogImportClient.analyzeUrl(repositoryUrl), + ).resolves.toEqual({ + locations: [ + { + entities: [ + { + kind: 'Location', + namespace: 'my-namespace', + name: 'my-entity', + }, + { + kind: 'Component', + namespace: 'my-namespace', + name: 'my-entity', + }, + ], + target: `${repositoryUrl}/blob/main/${entityFilename}`, + }, + ], + type: 'locations', + }); + }); }); describe('submitPullRequest', () => { @@ -443,6 +521,67 @@ describe('CatalogImportClient', () => { base: 'main', }); }); + + it('should create GitHub pull request with custom filename and branch name', async () => { + const entityFilename = 'anvil.yaml'; + const pullRequestBranchName = 'anvil-integration'; + + catalogImportClient = new CatalogImportClient({ + discoveryApi, + scmAuthApi, + scmIntegrationsApi, + identityApi, + catalogApi, + configApi: new ConfigReader({ + catalog: { + import: { + entityFilename, + pullRequestBranchName, + }, + }, + }), + }); + + await expect( + catalogImportClient.submitPullRequest({ + repositoryUrl: 'https://github.com/acme-corp/our-awesome-api', + fileContent: '', + title: `Add ${entityFilename} config file`, + body: `Add ${entityFilename} config file`, + }), + ).resolves.toEqual( + expect.objectContaining({ + link: 'http://pull/request/0', + location: `https://github.com/acme-corp/our-awesome-api/blob/main/${entityFilename}`, + }), + ); + + expect( + (new Octokit().git.createRef as any as jest.Mock).mock.calls[0][0], + ).toEqual( + expect.objectContaining({ + ref: `refs/heads/${pullRequestBranchName}`, + }), + ); + + expect( + (new Octokit().repos.createOrUpdateFileContents as any as jest.Mock) + .mock.calls[0][0], + ).toEqual( + expect.objectContaining({ + path: entityFilename, + branch: pullRequestBranchName, + }), + ); + + expect( + (new Octokit().pulls.create as any as jest.Mock).mock.calls[0][0], + ).toEqual( + expect.objectContaining({ + head: pullRequestBranchName, + }), + ); + }); }); describe('preparePullRequest', () => { @@ -452,5 +591,34 @@ describe('CatalogImportClient', () => { body: expect.any(String), }); }); + + test('should prepare pull request details with custom filename', async () => { + const entityFilename = 'anvil.yaml'; + const pullRequestBranchName = 'anvil-integration'; + + catalogImportClient = new CatalogImportClient({ + discoveryApi, + scmAuthApi, + scmIntegrationsApi, + identityApi, + catalogApi, + configApi: new ConfigReader({ + catalog: { + import: { + entityFilename, + pullRequestBranchName, + }, + }, + app: { + baseUrl: 'https://demo.backstage.io/', + }, + }), + }); + + await expect(catalogImportClient.preparePullRequest()).resolves.toEqual({ + title: `Add ${entityFilename} config file`, + body: expect.any(String), + }); + }); }); }); diff --git a/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/PreviewCatalogInfoComponent.test.tsx b/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/PreviewCatalogInfoComponent.test.tsx index fe5e76c968..aac54e084a 100644 --- a/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/PreviewCatalogInfoComponent.test.tsx +++ b/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/PreviewCatalogInfoComponent.test.tsx @@ -15,6 +15,9 @@ */ import { Entity } from '@backstage/catalog-model'; +import { ApiProvider } from '@backstage/core-app-api'; +import { configApiRef } from '@backstage/core-plugin-api'; +import { TestApiRegistry, MockConfigApi } from '@backstage/test-utils'; import { makeStyles } from '@material-ui/core'; import { render, screen } from '@testing-library/react'; import { renderHook } from '@testing-library/react-hooks'; @@ -44,13 +47,19 @@ const entities: Entity[] = [ }, ]; +const mockConfigApi = new MockConfigApi({}); + +const apis = TestApiRegistry.from([configApiRef, mockConfigApi]); + describe('', () => { it('renders without exploding', () => { render( - , + + + , ); const repositoryUrl = screen.getByText( @@ -67,11 +76,13 @@ describe('', () => { const { result } = renderHook(() => useStyles()); render( - , + + + , ); const repositoryUrl = screen.getByText( @@ -88,11 +99,13 @@ describe('', () => { const { result } = renderHook(() => useStyles()); render( - , + + + , ); const repositoryUrl = screen.getByText( @@ -104,4 +117,32 @@ describe('', () => { expect(kindText).toBeInTheDocument(); expect(kindText).not.toBeVisible(); }); + + it('renders with custom catalog filename', () => { + render( + + + , + ); + + const repositoryUrl = screen.getByText( + 'http://acme-corp/awesome-api/anvil.yaml', + ); + expect(repositoryUrl).toBeInTheDocument(); + expect(repositoryUrl).toBeVisible(); + }); }); diff --git a/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/StepPrepareCreatePullRequest.test.tsx b/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/StepPrepareCreatePullRequest.test.tsx index 3b6f353155..8d26657bb3 100644 --- a/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/StepPrepareCreatePullRequest.test.tsx +++ b/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/StepPrepareCreatePullRequest.test.tsx @@ -14,9 +14,9 @@ * limitations under the License. */ -import { errorApiRef } from '@backstage/core-plugin-api'; +import { configApiRef, errorApiRef } from '@backstage/core-plugin-api'; import { catalogApiRef } from '@backstage/plugin-catalog-react'; -import { TestApiProvider } from '@backstage/test-utils'; +import { TestApiProvider, MockConfigApi } from '@backstage/test-utils'; import { TextField } from '@material-ui/core'; import { act, render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; @@ -53,12 +53,15 @@ describe('', () => { post: jest.fn(), }; + const configApi = new MockConfigApi({}); + const Wrapper = ({ children }: { children?: React.ReactNode }) => ( {children}