diff --git a/.changeset/cuddly-impalas-wave.md b/.changeset/cuddly-impalas-wave.md new file mode 100644 index 0000000000..1199ef1482 --- /dev/null +++ b/.changeset/cuddly-impalas-wave.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +GitHub discovery processor passes over repositories that do not have a default branch diff --git a/plugins/catalog-backend/src/ingestion/processors/GithubDiscoveryProcessor.test.ts b/plugins/catalog-backend/src/ingestion/processors/GithubDiscoveryProcessor.test.ts index f8647cb5d2..12d9e66659 100644 --- a/plugins/catalog-backend/src/ingestion/processors/GithubDiscoveryProcessor.test.ts +++ b/plugins/catalog-backend/src/ingestion/processors/GithubDiscoveryProcessor.test.ts @@ -170,6 +170,92 @@ describe('GithubDiscoveryProcessor', () => { }); }); + it('output repositories with wildcards default branch option', async () => { + const location: LocationSpec = { + type: 'github-discovery', + target: 'https://github.com/backstage/*/blob/-/catalog.yaml', + }; + mockGetOrganizationRepositories.mockResolvedValueOnce({ + repositories: [ + { + name: 'backstage', + url: 'https://github.com/backstage/tech-docs', + isArchived: false, + defaultBranchRef: { + name: 'main', + }, + }, + ], + }); + const emitter = jest.fn(); + + await processor.readLocation(location, false, emitter); + + expect(emitter).toHaveBeenCalledWith({ + type: 'location', + location: { + type: 'url', + target: + 'https://github.com/backstage/tech-docs/blob/main/catalog.yaml', + }, + optional: true, + }); + }); + + it("doesn't output repositories as default branch returned is empty", async () => { + const location: LocationSpec = { + type: 'github-discovery', + target: 'https://github.com/backstage/blob/-/catalog.yaml', + }; + mockGetOrganizationRepositories.mockResolvedValueOnce({ + repositories: [ + { + name: 'backstage', + url: 'https://github.com/backstage/tech-docs', + isArchived: false, + defaultBranchRef: null, + }, + ], + }); + const emitter = jest.fn(); + + await processor.readLocation(location, false, emitter); + + expect(emitter).not.toHaveBeenCalled(); + }); + + it('output repositories with wildcards default branch option without catalog-info patch or branch match', async () => { + const location: LocationSpec = { + type: 'github-discovery', + target: 'https://github.com/backstage', + }; + mockGetOrganizationRepositories.mockResolvedValueOnce({ + repositories: [ + { + name: 'backstage', + url: 'https://github.com/backstage/backstage', + isArchived: false, + defaultBranchRef: { + name: 'master', + }, + }, + ], + }); + const emitter = jest.fn(); + + await processor.readLocation(location, false, emitter); + + expect(emitter).toHaveBeenCalledWith({ + type: 'location', + location: { + type: 'url', + target: + 'https://github.com/backstage/backstage/blob/master/catalog-info.yaml', + }, + optional: true, + }); + }); + it('output repositories with wildcards', async () => { const location: LocationSpec = { type: 'github-discovery', @@ -202,6 +288,12 @@ describe('GithubDiscoveryProcessor', () => { name: 'main', }, }, + { + name: 'techdocs-durp', + url: 'https://github.com/backstage/techdocs-durp', + isArchived: false, + defaultBranchRef: null, + }, ], }); const emitter = jest.fn(); @@ -227,6 +319,7 @@ describe('GithubDiscoveryProcessor', () => { optional: true, }); }); + it('filter unrelated and archived repositories', async () => { const location: LocationSpec = { type: 'github-discovery', diff --git a/plugins/catalog-backend/src/ingestion/processors/GithubDiscoveryProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/GithubDiscoveryProcessor.ts index 567f6536d0..b104d87542 100644 --- a/plugins/catalog-backend/src/ingestion/processors/GithubDiscoveryProcessor.ts +++ b/plugins/catalog-backend/src/ingestion/processors/GithubDiscoveryProcessor.ts @@ -108,9 +108,18 @@ export class GithubDiscoveryProcessor implements CatalogProcessor { ); for (const repository of matching) { - const path = `/blob/${ - branch === '-' ? repository.defaultBranchRef.name : branch - }${catalogPath}`; + const branchName = + branch === '-' ? repository.defaultBranchRef?.name : branch; + + if (!branchName) { + this.logger.info( + `the repository ${repository.url} does not have a default branch, skipping`, + ); + continue; + } + + const path = `/blob/${branchName}${catalogPath}`; + emit( results.location( { diff --git a/plugins/catalog-backend/src/ingestion/processors/github/github.ts b/plugins/catalog-backend/src/ingestion/processors/github/github.ts index 9eb5073710..fbbe9b3470 100644 --- a/plugins/catalog-backend/src/ingestion/processors/github/github.ts +++ b/plugins/catalog-backend/src/ingestion/processors/github/github.ts @@ -62,7 +62,7 @@ export type Repository = { isArchived: boolean; defaultBranchRef: { name: string; - }; + } | null; }; export type Connection = {