backend-common: make .readTree required
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
import fetch from 'cross-fetch';
|
||||
import { Config } from '@backstage/config';
|
||||
import { NotFoundError } from '../errors';
|
||||
import { ReaderFactory, UrlReader } from './types';
|
||||
import { ReaderFactory, ReadTreeResponse, UrlReader } from './types';
|
||||
|
||||
type Options = {
|
||||
// TODO: added here for future support, but we only allow dev.azure.com for now
|
||||
@@ -86,6 +86,10 @@ export class AzureUrlReader implements UrlReader {
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
readTree(): Promise<ReadTreeResponse> {
|
||||
throw new Error('AzureUrlReader does not implement readTree');
|
||||
}
|
||||
|
||||
// Converts
|
||||
// from: https://dev.azure.com/{organization}/{project}/_git/reponame?path={path}&version=GB{commitOrBranch}&_a=contents
|
||||
// to: https://dev.azure.com/{organization}/{project}/_apis/git/repositories/reponame/items?path={path}&version={commitOrBranch}
|
||||
|
||||
@@ -18,7 +18,7 @@ import { Config } from '@backstage/config';
|
||||
import parseGitUri from 'git-url-parse';
|
||||
import fetch from 'cross-fetch';
|
||||
import { NotFoundError } from '../errors';
|
||||
import { ReaderFactory, UrlReader } from './types';
|
||||
import { ReaderFactory, ReadTreeResponse, UrlReader } from './types';
|
||||
|
||||
const DEFAULT_BASE_URL = 'https://api.bitbucket.org/2.0';
|
||||
|
||||
@@ -209,6 +209,10 @@ export class BitbucketUrlReader implements UrlReader {
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
readTree(): Promise<ReadTreeResponse> {
|
||||
throw new Error('BitbucketUrlReader does not implement readTree');
|
||||
}
|
||||
|
||||
toString() {
|
||||
const { host, token, username, appPassword } = this.config;
|
||||
let authed = Boolean(token);
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
import fetch from 'cross-fetch';
|
||||
import { NotFoundError } from '../errors';
|
||||
import { UrlReader } from './types';
|
||||
import { ReadTreeResponse, UrlReader } from './types';
|
||||
|
||||
/**
|
||||
* A UrlReader that does a plain fetch of the URL.
|
||||
@@ -41,6 +41,10 @@ export class FetchUrlReader implements UrlReader {
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
readTree(): Promise<ReadTreeResponse> {
|
||||
throw new Error('FetchUrlReader does not implement readTree');
|
||||
}
|
||||
|
||||
toString() {
|
||||
return 'fetch{}';
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
import fetch from 'cross-fetch';
|
||||
import { Config } from '@backstage/config';
|
||||
import { NotFoundError } from '../errors';
|
||||
import { ReaderFactory, UrlReader } from './types';
|
||||
import { ReaderFactory, ReadTreeResponse, UrlReader } from './types';
|
||||
|
||||
type Options = {
|
||||
host: string;
|
||||
@@ -87,6 +87,10 @@ export class GitlabUrlReader implements UrlReader {
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
readTree(): Promise<ReadTreeResponse> {
|
||||
throw new Error('GitlabUrlReader does not implement readTree');
|
||||
}
|
||||
|
||||
// Converts
|
||||
// from: https://gitlab.example.com/a/b/blob/master/c.yaml
|
||||
// to: https://gitlab.example.com/a/b/raw/master/c.yaml
|
||||
|
||||
@@ -66,19 +66,12 @@ export class UrlReaderPredicateMux implements UrlReader {
|
||||
|
||||
for (const { predicate, reader } of this.readers) {
|
||||
if (predicate(parsed)) {
|
||||
if (reader.readTree) return reader.readTree(repoUrl, options);
|
||||
throw new Error(
|
||||
`Trying to call readTree on UrlReader which does not support the feature.`,
|
||||
);
|
||||
return reader.readTree(repoUrl, options);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.fallback) {
|
||||
if (this.fallback.readTree)
|
||||
return this.fallback.readTree(repoUrl, options);
|
||||
throw new Error(
|
||||
`Trying to call readTree on UrlReader which does not support the feature.`,
|
||||
);
|
||||
return this.fallback.readTree(repoUrl, options);
|
||||
}
|
||||
|
||||
throw new Error(`No reader found that could handle '${repoUrl}'`);
|
||||
|
||||
@@ -28,7 +28,7 @@ export type ReadTreeOptions = {
|
||||
*/
|
||||
export type UrlReader = {
|
||||
read(url: string): Promise<Buffer>;
|
||||
readTree?(url: string, options?: ReadTreeOptions): Promise<ReadTreeResponse>;
|
||||
readTree(url: string, options?: ReadTreeOptions): Promise<ReadTreeResponse>;
|
||||
};
|
||||
|
||||
export type UrlReaderPredicateTuple = {
|
||||
|
||||
@@ -157,14 +157,14 @@ describe('CodeOwnersProcessor', () => {
|
||||
const read = jest
|
||||
.fn()
|
||||
.mockResolvedValue(mockReadResult({ data: ownersText }));
|
||||
const reader = { read };
|
||||
const reader = { read, readTree: jest.fn() };
|
||||
const result = await findRawCodeOwners(mockLocation(), reader);
|
||||
expect(result).toEqual(ownersText);
|
||||
});
|
||||
|
||||
it('should raise error when no codeowner', async () => {
|
||||
const read = jest.fn().mockRejectedValue(mockReadResult());
|
||||
const reader = { read };
|
||||
const reader = { read, readTree: jest.fn() };
|
||||
|
||||
await expect(
|
||||
findRawCodeOwners(mockLocation(), reader),
|
||||
@@ -178,7 +178,7 @@ describe('CodeOwnersProcessor', () => {
|
||||
.mockImplementationOnce(() => mockReadResult({ error: 'foo' }))
|
||||
.mockImplementationOnce(() => mockReadResult({ error: 'bar' }))
|
||||
.mockResolvedValue(mockReadResult({ data: ownersText }));
|
||||
const reader = { read };
|
||||
const reader = { read, readTree: jest.fn() };
|
||||
|
||||
const result = await findRawCodeOwners(mockLocation(), reader);
|
||||
|
||||
@@ -197,7 +197,7 @@ describe('CodeOwnersProcessor', () => {
|
||||
const read = jest
|
||||
.fn()
|
||||
.mockResolvedValue(mockReadResult({ data: mockCodeOwnersText() }));
|
||||
const reader = { read };
|
||||
const reader = { read, readTree: jest.fn() };
|
||||
|
||||
const owner = await resolveCodeOwner(mockLocation(), reader);
|
||||
expect(owner).toBe('backstage-core');
|
||||
@@ -207,7 +207,7 @@ describe('CodeOwnersProcessor', () => {
|
||||
const read = jest
|
||||
.fn()
|
||||
.mockImplementation(() => mockReadResult({ error: 'error: foo' }));
|
||||
const reader = { read };
|
||||
const reader = { read, readTree: jest.fn() };
|
||||
|
||||
await expect(
|
||||
resolveCodeOwner(mockLocation(), reader),
|
||||
@@ -221,7 +221,7 @@ describe('CodeOwnersProcessor', () => {
|
||||
const read = jest
|
||||
.fn()
|
||||
.mockResolvedValue(mockReadResult({ data: mockCodeOwnersText() }));
|
||||
const reader = { read };
|
||||
const reader = { read, readTree: jest.fn() };
|
||||
const processor = new CodeOwnersProcessor({ reader });
|
||||
|
||||
return { entity, processor, read };
|
||||
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
|
||||
describe('PlaceholderProcessor', () => {
|
||||
const read: jest.MockedFunction<ResolverRead> = jest.fn();
|
||||
const reader: UrlReader = { read };
|
||||
const reader: UrlReader = { read, readTree: jest.fn() };
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
|
||||
@@ -40,7 +40,10 @@ const dummyEntityYaml = yaml.stringify(dummyEntity);
|
||||
|
||||
describe('CatalogBuilder', () => {
|
||||
let db: Knex<any, unknown[]>;
|
||||
const reader: jest.Mocked<UrlReader> = { read: jest.fn() };
|
||||
const reader: jest.Mocked<UrlReader> = {
|
||||
read: jest.fn(),
|
||||
readTree: jest.fn(),
|
||||
};
|
||||
const env: CatalogEnvironment = {
|
||||
logger: getVoidLogger(),
|
||||
database: { getClient: async () => db },
|
||||
|
||||
@@ -179,13 +179,7 @@ export const getDocFilesFromRepository = async (
|
||||
entity,
|
||||
);
|
||||
|
||||
if (reader.readTree) {
|
||||
const response = await reader.readTree(target);
|
||||
const response = await reader.readTree(target);
|
||||
|
||||
return response.dir();
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`No readTree method available on the UrlReader for ${target}`,
|
||||
);
|
||||
return await response.dir();
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user