ability to discover catalog-infos from default branch

Previously the github-discovery supported only repos from a specific
branch. This change cause the discovery to work in two modes. It continues
to work as it did with a wildcard for repositories on a specified branch.

The new mode added causes the discovery processor to use the default branch
and looks for a file called catalog-info.yaml.

Signed-off-by: Brian Fletcher <brian@roadie.io>
This commit is contained in:
Brian Fletcher
2021-08-23 18:44:21 +01:00
parent 5aebf54a12
commit c531345df6
3 changed files with 35 additions and 8 deletions
@@ -45,12 +45,15 @@ describe('GithubDiscoveryProcessor', () => {
repoSearchPath: /^proj.*$/,
catalogPath: '/blob/master/catalog.yaml',
});
expect(parseUrl('https://github.com/foo')).toEqual({
org: 'foo',
host: 'github.com',
});
});
it('throws on incorrectly formed URLs', () => {
expect(() => parseUrl('https://github.com')).toThrow();
expect(() => parseUrl('https://github.com//')).toThrow();
expect(() => parseUrl('https://github.com/foo')).toThrow();
expect(() => parseUrl('https://github.com//foo')).toThrow();
expect(() => parseUrl('https://github.com/org/teams')).toThrow();
expect(() => parseUrl('https://github.com/org//teams')).toThrow();
@@ -28,7 +28,15 @@ import { CatalogProcessor, CatalogProcessorEmit } from './types';
/**
* Extracts repositories out of a GitHub org.
*/
*
* It can be configured in two modes. The first will create locations for all
* catalog-info.yaml files on the default branch. The second will create locations
* for all projects which have a catalog-info.yaml on the master branch.
*
* target: "https://github.com/backstage"
* or
* target: https://github.com/backstage/*\/blob/master/catalog-info.yaml
**/
export class GithubDiscoveryProcessor implements CatalogProcessor {
private readonly integrations: ScmIntegrations;
private readonly logger: Logger;
@@ -87,9 +95,9 @@ export class GithubDiscoveryProcessor implements CatalogProcessor {
this.logger.info(`Reading GitHub repositories from ${location.target}`);
const { repositories } = await getOrganizationRepositories(client, org);
const matching = repositories.filter(
r => !r.isArchived && repoSearchPath.test(r.name),
);
const matching = repoSearchPath
? repositories.filter(r => !r.isArchived && repoSearchPath.test(r.name))
: repositories;
const duration = ((Date.now() - startTimestamp) / 1000).toFixed(1);
this.logger.debug(
@@ -97,11 +105,14 @@ export class GithubDiscoveryProcessor implements CatalogProcessor {
);
for (const repository of matching) {
const path = catalogPath
? catalogPath
: `/blob/${repository.defaultBranchRef.name}/catalog-info.yaml`;
emit(
results.location(
{
type: 'url',
target: `${repository.url}${catalogPath}`,
target: `${repository.url}${path}`,
},
// Not all locations may actually exist, since the user defined them as a wildcard pattern.
// Thus, we emit them as optional and let the downstream processor find them while not outputting
@@ -121,14 +132,16 @@ export class GithubDiscoveryProcessor implements CatalogProcessor {
export function parseUrl(urlString: string): {
org: string;
repoSearchPath: RegExp;
catalogPath: string;
repoSearchPath?: RegExp;
catalogPath?: 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]),
@@ -136,6 +149,11 @@ export function parseUrl(urlString: string): {
catalogPath: `/${decodeURIComponent(path.slice(2).join('/'))}`,
host: url.host,
};
} else if (path.length === 1 && path[0].length) {
return {
org: decodeURIComponent(path[0]),
host: url.host,
};
}
throw new Error(`Failed to parse ${urlString}`);
@@ -60,6 +60,9 @@ export type Repository = {
name: string;
url: string;
isArchived: boolean;
defaultBranchRef: {
name: string;
};
};
export type Connection<T> = {
@@ -252,6 +255,9 @@ export async function getOrganizationRepositories(
name
url
isArchived
defaultBranchRef {
name
}
}
pageInfo {
hasNextPage