backend-common: Remove read method from UrlReader
Signed-off-by: Johan Haals <johan.haals@gmail.com>
This commit is contained in:
@@ -33,9 +33,19 @@ import { MergeResult } from 'isomorphic-git';
|
||||
import { PushResult } from 'isomorphic-git';
|
||||
import { Readable } from 'stream';
|
||||
import { ReadCommitResult } from 'isomorphic-git';
|
||||
import { ReadTreeOptions } from '@backstage/backend-plugin-api';
|
||||
import { ReadTreeResponse } from '@backstage/backend-plugin-api';
|
||||
import { ReadTreeResponseDirOptions } from '@backstage/backend-plugin-api';
|
||||
import { ReadTreeResponseFile } from '@backstage/backend-plugin-api';
|
||||
import { ReadUrlOptions } from '@backstage/backend-plugin-api';
|
||||
import { ReadUrlResponse } from '@backstage/backend-plugin-api';
|
||||
import { RequestHandler } from 'express';
|
||||
import { Router } from 'express';
|
||||
import { SearchOptions } from '@backstage/backend-plugin-api';
|
||||
import { SearchResponse } from '@backstage/backend-plugin-api';
|
||||
import { SearchResponseFile } from '@backstage/backend-plugin-api';
|
||||
import { Server } from 'http';
|
||||
import { UrlReaderService as UrlReader } from '@backstage/backend-plugin-api';
|
||||
import { V1PodTemplateSpec } from '@kubernetes/client-node';
|
||||
import * as winston from 'winston';
|
||||
import { Writable } from 'stream';
|
||||
@@ -533,30 +543,11 @@ export type ReaderFactory = (options: {
|
||||
treeResponseFactory: ReadTreeResponseFactory;
|
||||
}) => UrlReaderPredicateTuple[];
|
||||
|
||||
// @public
|
||||
export type ReadTreeOptions = {
|
||||
filter?(
|
||||
path: string,
|
||||
info?: {
|
||||
size: number;
|
||||
},
|
||||
): boolean;
|
||||
etag?: string;
|
||||
signal?: AbortSignal;
|
||||
};
|
||||
export { ReadTreeOptions };
|
||||
|
||||
// @public
|
||||
export type ReadTreeResponse = {
|
||||
files(): Promise<ReadTreeResponseFile[]>;
|
||||
archive(): Promise<NodeJS.ReadableStream>;
|
||||
dir(options?: ReadTreeResponseDirOptions): Promise<string>;
|
||||
etag: string;
|
||||
};
|
||||
export { ReadTreeResponse };
|
||||
|
||||
// @public
|
||||
export type ReadTreeResponseDirOptions = {
|
||||
targetDir?: string;
|
||||
};
|
||||
export { ReadTreeResponseDirOptions };
|
||||
|
||||
// @public
|
||||
export interface ReadTreeResponseFactory {
|
||||
@@ -587,24 +578,11 @@ export type ReadTreeResponseFactoryOptions = {
|
||||
) => boolean;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type ReadTreeResponseFile = {
|
||||
path: string;
|
||||
content(): Promise<Buffer>;
|
||||
};
|
||||
export { ReadTreeResponseFile };
|
||||
|
||||
// @public
|
||||
export type ReadUrlOptions = {
|
||||
etag?: string;
|
||||
signal?: AbortSignal;
|
||||
};
|
||||
export { ReadUrlOptions };
|
||||
|
||||
// @public
|
||||
export type ReadUrlResponse = {
|
||||
buffer(): Promise<Buffer>;
|
||||
stream?(): Readable;
|
||||
etag?: string;
|
||||
};
|
||||
export { ReadUrlResponse };
|
||||
|
||||
// @public
|
||||
export class ReadUrlResponseFactory {
|
||||
@@ -652,23 +630,11 @@ export type RunContainerOptions = {
|
||||
pullImage?: boolean;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type SearchOptions = {
|
||||
etag?: string;
|
||||
signal?: AbortSignal;
|
||||
};
|
||||
export { SearchOptions };
|
||||
|
||||
// @public
|
||||
export type SearchResponse = {
|
||||
files: SearchResponseFile[];
|
||||
etag: string;
|
||||
};
|
||||
export { SearchResponse };
|
||||
|
||||
// @public
|
||||
export type SearchResponseFile = {
|
||||
url: string;
|
||||
content(): Promise<Buffer>;
|
||||
};
|
||||
export { SearchResponseFile };
|
||||
|
||||
// @public
|
||||
export class ServerTokenManager implements TokenManager {
|
||||
@@ -755,13 +721,7 @@ export interface TokenManager {
|
||||
}>;
|
||||
}
|
||||
|
||||
// @public
|
||||
export type UrlReader = {
|
||||
read(url: string): Promise<Buffer>;
|
||||
readUrl(url: string, options?: ReadUrlOptions): Promise<ReadUrlResponse>;
|
||||
readTree(url: string, options?: ReadTreeOptions): Promise<ReadTreeResponse>;
|
||||
search(url: string, options?: SearchOptions): Promise<SearchResponse>;
|
||||
};
|
||||
export { UrlReader };
|
||||
|
||||
// @public
|
||||
export type UrlReaderPredicateTuple = {
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
"test:kubernetes": "backstage-cli package test -t KubernetesContainerRunner --no-watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-plugin-api": "workspace:^",
|
||||
"@backstage/cli-common": "workspace:^",
|
||||
"@backstage/config": "workspace:^",
|
||||
"@backstage/config-loader": "workspace:^",
|
||||
|
||||
@@ -117,7 +117,7 @@ export function parseUrl(
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements a {@link UrlReader} for AWS S3 buckets.
|
||||
* Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for AWS S3 buckets.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
|
||||
@@ -40,7 +40,7 @@ import {
|
||||
import { ReadUrlResponseFactory } from './ReadUrlResponseFactory';
|
||||
|
||||
/**
|
||||
* Implements a {@link UrlReader} for Azure repos.
|
||||
* Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for Azure repos.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
|
||||
@@ -42,7 +42,7 @@ import {
|
||||
import { ReadUrlResponseFactory } from './ReadUrlResponseFactory';
|
||||
|
||||
/**
|
||||
* Implements a {@link UrlReader} for files from Bitbucket Cloud.
|
||||
* Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for files from Bitbucket Cloud.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
|
||||
@@ -41,7 +41,7 @@ import {
|
||||
import { ReadUrlResponseFactory } from './ReadUrlResponseFactory';
|
||||
|
||||
/**
|
||||
* Implements a {@link UrlReader} for files from Bitbucket Server APIs.
|
||||
* Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for files from Bitbucket Server APIs.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
|
||||
@@ -43,7 +43,7 @@ import {
|
||||
import { ReadUrlResponseFactory } from './ReadUrlResponseFactory';
|
||||
|
||||
/**
|
||||
* Implements a {@link UrlReader} for files from Bitbucket v1 and v2 APIs, such
|
||||
* Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for files from Bitbucket v1 and v2 APIs, such
|
||||
* as the one exposed by Bitbucket Cloud itself.
|
||||
*
|
||||
* @public
|
||||
|
||||
@@ -63,7 +63,7 @@ const parsePortPredicate = (port: string | undefined) => {
|
||||
};
|
||||
|
||||
/**
|
||||
* A {@link UrlReader} that does a plain fetch of the URL.
|
||||
* A {@link @backstage/backend-plugin-api#UrlReaderService} that does a plain fetch of the URL.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
|
||||
@@ -52,7 +52,7 @@ const createTemporaryDirectory = async (workDir: string): Promise<string> =>
|
||||
await fs.mkdtemp(joinPath(workDir, '/gerrit-clone-'));
|
||||
|
||||
/**
|
||||
* Implements a {@link UrlReader} for files in Gerrit.
|
||||
* Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for files in Gerrit.
|
||||
*
|
||||
* @remarks
|
||||
* To be able to link to Git contents for Gerrit providers in a user friendly
|
||||
|
||||
@@ -36,7 +36,7 @@ import {
|
||||
import { Readable } from 'stream';
|
||||
|
||||
/**
|
||||
* Implements a {@link UrlReader} for the Gitea v1 api.
|
||||
* Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for the Gitea v1 api.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
|
||||
@@ -51,7 +51,7 @@ export type GhBlobResponse =
|
||||
RestEndpointMethodTypes['git']['getBlob']['response']['data'];
|
||||
|
||||
/**
|
||||
* Implements a {@link UrlReader} for files through the GitHub v3 APIs, such as
|
||||
* Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for files through the GitHub v3 APIs, such as
|
||||
* the one exposed by GitHub itself.
|
||||
*
|
||||
* @public
|
||||
|
||||
@@ -42,7 +42,7 @@ import { trimEnd, trimStart } from 'lodash';
|
||||
import { ReadUrlResponseFactory } from './ReadUrlResponseFactory';
|
||||
|
||||
/**
|
||||
* Implements a {@link UrlReader} for files on GitLab.
|
||||
* Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for files on GitLab.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
|
||||
@@ -51,7 +51,7 @@ const parseURL = (
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements a {@link UrlReader} for files on Google GCS.
|
||||
* Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for files on Google GCS.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
|
||||
@@ -70,7 +70,6 @@ describe('UrlReaderPredicateMux', () => {
|
||||
mux.register({
|
||||
predicate: url => url.hostname === 'foo',
|
||||
reader: {
|
||||
read: jest.fn(),
|
||||
readUrl: jest.fn(),
|
||||
readTree: jest.fn(),
|
||||
search: jest.fn(),
|
||||
|
||||
@@ -45,18 +45,6 @@ export class UrlReaderPredicateMux implements UrlReader {
|
||||
this.readers.push(tuple);
|
||||
}
|
||||
|
||||
async read(url: string): Promise<Buffer> {
|
||||
const parsed = new URL(url);
|
||||
|
||||
for (const { predicate, reader } of this.readers) {
|
||||
if (predicate(parsed)) {
|
||||
return reader.read(url);
|
||||
}
|
||||
}
|
||||
|
||||
throw new NotAllowedError(notAllowedMessage(url));
|
||||
}
|
||||
|
||||
async readUrl(
|
||||
url: string,
|
||||
options?: ReadUrlOptions,
|
||||
|
||||
@@ -32,7 +32,7 @@ import { AwsS3UrlReader } from './AwsS3UrlReader';
|
||||
import { GiteaUrlReader } from './GiteaUrlReader';
|
||||
|
||||
/**
|
||||
* Creation options for {@link UrlReaders}.
|
||||
* Creation options for {@link @backstage/backend-plugin-api#UrlReaderService}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
@@ -46,13 +46,13 @@ export type UrlReadersOptions = {
|
||||
};
|
||||
|
||||
/**
|
||||
* Helps construct {@link UrlReader}s.
|
||||
* Helps construct {@link @backstage/backend-plugin-api#UrlReaderService}s.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export class UrlReaders {
|
||||
/**
|
||||
* Creates a custom {@link UrlReader} wrapper for your own set of factories.
|
||||
* Creates a custom {@link @backstage/backend-plugin-api#UrlReaderService} wrapper for your own set of factories.
|
||||
*/
|
||||
static create(options: UrlReadersOptions): UrlReader {
|
||||
const { logger, config, factories } = options;
|
||||
@@ -73,7 +73,7 @@ export class UrlReaders {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link UrlReader} wrapper that includes all the default factories
|
||||
* Creates a {@link @backstage/backend-plugin-api#UrlReaderService} wrapper that includes all the default factories
|
||||
* from this package.
|
||||
*
|
||||
* Any additional factories passed will be loaded before the default ones.
|
||||
|
||||
@@ -17,56 +17,38 @@
|
||||
import { Readable } from 'stream';
|
||||
import { Logger } from 'winston';
|
||||
import { Config } from '@backstage/config';
|
||||
import {
|
||||
UrlReaderService,
|
||||
ReadTreeResponse,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
|
||||
export type {
|
||||
UrlReaderService as UrlReader,
|
||||
ReadTreeOptions,
|
||||
ReadTreeResponse,
|
||||
ReadTreeResponseDirOptions,
|
||||
ReadTreeResponseFile,
|
||||
ReadUrlResponse,
|
||||
ReadUrlOptions,
|
||||
SearchOptions,
|
||||
SearchResponse,
|
||||
SearchResponseFile,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
|
||||
/**
|
||||
* A generic interface for fetching plain data from URLs.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type UrlReader = {
|
||||
/**
|
||||
* Reads a single file and return its content.
|
||||
* @deprecated use readUrl instead.
|
||||
*/
|
||||
read(url: string): Promise<Buffer>;
|
||||
|
||||
/**
|
||||
* Reads a single file and return its content.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* This is a replacement for the read method that supports options and
|
||||
* complex responses.
|
||||
*
|
||||
* Use this as the read method will be removed in a future release.
|
||||
*/
|
||||
readUrl(url: string, options?: ReadUrlOptions): Promise<ReadUrlResponse>;
|
||||
|
||||
/**
|
||||
* Reads a full or partial file tree.
|
||||
*/
|
||||
readTree(url: string, options?: ReadTreeOptions): Promise<ReadTreeResponse>;
|
||||
|
||||
/**
|
||||
* Searches for a file in a tree using a glob pattern.
|
||||
*/
|
||||
search(url: string, options?: SearchOptions): Promise<SearchResponse>;
|
||||
};
|
||||
|
||||
/**
|
||||
* A predicate that decides whether a specific {@link UrlReader} can handle a
|
||||
* A predicate that decides whether a specific {@link @backstage/backend-plugin-api#UrlReaderService} can handle a
|
||||
* given URL.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type UrlReaderPredicateTuple = {
|
||||
predicate: (url: URL) => boolean;
|
||||
reader: UrlReader;
|
||||
reader: UrlReaderService;
|
||||
};
|
||||
|
||||
/**
|
||||
* A factory function that can read config to construct zero or more
|
||||
* {@link UrlReader}s along with a predicate for when it should be used.
|
||||
* {@link @backstage/backend-plugin-api#UrlReaderService}s along with a predicate for when it should be used.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
@@ -76,72 +58,6 @@ export type ReaderFactory = (options: {
|
||||
treeResponseFactory: ReadTreeResponseFactory;
|
||||
}) => UrlReaderPredicateTuple[];
|
||||
|
||||
/**
|
||||
* An options object for readUrl operations.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ReadUrlOptions = {
|
||||
/**
|
||||
* An ETag which can be provided to check whether a
|
||||
* {@link UrlReader.readUrl} response has changed from a previous execution.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* In the {@link UrlReader.readUrl} response, an ETag is returned along with
|
||||
* the data. The ETag is a unique identifier of the data, usually the commit
|
||||
* SHA or ETag from the target.
|
||||
*
|
||||
* When an ETag is given in ReadUrlOptions, {@link UrlReader.readUrl} will
|
||||
* first compare the ETag against the ETag of the target. If they match,
|
||||
* {@link UrlReader.readUrl} will throw a
|
||||
* {@link @backstage/errors#NotModifiedError} indicating that the response
|
||||
* will not differ from the previous response which included this particular
|
||||
* ETag. If they do not match, {@link UrlReader.readUrl} will return the rest
|
||||
* of the response along with a new ETag.
|
||||
*/
|
||||
etag?: string;
|
||||
|
||||
/**
|
||||
* An abort signal to pass down to the underlying request.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Not all reader implementations may take this field into account.
|
||||
*/
|
||||
signal?: AbortSignal;
|
||||
};
|
||||
|
||||
/**
|
||||
* A response object for {@link UrlReader.readUrl} operations.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ReadUrlResponse = {
|
||||
/**
|
||||
* Returns the data that was read from the remote URL.
|
||||
*/
|
||||
buffer(): Promise<Buffer>;
|
||||
|
||||
/**
|
||||
* Returns the data that was read from the remote URL as a Readable stream.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* This method will be required in a future release.
|
||||
*/
|
||||
stream?(): Readable;
|
||||
|
||||
/**
|
||||
* Etag returned by content provider.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Can be used to compare and cache responses when doing subsequent calls.
|
||||
*/
|
||||
etag?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* An options object for {@link ReadUrlResponseFactory} factory methods.
|
||||
*
|
||||
@@ -151,119 +67,6 @@ export type ReadUrlResponseFactoryFromStreamOptions = {
|
||||
etag?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* An options object for {@link UrlReader.readTree} operations.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ReadTreeOptions = {
|
||||
/**
|
||||
* A filter that can be used to select which files should be included.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* The path passed to the filter function is the relative path from the URL
|
||||
* that the file tree is fetched from, without any leading '/'.
|
||||
*
|
||||
* For example, given the URL https://github.com/my/repo/tree/master/my-dir, a file
|
||||
* at https://github.com/my/repo/blob/master/my-dir/my-subdir/my-file.txt will
|
||||
* be represented as my-subdir/my-file.txt
|
||||
*
|
||||
* If no filter is provided, all files are extracted.
|
||||
*/
|
||||
filter?(path: string, info?: { size: number }): boolean;
|
||||
|
||||
/**
|
||||
* An ETag which can be provided to check whether a
|
||||
* {@link UrlReader.readTree} response has changed from a previous execution.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* In the {@link UrlReader.readTree} response, an ETag is returned along with
|
||||
* the tree blob. The ETag is a unique identifier of the tree blob, usually
|
||||
* the commit SHA or ETag from the target.
|
||||
*
|
||||
* When an ETag is given as a request option, {@link UrlReader.readTree} will
|
||||
* first compare the ETag against the ETag on the target branch. If they
|
||||
* match, {@link UrlReader.readTree} will throw a
|
||||
* {@link @backstage/errors#NotModifiedError} indicating that the response
|
||||
* will not differ from the previous response which included this particular
|
||||
* ETag. If they do not match, {@link UrlReader.readTree} will return the
|
||||
* rest of the response along with a new ETag.
|
||||
*/
|
||||
etag?: string;
|
||||
|
||||
/**
|
||||
* An abort signal to pass down to the underlying request.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Not all reader implementations may take this field into account.
|
||||
*/
|
||||
signal?: AbortSignal;
|
||||
};
|
||||
|
||||
/**
|
||||
* Options that control {@link ReadTreeResponse.dir} execution.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ReadTreeResponseDirOptions = {
|
||||
/**
|
||||
* The directory to write files to.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Defaults to the OS tmpdir, or `backend.workingDirectory` if set in config.
|
||||
*/
|
||||
targetDir?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* A response object for {@link UrlReader.readTree} operations.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ReadTreeResponse = {
|
||||
/**
|
||||
* Returns an array of all the files inside the tree, and corresponding
|
||||
* functions to read their content.
|
||||
*/
|
||||
files(): Promise<ReadTreeResponseFile[]>;
|
||||
|
||||
/**
|
||||
* Returns the tree contents as a binary archive, using a stream.
|
||||
*/
|
||||
archive(): Promise<NodeJS.ReadableStream>;
|
||||
|
||||
/**
|
||||
* Extracts the tree response into a directory and returns the path of the
|
||||
* directory.
|
||||
*
|
||||
* **NOTE**: It is the responsibility of the caller to remove the directory after use.
|
||||
*/
|
||||
dir(options?: ReadTreeResponseDirOptions): Promise<string>;
|
||||
|
||||
/**
|
||||
* Etag returned by content provider.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Can be used to compare and cache responses when doing subsequent calls.
|
||||
*/
|
||||
etag: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a single file in a {@link UrlReader.readTree} response.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ReadTreeResponseFile = {
|
||||
path: string;
|
||||
content(): Promise<Buffer>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Options that control execution of {@link ReadTreeResponseFactory} methods.
|
||||
*
|
||||
@@ -315,66 +118,3 @@ export interface ReadTreeResponseFactory {
|
||||
options: FromReadableArrayOptions,
|
||||
): Promise<ReadTreeResponse>;
|
||||
}
|
||||
|
||||
/**
|
||||
* An options object for search operations.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type SearchOptions = {
|
||||
/**
|
||||
* An etag can be provided to check whether the search response has changed from a previous execution.
|
||||
*
|
||||
* In the search() response, an etag is returned along with the files. The etag is a unique identifier
|
||||
* of the current tree, usually the commit SHA or etag from the target.
|
||||
*
|
||||
* When an etag is given in SearchOptions, search will first compare the etag against the etag
|
||||
* on the target branch. If they match, search will throw a NotModifiedError indicating that the search
|
||||
* response will not differ from the previous response which included this particular etag. If they mismatch,
|
||||
* search will return the rest of SearchResponse along with a new etag.
|
||||
*/
|
||||
etag?: string;
|
||||
|
||||
/**
|
||||
* An abort signal to pass down to the underlying request.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Not all reader implementations may take this field into account.
|
||||
*/
|
||||
signal?: AbortSignal;
|
||||
};
|
||||
|
||||
/**
|
||||
* The output of a search operation.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type SearchResponse = {
|
||||
/**
|
||||
* The files that matched the search query.
|
||||
*/
|
||||
files: SearchResponseFile[];
|
||||
|
||||
/**
|
||||
* A unique identifier of the current remote tree, usually the commit SHA or etag from the target.
|
||||
*/
|
||||
etag: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a single file in a search response.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type SearchResponseFile = {
|
||||
/**
|
||||
* The full URL to the file.
|
||||
*/
|
||||
url: string;
|
||||
|
||||
/**
|
||||
* The binary contents of the file.
|
||||
*/
|
||||
content(): Promise<Buffer>;
|
||||
};
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
/// <reference types="node" />
|
||||
|
||||
import { Config } from '@backstage/config';
|
||||
import { Handler } from 'express';
|
||||
import { Logger } from 'winston';
|
||||
@@ -12,9 +14,9 @@ import { PluginCacheManager } from '@backstage/backend-common';
|
||||
import { PluginDatabaseManager } from '@backstage/backend-common';
|
||||
import { PluginEndpointDiscovery } from '@backstage/backend-common';
|
||||
import { PluginTaskScheduler } from '@backstage/backend-tasks';
|
||||
import { Readable } from 'stream';
|
||||
import { TokenManager } from '@backstage/backend-common';
|
||||
import { TransportStreamOptions } from 'winston-transport';
|
||||
import { UrlReader } from '@backstage/backend-common';
|
||||
|
||||
// @public (undocumented)
|
||||
export interface BackendFeature {
|
||||
@@ -245,6 +247,50 @@ export interface PluginMetadataService {
|
||||
// @public (undocumented)
|
||||
const pluginMetadataServiceRef: ServiceRef<PluginMetadataService, 'plugin'>;
|
||||
|
||||
// @public
|
||||
export type ReadTreeOptions = {
|
||||
filter?(
|
||||
path: string,
|
||||
info?: {
|
||||
size: number;
|
||||
},
|
||||
): boolean;
|
||||
etag?: string;
|
||||
signal?: AbortSignal;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type ReadTreeResponse = {
|
||||
files(): Promise<ReadTreeResponseFile[]>;
|
||||
archive(): Promise<NodeJS.ReadableStream>;
|
||||
dir(options?: ReadTreeResponseDirOptions): Promise<string>;
|
||||
etag: string;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type ReadTreeResponseDirOptions = {
|
||||
targetDir?: string;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type ReadTreeResponseFile = {
|
||||
path: string;
|
||||
content(): Promise<Buffer>;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type ReadUrlOptions = {
|
||||
etag?: string;
|
||||
signal?: AbortSignal;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type ReadUrlResponse = {
|
||||
buffer(): Promise<Buffer>;
|
||||
stream?(): Readable;
|
||||
etag?: string;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export type RootLoggerService = LoggerService;
|
||||
|
||||
@@ -257,6 +303,24 @@ export type SchedulerService = PluginTaskScheduler;
|
||||
// @public (undocumented)
|
||||
const schedulerServiceRef: ServiceRef<PluginTaskScheduler, 'plugin'>;
|
||||
|
||||
// @public
|
||||
export type SearchOptions = {
|
||||
etag?: string;
|
||||
signal?: AbortSignal;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type SearchResponse = {
|
||||
files: SearchResponseFile[];
|
||||
etag: string;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type SearchResponseFile = {
|
||||
url: string;
|
||||
content(): Promise<Buffer>;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export type ServiceFactory<TService = unknown> =
|
||||
| {
|
||||
@@ -307,9 +371,13 @@ export type TypesToServiceRef<T> = {
|
||||
[key in keyof T]: ServiceRef<T[key]>;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export type UrlReaderService = UrlReader;
|
||||
// @public
|
||||
export type UrlReaderService = {
|
||||
readUrl(url: string, options?: ReadUrlOptions): Promise<ReadUrlResponse>;
|
||||
readTree(url: string, options?: ReadTreeOptions): Promise<ReadTreeResponse>;
|
||||
search(url: string, options?: SearchOptions): Promise<SearchResponse>;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
const urlReaderServiceRef: ServiceRef<UrlReader, 'plugin'>;
|
||||
const urlReaderServiceRef: ServiceRef<UrlReaderService, 'plugin'>;
|
||||
```
|
||||
|
||||
@@ -32,4 +32,15 @@ export type { PluginMetadataService } from './pluginMetadataServiceRef';
|
||||
export type { RootLoggerService } from './rootLoggerServiceRef';
|
||||
export type { SchedulerService } from './schedulerServiceRef';
|
||||
export type { TokenManagerService } from './tokenManagerServiceRef';
|
||||
export type { UrlReaderService } from './urlReaderServiceRef';
|
||||
export type {
|
||||
ReadTreeOptions,
|
||||
ReadTreeResponse,
|
||||
ReadTreeResponseDirOptions,
|
||||
ReadTreeResponseFile,
|
||||
ReadUrlResponse,
|
||||
ReadUrlOptions,
|
||||
SearchOptions,
|
||||
SearchResponse,
|
||||
SearchResponseFile,
|
||||
UrlReaderService,
|
||||
} from './urlReaderServiceRef';
|
||||
|
||||
@@ -15,10 +15,278 @@
|
||||
*/
|
||||
|
||||
import { createServiceRef } from '../system/types';
|
||||
import { UrlReader } from '@backstage/backend-common';
|
||||
import { Readable } from 'stream';
|
||||
|
||||
/** @public */
|
||||
export type UrlReaderService = UrlReader;
|
||||
/**
|
||||
* A generic interface for fetching plain data from URLs.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type UrlReaderService = {
|
||||
/**
|
||||
* Reads a single file and return its content.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* This is a replacement for the read method that supports options and
|
||||
* complex responses.
|
||||
*
|
||||
* Use this as the read method will be removed in a future release.
|
||||
*/
|
||||
readUrl(url: string, options?: ReadUrlOptions): Promise<ReadUrlResponse>;
|
||||
|
||||
/**
|
||||
* Reads a full or partial file tree.
|
||||
*/
|
||||
readTree(url: string, options?: ReadTreeOptions): Promise<ReadTreeResponse>;
|
||||
|
||||
/**
|
||||
* Searches for a file in a tree using a glob pattern.
|
||||
*/
|
||||
search(url: string, options?: SearchOptions): Promise<SearchResponse>;
|
||||
};
|
||||
|
||||
/**
|
||||
* An options object for readUrl operations.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ReadUrlOptions = {
|
||||
/**
|
||||
* An ETag which can be provided to check whether a
|
||||
* {@link UrlReaderService.readUrl} response has changed from a previous execution.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* In the {@link UrlReaderService.readUrl} response, an ETag is returned along with
|
||||
* the data. The ETag is a unique identifier of the data, usually the commit
|
||||
* SHA or ETag from the target.
|
||||
*
|
||||
* When an ETag is given in ReadUrlOptions, {@link UrlReaderService.readUrl} will
|
||||
* first compare the ETag against the ETag of the target. If they match,
|
||||
* {@link UrlReaderService.readUrl} will throw a
|
||||
* {@link @backstage/errors#NotModifiedError} indicating that the response
|
||||
* will not differ from the previous response which included this particular
|
||||
* ETag. If they do not match, {@link UrlReaderService.readUrl} will return the rest
|
||||
* of the response along with a new ETag.
|
||||
*/
|
||||
etag?: string;
|
||||
|
||||
/**
|
||||
* An abort signal to pass down to the underlying request.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Not all reader implementations may take this field into account.
|
||||
*/
|
||||
signal?: AbortSignal;
|
||||
};
|
||||
|
||||
/**
|
||||
* A response object for {@link UrlReaderService.readUrl} operations.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ReadUrlResponse = {
|
||||
/**
|
||||
* Returns the data that was read from the remote URL.
|
||||
*/
|
||||
buffer(): Promise<Buffer>;
|
||||
|
||||
/**
|
||||
* Returns the data that was read from the remote URL as a Readable stream.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* This method will be required in a future release.
|
||||
*/
|
||||
stream?(): Readable;
|
||||
|
||||
/**
|
||||
* Etag returned by content provider.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Can be used to compare and cache responses when doing subsequent calls.
|
||||
*/
|
||||
etag?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* An options object for {@link UrlReaderService.readTree} operations.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ReadTreeOptions = {
|
||||
/**
|
||||
* A filter that can be used to select which files should be included.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* The path passed to the filter function is the relative path from the URL
|
||||
* that the file tree is fetched from, without any leading '/'.
|
||||
*
|
||||
* For example, given the URL https://github.com/my/repo/tree/master/my-dir, a file
|
||||
* at https://github.com/my/repo/blob/master/my-dir/my-subdir/my-file.txt will
|
||||
* be represented as my-subdir/my-file.txt
|
||||
*
|
||||
* If no filter is provided, all files are extracted.
|
||||
*/
|
||||
filter?(path: string, info?: { size: number }): boolean;
|
||||
|
||||
/**
|
||||
* An ETag which can be provided to check whether a
|
||||
* {@link UrlReaderService.readTree} response has changed from a previous execution.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* In the {@link UrlReaderService.readTree} response, an ETag is returned along with
|
||||
* the tree blob. The ETag is a unique identifier of the tree blob, usually
|
||||
* the commit SHA or ETag from the target.
|
||||
*
|
||||
* When an ETag is given as a request option, {@link UrlReaderService.readTree} will
|
||||
* first compare the ETag against the ETag on the target branch. If they
|
||||
* match, {@link UrlReaderService.readTree} will throw a
|
||||
* {@link @backstage/errors#NotModifiedError} indicating that the response
|
||||
* will not differ from the previous response which included this particular
|
||||
* ETag. If they do not match, {@link UrlReaderService.readTree} will return the
|
||||
* rest of the response along with a new ETag.
|
||||
*/
|
||||
etag?: string;
|
||||
|
||||
/**
|
||||
* An abort signal to pass down to the underlying request.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Not all reader implementations may take this field into account.
|
||||
*/
|
||||
signal?: AbortSignal;
|
||||
};
|
||||
|
||||
/**
|
||||
* Options that control {@link ReadTreeResponse.dir} execution.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ReadTreeResponseDirOptions = {
|
||||
/**
|
||||
* The directory to write files to.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Defaults to the OS tmpdir, or `backend.workingDirectory` if set in config.
|
||||
*/
|
||||
targetDir?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* A response object for {@link UrlReaderService.readTree} operations.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ReadTreeResponse = {
|
||||
/**
|
||||
* Returns an array of all the files inside the tree, and corresponding
|
||||
* functions to read their content.
|
||||
*/
|
||||
files(): Promise<ReadTreeResponseFile[]>;
|
||||
|
||||
/**
|
||||
* Returns the tree contents as a binary archive, using a stream.
|
||||
*/
|
||||
archive(): Promise<NodeJS.ReadableStream>;
|
||||
|
||||
/**
|
||||
* Extracts the tree response into a directory and returns the path of the
|
||||
* directory.
|
||||
*
|
||||
* **NOTE**: It is the responsibility of the caller to remove the directory after use.
|
||||
*/
|
||||
dir(options?: ReadTreeResponseDirOptions): Promise<string>;
|
||||
|
||||
/**
|
||||
* Etag returned by content provider.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Can be used to compare and cache responses when doing subsequent calls.
|
||||
*/
|
||||
etag: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a single file in a {@link UrlReaderService.readTree} response.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ReadTreeResponseFile = {
|
||||
path: string;
|
||||
content(): Promise<Buffer>;
|
||||
};
|
||||
|
||||
/**
|
||||
* An options object for search operations.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type SearchOptions = {
|
||||
/**
|
||||
* An etag can be provided to check whether the search response has changed from a previous execution.
|
||||
*
|
||||
* In the search() response, an etag is returned along with the files. The etag is a unique identifier
|
||||
* of the current tree, usually the commit SHA or etag from the target.
|
||||
*
|
||||
* When an etag is given in SearchOptions, search will first compare the etag against the etag
|
||||
* on the target branch. If they match, search will throw a NotModifiedError indicating that the search
|
||||
* response will not differ from the previous response which included this particular etag. If they mismatch,
|
||||
* search will return the rest of SearchResponse along with a new etag.
|
||||
*/
|
||||
etag?: string;
|
||||
|
||||
/**
|
||||
* An abort signal to pass down to the underlying request.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Not all reader implementations may take this field into account.
|
||||
*/
|
||||
signal?: AbortSignal;
|
||||
};
|
||||
|
||||
/**
|
||||
* The output of a search operation.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type SearchResponse = {
|
||||
/**
|
||||
* The files that matched the search query.
|
||||
*/
|
||||
files: SearchResponseFile[];
|
||||
|
||||
/**
|
||||
* A unique identifier of the current remote tree, usually the commit SHA or etag from the target.
|
||||
*/
|
||||
etag: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a single file in a search response.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type SearchResponseFile = {
|
||||
/**
|
||||
* The full URL to the file.
|
||||
*/
|
||||
url: string;
|
||||
|
||||
/**
|
||||
* The binary contents of the file.
|
||||
*/
|
||||
content(): Promise<Buffer>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @public
|
||||
|
||||
@@ -255,7 +255,6 @@ describe('replaceReadme', () => {
|
||||
}),
|
||||
readTree: jest.fn(),
|
||||
search: jest.fn(),
|
||||
read: jest.fn(),
|
||||
};
|
||||
|
||||
const result = await replaceReadme(
|
||||
|
||||
@@ -84,10 +84,14 @@ export class OpenApiRefProcessor implements CatalogProcessor {
|
||||
|
||||
this.logger.debug(`Bundling OpenAPI specification from ${location.target}`);
|
||||
try {
|
||||
const read = async (url: string) => {
|
||||
const { buffer } = await this.reader.readUrl(url);
|
||||
return await buffer();
|
||||
};
|
||||
const bundledSpec = await bundleFileWithRefs(
|
||||
definition.toString(),
|
||||
location.target,
|
||||
this.reader.read,
|
||||
read,
|
||||
resolveUrl,
|
||||
);
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@ const integrations = ScmIntegrations.fromConfig(new ConfigReader({}));
|
||||
|
||||
describe('PlaceholderProcessor', () => {
|
||||
const reader: jest.Mocked<UrlReader> = {
|
||||
read: jest.fn(),
|
||||
readTree: jest.fn(),
|
||||
search: jest.fn(),
|
||||
readUrl: jest.fn(),
|
||||
|
||||
@@ -194,7 +194,6 @@ describe('UrlReaderProcessor', () => {
|
||||
const logger = getVoidLogger();
|
||||
|
||||
const reader: jest.Mocked<UrlReader> = {
|
||||
read: jest.fn(),
|
||||
readUrl: jest.fn(),
|
||||
readTree: jest.fn(),
|
||||
search: jest.fn().mockImplementation(async () => []),
|
||||
|
||||
@@ -75,7 +75,6 @@ describe('fetch:cookiecutter', () => {
|
||||
|
||||
const mockReader: UrlReader = {
|
||||
readUrl: jest.fn(),
|
||||
read: jest.fn(),
|
||||
readTree: jest.fn(),
|
||||
search: jest.fn(),
|
||||
};
|
||||
|
||||
@@ -74,7 +74,6 @@ describe('fetch:rails', () => {
|
||||
};
|
||||
|
||||
const mockReader: UrlReader = {
|
||||
read: jest.fn(),
|
||||
readUrl: jest.fn(),
|
||||
readTree: jest.fn(),
|
||||
search: jest.fn(),
|
||||
|
||||
@@ -39,7 +39,6 @@ describe('fetchContent helper', () => {
|
||||
|
||||
const readTree = jest.fn();
|
||||
const reader: UrlReader = {
|
||||
read: jest.fn(),
|
||||
readUrl: jest.fn(),
|
||||
readTree,
|
||||
search: jest.fn(),
|
||||
|
||||
@@ -34,7 +34,6 @@ describe('fetch:plain', () => {
|
||||
);
|
||||
const reader: UrlReader = {
|
||||
readUrl: jest.fn(),
|
||||
read: jest.fn(),
|
||||
readTree: jest.fn(),
|
||||
search: jest.fn(),
|
||||
};
|
||||
|
||||
@@ -53,7 +53,6 @@ describe('DefaultCatalogCollatorFactory', () => {
|
||||
readable._read = () => {};
|
||||
reader = {
|
||||
search: jest.fn(),
|
||||
read: jest.fn(),
|
||||
readTree: jest.fn(),
|
||||
readUrl: jest.fn(),
|
||||
};
|
||||
|
||||
@@ -53,7 +53,6 @@ export async function startStandaloneServer(
|
||||
});
|
||||
const discovery = SingleHostDiscovery.fromConfig(config);
|
||||
const mockUrlReader: jest.Mocked<UrlReader> = {
|
||||
read: jest.fn(),
|
||||
readUrl: jest.fn(),
|
||||
readTree: jest.fn(),
|
||||
search: jest.fn(),
|
||||
|
||||
@@ -45,7 +45,6 @@ const createMockEntity = (annotations: {}) => {
|
||||
|
||||
const mockConfig = new ConfigReader({});
|
||||
const mockUrlReader: jest.Mocked<UrlReader> = {
|
||||
read: jest.fn(),
|
||||
readUrl: jest.fn(),
|
||||
readTree: jest.fn(),
|
||||
search: jest.fn(),
|
||||
|
||||
@@ -3392,6 +3392,7 @@ __metadata:
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@backstage/backend-common@workspace:packages/backend-common"
|
||||
dependencies:
|
||||
"@backstage/backend-plugin-api": "workspace:^"
|
||||
"@backstage/backend-test-utils": "workspace:^"
|
||||
"@backstage/cli": "workspace:^"
|
||||
"@backstage/cli-common": "workspace:^"
|
||||
|
||||
Reference in New Issue
Block a user