diff --git a/plugins/catalog-backend/api-report.md b/plugins/catalog-backend/api-report.md index 5745588873..bf53badd87 100644 --- a/plugins/catalog-backend/api-report.md +++ b/plugins/catalog-backend/api-report.md @@ -78,6 +78,7 @@ export type AnalyzeLocationGenerateEntity = { // @public (undocumented) export type AnalyzeLocationRequest = { location: LocationSpec; + catalogFilename?: string; }; // @public (undocumented) diff --git a/plugins/catalog-backend/src/ingestion/LocationAnalyzer.ts b/plugins/catalog-backend/src/ingestion/LocationAnalyzer.ts index f1fede65df..24c5821d92 100644 --- a/plugins/catalog-backend/src/ingestion/LocationAnalyzer.ts +++ b/plugins/catalog-backend/src/ingestion/LocationAnalyzer.ts @@ -65,6 +65,7 @@ export class RepoLocationAnalyzer implements LocationAnalyzer { analyzer = new GitHubLocationAnalyzer({ integration, discovery: this.discovery, + catalogFilename: request.catalogFilename, }); break; case 'gitlab': diff --git a/plugins/catalog-backend/src/ingestion/analyzers/GitHubLocationAnalyzer.test.ts b/plugins/catalog-backend/src/ingestion/analyzers/GitHubLocationAnalyzer.test.ts index 7f02fee620..fbc9ae3454 100644 --- a/plugins/catalog-backend/src/ingestion/analyzers/GitHubLocationAnalyzer.test.ts +++ b/plugins/catalog-backend/src/ingestion/analyzers/GitHubLocationAnalyzer.test.ts @@ -94,6 +94,10 @@ describe('GitHubLocationAnalyzer', () => { ); }), ); + + octokit.repos.get.mockResolvedValue({ + data: { default_branch: 'my_default_branch' }, + }); }); it('should analyze', async () => { @@ -106,10 +110,6 @@ describe('GitHubLocationAnalyzer', () => { return Promise.reject(); }); - octokit.repos.get.mockResolvedValue({ - data: { default_branch: 'my_default_branch' }, - }); - const analyzer = new GitHubLocationAnalyzer({ discovery: mockDiscoveryApi, integration, @@ -123,5 +123,26 @@ describe('GitHubLocationAnalyzer', () => { 'https://github.com/foo/bar/blob/my_default_branch/catalog-info.yaml', }); }); - it('should'); + it('should use the provided entity filename for search', async () => { + octokit.search.code.mockImplementation((opts: { q: string }) => { + if (opts.q === 'filename:anvil.yaml repo:foo/bar') { + return Promise.resolve({ + data: { items: [{ path: 'anvil.yaml' }], total_count: 1 }, + }); + } + return Promise.reject(); + }); + + const analyzer = new GitHubLocationAnalyzer({ + discovery: mockDiscoveryApi, + integration, + catalogFilename: 'anvil.yaml', + }); + const result = await analyzer.analyze('https://github.com/foo/bar'); + + expect(result[0].location).toEqual({ + type: 'url', + target: 'https://github.com/foo/bar/blob/my_default_branch/anvil.yaml', + }); + }); }); diff --git a/plugins/catalog-backend/src/ingestion/types.ts b/plugins/catalog-backend/src/ingestion/types.ts index 9da7b037aa..8dc833abd8 100644 --- a/plugins/catalog-backend/src/ingestion/types.ts +++ b/plugins/catalog-backend/src/ingestion/types.ts @@ -34,6 +34,7 @@ export type LocationAnalyzer = { /** @public */ export type AnalyzeLocationRequest = { location: LocationSpec; + catalogFilename?: string; }; /** @public */ diff --git a/plugins/catalog-backend/src/service/createRouter.ts b/plugins/catalog-backend/src/service/createRouter.ts index 639893dcc1..93a4e20726 100644 --- a/plugins/catalog-backend/src/service/createRouter.ts +++ b/plugins/catalog-backend/src/service/createRouter.ts @@ -229,9 +229,15 @@ export async function createRouter( router.post('/analyze-location', async (req, res) => { const body = await validateRequestBody( req, - z.object({ location: locationInput }), + z.object({ + location: locationInput, + catalogFilename: z.string().optional(), + }), ); - const schema = z.object({ location: locationInput }); + const schema = z.object({ + location: locationInput, + catalogFilename: z.string().optional(), + }); const output = await locationAnalyzer.analyzeLocation(schema.parse(body)); res.status(200).json(output); }); diff --git a/plugins/catalog-import/src/api/CatalogImportClient.test.ts b/plugins/catalog-import/src/api/CatalogImportClient.test.ts index 30b9f47d99..d507ac3bef 100644 --- a/plugins/catalog-import/src/api/CatalogImportClient.test.ts +++ b/plugins/catalog-import/src/api/CatalogImportClient.test.ts @@ -297,7 +297,7 @@ describe('CatalogImportClient', () => { it('should find locations from github', async () => { (new Octokit().search.code as any as jest.Mock).mockResolvedValueOnce({ data: { - total_count: 2, + total_count: 3, items: [ { path: 'simple/path/catalog-info.yaml' }, { path: 'co/mple/x/path/catalog-info.yaml' }, @@ -305,24 +305,72 @@ describe('CatalogImportClient', () => { ], }, }); - - catalogApi.addLocation.mockImplementation(async ({ type, target }) => ({ - location: { - id: 'id-0', - type: type ?? 'url', - target, - }, - entities: [ - { - apiVersion: '1', - kind: 'k', - metadata: { - name: 'e', - namespace: 'n', + server.use( + rest.post(`${mockBaseUrl}/analyze-location`, (req, res, ctx) => { + expect(req.body).toEqual({ + location: { + target: 'https://github.com/backstage/backstage', + type: 'url', }, - }, - ], - })); + }); + + return res( + ctx.json({ + generateEntities: [], + existingEntityFiles: [ + { + isRegistered: false, + location: { + type: 'url', + target: + 'https://github.com/backstage/backstage/blob/main/simple/path/catalog-info.yaml', + }, + entity: { + apiVersion: '1', + kind: 'k', + metadata: { + name: 'e', + namespace: 'n', + }, + }, + }, + { + isRegistered: false, + location: { + type: 'url', + target: + 'https://github.com/backstage/backstage/blob/main/co/mple/x/path/catalog-info.yaml', + }, + entity: { + apiVersion: '1', + kind: 'k', + metadata: { + name: 'e', + namespace: 'n', + }, + }, + }, + { + isRegistered: false, + location: { + type: 'url', + target: + 'https://github.com/backstage/backstage/blob/main/catalog-info.yaml', + }, + entity: { + apiVersion: '1', + kind: 'k', + metadata: { + name: 'e', + namespace: 'n', + }, + }, + }, + ], + }), + ); + }), + ); await expect( catalogImportClient.analyzeUrl( @@ -332,16 +380,19 @@ describe('CatalogImportClient', () => { locations: [ { entities: [{ kind: 'k', name: 'e', namespace: 'n' }], + exists: false, target: 'https://github.com/backstage/backstage/blob/main/simple/path/catalog-info.yaml', }, { entities: [{ kind: 'k', name: 'e', namespace: 'n' }], + exists: false, target: 'https://github.com/backstage/backstage/blob/main/co/mple/x/path/catalog-info.yaml', }, { entities: [{ kind: 'k', name: 'e', namespace: 'n' }], + exists: false, target: 'https://github.com/backstage/backstage/blob/main/catalog-info.yaml', }, @@ -426,31 +477,57 @@ describe('CatalogImportClient', () => { }), ); - 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', + server.use( + rest.post(`${mockBaseUrl}/analyze-location`, (req, res, ctx) => { + expect(req.body).toEqual({ + location: { + target: 'https://github.com/acme-corp/our-awesome-api', + type: 'url', }, - }, - { - apiVersion: '1', - kind: 'Component', - metadata: { - name: 'my-entity', - namespace: 'my-namespace', - }, - }, - ], - })); + catalogFilename: 'anvil.yaml', + }); + + return res( + ctx.json({ + generateEntities: [], + existingEntityFiles: [ + { + isRegistered: false, + location: { + type: 'url', + target: + 'https://github.com/acme-corp/our-awesome-api/blob/main/anvil.yaml', + }, + entity: { + apiVersion: '1', + kind: 'Location', + metadata: { + name: 'my-entity', + namespace: 'my-namespace', + }, + }, + }, + { + isRegistered: false, + location: { + type: 'url', + target: + 'https://github.com/acme-corp/our-awesome-api/blob/main/anvil.yaml', + }, + entity: { + apiVersion: '1', + kind: 'Component', + metadata: { + name: 'my-entity', + namespace: 'my-namespace', + }, + }, + }, + ], + }), + ); + }), + ); await expect( catalogImportClient.analyzeUrl(repositoryUrl), @@ -470,6 +547,7 @@ describe('CatalogImportClient', () => { }, ], target: `${repositoryUrl}/blob/main/${entityFilename}`, + exists: false, }, ], type: 'locations', diff --git a/plugins/catalog-import/src/api/CatalogImportClient.ts b/plugins/catalog-import/src/api/CatalogImportClient.ts index 7aa3365488..5dd3a3178f 100644 --- a/plugins/catalog-import/src/api/CatalogImportClient.ts +++ b/plugins/catalog-import/src/api/CatalogImportClient.ts @@ -209,6 +209,13 @@ the component will become available.\n\nFor more information, read an \ method: 'POST', body: JSON.stringify({ location: { type: 'url', target: options.repo }, + ...(this.configApi.getOptionalString( + 'catalog.import.entityFilename', + ) && { + catalogFilename: this.configApi.getOptionalString( + 'catalog.import.entityFilename', + ), + }), }), }, ).catch(e => {