use more robust matching for CODEOWNERS entries
Signed-off-by: Kiss Miklos <miklos@roadie.io>
This commit is contained in:
@@ -106,15 +106,11 @@ describe('CodeOwnersProcessor', () => {
|
||||
});
|
||||
});
|
||||
it('should use the "backstage.io/managed-by-location" annotation as pattern', async () => {
|
||||
const { entity, processor } = setupTest({
|
||||
metadata: {
|
||||
annotations: { 'backstage.io/managed-by-location': '/docs' },
|
||||
},
|
||||
});
|
||||
const { entity, processor } = setupTest();
|
||||
|
||||
const result = await processor.preProcessEntity(
|
||||
entity as any,
|
||||
mockLocation(),
|
||||
mockLocation({ basePath: 'docs/' }),
|
||||
);
|
||||
|
||||
expect(result).toEqual({
|
||||
|
||||
@@ -80,14 +80,10 @@ export class CodeOwnersProcessor implements CatalogProcessor {
|
||||
return entity;
|
||||
}
|
||||
|
||||
const pattern =
|
||||
entity.metadata?.annotations?.['backstage.io/managed-by-location'];
|
||||
|
||||
const owner = await findCodeOwnerByTarget(
|
||||
this.reader,
|
||||
location.target,
|
||||
scmIntegration,
|
||||
pattern,
|
||||
);
|
||||
|
||||
if (!owner) {
|
||||
|
||||
@@ -52,7 +52,6 @@ export async function findCodeOwnerByTarget(
|
||||
reader: UrlReader,
|
||||
targetUrl: string,
|
||||
scmIntegration: ScmIntegration,
|
||||
pattern?: string,
|
||||
): Promise<string | undefined> {
|
||||
const codeownersPaths = scmCodeOwnersPaths[scmIntegration?.type ?? ''];
|
||||
|
||||
@@ -71,7 +70,7 @@ export async function findCodeOwnerByTarget(
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const owner = resolveCodeOwner(contents, pattern);
|
||||
const owner = resolveCodeOwner(contents, targetUrl);
|
||||
|
||||
return owner;
|
||||
}
|
||||
|
||||
@@ -23,16 +23,29 @@ const mockCodeOwnersText = () => `
|
||||
|
||||
describe('resolveCodeOwner', () => {
|
||||
it('should parse the codeowners file', () => {
|
||||
expect(resolveCodeOwner(mockCodeOwnersText())).toBe('team-foo');
|
||||
expect(
|
||||
resolveCodeOwner(
|
||||
mockCodeOwnersText(),
|
||||
'https://github.com/can/be/tree/anything/catalog-info.yaml',
|
||||
),
|
||||
).toBe('team-foo');
|
||||
});
|
||||
it('should include the codeowners path into the provided pattern', () => {
|
||||
expect(
|
||||
resolveCodeOwner(
|
||||
mockCodeOwnersText(),
|
||||
'url:https://github.com/acem/repo/main/docs/catalog-info.yaml',
|
||||
'https://github.com/acme/repo/tree/main/docs/catalog-info.yaml',
|
||||
),
|
||||
).toBe('team-docs');
|
||||
});
|
||||
it('should match only in resource path', () => {
|
||||
expect(
|
||||
resolveCodeOwner(
|
||||
mockCodeOwnersText(),
|
||||
'https://github.com/acme/repo/tree/docs/catalog-info.yaml',
|
||||
),
|
||||
).toBe('team-foo');
|
||||
});
|
||||
});
|
||||
|
||||
describe('normalizeCodeOwner', () => {
|
||||
|
||||
@@ -15,8 +15,7 @@
|
||||
*/
|
||||
|
||||
import * as codeowners from 'codeowners-utils';
|
||||
import { CodeOwnersEntry } from 'codeowners-utils';
|
||||
import { get, head, pipe, reverse } from 'lodash/fp';
|
||||
import parseGitUrl from 'git-url-parse';
|
||||
|
||||
const USER_PATTERN = /^@.*/;
|
||||
const GROUP_PATTERN = /^@.*\/.*/;
|
||||
@@ -24,26 +23,20 @@ const EMAIL_PATTERN = /^.*@.*\..*$/;
|
||||
|
||||
export function resolveCodeOwner(
|
||||
contents: string,
|
||||
pattern?: string,
|
||||
catalogInfoFileUrl: string,
|
||||
): string | undefined {
|
||||
const owners = codeowners.parse(contents);
|
||||
const codeOwnerEntries = codeowners.parse(contents);
|
||||
|
||||
let filteredOwners = owners.filter((e: CodeOwnersEntry) =>
|
||||
pattern?.includes(e.pattern),
|
||||
);
|
||||
if (filteredOwners.length === 0) {
|
||||
filteredOwners = owners.filter((e: CodeOwnersEntry) => e.pattern === '*');
|
||||
const { filepath } = parseGitUrl(catalogInfoFileUrl);
|
||||
const match = codeowners.matchFile(filepath, codeOwnerEntries);
|
||||
|
||||
if (!match) {
|
||||
throw new Error(
|
||||
`There is no matching entry for path: ${filepath} in the CODEOWNERS file`,
|
||||
);
|
||||
}
|
||||
|
||||
const result = pipe(
|
||||
reverse,
|
||||
head,
|
||||
get('owners'),
|
||||
head,
|
||||
normalizeCodeOwner,
|
||||
)(filteredOwners);
|
||||
|
||||
return result;
|
||||
return normalizeCodeOwner(match.owners[0]);
|
||||
}
|
||||
|
||||
export function normalizeCodeOwner(owner: string) {
|
||||
|
||||
Reference in New Issue
Block a user