Merge pull request #9955 from backstage/blam/scaffolder-breaking-changes

🧹 remove the deprecations from the `scaffolder` and other related packages
This commit is contained in:
Fredrik Adelöw
2022-03-07 13:45:15 +01:00
committed by GitHub
66 changed files with 233 additions and 1678 deletions
+21
View File
@@ -0,0 +1,21 @@
---
'@backstage/plugin-scaffolder': minor
'@backstage/plugin-scaffolder-backend': minor
'@backstage/plugin-scaffolder-common': minor
---
The following deprecations are now breaking and have been removed:
- **BREAKING**: Support for `backstage.io/v1beta2` Software Templates has been removed. Please migrate your legacy templates to the new `scaffolder.backstage.io/v1beta3` `apiVersion` by following the [migration guide](https://backstage.io/docs/features/software-templates/migrating-from-v1beta2-to-v1beta3)
- **BREAKING**: Removed the deprecated `TemplateMetadata`. Please use `TemplateInfo` instead.
- **BREAKING**: Removed the deprecated `context.baseUrl`. It's now available on `context.templateInfo.baseUrl`.
- **BREAKING**: Removed the deprecated `DispatchResult`, use `TaskBrokerDispatchResult` instead.
- **BREAKING**: Removed the deprecated `runCommand`, use `executeShellCommond` instead.
- **BREAKING**: Removed the deprecated `Status` in favour of `TaskStatus` instead.
- **BREAKING**: Removed the deprecated `TaskState` in favour of `CurrentClaimedTask` instead.
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/create-app': patch
'@backstage/plugin-catalog-backend': minor
---
- **BREAKING**: Support for `backstage.io/v1beta2` Software Templates has been removed. Please migrate your legacy templates to the new `scaffolder.backstage.io/v1beta3` `apiVersion` by following the [migration guide](https://backstage.io/docs/features/software-templates/migrating-from-v1beta2-to-v1beta3)
+12 -14
View File
@@ -24,7 +24,7 @@ import { isChildPath } from '@backstage/cli-common';
import { JsonValue } from '@backstage/types';
import { Knex } from 'knex';
import { LoadConfigOptionsRemote } from '@backstage/config-loader';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
import { MergeResult } from 'isomorphic-git';
import { PushResult } from 'isomorphic-git';
import { Readable } from 'stream';
@@ -135,7 +135,7 @@ export class CacheManager {
// @public
export type CacheManagerOptions = {
logger?: Logger_2;
logger?: Logger;
onError?: (err: Error) => void;
};
@@ -187,7 +187,7 @@ export function createServiceBuilder(_module: NodeModule): ServiceBuilder;
// @public
export function createStatusCheckRouter(options: {
logger: Logger_2;
logger: Logger;
path?: string;
statusCheck?: StatusCheck;
}): Promise<express.Router>;
@@ -227,7 +227,7 @@ export function errorHandler(
// @public
export type ErrorHandlerOptions = {
showStackTraces?: boolean;
logger?: Logger_2;
logger?: Logger;
logClientErrors?: boolean;
};
@@ -297,7 +297,7 @@ export class Git {
static fromAuth: (options: {
username?: string;
password?: string;
logger?: Logger_2;
logger?: Logger;
}) => Git;
// (undocumented)
init(options: { dir: string; defaultBranch?: string }): Promise<void>;
@@ -373,7 +373,7 @@ export function isDatabaseConflictError(e: unknown): boolean;
// @public
export function loadBackendConfig(options: {
logger: Logger_2;
logger: Logger;
remote?: LoadConfigOptionsRemote;
argv: string[];
}): Promise<Config>;
@@ -403,7 +403,7 @@ export type PluginEndpointDiscovery = {
// @public
export type ReaderFactory = (options: {
config: Config;
logger: Logger_2;
logger: Logger;
treeResponseFactory: ReadTreeResponseFactory;
}) => UrlReaderPredicateTuple[];
@@ -480,12 +480,10 @@ export type ReadUrlResponse = {
};
// @public
export function requestLoggingHandler(logger?: Logger_2): RequestHandler;
export function requestLoggingHandler(logger?: Logger): RequestHandler;
// @public
export type RequestLoggingHandlerFactory = (
logger?: Logger_2,
) => RequestHandler;
export type RequestLoggingHandlerFactory = (logger?: Logger) => RequestHandler;
// @public
export function resolvePackagePath(name: string, ...paths: string[]): string;
@@ -531,7 +529,7 @@ export class ServerTokenManager implements TokenManager {
static fromConfig(
config: Config,
options: {
logger: Logger_2;
logger: Logger;
},
): ServerTokenManager;
// (undocumented)
@@ -547,7 +545,7 @@ export type ServiceBuilder = {
loadConfig(config: Config): ServiceBuilder;
setPort(port: number): ServiceBuilder;
setHost(host: string): ServiceBuilder;
setLogger(logger: Logger_2): ServiceBuilder;
setLogger(logger: Logger): ServiceBuilder;
enableCors(options: cors.CorsOptions): ServiceBuilder;
setHttpsSettings(settings: {
certificate:
@@ -631,7 +629,7 @@ export class UrlReaders {
// @public
export type UrlReadersOptions = {
config: Config;
logger: Logger_2;
logger: Logger;
factories?: ReaderFactory[];
};
+3 -3
View File
@@ -7,7 +7,7 @@ import { AbortSignal as AbortSignal_2 } from 'node-abort-controller';
import { Config } from '@backstage/config';
import { DatabaseManager } from '@backstage/backend-common';
import { Duration } from 'luxon';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
// @public
export interface PluginTaskScheduler {
@@ -31,14 +31,14 @@ export type TaskFunction =
// @public
export class TaskScheduler {
constructor(databaseManager: DatabaseManager, logger: Logger_2);
constructor(databaseManager: DatabaseManager, logger: Logger);
forPlugin(pluginId: string): PluginTaskScheduler;
// (undocumented)
static fromConfig(
config: Config,
options?: {
databaseManager?: DatabaseManager;
logger?: Logger_2;
logger?: Logger;
},
): TaskScheduler;
}
+2 -2
View File
@@ -5,7 +5,7 @@
```ts
import { Config } from '@backstage/config';
import express from 'express';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
// @public
export interface AirbrakeConfig {
@@ -21,6 +21,6 @@ export function extractAirbrakeConfig(config: Config): AirbrakeConfig;
// @public
export interface RouterOptions {
airbrakeConfig: AirbrakeConfig;
logger: Logger_2;
logger: Logger;
}
```
+2 -2
View File
@@ -5,7 +5,7 @@
```ts
import { Config } from '@backstage/config';
import express from 'express';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
import { PluginDatabaseManager } from '@backstage/backend-common';
// Warning: (ae-missing-release-tag) "createRouter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
@@ -23,7 +23,7 @@ export interface RouterOptions {
database?: PluginDatabaseManager;
disableConfigInjection?: boolean;
// (undocumented)
logger: Logger_2;
logger: Logger;
staticFallbackHandler?: express.Handler;
}
```
+4 -4
View File
@@ -11,7 +11,7 @@ import { CatalogApi } from '@backstage/catalog-client';
import { Config } from '@backstage/config';
import express from 'express';
import { JsonValue } from '@backstage/types';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
import { PluginDatabaseManager } from '@backstage/backend-common';
import { PluginEndpointDiscovery } from '@backstage/backend-common';
import { Profile } from 'passport';
@@ -85,7 +85,7 @@ export type AuthProviderFactoryOptions = {
providerId: string;
globalConfig: AuthProviderConfig;
config: Config;
logger: Logger_2;
logger: Logger;
tokenManager: TokenManager;
tokenIssuer: TokenIssuer;
discovery: PluginEndpointDiscovery;
@@ -106,7 +106,7 @@ export interface AuthProviderRouteHandlers {
export type AuthResolverContext = {
tokenIssuer: TokenIssuer;
catalogIdentityClient: CatalogIdentityClient;
logger: Logger_2;
logger: Logger;
};
// Warning: (ae-missing-release-tag) "AuthResponse" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
@@ -642,7 +642,7 @@ export interface RouterOptions {
// (undocumented)
discovery: PluginEndpointDiscovery;
// (undocumented)
logger: Logger_2;
logger: Logger;
// Warning: (ae-forgotten-export) The symbol "ProviderFactories" needs to be exported by the entry point index.d.ts
//
// (undocumented)
+3 -3
View File
@@ -10,7 +10,7 @@ import { Config } from '@backstage/config';
import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common';
import express from 'express';
import { GitRepository } from 'azure-devops-node-api/interfaces/GitInterfaces';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
import { PullRequest } from '@backstage/plugin-azure-devops-common';
import { PullRequestOptions } from '@backstage/plugin-azure-devops-common';
import { RepoBuild } from '@backstage/plugin-azure-devops-common';
@@ -22,7 +22,7 @@ import { WebApi } from 'azure-devops-node-api';
//
// @public (undocumented)
export class AzureDevOpsApi {
constructor(logger: Logger_2, webApi: WebApi);
constructor(logger: Logger, webApi: WebApi);
// (undocumented)
getAllTeams(): Promise<Team[]>;
// (undocumented)
@@ -96,7 +96,7 @@ export interface RouterOptions {
// (undocumented)
config: Config;
// (undocumented)
logger: Logger_2;
logger: Logger;
}
// (No @packageDocumentation comment for this package)
+2 -2
View File
@@ -5,7 +5,7 @@
```ts
import { Config } from '@backstage/config';
import express from 'express';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
import { PluginDatabaseManager } from '@backstage/backend-common';
// Warning: (ae-missing-release-tag) "createRouter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
@@ -22,7 +22,7 @@ export interface RouterOptions {
// (undocumented)
database: PluginDatabaseManager;
// (undocumented)
logger: Logger_2;
logger: Logger;
}
// (No @packageDocumentation comment for this package)
@@ -8,7 +8,7 @@ import { CatalogProcessorEmit } from '@backstage/plugin-catalog-backend';
import { CatalogProcessorParser } from '@backstage/plugin-catalog-backend';
import { Config } from '@backstage/config';
import { LocationSpec } from '@backstage/plugin-catalog-backend';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
import { UrlReader } from '@backstage/backend-common';
// @public
@@ -17,7 +17,7 @@ export class AwsOrganizationCloudAccountProcessor implements CatalogProcessor {
static fromConfig(
config: Config,
options: {
logger: Logger_2;
logger: Logger;
},
): AwsOrganizationCloudAccountProcessor;
// (undocumented)
@@ -7,20 +7,20 @@ import { CatalogProcessor } from '@backstage/plugin-catalog-backend';
import { CatalogProcessorEmit } from '@backstage/plugin-catalog-backend';
import { Config } from '@backstage/config';
import { LocationSpec } from '@backstage/plugin-catalog-backend';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
import { ScmIntegrationRegistry } from '@backstage/integration';
// @public
export class AzureDevOpsDiscoveryProcessor implements CatalogProcessor {
constructor(options: {
integrations: ScmIntegrationRegistry;
logger: Logger_2;
logger: Logger;
});
// (undocumented)
static fromConfig(
config: Config,
options: {
logger: Logger_2;
logger: Logger;
},
): AzureDevOpsDiscoveryProcessor;
// (undocumented)
@@ -7,7 +7,7 @@ import { CatalogProcessor } from '@backstage/plugin-catalog-backend';
import { CatalogProcessorEmit } from '@backstage/plugin-catalog-backend';
import { Config } from '@backstage/config';
import { LocationSpec } from '@backstage/plugin-catalog-backend';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
// @public
export class GitLabDiscoveryProcessor implements CatalogProcessor {
@@ -15,7 +15,7 @@ export class GitLabDiscoveryProcessor implements CatalogProcessor {
static fromConfig(
config: Config,
options: {
logger: Logger_2;
logger: Logger;
},
): GitLabDiscoveryProcessor;
// (undocumented)
@@ -12,7 +12,7 @@ import { EntityProviderConnection } from '@backstage/plugin-catalog-backend';
import { GroupEntity } from '@backstage/catalog-model';
import { JsonValue } from '@backstage/types';
import { LocationSpec } from '@backstage/plugin-catalog-backend';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
import { SearchEntry } from 'ldapjs';
import { SearchOptions } from 'ldapjs';
import { UserEntity } from '@backstage/catalog-model';
@@ -75,10 +75,10 @@ export const LDAP_UUID_ANNOTATION = 'backstage.io/ldap-uuid';
// @public
export class LdapClient {
constructor(client: Client, logger: Logger_2);
constructor(client: Client, logger: Logger);
// (undocumented)
static create(
logger: Logger_2,
logger: Logger,
target: string,
bind?: BindConfig,
): Promise<LdapClient>;
@@ -97,7 +97,7 @@ export class LdapOrgEntityProvider implements EntityProvider {
constructor(options: {
id: string;
provider: LdapProviderConfig;
logger: Logger_2;
logger: Logger;
userTransformer?: UserTransformer;
groupTransformer?: GroupTransformer;
});
@@ -111,7 +111,7 @@ export class LdapOrgEntityProvider implements EntityProvider {
target: string;
userTransformer?: UserTransformer;
groupTransformer?: GroupTransformer;
logger: Logger_2;
logger: Logger;
},
): LdapOrgEntityProvider;
// (undocumented)
@@ -123,7 +123,7 @@ export class LdapOrgEntityProvider implements EntityProvider {
export class LdapOrgReaderProcessor implements CatalogProcessor {
constructor(options: {
providers: LdapProviderConfig[];
logger: Logger_2;
logger: Logger;
groupTransformer?: GroupTransformer;
userTransformer?: UserTransformer;
});
@@ -131,7 +131,7 @@ export class LdapOrgReaderProcessor implements CatalogProcessor {
static fromConfig(
config: Config,
options: {
logger: Logger_2;
logger: Logger;
groupTransformer?: GroupTransformer;
userTransformer?: UserTransformer;
},
@@ -180,7 +180,7 @@ export function readLdapOrg(
options: {
groupTransformer?: GroupTransformer;
userTransformer?: UserTransformer;
logger: Logger_2;
logger: Logger;
},
): Promise<{
users: UserEntity[];
@@ -10,7 +10,7 @@ import { EntityProvider } from '@backstage/plugin-catalog-backend';
import { EntityProviderConnection } from '@backstage/plugin-catalog-backend';
import { GroupEntity } from '@backstage/catalog-model';
import { LocationSpec } from '@backstage/plugin-catalog-backend';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
import * as MicrosoftGraph from '@microsoft/microsoft-graph-types';
import * as msal from '@azure/msal-node';
import { Response as Response_2 } from 'node-fetch';
@@ -100,7 +100,7 @@ export class MicrosoftGraphOrgEntityProvider implements EntityProvider {
constructor(options: {
id: string;
provider: MicrosoftGraphProviderConfig;
logger: Logger_2;
logger: Logger;
userTransformer?: UserTransformer;
groupTransformer?: GroupTransformer;
organizationTransformer?: OrganizationTransformer;
@@ -113,7 +113,7 @@ export class MicrosoftGraphOrgEntityProvider implements EntityProvider {
options: {
id: string;
target: string;
logger: Logger_2;
logger: Logger;
userTransformer?: UserTransformer;
groupTransformer?: GroupTransformer;
organizationTransformer?: OrganizationTransformer;
@@ -128,7 +128,7 @@ export class MicrosoftGraphOrgEntityProvider implements EntityProvider {
export class MicrosoftGraphOrgReaderProcessor implements CatalogProcessor {
constructor(options: {
providers: MicrosoftGraphProviderConfig[];
logger: Logger_2;
logger: Logger;
userTransformer?: UserTransformer;
groupTransformer?: GroupTransformer;
organizationTransformer?: OrganizationTransformer;
@@ -137,7 +137,7 @@ export class MicrosoftGraphOrgReaderProcessor implements CatalogProcessor {
static fromConfig(
config: Config,
options: {
logger: Logger_2;
logger: Logger;
userTransformer?: UserTransformer;
groupTransformer?: GroupTransformer;
organizationTransformer?: OrganizationTransformer;
@@ -205,7 +205,7 @@ export function readMicrosoftGraphOrg(
userTransformer?: UserTransformer;
groupTransformer?: GroupTransformer;
organizationTransformer?: OrganizationTransformer;
logger: Logger_2;
logger: Logger;
},
): Promise<{
users: UserEntity[];
+20 -20
View File
@@ -22,7 +22,7 @@ import { GitHubIntegrationConfig } from '@backstage/integration';
import { JsonObject } from '@backstage/types';
import { JsonValue } from '@backstage/types';
import { Location as Location_2 } from '@backstage/catalog-client';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
import { Permission } from '@backstage/plugin-permission-common';
import { PermissionAuthorizer } from '@backstage/plugin-permission-common';
import { PermissionCondition } from '@backstage/plugin-permission-common';
@@ -104,9 +104,9 @@ export class BitbucketDiscoveryProcessor implements CatalogProcessor {
parser?: (options: {
integration: BitbucketIntegration;
target: string;
logger: Logger_2;
logger: Logger;
}) => AsyncIterable<CatalogProcessorResult>;
logger: Logger_2;
logger: Logger;
});
// (undocumented)
static fromConfig(
@@ -115,9 +115,9 @@ export class BitbucketDiscoveryProcessor implements CatalogProcessor {
parser?: (options: {
integration: BitbucketIntegration;
target: string;
logger: Logger_2;
logger: Logger;
}) => AsyncIterable<CatalogProcessorResult>;
logger: Logger_2;
logger: Logger;
},
): BitbucketDiscoveryProcessor;
// (undocumented)
@@ -134,7 +134,7 @@ export class BitbucketDiscoveryProcessor implements CatalogProcessor {
export type BitbucketRepositoryParser = (options: {
integration: BitbucketIntegration;
target: string;
logger: Logger_2;
logger: Logger;
}) => AsyncIterable<CatalogProcessorResult>;
// @public (undocumented)
@@ -222,7 +222,7 @@ export type CatalogEntityDocument = CatalogEntityDocument_2;
// @public (undocumented)
export type CatalogEnvironment = {
logger: Logger_2;
logger: Logger;
database: PluginDatabaseManager;
config: Config;
reader: UrlReader;
@@ -337,14 +337,14 @@ export type CatalogRulesEnforcer = {
export class CodeOwnersProcessor implements CatalogProcessor {
constructor(options: {
integrations: ScmIntegrationRegistry;
logger: Logger_2;
logger: Logger;
reader: UrlReader;
});
// (undocumented)
static fromConfig(
config: Config,
options: {
logger: Logger_2;
logger: Logger;
reader: UrlReader;
},
): CodeOwnersProcessor;
@@ -452,7 +452,7 @@ export class DefaultCatalogProcessingOrchestrator
constructor(options: {
processors: CatalogProcessor[];
integrations: ScmIntegrationRegistry;
logger: Logger_2;
logger: Logger;
parser: CatalogProcessorParser;
policy: EntityPolicy;
rulesEnforcer: CatalogRulesEnforcer;
@@ -640,14 +640,14 @@ function generalError(
export class GithubDiscoveryProcessor implements CatalogProcessor {
constructor(options: {
integrations: ScmIntegrationRegistry;
logger: Logger_2;
logger: Logger;
githubCredentialsProvider?: GithubCredentialsProvider;
});
// (undocumented)
static fromConfig(
config: Config,
options: {
logger: Logger_2;
logger: Logger;
githubCredentialsProvider?: GithubCredentialsProvider;
},
): GithubDiscoveryProcessor;
@@ -672,7 +672,7 @@ export type GithubMultiOrgConfig = Array<{
export class GithubMultiOrgReaderProcessor implements CatalogProcessor {
constructor(options: {
integrations: ScmIntegrationRegistry;
logger: Logger_2;
logger: Logger;
orgs: GithubMultiOrgConfig;
githubCredentialsProvider?: GithubCredentialsProvider;
});
@@ -680,7 +680,7 @@ export class GithubMultiOrgReaderProcessor implements CatalogProcessor {
static fromConfig(
config: Config,
options: {
logger: Logger_2;
logger: Logger;
githubCredentialsProvider?: GithubCredentialsProvider;
},
): GithubMultiOrgReaderProcessor;
@@ -700,7 +700,7 @@ export class GitHubOrgEntityProvider implements EntityProvider {
id: string;
orgUrl: string;
gitHubConfig: GitHubIntegrationConfig;
logger: Logger_2;
logger: Logger;
githubCredentialsProvider?: GithubCredentialsProvider;
});
// (undocumented)
@@ -711,7 +711,7 @@ export class GitHubOrgEntityProvider implements EntityProvider {
options: {
id: string;
orgUrl: string;
logger: Logger_2;
logger: Logger;
githubCredentialsProvider?: GithubCredentialsProvider;
},
): GitHubOrgEntityProvider;
@@ -725,14 +725,14 @@ export class GitHubOrgEntityProvider implements EntityProvider {
export class GithubOrgReaderProcessor implements CatalogProcessor {
constructor(options: {
integrations: ScmIntegrationRegistry;
logger: Logger_2;
logger: Logger;
githubCredentialsProvider?: GithubCredentialsProvider;
});
// (undocumented)
static fromConfig(
config: Config,
options: {
logger: Logger_2;
logger: Logger;
githubCredentialsProvider?: GithubCredentialsProvider;
},
): GithubOrgReaderProcessor;
@@ -1007,7 +1007,7 @@ export interface RouterOptions {
// (undocumented)
locationService: LocationService;
// (undocumented)
logger: Logger_2;
logger: Logger;
// (undocumented)
permissionIntegrationRouter?: express.Router;
// (undocumented)
@@ -1016,7 +1016,7 @@ export interface RouterOptions {
// @public (undocumented)
export class UrlReaderProcessor implements CatalogProcessor {
constructor(options: { reader: UrlReader; logger: Logger_2 });
constructor(options: { reader: UrlReader; logger: Logger });
// (undocumented)
getProcessorName(): string;
// (undocumented)
@@ -23,7 +23,6 @@ import {
SystemEntity,
UserEntity,
} from '@backstage/catalog-model';
import { TemplateEntityV1beta2 } from '@backstage/plugin-scaffolder-common';
import { BuiltinKindsEntityProcessor } from './BuiltinKindsEntityProcessor';
describe('BuiltinKindsEntityProcessor', () => {
@@ -539,38 +538,5 @@ describe('BuiltinKindsEntityProcessor', () => {
},
});
});
it('generates relations for template entities', async () => {
const entity: TemplateEntityV1beta2 = {
apiVersion: 'backstage.io/v1beta2',
kind: 'Template',
metadata: { name: 'n' },
spec: {
parameters: {},
steps: [],
type: 'service',
owner: 'o',
},
};
await processor.postProcessEntity(entity, location, emit);
expect(emit).toBeCalledTimes(2);
expect(emit).toBeCalledWith({
type: 'relation',
relation: {
source: { kind: 'Group', namespace: 'default', name: 'o' },
type: 'ownerOf',
target: { kind: 'Template', namespace: 'default', name: 'n' },
},
});
expect(emit).toBeCalledWith({
type: 'relation',
relation: {
source: { kind: 'Template', namespace: 'default', name: 'n' },
type: 'ownedBy',
target: { kind: 'Group', namespace: 'default', name: 'o' },
},
});
});
});
});
@@ -48,10 +48,6 @@ import {
UserEntity,
userEntityV1alpha1Validator,
} from '@backstage/catalog-model';
import {
TemplateEntityV1beta2,
templateEntityV1beta2Validator,
} from '@backstage/plugin-scaffolder-common';
import {
CatalogProcessor,
CatalogProcessorEmit,
@@ -67,7 +63,6 @@ export class BuiltinKindsEntityProcessor implements CatalogProcessor {
resourceEntityV1alpha1Validator,
groupEntityV1alpha1Validator,
locationEntityV1alpha1Validator,
templateEntityV1beta2Validator,
userEntityV1alpha1Validator,
systemEntityV1alpha1Validator,
domainEntityV1alpha1Validator,
@@ -135,19 +130,6 @@ export class BuiltinKindsEntityProcessor implements CatalogProcessor {
}
}
/*
* Emit relations for the Template kind
*/
if (entity.kind === 'Template') {
const template = entity as TemplateEntityV1beta2;
doEmit(
template.spec.owner,
{ defaultKind: 'Group', defaultNamespace: selfRef.namespace },
RELATION_OWNED_BY,
RELATION_OWNER_OF,
);
}
/*
* Emit relations for the Component kind
*/
+2 -2
View File
@@ -4,7 +4,7 @@
```ts
import { Config } from '@backstage/config';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
import { Module } from 'graphql-modules';
// Warning: (ae-missing-release-tag) "createModule" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
@@ -19,6 +19,6 @@ export interface ModuleOptions {
// (undocumented)
config: Config;
// (undocumented)
logger: Logger_2;
logger: Logger;
}
```
+4 -4
View File
@@ -15,7 +15,7 @@
*/
import { Entity } from '@backstage/catalog-model';
import { TemplateEntityV1beta2 } from '@backstage/plugin-scaffolder-common';
import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';
import { EntityTextFilter } from './filters';
const entities: Entity[] = [
@@ -37,9 +37,9 @@ const entities: Entity[] = [
},
];
const templates: TemplateEntityV1beta2[] = [
const templates: TemplateEntityV1beta3[] = [
{
apiVersion: 'backstage.io/v1beta2',
apiVersion: 'scaffolder.backstage.io/v1beta3',
kind: 'Template',
metadata: {
name: 'react-app',
@@ -52,7 +52,7 @@ const templates: TemplateEntityV1beta2[] = [
},
},
{
apiVersion: 'backstage.io/v1beta2',
apiVersion: 'scaffolder.backstage.io/v1beta3',
kind: 'Template',
metadata: {
name: 'gRPC service',
+2 -2
View File
@@ -5,7 +5,7 @@
```ts
import { Config } from '@backstage/config';
import express from 'express';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
import { PluginDatabaseManager } from '@backstage/backend-common';
import { PluginEndpointDiscovery } from '@backstage/backend-common';
import { UrlReader } from '@backstage/backend-common';
@@ -39,7 +39,7 @@ export interface RouterOptions {
// (undocumented)
discovery: PluginEndpointDiscovery;
// (undocumented)
logger: Logger_2;
logger: Logger;
// (undocumented)
urlReader: UrlReader;
}
+2 -2
View File
@@ -5,7 +5,7 @@
```ts
import { Config } from '@backstage/config';
import express from 'express';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
// Warning: (ae-missing-release-tag) "createRouter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
@@ -19,6 +19,6 @@ export interface RouterOptions {
// (undocumented)
config: Config;
// (undocumented)
logger: Logger_2;
logger: Logger;
}
```
+2 -2
View File
@@ -7,7 +7,7 @@ import { CatalogApi } from '@backstage/catalog-client';
import { CompoundEntityRef } from '@backstage/catalog-model';
import { Config } from '@backstage/config';
import express from 'express';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
import { PermissionAuthorizer } from '@backstage/plugin-permission-common';
// Warning: (ae-missing-release-tag) "createRouter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
@@ -94,7 +94,7 @@ export interface RouterOptions {
// (undocumented)
jenkinsInfoProvider: JenkinsInfoProvider;
// (undocumented)
logger: Logger_2;
logger: Logger;
// (undocumented)
permissions?: PermissionAuthorizer;
}
+1 -1
View File
@@ -5,7 +5,7 @@
```ts
import { Config } from '@backstage/config';
import express from 'express';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
// Warning: (ae-forgotten-export) The symbol "RouterOptions" needs to be exported by the entry point index.d.ts
// Warning: (ae-missing-release-tag) "createRouter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
+4 -4
View File
@@ -9,7 +9,7 @@ import type { FetchResponse } from '@backstage/plugin-kubernetes-common';
import type { JsonObject } from '@backstage/types';
import type { KubernetesFetchError } from '@backstage/plugin-kubernetes-common';
import type { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
import type { ObjectsByEntityResponse } from '@backstage/plugin-kubernetes-common';
import { PodStatus } from '@kubernetes/client-node/dist/top';
@@ -160,7 +160,7 @@ export interface KubernetesEnvironment {
// (undocumented)
config: Config;
// (undocumented)
logger: Logger_2;
logger: Logger;
}
// Warning: (ae-missing-release-tag) "KubernetesFetcher" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
@@ -197,7 +197,7 @@ export interface KubernetesObjectsProviderOptions {
// (undocumented)
fetcher: KubernetesFetcher;
// (undocumented)
logger: Logger_2;
logger: Logger;
// (undocumented)
objectTypesToFetch?: ObjectToFetch[];
// (undocumented)
@@ -275,7 +275,7 @@ export interface RouterOptions {
// (undocumented)
config: Config;
// (undocumented)
logger: Logger_2;
logger: Logger;
}
// Warning: (ae-missing-release-tag) "ServiceAccountClusterDetails" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
+2 -2
View File
@@ -6,7 +6,7 @@
import { Config } from '@backstage/config';
import express from 'express';
import { IdentityClient } from '@backstage/plugin-auth-node';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
import { PermissionPolicy } from '@backstage/plugin-permission-node';
import { PluginEndpointDiscovery } from '@backstage/backend-common';
@@ -22,7 +22,7 @@ export interface RouterOptions {
// (undocumented)
identity: IdentityClient;
// (undocumented)
logger: Logger_2;
logger: Logger;
// (undocumented)
policy: PermissionPolicy;
}
+1 -1
View File
@@ -5,7 +5,7 @@
```ts
import { Config } from '@backstage/config';
import express from 'express';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
import { PluginEndpointDiscovery } from '@backstage/backend-common';
// Warning: (ae-forgotten-export) The symbol "RouterOptions" needs to be exported by the entry point index.d.ts
+3 -3
View File
@@ -5,7 +5,7 @@
```ts
import { Config } from '@backstage/config';
import express from 'express';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
// Warning: (ae-missing-release-tag) "createRouter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
@@ -25,7 +25,7 @@ export function getRequestHeaders(token: string): {
//
// @public (undocumented)
export class RollbarApi {
constructor(accessToken: string, logger: Logger_2);
constructor(accessToken: string, logger: Logger);
// (undocumented)
getActivatedCounts(
projectName: string,
@@ -107,7 +107,7 @@ export interface RouterOptions {
// (undocumented)
config: Config;
// (undocumented)
logger: Logger_2;
logger: Logger;
// (undocumented)
rollbarApi?: RollbarApi;
}
+7 -24
View File
@@ -17,7 +17,7 @@ import { JsonObject } from '@backstage/types';
import { JsonValue } from '@backstage/types';
import { Knex } from 'knex';
import { LocationSpec } from '@backstage/plugin-catalog-backend';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
import { Observable } from '@backstage/types';
import { PluginDatabaseManager } from '@backstage/backend-common';
import { Schema } from 'jsonschema';
@@ -25,28 +25,23 @@ import { ScmIntegrationRegistry } from '@backstage/integration';
import { ScmIntegrations } from '@backstage/integration';
import { SpawnOptionsWithoutStdio } from 'child_process';
import { TaskSpec } from '@backstage/plugin-scaffolder-common';
import { TaskSpecV1beta3 } from '@backstage/plugin-scaffolder-common';
import { TemplateInfo } from '@backstage/plugin-scaffolder-common';
import { TemplateMetadata } from '@backstage/plugin-scaffolder-common';
import { UrlReader } from '@backstage/backend-common';
import { Writable } from 'stream';
// @public
export type ActionContext<Input extends JsonObject> = {
baseUrl?: string;
logger: Logger_2;
logger: Logger;
logStream: Writable;
secrets?: TaskSecrets;
workspacePath: string;
input: Input;
output(name: string, value: JsonValue): void;
createTemporaryDirectory(): Promise<string>;
metadata?: TemplateMetadata;
templateInfo?: TemplateInfo;
};
// @public @deprecated
export type CompletedTaskState = TaskCompletionState;
// @public
export const createBuiltinActions: (
options: CreateBuiltInActionsOptions,
@@ -297,7 +292,7 @@ export type CreateWorkerOptions = {
actionRegistry: TemplateActionRegistry;
integrations: ScmIntegrations;
workingDirectory: string;
logger: Logger_2;
logger: Logger;
additionalTemplateFilters?: Record<string, TemplateFilter>;
};
@@ -360,9 +355,6 @@ export type DatabaseTaskStoreOptions = {
database: Knex;
};
// @public @deprecated
export type DispatchResult = TaskBrokerDispatchResult;
// @public
export const executeShellCommand: (options: RunCommandOptions) => Promise<void>;
@@ -404,7 +396,7 @@ export interface RouterOptions {
// (undocumented)
database: PluginDatabaseManager;
// (undocumented)
logger: Logger_2;
logger: Logger;
// (undocumented)
reader: UrlReader;
// (undocumented)
@@ -413,9 +405,6 @@ export interface RouterOptions {
taskWorkers?: number;
}
// @public @deprecated
export const runCommand: (options: RunCommandOptions) => Promise<void>;
// @public (undocumented)
export type RunCommandOptions = {
command: string;
@@ -457,9 +446,6 @@ export type SerializedTaskEvent = {
createdAt: string;
};
// @public @deprecated
export type Status = TaskStatus;
// @public
export interface TaskBroker {
// (undocumented)
@@ -519,7 +505,7 @@ export class TaskManager implements TaskContext {
static create(
task: CurrentClaimedTask,
storage: TaskStore,
logger: Logger_2,
logger: Logger,
): TaskManager;
// (undocumented)
get done(): boolean;
@@ -530,7 +516,7 @@ export class TaskManager implements TaskContext {
// (undocumented)
get secrets(): TaskSecrets | undefined;
// (undocumented)
get spec(): TaskSpec;
get spec(): TaskSpecV1beta3;
}
// @public
@@ -538,9 +524,6 @@ export type TaskSecrets = Record<string, string> & {
backstageToken?: string;
};
// @public @deprecated
export type TaskState = CurrentClaimedTask;
// @public
export type TaskStatus =
| 'open'
-1
View File
@@ -56,7 +56,6 @@
"fs-extra": "10.0.0",
"git-url-parse": "^11.6.0",
"globby": "^11.0.0",
"handlebars": "^4.7.6",
"isbinaryfile": "^4.0.8",
"isomorphic-git": "^1.8.0",
"jsonschema": "^1.2.6",
@@ -78,6 +78,7 @@ export const createBuiltinActions = (
config,
additionalTemplateFilters,
} = options;
const githubCredentialsProvider: GithubCredentialsProvider =
DefaultGithubCredentialsProvider.fromIntegrations(integrations);
@@ -71,13 +71,6 @@ export const executeShellCommand = async (options: RunCommandOptions) => {
});
};
/**
* Run a command in a sub-process, normally a shell command.
* @public
* @deprecated use {@link executeShellCommand} instead
*/
export const runCommand = executeShellCommand;
export async function initRepoAndPush({
dir,
remoteUrl,
@@ -22,5 +22,5 @@ export * from './filesystem';
export * from './publish';
export * from './github';
export { runCommand, executeShellCommand } from './helpers';
export { executeShellCommand } from './helpers';
export type { RunCommandOptions } from './helpers';
@@ -19,22 +19,13 @@ import { Writable } from 'stream';
import { JsonValue, JsonObject } from '@backstage/types';
import { Schema } from 'jsonschema';
import { TaskSecrets } from '../tasks/types';
import {
TemplateInfo,
TemplateMetadata,
} from '@backstage/plugin-scaffolder-common';
import { TemplateInfo } from '@backstage/plugin-scaffolder-common';
/**
* ActionContext is passed into scaffolder actions.
* @public
*/
export type ActionContext<Input extends JsonObject> = {
/**
* Base URL for the location of the task spec, typically the url of the source entity file.
* @deprecated please use templateInfo.baseUrl instead
*/
baseUrl?: string;
logger: Logger;
logStream: Writable;
secrets?: TaskSecrets;
@@ -47,10 +38,6 @@ export type ActionContext<Input extends JsonObject> = {
*/
createTemporaryDirectory(): Promise<string>;
/**
* @deprecated please use templateInfo instead
*/
metadata?: TemplateMetadata;
templateInfo?: TemplateInfo;
};
@@ -1,441 +0,0 @@
/*
* Copyright 2021 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import mockFs from 'mock-fs';
import * as winston from 'winston';
import { createTemplateAction, TemplateActionRegistry } from '../actions';
import { ScmIntegrations } from '@backstage/integration';
import { ConfigReader } from '@backstage/config';
import { getVoidLogger } from '@backstage/backend-common';
import { HandlebarsWorkflowRunner } from './HandlebarsWorkflowRunner';
import { TaskContext } from './types';
import { RepoSpec } from '../actions/builtin/publish/util';
import { TaskSpec } from '@backstage/plugin-scaffolder-common';
describe('LegacyWorkflowRunner', () => {
let runner: HandlebarsWorkflowRunner;
const logger = getVoidLogger();
let actionRegistry = new TemplateActionRegistry();
let fakeActionHandler: jest.Mock;
const integrations = ScmIntegrations.fromConfig(
new ConfigReader({
integrations: {
github: [{ host: 'github.com', token: 'token' }],
},
}),
);
const createMockTaskWithSpec = (spec: TaskSpec): TaskContext => ({
spec,
complete: async () => {},
done: false,
emitLog: async () => {},
getWorkspaceName: () => Promise.resolve('test-workspace'),
});
beforeEach(() => {
winston.format.simple(); // put logform the require cache before mocking fs
mockFs({
'/tmp': mockFs.directory(),
});
actionRegistry = new TemplateActionRegistry();
actionRegistry.register({
id: 'test-action',
handler: async ctx => {
ctx.output('testOutput', 'mockOutputData');
ctx.output('badOutput', false);
},
});
fakeActionHandler = jest.fn();
actionRegistry.register({
id: 'test-metadata-action',
handler: fakeActionHandler,
});
runner = new HandlebarsWorkflowRunner({
actionRegistry,
integrations,
workingDirectory: '/tmp',
logger,
});
});
afterEach(() => {
mockFs.restore();
});
it('should fail when the action does not exist', async () => {
const task = createMockTaskWithSpec({
apiVersion: 'backstage.io/v1beta2',
steps: [{ id: 'test', name: 'test', action: 'not-found-action' }],
output: {
result: '{{ steps.test.output.testOutput }}',
},
values: {},
});
await expect(() => runner.execute(task)).rejects.toThrow(
/Template action with ID 'not-found-action' is not registered/,
);
});
it('should pass metadata through', async () => {
const entityRef = `template:default/templateName`;
const task = createMockTaskWithSpec({
apiVersion: 'backstage.io/v1beta2',
steps: [
{
id: 'test',
name: 'name',
action: 'test-metadata-action',
input: { foo: 1 },
},
],
output: {},
values: {},
templateInfo: { entityRef },
});
await runner.execute(task);
expect(fakeActionHandler.mock.calls[0][0].templateInfo).toEqual({
entityRef,
});
});
describe('templating', () => {
it('should template the output', async () => {
const task = createMockTaskWithSpec({
apiVersion: 'backstage.io/v1beta2',
steps: [{ id: 'test', name: 'test', action: 'test-action' }],
output: {
result: '{{ steps.test.output.testOutput }}',
},
values: {},
});
const { output } = await runner.execute(task);
expect(output.result).toBe('mockOutputData');
});
it('should template the input', async () => {
const inputAction = createTemplateAction<{
name: string;
}>({
id: 'test-input',
schema: {
input: {
type: 'object',
required: ['name'],
properties: {
name: {
title: 'name',
description: 'Enter name',
type: 'string',
},
},
},
},
async handler(ctx) {
if (ctx.input.name !== 'mockOutputData') {
throw new Error(
`expected name to be "mockOutputData" got ${ctx.input.name}`,
);
}
},
});
actionRegistry.register(inputAction);
const task = createMockTaskWithSpec({
apiVersion: 'backstage.io/v1beta2',
steps: [
{ id: 'test', name: 'test', action: 'test-action' },
{
id: 'test-input',
name: 'test-input',
action: 'test-input',
input: {
name: '{{ steps.test.output.testOutput }}',
},
},
],
output: {
result: '{{ steps.test.output.testOutput }}',
},
values: {},
});
const { output } = await runner.execute(task);
expect(output.result).toBe('mockOutputData');
});
});
describe('conditionals', () => {
it('should execute steps conditionally', async () => {
const task = createMockTaskWithSpec({
apiVersion: 'backstage.io/v1beta2',
steps: [
{ id: 'test', name: 'test', action: 'test-action' },
{
id: 'conditional',
name: 'conditional',
action: 'test-action',
if: '{{ steps.test.output.testOutput }}',
},
],
output: {
result: '{{ steps.conditional.output.testOutput }}',
},
values: {},
});
const { output } = await runner.execute(task);
expect(output.result).toBe('mockOutputData');
});
it('should execute steps conditionally with eq helper', async () => {
const task = createMockTaskWithSpec({
apiVersion: 'backstage.io/v1beta2',
steps: [
{ id: 'test', name: 'test', action: 'test-action' },
{
id: 'conditional',
name: 'conditional',
action: 'test-action',
if: '{{ eq steps.test.output.testOutput "mockOutputData" }}',
},
],
output: {
result: '{{ steps.conditional.output.testOutput }}',
},
values: {},
});
const { output } = await runner.execute(task);
expect(output.result).toBe('mockOutputData');
});
it('should skip test conditionally', async () => {
const task = createMockTaskWithSpec({
apiVersion: 'backstage.io/v1beta2',
steps: [
{ id: 'test', name: 'test', action: 'test-action' },
{
id: 'conditional',
name: 'conditional',
action: 'test-action',
if: '{{ steps.test.output.badOutput }}',
},
],
output: {
result: '{{ steps.conditional.output.testOutput }}',
},
values: {},
});
const { output } = await runner.execute(task);
expect(output.result).toBeUndefined();
});
});
describe('parsing', () => {
it('should parse strings as objects if possible', async () => {
const inputAction = createTemplateAction<{
address: { line1: string };
list: string[];
address2: string;
}>({
id: 'test-input',
schema: {
input: {
type: 'object',
required: ['address'],
properties: {
address: {
title: 'address',
description: 'Enter name',
type: 'object',
properties: {
line1: {
type: 'string',
},
},
},
address2: {
type: 'string',
},
list: {
type: 'array',
items: {
type: 'string',
},
},
},
},
},
async handler(ctx) {
if (ctx.input.list.length !== 1) {
throw new Error(
`expected list to have length "1" got ${ctx.input.list.length}`,
);
}
if (ctx.input.address.line1 !== 'line 1') {
throw new Error(
`expected address.line1 to be "line 1" got ${ctx.input.address.line1}`,
);
}
if (ctx.input.address2 !== '{"not valid"}') {
throw new Error(
`expected address2 to be "{"not valid"}" got ${ctx.input.address2}`,
);
}
ctx.output('address', ctx.input.address.line1);
},
});
actionRegistry.register(inputAction);
const task = createMockTaskWithSpec({
apiVersion: 'backstage.io/v1beta2',
steps: [
{
id: 'test-input',
name: 'test-input',
action: 'test-input',
input: {
address: JSON.stringify({ line1: 'line 1' }),
list: JSON.stringify(['hey!']),
address2: '{"not valid"}',
},
},
],
output: {
result: '{{ steps.test-input.output.address }}',
},
values: {},
});
const { output } = await runner.execute(task);
expect(output.result).toBe('line 1');
});
it('should provide a parseRepoUrl helper', async () => {
const inputAction = createTemplateAction<{
destination: RepoSpec;
}>({
id: 'test-input',
schema: {
input: {
type: 'object',
required: ['destination'],
properties: {
destination: {
title: 'destination',
type: 'object',
properties: {
repo: {
type: 'string',
},
host: {
type: 'string',
},
owner: {
type: 'string',
},
organization: {
type: 'string',
},
workspace: {
type: 'string',
},
project: {
type: 'string',
},
},
},
},
},
},
async handler(ctx) {
ctx.output('host', ctx.input.destination.host);
ctx.output('repo', ctx.input.destination.repo);
if (ctx.input.destination.owner) {
ctx.output('owner', ctx.input.destination.owner);
}
if (ctx.input.destination.host !== 'github.com') {
throw new Error(
`expected host to be "github.com" got ${ctx.input.destination.host}`,
);
}
if (ctx.input.destination.repo !== 'repo') {
throw new Error(
`expected repo to be "repo" got ${ctx.input.destination.repo}`,
);
}
if (
ctx.input.destination.owner &&
ctx.input.destination.owner !== 'owner'
) {
throw new Error(
`expected repo to be "owner" got ${ctx.input.destination.owner}`,
);
}
},
});
actionRegistry.register(inputAction);
const task = createMockTaskWithSpec({
apiVersion: 'backstage.io/v1beta2',
steps: [
{
id: 'test-input',
name: 'test-input',
action: 'test-input',
input: {
destination: '{{ parseRepoUrl parameters.repoUrl }}',
},
},
],
output: {
host: '{{ steps.test-input.output.host }}',
repo: '{{ steps.test-input.output.repo }}',
owner: '{{ steps.test-input.output.owner }}',
},
values: {
repoUrl: 'github.com?repo=repo&owner=owner',
},
});
const { output } = await runner.execute(task);
expect(output.host).toBe('github.com');
expect(output.repo).toBe('repo');
expect(output.owner).toBe('owner');
});
});
});
@@ -1,308 +0,0 @@
/*
* Copyright 2021 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { TaskContext, WorkflowRunner, WorkflowResponse } from './types';
import * as Handlebars from 'handlebars';
import { TemplateActionRegistry } from '..';
import { ScmIntegrations } from '@backstage/integration';
import { parseRepoUrl } from '../actions/builtin/publish/util';
import { isTruthy } from './helper';
import { PassThrough } from 'stream';
import * as winston from 'winston';
import { Logger } from 'winston';
import path from 'path';
import fs from 'fs-extra';
import { validate as validateJsonSchema } from 'jsonschema';
import { JsonObject, JsonValue } from '@backstage/types';
import { InputError } from '@backstage/errors';
import { TaskSpec, TaskSpecV1beta2 } from '@backstage/plugin-scaffolder-common';
type Options = {
workingDirectory: string;
actionRegistry: TemplateActionRegistry;
integrations: ScmIntegrations;
logger: Logger;
};
const isValidTaskSpec = (taskSpec: TaskSpec): taskSpec is TaskSpecV1beta2 =>
taskSpec.apiVersion === 'backstage.io/v1beta2';
/**
* This is the legacy workflow runner, which supports handlebars. This entire implementation will be replaced
* with the default workflow runner interface in the future so this entire thing can go bye bye.
*/
export class HandlebarsWorkflowRunner implements WorkflowRunner {
private readonly handlebars: typeof Handlebars;
constructor(private readonly options: Options) {
this.handlebars = Handlebars.create();
// TODO(blam): this should be a public facing API but it's a little
// scary right now, so we're going to lock it off like the component API is
// in the frontend until we can work out a nice way to do it.
this.handlebars.registerHelper('parseRepoUrl', repoUrl => {
return JSON.stringify(parseRepoUrl(repoUrl, this.options.integrations));
});
this.handlebars.registerHelper('projectSlug', repoUrl => {
const { owner, repo } = parseRepoUrl(repoUrl, this.options.integrations);
return `${owner}/${repo}`;
});
this.handlebars.registerHelper('json', obj => JSON.stringify(obj));
this.handlebars.registerHelper('not', value => !isTruthy(value));
this.handlebars.registerHelper('eq', (a, b) => a === b);
}
async execute(task: TaskContext): Promise<WorkflowResponse> {
if (!isValidTaskSpec(task.spec)) {
throw new InputError(`Task spec is not a valid v1beta2 task spec`);
}
const { actionRegistry } = this.options;
const workspacePath = path.join(
this.options.workingDirectory,
await task.getWorkspaceName(),
);
try {
await fs.ensureDir(workspacePath);
await task.emitLog(
`Starting up task with ${task.spec.steps.length} steps`,
);
const templateCtx: {
parameters: JsonObject;
steps: {
[stepName: string]: { output: { [outputName: string]: JsonValue } };
};
} = { parameters: task.spec.values, steps: {} };
for (const step of task.spec.steps) {
const metadata = { stepId: step.id };
try {
const taskLogger = winston.createLogger({
level: process.env.LOG_LEVEL || 'info',
format: winston.format.combine(
winston.format.colorize(),
winston.format.timestamp(),
winston.format.simple(),
),
defaultMeta: {},
});
const stream = new PassThrough();
stream.on('data', async data => {
const message = data.toString().trim();
if (message?.length > 1) {
await task.emitLog(message, metadata);
}
});
taskLogger.add(new winston.transports.Stream({ stream }));
if (step.if !== undefined) {
// Support passing values like false to disable steps
let skip = !step.if;
// Evaluate strings as handlebar templates
if (typeof step.if === 'string') {
const condition = JSON.parse(
JSON.stringify(step.if),
(_key, value) => {
if (typeof value === 'string') {
const templated = this.handlebars.compile(value, {
noEscape: true,
data: false,
preventIndent: true,
})(templateCtx);
// If it's just an empty string, treat it as undefined
if (templated === '') {
return undefined;
}
try {
return JSON.parse(templated);
} catch {
return templated;
}
}
return value;
},
);
skip = !isTruthy(condition);
}
if (skip) {
await task.emitLog(`Skipped step ${step.name}`, {
...metadata,
status: 'skipped',
});
continue;
}
}
await task.emitLog(`Beginning step ${step.name}`, {
...metadata,
status: 'processing',
});
const action = actionRegistry.get(step.action);
if (!action) {
throw new Error(`Action '${step.action}' does not exist`);
}
const input =
step.input &&
JSON.parse(JSON.stringify(step.input), (_key, value) => {
if (typeof value === 'string') {
const templated = this.handlebars.compile(value, {
noEscape: true,
data: false,
preventIndent: true,
})(templateCtx);
// If it smells like a JSON object then give it a parse as an object and if it fails return the string
if (
(templated.startsWith('"') && templated.endsWith('"')) ||
(templated.startsWith('{') && templated.endsWith('}')) ||
(templated.startsWith('[') && templated.endsWith(']'))
) {
try {
// Don't recursively JSON parse the values of this string.
// Shouldn't need to, don't want to encourage the use of returning handlebars from somewhere else
return JSON.parse(templated);
} catch {
return templated;
}
}
return templated;
}
return value;
});
if (action.schema?.input) {
const validateResult = validateJsonSchema(
input,
action.schema.input,
);
if (!validateResult.valid) {
const errors = validateResult.errors.join(', ');
throw new InputError(
`Invalid input passed to action ${action.id}, ${errors}`,
);
}
}
const stepOutputs: { [name: string]: JsonValue } = {};
// Keep track of all tmp dirs that are created by the action so we can remove them after
const tmpDirs = new Array<string>();
this.options.logger.debug(`Running ${action.id} with input`, {
input: JSON.stringify(input, null, 2),
});
await action.handler({
// deprecated in favor of templateInfo.baseUrl
baseUrl: task.spec.baseUrl,
logger: taskLogger,
logStream: stream,
input,
secrets: task.secrets ?? {},
workspacePath,
async createTemporaryDirectory() {
const tmpDir = await fs.mkdtemp(
`${workspacePath}_step-${step.id}-`,
);
tmpDirs.push(tmpDir);
return tmpDir;
},
output(name: string, value: JsonValue) {
stepOutputs[name] = value;
},
// deprecated in favor of templateInfo
metadata: task.spec.metadata,
templateInfo: task.spec.templateInfo,
});
// Remove all temporary directories that were created when executing the action
for (const tmpDir of tmpDirs) {
await fs.remove(tmpDir);
}
templateCtx.steps[step.id] = { output: stepOutputs };
await task.emitLog(`Finished step ${step.name}`, {
...metadata,
status: 'completed',
});
} catch (error) {
await task.emitLog(String(error.stack), {
...metadata,
status: 'failed',
});
throw error;
}
}
const output = JSON.parse(
JSON.stringify(task.spec.output),
(_key, value) => {
if (typeof value === 'string') {
const templated = this.handlebars.compile(value, {
noEscape: true,
data: false,
preventIndent: true,
})(templateCtx);
// If it's just an empty string, treat it as undefined
if (templated === '') {
return undefined;
}
// If it smells like a JSON object then give it a parse as an object and if it fails return the string
if (
(templated.startsWith('"') && templated.endsWith('"')) ||
(templated.startsWith('{') && templated.endsWith('}')) ||
(templated.startsWith('[') && templated.endsWith(']'))
) {
try {
// Don't recursively JSON parse the values of this string.
// Shouldn't need to, don't want to encourage the use of returning handlebars from somewhere else
return JSON.parse(templated);
} catch {
return templated;
}
}
return templated;
}
return value;
},
);
return { output };
} finally {
if (workspacePath) {
await fs.remove(workspacePath);
}
}
}
}
@@ -257,8 +257,6 @@ export class NunjucksWorkflowRunner implements WorkflowRunner {
const stepOutput: { [outputName: string]: JsonValue } = {};
await action.handler({
// deprecated in favourof templateInfo.baseUrl
baseUrl: task.spec.baseUrl,
input,
secrets: task.secrets ?? {},
logger: taskLogger,
@@ -274,8 +272,6 @@ export class NunjucksWorkflowRunner implements WorkflowRunner {
output(name: string, value: JsonValue) {
stepOutput[name] = value;
},
// deprecated in favour of templateInfo
metadata: task.spec.metadata,
templateInfo: task.spec.templateInfo,
});
@@ -120,14 +120,6 @@ export interface CurrentClaimedTask {
secrets?: TaskSecrets;
}
/**
* TaskState
*
* @public
* @deprecated use CurrentClaimedTask instead
*/
export type TaskState = CurrentClaimedTask;
function defer() {
let resolve = () => {};
const promise = new Promise<void>(_resolve => {
@@ -19,16 +19,10 @@ import { ConfigReader } from '@backstage/config';
import { DatabaseTaskStore } from './DatabaseTaskStore';
import { StorageTaskBroker } from './StorageTaskBroker';
import { TaskWorker } from './TaskWorker';
import { HandlebarsWorkflowRunner } from './HandlebarsWorkflowRunner';
import { ScmIntegrations } from '@backstage/integration';
import { TemplateActionRegistry } from '../actions';
import { NunjucksWorkflowRunner } from './NunjucksWorkflowRunner';
jest.mock('./HandlebarsWorkflowRunner');
const MockedHandlebarsWorkflowRunner =
HandlebarsWorkflowRunner as jest.Mock<HandlebarsWorkflowRunner>;
MockedHandlebarsWorkflowRunner.mockImplementation();
jest.mock('./NunjucksWorkflowRunner');
const MockedNunjucksWorkflowRunner =
NunjucksWorkflowRunner as jest.Mock<NunjucksWorkflowRunner>;
@@ -58,10 +52,6 @@ describe('TaskWorker', () => {
const actionRegistry: TemplateActionRegistry = {} as TemplateActionRegistry;
const workingDirectory = '/tmp/scaffolder';
const handlebarsWorkflowRunner: HandlebarsWorkflowRunner = {
execute: jest.fn(),
} as unknown as HandlebarsWorkflowRunner;
const workflowRunner: NunjucksWorkflowRunner = {
execute: jest.fn(),
} as unknown as NunjucksWorkflowRunner;
@@ -72,47 +62,11 @@ describe('TaskWorker', () => {
beforeEach(() => {
jest.resetAllMocks();
MockedHandlebarsWorkflowRunner.mockImplementation(
() => handlebarsWorkflowRunner,
);
MockedNunjucksWorkflowRunner.mockImplementation(() => workflowRunner);
});
const logger = getVoidLogger();
it('should call the legacy workflow runner when the apiVersion is not beta3', async () => {
const broker = new StorageTaskBroker(storage, logger);
const taskWorker = await TaskWorker.create({
logger,
workingDirectory,
integrations,
taskBroker: broker,
actionRegistry,
});
await broker.dispatch({
spec: {
apiVersion: 'backstage.io/v1beta2',
steps: [{ id: 'test', name: 'test', action: 'not-found-action' }],
output: {
result: '{{ steps.test.output.testOutput }}',
},
values: {},
},
});
const task = await broker.claim();
await taskWorker.runOneTask(task);
expect(MockedHandlebarsWorkflowRunner).toBeCalledWith({
actionRegistry,
integrations,
logger,
workingDirectory,
});
expect(handlebarsWorkflowRunner.execute).toHaveBeenCalled();
});
it('should call the default workflow runner when the apiVersion is beta3', async () => {
const broker = new StorageTaskBroker(storage, logger);
const taskWorker = await TaskWorker.create({
@@ -15,7 +15,6 @@
*/
import { TaskContext, TaskBroker, WorkflowRunner } from './types';
import { HandlebarsWorkflowRunner } from './HandlebarsWorkflowRunner';
import { NunjucksWorkflowRunner } from './NunjucksWorkflowRunner';
import { Logger } from 'winston';
import { TemplateActionRegistry } from '../actions';
@@ -31,7 +30,6 @@ import { TemplateFilter } from '../../lib/templating/SecureTemplater';
export type TaskWorkerOptions = {
taskBroker: TaskBroker;
runners: {
legacyWorkflowRunner: HandlebarsWorkflowRunner;
workflowRunner: WorkflowRunner;
};
};
@@ -68,13 +66,6 @@ export class TaskWorker {
additionalTemplateFilters,
} = options;
const legacyWorkflowRunner = new HandlebarsWorkflowRunner({
logger,
actionRegistry,
integrations,
workingDirectory,
});
const workflowRunner = new NunjucksWorkflowRunner({
actionRegistry,
integrations,
@@ -85,7 +76,7 @@ export class TaskWorker {
return new TaskWorker({
taskBroker: taskBroker,
runners: { legacyWorkflowRunner, workflowRunner },
runners: { workflowRunner },
});
}
@@ -100,10 +91,15 @@ export class TaskWorker {
async runOneTask(task: TaskContext) {
try {
const { output } =
task.spec.apiVersion === 'scaffolder.backstage.io/v1beta3'
? await this.options.runners.workflowRunner.execute(task)
: await this.options.runners.legacyWorkflowRunner.execute(task);
if (task.spec.apiVersion !== 'scaffolder.backstage.io/v1beta3') {
throw new Error(
`Unsupported Template apiVersion ${task.spec.apiVersion}`,
);
}
const { output } = await this.options.runners.workflowRunner.execute(
task,
);
await task.complete('completed', { output });
} catch (error) {
@@ -16,24 +16,21 @@
export { DatabaseTaskStore } from './DatabaseTaskStore';
export type { DatabaseTaskStoreOptions } from './DatabaseTaskStore';
export { TaskManager } from './StorageTaskBroker';
export type { CurrentClaimedTask, TaskState } from './StorageTaskBroker';
export type { CurrentClaimedTask } from './StorageTaskBroker';
export { TaskWorker } from './TaskWorker';
export type { CreateWorkerOptions } from './TaskWorker';
export type {
TaskSecrets,
TaskCompletionState,
CompletedTaskState,
TaskStoreEmitOptions,
TaskStoreListEventsOptions,
SerializedTask,
SerializedTaskEvent,
Status,
TaskStatus,
TaskEventType,
TaskBroker,
TaskContext,
TaskStore,
DispatchResult,
TaskBrokerDispatchResult,
TaskBrokerDispatchOptions,
TaskStoreCreateTaskOptions,
@@ -29,14 +29,6 @@ export type TaskStatus =
| 'cancelled'
| 'completed';
/**
* The status of each step of the Task
*
* @public
* @deprecated use TaskStatus instead
*/
export type Status = TaskStatus;
/**
* The state of a completed task.
*
@@ -44,14 +36,6 @@ export type Status = TaskStatus;
*/
export type TaskCompletionState = 'failed' | 'completed';
/**
* The state of a completed task.
*
* @public
* @deprecated use TaskCompletionState instead
*/
export type CompletedTaskState = TaskCompletionState;
/**
* SerializedTask
*
@@ -115,14 +99,6 @@ export type TaskBrokerDispatchOptions = {
secrets?: TaskSecrets;
};
/**
* DispatchResult
*
* @public
* @deprecated use TaskBrokerDispatchResult instead
*/
export type DispatchResult = TaskBrokerDispatchResult;
/**
* Task
*
@@ -26,10 +26,7 @@ import {
} from '@backstage/catalog-model';
import { Config } from '@backstage/config';
import { assertError, InputError, NotFoundError } from '@backstage/errors';
import {
TemplateEntityV1beta2,
TemplateEntityV1beta3,
} from '@backstage/plugin-scaffolder-common';
import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';
import fs from 'fs-extra';
import os from 'os';
import { Logger } from 'winston';
@@ -95,7 +92,7 @@ export async function findTemplate(options: {
entityRef: CompoundEntityRef;
token?: string;
catalogApi: CatalogApi;
}): Promise<TemplateEntityV1beta3 | TemplateEntityV1beta2> {
}): Promise<TemplateEntityV1beta3> {
const { entityRef, token, catalogApi } = options;
if (entityRef.namespace.toLocaleLowerCase('en-US') !== DEFAULT_NAMESPACE) {
@@ -114,5 +111,5 @@ export async function findTemplate(options: {
);
}
return template as TemplateEntityV1beta3 | TemplateEntityV1beta2;
return template as TemplateEntityV1beta3;
}
@@ -35,7 +35,7 @@ import {
UrlReaders,
} from '@backstage/backend-common';
import { CatalogApi } from '@backstage/catalog-client';
import { TemplateEntityV1beta2 } from '@backstage/plugin-scaffolder-common';
import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';
import { ConfigReader } from '@backstage/config';
import ObservableImpl from 'zen-observable';
import express from 'express';
@@ -76,8 +76,8 @@ const mockUrlReader = UrlReaders.default({
describe('createRouter', () => {
let app: express.Express;
let taskBroker: TaskBroker;
const template: TemplateEntityV1beta2 = {
apiVersion: 'backstage.io/v1beta2',
const template: TemplateEntityV1beta3 = {
apiVersion: 'scaffolder.backstage.io/v1beta3',
kind: 'Template',
metadata: {
description: 'Create a new CRA website project',
@@ -22,11 +22,8 @@ import { Config } from '@backstage/config';
import { InputError, NotFoundError } from '@backstage/errors';
import { ScmIntegrations } from '@backstage/integration';
import {
TemplateEntityV1beta2,
TemplateEntityV1beta3,
TaskSpecV1beta3,
TaskSpec,
TaskSpecV1beta2,
} from '@backstage/plugin-scaffolder-common';
import express from 'express';
import Router from 'express-promise-router';
@@ -61,13 +58,8 @@ export interface RouterOptions {
additionalTemplateFilters?: Record<string, TemplateFilter>;
}
function isSupportedTemplate(
entity: TemplateEntityV1beta2 | TemplateEntityV1beta3,
) {
return (
entity.apiVersion === 'backstage.io/v1beta2' ||
entity.apiVersion === 'scaffolder.backstage.io/v1beta3'
);
function isSupportedTemplate(entity: TemplateEntityV1beta3) {
return entity.apiVersion === 'scaffolder.backstage.io/v1beta3';
}
/** @public */
@@ -181,64 +173,7 @@ export async function createRouter(
token: getBearerToken(req.headers.authorization),
});
let taskSpec: TaskSpec;
if (isSupportedTemplate(template)) {
if (template.apiVersion === 'backstage.io/v1beta2') {
logger.warn(
`Scaffolding ${stringifyEntityRef(
template,
)} with deprecated apiVersion ${
template.apiVersion
}. Please migrate the template to backstage.io/v1beta3. https://backstage.io/docs/features/software-templates/migrating-from-v1beta2-to-v1beta3`,
);
}
for (const parameters of [template.spec.parameters ?? []].flat()) {
const result = validate(values, parameters);
if (!result.valid) {
res.status(400).json({ errors: result.errors });
return;
}
}
const baseUrl = getEntityBaseUrl(template);
const baseTaskSpec = {
baseUrl,
steps: template.spec.steps.map((step, index) => ({
...step,
id: step.id ?? `step-${index + 1}`,
name: step.name ?? step.action,
})),
output: template.spec.output ?? {},
// deprecated in favour of templateInfo
metadata: { name: template.metadata?.name },
templateInfo: {
entityRef: stringifyEntityRef({
kind,
namespace,
name: template.metadata?.name,
}),
baseUrl,
},
};
taskSpec =
template.apiVersion === 'backstage.io/v1beta2'
? ({
...baseTaskSpec,
apiVersion: template.apiVersion,
values,
} as TaskSpecV1beta2)
: ({
...baseTaskSpec,
apiVersion: template.apiVersion,
parameters: values,
} as TaskSpecV1beta3);
} else {
if (!isSupportedTemplate(template)) {
throw new InputError(
`Unsupported apiVersion field in schema entity, ${
(template as Entity).apiVersion
@@ -246,6 +181,35 @@ export async function createRouter(
);
}
for (const parameters of [template.spec.parameters ?? []].flat()) {
const result = validate(values, parameters);
if (!result.valid) {
res.status(400).json({ errors: result.errors });
return;
}
}
const baseUrl = getEntityBaseUrl(template);
const taskSpec: TaskSpec = {
apiVersion: template.apiVersion,
steps: template.spec.steps.map((step, index) => ({
...step,
id: step.id ?? `step-${index + 1}`,
name: step.name ?? step.action,
})),
output: template.spec.output ?? {},
parameters: values,
templateInfo: {
entityRef: stringifyEntityRef({
kind,
namespace,
name: template.metadata?.name,
}),
baseUrl,
},
};
const result = await taskBroker.dispatch({
spec: taskSpec,
secrets: {
+1 -57
View File
@@ -9,36 +9,12 @@ import { JsonValue } from '@backstage/types';
import { KindValidator } from '@backstage/catalog-model';
// @public
export type TaskSpec = TaskSpecV1beta2 | TaskSpecV1beta3;
// @public @deprecated
export interface TaskSpecV1beta2 {
// (undocumented)
apiVersion: 'backstage.io/v1beta2';
// @deprecated (undocumented)
baseUrl?: string;
// @deprecated (undocumented)
metadata?: TemplateMetadata;
// (undocumented)
output: {
[name: string]: string;
};
// (undocumented)
steps: TaskStep[];
// (undocumented)
templateInfo?: TemplateInfo;
// (undocumented)
values: JsonObject;
}
export type TaskSpec = TaskSpecV1beta3;
// @public
export interface TaskSpecV1beta3 {
// (undocumented)
apiVersion: 'scaffolder.backstage.io/v1beta3';
// @deprecated (undocumented)
baseUrl?: string;
// @deprecated (undocumented)
metadata?: TemplateMetadata;
// (undocumented)
output: {
[name: string]: JsonValue;
@@ -65,33 +41,6 @@ export interface TaskStep {
name: string;
}
// @public @deprecated
export interface TemplateEntityV1beta2 extends Entity {
// (undocumented)
apiVersion: 'backstage.io/v1beta2';
// (undocumented)
kind: 'Template';
// (undocumented)
spec: {
type: string;
parameters?: JsonObject | JsonObject[];
steps: Array<{
id?: string;
name?: string;
action: string;
input?: JsonObject;
if?: string | boolean;
}>;
output?: {
[name: string]: string;
};
owner?: string;
};
}
// @public @deprecated
export const templateEntityV1beta2Validator: KindValidator;
// @public
export interface TemplateEntityV1beta3 extends Entity {
// (undocumented)
@@ -124,9 +73,4 @@ export type TemplateInfo = {
entityRef: string;
baseUrl?: string;
};
// @public @deprecated
export type TemplateMetadata = {
name: string;
};
```
+1 -36
View File
@@ -16,17 +16,6 @@
import { JsonValue, JsonObject } from '@backstage/types';
/**
* Metadata about the Template that was the originator of a scaffolder task, as
* stored in the database.
*
* @public
* @deprecated use templateInfo on the spec instead
*/
export type TemplateMetadata = {
name: string;
};
/**
* Information about a template that is stored on a task specification.
* Includes a stringified entityRef, and the baseUrl which is usually the relative path of the template definition
@@ -51,26 +40,6 @@ export interface TaskStep {
if?: string | boolean;
}
/**
* A scaffolder task as stored in the database, generated from a v1beta2
* apiVersion Template.
*
* @public
* @deprecated Please convert your templates to TaskSpecV1beta3 on apiVersion
* scaffolder.backstage.io/v1beta3
*/
export interface TaskSpecV1beta2 {
apiVersion: 'backstage.io/v1beta2';
/** @deprecated use templateInfo.baseUrl instead */
baseUrl?: string;
values: JsonObject;
steps: TaskStep[];
output: { [name: string]: string };
/** @deprecated use templateInfo instead */
metadata?: TemplateMetadata;
templateInfo?: TemplateInfo;
}
/**
* A scaffolder task as stored in the database, generated from a v1beta3
* apiVersion Template.
@@ -79,13 +48,9 @@ export interface TaskSpecV1beta2 {
*/
export interface TaskSpecV1beta3 {
apiVersion: 'scaffolder.backstage.io/v1beta3';
/** @deprecated use templateInfo.baseUrl instead */
baseUrl?: string;
parameters: JsonObject;
steps: TaskStep[];
output: { [name: string]: JsonValue };
/** @deprecated use templateInfo instead */
metadata?: TemplateMetadata;
templateInfo?: TemplateInfo;
}
@@ -94,4 +59,4 @@ export interface TaskSpecV1beta3 {
*
* @public
*/
export type TaskSpec = TaskSpecV1beta2 | TaskSpecV1beta3;
export type TaskSpec = TaskSpecV1beta3;
@@ -1,182 +0,0 @@
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "TemplateV1beta2",
"description": "A Template describes a scaffolding task for use with the Scaffolder. It describes the required parameters as well as a series of steps that will be taken to execute the scaffolding task.",
"examples": [
{
"apiVersion": "backstage.io/v1beta2",
"kind": "Template",
"metadata": {
"name": "react-ssr-template",
"title": "React SSR Template",
"description": "Next.js application skeleton for creating isomorphic web applications.",
"tags": ["recommended", "react"]
},
"spec": {
"owner": "artist-relations-team",
"type": "website",
"parameters": {
"required": ["name", "description"],
"properties": {
"name": {
"title": "Name",
"type": "string",
"description": "Unique name of the component"
},
"description": {
"title": "Description",
"type": "string",
"description": "Description of the component"
}
}
},
"steps": [
{
"id": "fetch",
"name": "Fetch",
"action": "fetch:plain",
"parameters": {
"url": "./template"
}
},
{
"id": "publish",
"name": "Publish to GitHub",
"action": "publish:github",
"parameters": {
"repoUrl": "{{ parameters.repoUrl }}"
},
"if": "{{ parameters.repoUrl }}"
}
],
"output": {
"catalogInfoUrl": "{{ steps.publish.output.catalogInfoUrl }}"
}
}
}
],
"allOf": [
{
"$ref": "Entity"
},
{
"type": "object",
"required": ["spec"],
"properties": {
"apiVersion": {
"enum": ["backstage.io/v1beta2"]
},
"kind": {
"enum": ["Template"]
},
"spec": {
"type": "object",
"required": ["type", "steps"],
"properties": {
"type": {
"type": "string",
"description": "The type of component created by the template. The software catalog accepts any type value, but an organization should take great care to establish a proper taxonomy for these. Tools including Backstage itself may read this field and behave differently depending on its value. For example, a website type component may present tooling in the Backstage interface that is specific to just websites.",
"examples": ["service", "website", "library"],
"minLength": 1
},
"parameters": {
"oneOf": [
{
"type": "object",
"description": "The JSONSchema describing the inputs for the template."
},
{
"type": "array",
"description": "A list of separate forms to collect parameters.",
"items": {
"type": "object",
"description": "The JSONSchema describing the inputs for the template."
}
}
]
},
"steps": {
"type": "array",
"description": "A list of steps to execute.",
"items": {
"type": "object",
"description": "A description of the step to execute.",
"required": ["action"],
"properties": {
"id": {
"type": "string",
"description": "The ID of the step, which can be used to refer to its outputs."
},
"name": {
"type": "string",
"description": "The name of the step, which will be displayed in the UI during the scaffolding process."
},
"action": {
"type": "string",
"description": "The name of the action to execute."
},
"input": {
"type": "object",
"description": "A templated object describing the inputs to the action."
},
"if": {
"type": ["string", "boolean"],
"description": "A templated condition that skips the step when evaluated to false. If the condition is true or not defined, the step is executed. The condition is true, if the input is not `false`, `undefined`, `null`, `\"\"`, `0`, or `[]`."
}
}
}
},
"output": {
"type": "object",
"description": "A templated object describing the outputs of the scaffolding task.",
"properties": {
"links": {
"type": "array",
"description": "A list of external hyperlinks, typically pointing to resources created or updated by the template",
"items": {
"type": "object",
"required": [],
"properties": {
"url": {
"type": "string",
"description": "A url in a standard uri format.",
"examples": ["https://github.com/my-org/my-new-repo"],
"minLength": 1
},
"entityRef": {
"type": "string",
"description": "An entity reference to an entity in the catalog.",
"examples": ["Component:default/my-app"],
"minLength": 1
},
"title": {
"type": "string",
"description": "A user friendly display name for the link.",
"examples": ["View new repo"],
"minLength": 1
},
"icon": {
"type": "string",
"description": "A key representing a visual icon to be displayed in the UI.",
"examples": ["dashboard"],
"minLength": 1
}
}
}
}
},
"additionalProperties": {
"type": "string"
}
},
"owner": {
"type": "string",
"description": "The user (or group) owner of the template",
"minLength": 1
}
}
}
}
}
]
}
@@ -1,161 +0,0 @@
/*
* Copyright 2020 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
TemplateEntityV1beta2,
templateEntityV1beta2Validator as validator,
} from './TemplateEntityV1beta2';
describe('templateEntityV1beta2Validator', () => {
let entity: TemplateEntityV1beta2;
beforeEach(() => {
entity = {
apiVersion: 'backstage.io/v1beta2',
kind: 'Template',
metadata: {
name: 'test',
},
spec: {
type: 'website',
parameters: {
required: ['storePath', 'owner'],
properties: {
owner: {
type: 'string',
title: 'Owner',
description: 'Who is going to own this component',
},
storePath: {
type: 'string',
title: 'Store path',
description: 'GitHub store path in org/repo format',
},
},
},
steps: [
{
id: 'fetch',
name: 'Fetch',
action: 'fetch:plan',
input: {
url: './template',
},
if: '{{ parameters.owner }}',
},
],
output: {
fetchUrl: '{{ steps.fetch.output.targetUrl }}',
},
owner: 'team-b@example.com',
},
};
});
it('happy path: accepts valid data', async () => {
await expect(validator.check(entity)).resolves.toBe(true);
});
it('ignores unknown apiVersion', async () => {
(entity as any).apiVersion = 'backstage.io/v1beta0';
await expect(validator.check(entity)).resolves.toBe(false);
});
it('ignores unknown kind', async () => {
(entity as any).kind = 'Wizard';
await expect(validator.check(entity)).resolves.toBe(false);
});
it('rejects missing type', async () => {
delete (entity as any).spec.type;
await expect(validator.check(entity)).rejects.toThrow(/type/);
});
it('accepts any other type', async () => {
(entity as any).spec.type = 'hallo';
await expect(validator.check(entity)).resolves.toBe(true);
});
it('accepts missing parameters', async () => {
delete (entity as any).spec.parameters;
await expect(validator.check(entity)).resolves.toBe(true);
});
it('accepts missing outputs', async () => {
delete (entity as any).spec.outputs;
await expect(validator.check(entity)).resolves.toBe(true);
});
it('rejects empty type', async () => {
(entity as any).spec.type = '';
await expect(validator.check(entity)).rejects.toThrow(/type/);
});
it('rejects missing steps', async () => {
delete (entity as any).spec.steps;
await expect(validator.check(entity)).rejects.toThrow(/steps/);
});
it('accepts step with missing id', async () => {
delete (entity as any).spec.steps[0].id;
await expect(validator.check(entity)).resolves.toBe(true);
});
it('accepts step with missing name', async () => {
delete (entity as any).spec.steps[0].name;
await expect(validator.check(entity)).resolves.toBe(true);
});
it('rejects step with missing action', async () => {
delete (entity as any).spec.steps[0].action;
await expect(validator.check(entity)).rejects.toThrow(/action/);
});
it('accepts missing owner', async () => {
delete (entity as any).spec.owner;
await expect(validator.check(entity)).resolves.toBe(true);
});
it('rejects empty owner', async () => {
(entity as any).spec.owner = '';
await expect(validator.check(entity)).rejects.toThrow(/owner/);
});
it('rejects wrong type owner', async () => {
(entity as any).spec.owner = 5;
await expect(validator.check(entity)).rejects.toThrow(/owner/);
});
it('accepts missing if', async () => {
delete (entity as any).spec.steps[0].if;
await expect(validator.check(entity)).resolves.toBe(true);
});
it('accepts boolean in if', async () => {
(entity as any).spec.steps[0].if = true;
await expect(validator.check(entity)).resolves.toBe(true);
});
it('accepts empty if', async () => {
(entity as any).spec.steps[0].if = '';
await expect(validator.check(entity)).resolves.toBe(true);
});
it('rejects wrong type if', async () => {
(entity as any).spec.steps[0].if = 5;
await expect(validator.check(entity)).rejects.toThrow(/if/);
});
});
@@ -1,65 +0,0 @@
/*
* Copyright 2020 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
Entity,
entityKindSchemaValidator,
KindValidator,
} from '@backstage/catalog-model';
import { JsonObject } from '@backstage/types';
import schema from './Template.v1beta2.schema.json';
/**
* Backstage catalog Template kind Entity. Templates are used by the Scaffolder
* plugin to create new entities, such as Components.
*
* @public
* @deprecated Please convert your templates to TemplateEntityV1beta3 on
* apiVersion scaffolder.backstage.io/v1beta3
*/
export interface TemplateEntityV1beta2 extends Entity {
apiVersion: 'backstage.io/v1beta2';
kind: 'Template';
spec: {
type: string;
parameters?: JsonObject | JsonObject[];
steps: Array<{
id?: string;
name?: string;
action: string;
input?: JsonObject;
if?: string | boolean;
}>;
output?: { [name: string]: string };
owner?: string;
};
}
const validator = entityKindSchemaValidator(schema);
/**
* Entity data validator for {@link TemplateEntityV1beta2}.
*
* @public
* @deprecated Please convert your templates to TemplateEntityV1beta3 on
* apiVersion scaffolder.backstage.io/v1beta3
*/
export const templateEntityV1beta2Validator: KindValidator = {
// TODO(freben): Emulate the old KindValidator until we fix that type
async check(data: Entity) {
return validator(data) === data;
},
};
-2
View File
@@ -21,7 +21,5 @@
*/
export * from './TaskSpec';
export { templateEntityV1beta2Validator } from './TemplateEntityV1beta2';
export type { TemplateEntityV1beta2 } from './TemplateEntityV1beta2';
export { templateEntityV1beta3Validator } from './TemplateEntityV1beta3';
export type { TemplateEntityV1beta3 } from './TemplateEntityV1beta3';
+4 -4
View File
@@ -24,7 +24,7 @@ import { default as React_2 } from 'react';
import { RouteRef } from '@backstage/core-plugin-api';
import { ScmIntegrationRegistry } from '@backstage/integration';
import { TaskSpec } from '@backstage/plugin-scaffolder-common';
import { TemplateEntityV1beta2 } from '@backstage/plugin-scaffolder-common';
import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';
// @public
export function createScaffolderFieldExtension<
@@ -222,14 +222,14 @@ export interface RepoUrlPickerUiOptions {
export type RouterProps = {
TemplateCardComponent?:
| ComponentType<{
template: TemplateEntityV1beta2;
template: TemplateEntityV1beta3;
}>
| undefined;
TaskPageComponent?: ComponentType<{}>;
components?: {
TemplateCardComponent?:
| ComponentType<{
template: TemplateEntityV1beta2;
template: TemplateEntityV1beta3;
}>
| undefined;
TaskPageComponent?: ComponentType<{}>;
@@ -427,7 +427,7 @@ export const TemplateList: ({
export type TemplateListProps = {
TemplateCardComponent?:
| ComponentType<{
template: TemplateEntityV1beta2;
template: TemplateEntityV1beta3;
}>
| undefined;
group?: {
+3 -3
View File
@@ -17,7 +17,7 @@
import React, { ComponentType } from 'react';
import { Routes, Route, useOutlet } from 'react-router';
import { Entity } from '@backstage/catalog-model';
import { TemplateEntityV1beta2 } from '@backstage/plugin-scaffolder-common';
import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';
import { ScaffolderPage } from './ScaffolderPage';
import { TemplatePage } from './TemplatePage';
import { TaskPage } from './TaskPage';
@@ -35,14 +35,14 @@ import { useElementFilter } from '@backstage/core-plugin-api';
export type RouterProps = {
/** @deprecated use components.TemplateCardComponent instead */
TemplateCardComponent?:
| ComponentType<{ template: TemplateEntityV1beta2 }>
| ComponentType<{ template: TemplateEntityV1beta3 }>
| undefined;
/** @deprecated use component.TaskPageComponent instead */
TaskPageComponent?: ComponentType<{}>;
components?: {
TemplateCardComponent?:
| ComponentType<{ template: TemplateEntityV1beta2 }>
| ComponentType<{ template: TemplateEntityV1beta3 }>
| undefined;
TaskPageComponent?: ComponentType<{}>;
};
@@ -24,7 +24,7 @@ import {
SupportButton,
} from '@backstage/core-components';
import { Entity } from '@backstage/catalog-model';
import { TemplateEntityV1beta2 } from '@backstage/plugin-scaffolder-common';
import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';
import { useRouteRef } from '@backstage/core-plugin-api';
import {
EntityKindPicker,
@@ -52,7 +52,7 @@ const useStyles = makeStyles(theme => ({
export type ScaffolderPageProps = {
TemplateCardComponent?:
| ComponentType<{ template: TemplateEntityV1beta2 }>
| ComponentType<{ template: TemplateEntityV1beta3 }>
| undefined;
groups?: Array<{
title?: React.ReactNode;
@@ -298,10 +298,7 @@ export const TaskPage = ({ loadingText }: TaskPageProps) => {
return;
}
const formData =
taskStream.task!.spec.apiVersion === 'backstage.io/v1beta2'
? taskStream.task!.spec.values
: taskStream.task!.spec.parameters;
const formData = taskStream.task!.spec.parameters;
const { name } = parseEntityRef(
taskStream.task!.spec.templateInfo?.entityRef,
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { Entity, RELATION_OWNED_BY } from '@backstage/catalog-model';
import { TemplateEntityV1beta2 } from '@backstage/plugin-scaffolder-common';
import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';
import {
ScmIntegrationIcon,
scmIntegrationsApiRef,
@@ -99,7 +99,7 @@ const useDeprecationStyles = makeStyles(theme => ({
}));
export type TemplateCardProps = {
template: TemplateEntityV1beta2;
template: TemplateEntityV1beta3;
deprecated?: boolean;
};
@@ -112,7 +112,7 @@ type TemplateProps = {
};
const getTemplateCardProps = (
template: TemplateEntityV1beta2,
template: TemplateEntityV1beta3,
): TemplateProps & { key: string } => {
return {
key: template.metadata.uid!,
@@ -16,7 +16,7 @@
import React, { ComponentType } from 'react';
import { Entity, stringifyEntityRef } from '@backstage/catalog-model';
import { TemplateEntityV1beta2 } from '@backstage/plugin-scaffolder-common';
import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';
import {
Content,
ContentHeader,
@@ -34,7 +34,7 @@ import { TemplateCard } from '../TemplateCard';
*/
export type TemplateListProps = {
TemplateCardComponent?:
| ComponentType<{ template: TemplateEntityV1beta2 }>
| ComponentType<{ template: TemplateEntityV1beta3 }>
| undefined;
group?: {
title?: React.ReactNode;
@@ -106,7 +106,7 @@ export const TemplateList = ({
maybeFilteredEntities.map((template: Entity) => (
<Card
key={stringifyEntityRef(template)}
template={template as TemplateEntityV1beta2}
template={template as TemplateEntityV1beta3}
deprecated={template.apiVersion === 'backstage.io/v1beta2'}
/>
))}
@@ -10,7 +10,7 @@ import { Client } from '@elastic/elasticsearch';
import { Config } from '@backstage/config';
import type { ConnectionOptions } from 'tls';
import { IndexableDocument } from '@backstage/plugin-search-common';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
import { SearchEngine } from '@backstage/plugin-search-common';
import { SearchQuery } from '@backstage/plugin-search-common';
import { SearchResultSet } from '@backstage/plugin-search-common';
@@ -104,7 +104,7 @@ export class ElasticSearchSearchEngine implements SearchEngine {
elasticSearchClientOptions: ElasticSearchClientOptions,
aliasPostfix: string,
indexPrefix: string,
logger: Logger_2,
logger: Logger,
);
// Warning: (ae-forgotten-export) The symbol "ElasticSearchOptions" needs to be exported by the entry point index.d.ts
//
@@ -153,7 +153,7 @@ export type ElasticSearchSearchEngineIndexerOptions = {
indexPrefix: string;
indexSeparator: string;
alias: string;
logger: Logger_2;
logger: Logger;
elasticSearchClient: Client;
};
```
+5 -5
View File
@@ -9,7 +9,7 @@ import { DocumentCollatorFactory } from '@backstage/plugin-search-common';
import { DocumentDecoratorFactory } from '@backstage/plugin-search-common';
import { DocumentTypeInfo } from '@backstage/plugin-search-common';
import { IndexableDocument } from '@backstage/plugin-search-common';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
import { default as lunr_2 } from 'lunr';
import { QueryTranslator } from '@backstage/plugin-search-common';
import { Readable } from 'stream';
@@ -69,7 +69,7 @@ export class IndexBuilder {
// @beta (undocumented)
export type IndexBuilderOptions = {
searchEngine: SearchEngine;
logger: Logger_2;
logger: Logger;
};
// @beta (undocumented)
@@ -77,13 +77,13 @@ export type LunrQueryTranslator = (query: SearchQuery) => ConcreteLunrQuery;
// @beta (undocumented)
export class LunrSearchEngine implements SearchEngine {
constructor({ logger }: { logger: Logger_2 });
constructor({ logger }: { logger: Logger });
// (undocumented)
protected docStore: Record<string, IndexableDocument>;
// (undocumented)
getIndexer(type: string): Promise<LunrSearchEngineIndexer>;
// (undocumented)
protected logger: Logger_2;
protected logger: Logger;
// (undocumented)
protected lunrIndices: Record<string, lunr_2.Index>;
// (undocumented)
@@ -122,7 +122,7 @@ export interface RegisterDecoratorParameters {
// @beta (undocumented)
export class Scheduler {
constructor({ logger }: { logger: Logger_2 });
constructor({ logger }: { logger: Logger });
addToSchedule(task: Function, interval: number): void;
start(): void;
stop(): void;
+2 -2
View File
@@ -6,7 +6,7 @@
import { Config } from '@backstage/config';
import { DocumentTypeInfo } from '@backstage/plugin-search-common';
import express from 'express';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
import { PermissionAuthorizer } from '@backstage/plugin-permission-common';
import { SearchEngine } from '@backstage/plugin-search-backend-node';
@@ -23,6 +23,6 @@ export type RouterOptions = {
types: Record<string, DocumentTypeInfo>;
permissions: PermissionAuthorizer;
config: Config;
logger: Logger_2;
logger: Logger;
};
```
@@ -7,7 +7,7 @@ import { BooleanCheckResult } from '@backstage/plugin-tech-insights-common';
import { CheckResponse } from '@backstage/plugin-tech-insights-common';
import { CheckValidationResponse } from '@backstage/plugin-tech-insights-node';
import { FactChecker } from '@backstage/plugin-tech-insights-node';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
import { Operator } from 'json-rules-engine';
import { TechInsightCheck } from '@backstage/plugin-tech-insights-node';
import { TechInsightCheckRegistry } from '@backstage/plugin-tech-insights-node';
@@ -79,7 +79,7 @@ export class JsonRulesEngineFactCheckerFactory {
// @public
export type JsonRulesEngineFactCheckerFactoryOptions = {
checks: TechInsightJsonRuleCheck[];
logger: Logger_2;
logger: Logger;
checkRegistry?: TechInsightCheckRegistry<TechInsightJsonRuleCheck>;
operators?: Operator[];
};
@@ -88,7 +88,7 @@ export type JsonRulesEngineFactCheckerFactoryOptions = {
export type JsonRulesEngineFactCheckerOptions = {
checks: TechInsightJsonRuleCheck[];
repository: TechInsightsStore;
logger: Logger_2;
logger: Logger;
checkRegistry?: TechInsightCheckRegistry<any>;
operators?: Operator[];
};
+3 -3
View File
@@ -11,7 +11,7 @@ import { FactCheckerFactory } from '@backstage/plugin-tech-insights-node';
import { FactLifecycle } from '@backstage/plugin-tech-insights-node';
import { FactRetriever } from '@backstage/plugin-tech-insights-node';
import { FactRetrieverRegistration } from '@backstage/plugin-tech-insights-node';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
import { PluginDatabaseManager } from '@backstage/backend-common';
import { PluginEndpointDiscovery } from '@backstage/backend-common';
import { TechInsightCheck } from '@backstage/plugin-tech-insights-node';
@@ -63,7 +63,7 @@ export interface RouterOptions<
> {
config: Config;
factChecker?: FactChecker<CheckType, CheckResultType>;
logger: Logger_2;
logger: Logger;
persistenceContext: PersistenceContext;
}
@@ -93,7 +93,7 @@ export interface TechInsightsOptions<
factCheckerFactory?: FactCheckerFactory<CheckType, CheckResultType>;
factRetrievers: FactRetrieverRegistration[];
// (undocumented)
logger: Logger_2;
logger: Logger;
}
// (No @packageDocumentation comment for this package)
+2 -2
View File
@@ -7,7 +7,7 @@ import { CheckResult } from '@backstage/plugin-tech-insights-common';
import { Config } from '@backstage/config';
import { DateTime } from 'luxon';
import { DurationLike } from 'luxon';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
import { PluginEndpointDiscovery } from '@backstage/backend-common';
// @public
@@ -56,7 +56,7 @@ export interface FactRetriever {
export type FactRetrieverContext = {
config: Config;
discovery: PluginEndpointDiscovery;
logger: Logger_2;
logger: Logger;
entityFilter?:
| Record<string, string | symbol | (string | symbol)[]>[]
| Record<string, string | symbol | (string | symbol)[]>;
+5 -5
View File
@@ -12,7 +12,7 @@ import { Entity } from '@backstage/catalog-model';
import express from 'express';
import { GeneratorBuilder } from '@backstage/plugin-techdocs-node';
import { Knex } from 'knex';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
import { Permission } from '@backstage/plugin-permission-common';
import { PluginCacheManager } from '@backstage/backend-common';
import { PluginEndpointDiscovery } from '@backstage/backend-common';
@@ -71,7 +71,7 @@ export type OutOfTheBoxDeploymentOptions = {
preparers: PreparerBuilder;
generators: GeneratorBuilder;
publisher: PublisherBase;
logger: Logger_2;
logger: Logger;
discovery: PluginEndpointDiscovery;
database?: Knex;
config: Config;
@@ -82,7 +82,7 @@ export type OutOfTheBoxDeploymentOptions = {
// @public
export type RecommendedDeploymentOptions = {
publisher: PublisherBase;
logger: Logger_2;
logger: Logger;
discovery: PluginEndpointDiscovery;
config: Config;
cache: PluginCacheManager;
@@ -102,7 +102,7 @@ export type ShouldBuildParameters = {
// @public
export type TechDocsCollatorFactoryOptions = {
discovery: PluginEndpointDiscovery;
logger: Logger_2;
logger: Logger;
tokenManager: TokenManager;
locationTemplate?: string;
catalogClient?: CatalogApi;
@@ -113,7 +113,7 @@ export type TechDocsCollatorFactoryOptions = {
// @public
export type TechDocsCollatorOptions = {
discovery: PluginEndpointDiscovery;
logger: Logger_2;
logger: Logger;
tokenManager: TokenManager;
locationTemplate?: string;
catalogClient?: CatalogApi;
+11 -11
View File
@@ -11,7 +11,7 @@ import { ContainerRunner } from '@backstage/backend-common';
import { Entity } from '@backstage/catalog-model';
import express from 'express';
import { IndexableDocument } from '@backstage/plugin-search-common';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
import { PluginEndpointDiscovery } from '@backstage/backend-common';
import { ScmIntegrationRegistry } from '@backstage/integration';
import { UrlReader } from '@backstage/backend-common';
@@ -20,7 +20,7 @@ import { Writable } from 'stream';
// @public
export class DirectoryPreparer implements PreparerBase {
// @deprecated
constructor(config: Config, _logger: Logger_2 | null, reader: UrlReader);
constructor(config: Config, _logger: Logger | null, reader: UrlReader);
static fromConfig(
config: Config,
{ logger, reader }: PreparerConfig,
@@ -45,7 +45,7 @@ export type GeneratorBuilder = {
// @public
export type GeneratorOptions = {
containerRunner: ContainerRunner;
logger: Logger_2;
logger: Logger;
};
// @public
@@ -54,7 +54,7 @@ export type GeneratorRunOptions = {
outputDir: string;
parsedLocationAnnotation?: ParsedLocationAnnotation;
etag?: string;
logger: Logger_2;
logger: Logger;
logStream?: Writable;
};
@@ -63,7 +63,7 @@ export class Generators implements GeneratorBuilder {
static fromConfig(
config: Config,
options: {
logger: Logger_2;
logger: Logger;
containerRunner: ContainerRunner;
},
): Promise<GeneratorBuilder>;
@@ -78,7 +78,7 @@ export const getDocFilesFromRepository: (
opts?:
| {
etag?: string | undefined;
logger?: Logger_2 | undefined;
logger?: Logger | undefined;
}
| undefined,
) => Promise<PreparerResponse>;
@@ -120,13 +120,13 @@ export type PreparerBuilder = {
// @public
export type PreparerConfig = {
logger: Logger_2;
logger: Logger;
reader: UrlReader;
};
// @public
export type PreparerOptions = {
logger?: Logger_2;
logger?: Logger;
etag?: ETag;
};
@@ -168,7 +168,7 @@ export interface PublisherBase {
// @public
export type PublisherFactory = {
logger: Logger_2;
logger: Logger;
discovery: PluginEndpointDiscovery;
};
@@ -216,7 +216,7 @@ export interface TechDocsDocument extends IndexableDocument {
// @public
export class TechdocsGenerator implements GeneratorBase {
constructor(options: {
logger: Logger_2;
logger: Logger;
containerRunner: ContainerRunner;
config: Config;
scmIntegrations: ScmIntegrationRegistry;
@@ -251,7 +251,7 @@ export const transformDirLocation: (
// @public
export class UrlPreparer implements PreparerBase {
// @deprecated
constructor(reader: UrlReader, logger: Logger_2);
constructor(reader: UrlReader, logger: Logger);
static fromConfig({ reader, logger }: PreparerConfig): UrlPreparer;
prepare(entity: Entity, options?: PreparerOptions): Promise<PreparerResponse>;
}
+2 -2
View File
@@ -7,7 +7,7 @@ import { CatalogApi } from '@backstage/catalog-client';
import { CompoundEntityRef } from '@backstage/catalog-model';
import { Config } from '@backstage/config';
import express from 'express';
import { Logger as Logger_2 } from 'winston';
import { Logger } from 'winston';
import { ScmIntegrations } from '@backstage/integration';
import { UrlReader } from '@backstage/backend-common';
@@ -127,7 +127,7 @@ export class TodoScmReader implements TodoReader {
// @public (undocumented)
export type TodoScmReaderOptions = {
logger: Logger_2;
logger: Logger;
reader: UrlReader;
integrations: ScmIntegrations;
parser?: TodoParser;
+1 -1
View File
@@ -13539,7 +13539,7 @@ handle-thing@^2.0.0:
resolved "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.0.tgz#0e039695ff50c93fc288557d696f3c1dc6776754"
integrity sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ==
handlebars@^4.7.3, handlebars@^4.7.6, handlebars@^4.7.7:
handlebars@^4.7.3, handlebars@^4.7.7:
version "4.7.7"
resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1"
integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==