From 661594bf438e8ac039216af21d09c10114d00b9e Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 15 Feb 2022 17:54:45 +0100 Subject: [PATCH] scaffolder-backend: update TemplateAction to use more precise types Signed-off-by: Patrik Oldsberg --- .changeset/fast-mangos-tell.md | 5 + .changeset/witty-mails-search.md | 7 + .../api-report.md | 10 +- .../api-report.md | 8 +- .../api-report.md | 7 +- plugins/scaffolder-backend/api-report.md | 164 ++++++++++++++---- .../actions/TemplateActionRegistry.ts | 9 +- .../actions/builtin/createBuiltinActions.ts | 6 +- .../actions/builtin/debug/log.test.ts | 2 +- .../actions/builtin/fetch/template.test.ts | 8 +- .../actions/builtin/fetch/template.ts | 27 ++- .../actions/builtin/filesystem/delete.test.ts | 8 +- .../actions/builtin/filesystem/rename.test.ts | 14 +- .../actions/builtin/filesystem/rename.ts | 14 +- .../actions/builtin/github/githubWebhook.ts | 4 +- .../actions/builtin/publish/bitbucket.test.ts | 2 +- .../actions/builtin/publish/bitbucket.ts | 10 +- .../actions/builtin/publish/github.test.ts | 2 +- .../actions/builtin/publish/github.ts | 10 +- .../builtin/publish/githubPullRequest.test.ts | 7 +- .../builtin/publish/githubPullRequest.ts | 20 +-- .../actions/builtin/publish/gitlab.test.ts | 2 +- .../actions/builtin/publish/gitlab.ts | 2 +- .../builtin/publish/gitlabMergeRequest.ts | 20 +-- .../actions/createTemplateAction.ts | 9 +- .../src/scaffolder/actions/types.ts | 8 +- 26 files changed, 257 insertions(+), 128 deletions(-) create mode 100644 .changeset/fast-mangos-tell.md create mode 100644 .changeset/witty-mails-search.md diff --git a/.changeset/fast-mangos-tell.md b/.changeset/fast-mangos-tell.md new file mode 100644 index 0000000000..bfcf429485 --- /dev/null +++ b/.changeset/fast-mangos-tell.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': minor +--- + +**BREAKING**: Updated `TemplateAction` and related types to have its type parameter extend `JsonObject` instead of `InputBase`. The `createTemplateAction` has also been updated to pass through the `TInput` type parameter to the return type, meaning the `TemplateAction` retains its type. This can lead to breakages during type checking especially within tests. diff --git a/.changeset/witty-mails-search.md b/.changeset/witty-mails-search.md new file mode 100644 index 0000000000..a98fc52884 --- /dev/null +++ b/.changeset/witty-mails-search.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-scaffolder-backend-module-cookiecutter': minor +'@backstage/plugin-scaffolder-backend-module-rails': minor +'@backstage/plugin-scaffolder-backend-module-yeoman': minor +--- + +Updated to the latest version of `@backstage/plugin-scaffolder-backend`, meaning the `TemplateAction` now exposes the precise input type rather than `any`. diff --git a/plugins/scaffolder-backend-module-cookiecutter/api-report.md b/plugins/scaffolder-backend-module-cookiecutter/api-report.md index 132d3d4225..e55c6368c4 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/api-report.md +++ b/plugins/scaffolder-backend-module-cookiecutter/api-report.md @@ -6,6 +6,7 @@ /// import { ContainerRunner } from '@backstage/backend-common'; +import { JsonObject } from '@backstage/types'; import { ScmIntegrations } from '@backstage/integration'; import { TemplateAction } from '@backstage/plugin-scaffolder-backend'; import { UrlReader } from '@backstage/backend-common'; @@ -15,5 +16,12 @@ export function createFetchCookiecutterAction(options: { reader: UrlReader; integrations: ScmIntegrations; containerRunner: ContainerRunner; -}): TemplateAction; +}): TemplateAction<{ + url: string; + targetPath?: string | undefined; + values: JsonObject; + copyWithoutRender?: string[] | undefined; + extensions?: string[] | undefined; + imageName?: string | undefined; +}>; ``` diff --git a/plugins/scaffolder-backend-module-rails/api-report.md b/plugins/scaffolder-backend-module-rails/api-report.md index 9c0610d4f2..aa631c5333 100644 --- a/plugins/scaffolder-backend-module-rails/api-report.md +++ b/plugins/scaffolder-backend-module-rails/api-report.md @@ -4,6 +4,7 @@ ```ts import { ContainerRunner } from '@backstage/backend-common'; +import { JsonObject } from '@backstage/types'; import { ScmIntegrations } from '@backstage/integration'; import { TemplateAction } from '@backstage/plugin-scaffolder-backend'; import { UrlReader } from '@backstage/backend-common'; @@ -13,5 +14,10 @@ export function createFetchRailsAction(options: { reader: UrlReader; integrations: ScmIntegrations; containerRunner: ContainerRunner; -}): TemplateAction; +}): TemplateAction<{ + url: string; + targetPath?: string | undefined; + values: JsonObject; + imageName?: string | undefined; +}>; ``` diff --git a/plugins/scaffolder-backend-module-yeoman/api-report.md b/plugins/scaffolder-backend-module-yeoman/api-report.md index fc18814faa..0f8747e592 100644 --- a/plugins/scaffolder-backend-module-yeoman/api-report.md +++ b/plugins/scaffolder-backend-module-yeoman/api-report.md @@ -3,8 +3,13 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { JsonObject } from '@backstage/types'; import { TemplateAction } from '@backstage/plugin-scaffolder-backend'; // @public -export function createRunYeomanAction(): TemplateAction; +export function createRunYeomanAction(): TemplateAction<{ + namespace: string; + args?: string[] | undefined; + options?: JsonObject | undefined; +}>; ``` diff --git a/plugins/scaffolder-backend/api-report.md b/plugins/scaffolder-backend/api-report.md index 5e7b5a428b..19411df800 100644 --- a/plugins/scaffolder-backend/api-report.md +++ b/plugins/scaffolder-backend/api-report.md @@ -34,11 +34,10 @@ import { TemplateMetadata } from '@backstage/plugin-scaffolder-common'; import { UrlReader } from '@backstage/backend-common'; import { Writable } from 'stream'; -// Warning: (ae-forgotten-export) The symbol "InputBase" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "ActionContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export type ActionContext = { +export type ActionContext = { baseUrl?: string; logger: Logger_2; logStream: Writable; @@ -77,7 +76,7 @@ export const createBuiltinActions: (options: { containerRunner?: ContainerRunner; config: Config; additionalTemplateFilters?: Record; -}) => TemplateAction[]; +}) => TemplateAction[]; // Warning: (ae-missing-release-tag) "createCatalogRegisterAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -85,17 +84,33 @@ export const createBuiltinActions: (options: { export function createCatalogRegisterAction(options: { catalogClient: CatalogApi; integrations: ScmIntegrations; -}): TemplateAction; +}): TemplateAction< + | { + catalogInfoUrl: string; + optional?: boolean | undefined; + } + | { + repoContentsUrl: string; + catalogInfoPath?: string | undefined; + optional?: boolean | undefined; + } +>; // Warning: (ae-missing-release-tag) "createCatalogWriteAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export function createCatalogWriteAction(): TemplateAction; +export function createCatalogWriteAction(): TemplateAction<{ + filePath?: string | undefined; + entity: Entity; +}>; // Warning: (ae-missing-release-tag) "createDebugLogAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public -export function createDebugLogAction(): TemplateAction; +export function createDebugLogAction(): TemplateAction<{ + message?: string | undefined; + listWorkspace?: boolean | undefined; +}>; export { createFetchCookiecutterAction }; @@ -105,7 +120,10 @@ export { createFetchCookiecutterAction }; export function createFetchPlainAction(options: { reader: UrlReader; integrations: ScmIntegrations; -}): TemplateAction; +}): TemplateAction<{ + url: string; + targetPath?: string | undefined; +}>; // Warning: (ae-missing-release-tag) "createFetchTemplateAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -114,17 +132,32 @@ export function createFetchTemplateAction(options: { reader: UrlReader; integrations: ScmIntegrations; additionalTemplateFilters?: Record; -}): TemplateAction; +}): TemplateAction<{ + url: string; + targetPath?: string | undefined; + values: any; + templateFileExtension?: string | boolean | undefined; + copyWithoutRender?: string[] | undefined; + cookiecutterCompat?: boolean | undefined; +}>; // Warning: (ae-missing-release-tag) "createFilesystemDeleteAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const createFilesystemDeleteAction: () => TemplateAction; +export const createFilesystemDeleteAction: () => TemplateAction<{ + files: string[]; +}>; // Warning: (ae-missing-release-tag) "createFilesystemRenameAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const createFilesystemRenameAction: () => TemplateAction; +export const createFilesystemRenameAction: () => TemplateAction<{ + files: Array<{ + from: string; + to: string; + overwrite?: boolean; + }>; +}>; // Warning: (ae-missing-release-tag) "createGithubActionsDispatchAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -132,7 +165,17 @@ export const createFilesystemRenameAction: () => TemplateAction; export function createGithubActionsDispatchAction(options: { integrations: ScmIntegrations; githubCredentialsProvider?: GithubCredentialsProvider; -}): TemplateAction; +}): TemplateAction<{ + repoUrl: string; + workflowId: string; + branchOrTagName: string; + workflowInputs?: + | { + [key: string]: string; + } + | undefined; + token?: string | undefined; +}>; // Warning: (ae-missing-release-tag) "createGithubWebhookAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -141,7 +184,16 @@ export function createGithubWebhookAction(options: { integrations: ScmIntegrationRegistry; defaultWebhookSecret?: string; githubCredentialsProvider?: GithubCredentialsProvider; -}): TemplateAction; +}): TemplateAction<{ + repoUrl: string; + webhookUrl: string; + webhookSecret?: string | undefined; + events?: string[] | undefined; + active?: boolean | undefined; + contentType?: 'form' | 'json' | undefined; + insecureSsl?: boolean | undefined; + token?: string | undefined; +}>; // Warning: (ae-missing-release-tag) "createPublishAzureAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -149,7 +201,13 @@ export function createGithubWebhookAction(options: { export function createPublishAzureAction(options: { integrations: ScmIntegrationRegistry; config: Config; -}): TemplateAction; +}): TemplateAction<{ + repoUrl: string; + description?: string | undefined; + defaultBranch?: string | undefined; + sourcePath?: string | undefined; + token?: string | undefined; +}>; // Warning: (ae-missing-release-tag) "createPublishBitbucketAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -157,12 +215,22 @@ export function createPublishAzureAction(options: { export function createPublishBitbucketAction(options: { integrations: ScmIntegrationRegistry; config: Config; -}): TemplateAction; +}): TemplateAction<{ + repoUrl: string; + description?: string | undefined; + defaultBranch?: string | undefined; + repoVisibility?: 'private' | 'public' | undefined; + sourcePath?: string | undefined; + enableLFS?: boolean | undefined; + token?: string | undefined; +}>; // Warning: (ae-missing-release-tag) "createPublishFileAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public -export function createPublishFileAction(): TemplateAction; +export function createPublishFileAction(): TemplateAction<{ + path: string; +}>; // Warning: (ae-missing-release-tag) "createPublishGithubAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -171,7 +239,23 @@ export function createPublishGithubAction(options: { integrations: ScmIntegrationRegistry; config: Config; githubCredentialsProvider?: GithubCredentialsProvider; -}): TemplateAction; +}): TemplateAction<{ + repoUrl: string; + description?: string | undefined; + access?: string | undefined; + defaultBranch?: string | undefined; + sourcePath?: string | undefined; + requireCodeOwnerReviews?: boolean | undefined; + repoVisibility?: 'internal' | 'private' | 'public' | undefined; + collaborators?: + | { + username: string; + access: 'pull' | 'push' | 'admin' | 'maintain' | 'triage'; + }[] + | undefined; + token?: string | undefined; + topics?: string[] | undefined; +}>; // Warning: (ae-forgotten-export) The symbol "CreateGithubPullRequestActionOptions" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "createPublishGithubPullRequestAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -181,7 +265,15 @@ export const createPublishGithubPullRequestAction: ({ integrations, githubCredentialsProvider, clientFactory, -}: CreateGithubPullRequestActionOptions) => TemplateAction; +}: CreateGithubPullRequestActionOptions) => TemplateAction<{ + title: string; + branchName: string; + description: string; + repoUrl: string; + targetPath?: string | undefined; + sourcePath?: string | undefined; + token?: string | undefined; +}>; // Warning: (ae-missing-release-tag) "createPublishGitlabAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -189,14 +281,28 @@ export const createPublishGithubPullRequestAction: ({ export function createPublishGitlabAction(options: { integrations: ScmIntegrationRegistry; config: Config; -}): TemplateAction; +}): TemplateAction<{ + repoUrl: string; + defaultBranch?: string | undefined; + repoVisibility?: 'internal' | 'private' | 'public' | undefined; + sourcePath?: string | undefined; + token?: string | undefined; +}>; // Warning: (ae-missing-release-tag) "createPublishGitlabMergeRequestAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) export const createPublishGitlabMergeRequestAction: (options: { integrations: ScmIntegrationRegistry; -}) => TemplateAction; +}) => TemplateAction<{ + projectid: string; + repoUrl: string; + title: string; + description: string; + branchName: string; + targetPath: string; + token?: string | undefined; +}>; // Warning: (ae-missing-release-tag) "createRouter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -206,13 +312,9 @@ export function createRouter(options: RouterOptions): Promise; // Warning: (ae-missing-release-tag) "createTemplateAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const createTemplateAction: < - Input extends Partial<{ - [name: string]: JsonValue | Partial | undefined; - }>, ->( - templateAction: TemplateAction, -) => TemplateAction; +export const createTemplateAction: ( + templateAction: TemplateAction, +) => TemplateAction; // @public export type CreateWorkerOptions = { @@ -531,7 +633,7 @@ export class TaskWorker { // Warning: (ae-missing-release-tag) "TemplateAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export type TemplateAction = { +export type TemplateAction = { id: string; description?: string; schema?: { @@ -546,13 +648,11 @@ export type TemplateAction = { // @public (undocumented) export class TemplateActionRegistry { // (undocumented) - get(actionId: string): TemplateAction; + get(actionId: string): TemplateAction; // (undocumented) - list(): TemplateAction[]; + list(): TemplateAction[]; // (undocumented) - register( - action: TemplateAction, - ): void; + register(action: TemplateAction): void; } // Warning: (ae-missing-release-tag) "TemplateFilter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/TemplateActionRegistry.ts b/plugins/scaffolder-backend/src/scaffolder/actions/TemplateActionRegistry.ts index cd31db49eb..e546d5bf9a 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/TemplateActionRegistry.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/TemplateActionRegistry.ts @@ -14,13 +14,14 @@ * limitations under the License. */ -import { InputBase, TemplateAction } from './types'; +import { JsonObject } from '@backstage/types'; import { ConflictError, NotFoundError } from '@backstage/errors'; +import { TemplateAction } from './types'; export class TemplateActionRegistry { private readonly actions = new Map>(); - register(action: TemplateAction) { + register(action: TemplateAction) { if (this.actions.has(action.id)) { throw new ConflictError( `Template action with ID '${action.id}' has already been registered`, @@ -29,7 +30,7 @@ export class TemplateActionRegistry { this.actions.set(action.id, action); } - get(actionId: string): TemplateAction { + get(actionId: string): TemplateAction { const action = this.actions.get(actionId); if (!action) { throw new NotFoundError( @@ -39,7 +40,7 @@ export class TemplateActionRegistry { return action; } - list(): TemplateAction[] { + list(): TemplateAction[] { return [...this.actions.values()]; } } diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts index 481ab894ec..9df2b7146e 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts @@ -15,6 +15,7 @@ */ import { ContainerRunner, UrlReader } from '@backstage/backend-common'; +import { JsonObject } from '@backstage/types'; import { CatalogApi } from '@backstage/catalog-client'; import { GithubCredentialsProvider, @@ -47,6 +48,7 @@ import { createGithubWebhookAction, } from './github'; import { TemplateFilter } from '../../../lib'; +import { TemplateAction } from '../types'; export const createBuiltinActions = (options: { reader: UrlReader; @@ -55,7 +57,7 @@ export const createBuiltinActions = (options: { containerRunner?: ContainerRunner; config: Config; additionalTemplateFilters?: Record; -}) => { +}): TemplateAction[] => { const { reader, integrations, @@ -126,5 +128,5 @@ export const createBuiltinActions = (options: { ); } - return actions; + return actions as TemplateAction[]; }; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/debug/log.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/debug/log.test.ts index 38c50afecc..ecd0f33e21 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/debug/log.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/debug/log.test.ts @@ -61,7 +61,7 @@ describe('debug:log', () => { const context = { ...mockContext, input: { - listWorkspace: 'true', + listWorkspace: true, }, }; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.test.ts index 6ee8f8ce01..2f9bfd3796 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.test.ts @@ -27,12 +27,18 @@ import { ScmIntegrations } from '@backstage/integration'; import { PassThrough } from 'stream'; import { fetchContents } from './helpers'; import { ActionContext, TemplateAction } from '../../types'; -import { createFetchTemplateAction, FetchTemplateInput } from './template'; +import { createFetchTemplateAction } from './template'; jest.mock('./helpers', () => ({ fetchContents: jest.fn(), })); +type FetchTemplateInput = ReturnType< + typeof createFetchTemplateAction +> extends TemplateAction + ? U + : never; + const realFiles = Object.fromEntries( [ resolvePackagePath( diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.ts index 32a3a84070..08dfc46caf 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.ts @@ -28,22 +28,6 @@ import { SecureTemplater, } from '../../../../lib/templating/SecureTemplater'; -type CookieCompatInput = { - copyWithoutRender?: string[]; - cookiecutterCompat?: boolean; -}; - -type ExtensionInput = { - templateFileExtension?: string | boolean; -}; - -export type FetchTemplateInput = { - url: string; - targetPath?: string; - values: any; -} & CookieCompatInput & - ExtensionInput; - export function createFetchTemplateAction(options: { reader: UrlReader; integrations: ScmIntegrations; @@ -51,7 +35,16 @@ export function createFetchTemplateAction(options: { }) { const { reader, integrations, additionalTemplateFilters } = options; - return createTemplateAction({ + return createTemplateAction<{ + url: string; + targetPath?: string; + values: any; + templateFileExtension?: string | boolean; + + // Cookiecutter compat options + copyWithoutRender?: string[]; + cookiecutterCompat?: boolean; + }>({ id: 'fetch:template', description: "Downloads a skeleton, templates variables into file and directory names and content, and places the result in the workspace, or optionally in a subdirectory specified by the 'targetPath' input option.", diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/filesystem/delete.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/filesystem/delete.test.ts index ba8a145721..713de5b0ad 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/filesystem/delete.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/filesystem/delete.test.ts @@ -61,28 +61,28 @@ describe('fs:delete', () => { await expect( action.handler({ ...mockContext, - input: { files: undefined }, + input: { files: undefined } as any, }), ).rejects.toThrow(/files must be an Array/); await expect( action.handler({ ...mockContext, - input: { files: {} }, + input: { files: {} } as any, }), ).rejects.toThrow(/files must be an Array/); await expect( action.handler({ ...mockContext, - input: { files: '' }, + input: { files: '' } as any, }), ).rejects.toThrow(/files must be an Array/); await expect( action.handler({ ...mockContext, - input: { files: null }, + input: { files: null } as any, }), ).rejects.toThrow(/files must be an Array/); }); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/filesystem/rename.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/filesystem/rename.test.ts index 8452735083..b12e4269c2 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/filesystem/rename.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/filesystem/rename.test.ts @@ -76,28 +76,28 @@ describe('fs:rename', () => { await expect( action.handler({ ...mockContext, - input: { files: undefined }, + input: { files: undefined } as any, }), ).rejects.toThrow(/files must be an Array/); await expect( action.handler({ ...mockContext, - input: { files: {} }, + input: { files: {} } as any, }), ).rejects.toThrow(/files must be an Array/); await expect( action.handler({ ...mockContext, - input: { files: '' }, + input: { files: '' } as any, }), ).rejects.toThrow(/files must be an Array/); await expect( action.handler({ ...mockContext, - input: { files: null }, + input: { files: null } as any, }), ).rejects.toThrow(/files must be an Array/); }); @@ -106,21 +106,21 @@ describe('fs:rename', () => { await expect( action.handler({ ...mockContext, - input: { files: ['old.md'] }, + input: { files: ['old.md'] } as any, }), ).rejects.toThrow(/each file must have a from and to property/); await expect( action.handler({ ...mockContext, - input: { files: [{ from: 'old.md' }] }, + input: { files: [{ from: 'old.md' }] } as any, }), ).rejects.toThrow(/each file must have a from and to property/); await expect( action.handler({ ...mockContext, - input: { files: [{ to: 'new.md' }] }, + input: { files: [{ to: 'new.md' }] } as any, }), ).rejects.toThrow(/each file must have a from and to property/); }); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/filesystem/rename.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/filesystem/rename.ts index 4bdba96750..c3e128cec5 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/filesystem/rename.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/filesystem/rename.ts @@ -17,16 +17,16 @@ import { createTemplateAction } from '../../createTemplateAction'; import { resolveSafeChildPath } from '@backstage/backend-common'; import { InputError } from '@backstage/errors'; -import { JsonObject } from '@backstage/types'; import fs from 'fs-extra'; -interface FilesToRename extends JsonObject { - from: string; - to: string; -} - export const createFilesystemRenameAction = () => { - return createTemplateAction<{ files: FilesToRename }>({ + return createTemplateAction<{ + files: Array<{ + from: string; + to: string; + overwrite?: boolean; + }>; + }>({ id: 'fs:rename', description: 'Renames files and directories within the workspace', schema: { diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubWebhook.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubWebhook.ts index 660c7793f2..0c93ae1dd5 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubWebhook.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubWebhook.ts @@ -23,8 +23,6 @@ import { OctokitProvider } from './OctokitProvider'; import { emitterEventNames } from '@octokit/webhooks'; import { assertError } from '@backstage/errors'; -type ContentType = 'form' | 'json'; - export function createGithubWebhookAction(options: { integrations: ScmIntegrationRegistry; defaultWebhookSecret?: string; @@ -45,7 +43,7 @@ export function createGithubWebhookAction(options: { webhookSecret?: string; events?: string[]; active?: boolean; - contentType?: ContentType; + contentType?: 'form' | 'json'; insecureSsl?: boolean; token?: string; }>({ diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.test.ts index 3d14710f3e..5493219d57 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.test.ts @@ -51,7 +51,7 @@ describe('publish:bitbucket', () => { const mockContext = { input: { repoUrl: 'bitbucket.org?workspace=workspace&project=project&repo=repo', - repoVisibility: 'private', + repoVisibility: 'private' as const, }, workspacePath: 'lol', logger: getVoidLogger(), diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.ts index 8ba8592642..47ebce0550 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.ts @@ -29,7 +29,7 @@ const createBitbucketCloudRepository = async (opts: { workspace: string; project: string; repo: string; - description: string; + description?: string; repoVisibility: 'private' | 'public'; authorization: string; }) => { @@ -91,7 +91,7 @@ const createBitbucketServerRepository = async (opts: { host: string; project: string; repo: string; - description: string; + description?: string; repoVisibility: 'private' | 'public'; authorization: string; apiBaseUrl?: string; @@ -200,11 +200,11 @@ export function createPublishBitbucketAction(options: { return createTemplateAction<{ repoUrl: string; - description: string; + description?: string; defaultBranch?: string; - repoVisibility: 'private' | 'public'; + repoVisibility?: 'private' | 'public'; sourcePath?: string; - enableLFS: boolean; + enableLFS?: boolean; token?: string; }>({ id: 'publish:bitbucket', diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts index 5467ca651c..1e58635bbe 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts @@ -52,7 +52,7 @@ describe('publish:github', () => { input: { repoUrl: 'github.com?repo=repo&owner=owner', description: 'description', - repoVisibility: 'private', + repoVisibility: 'private' as const, access: 'owner/blam', }, workspacePath: 'lol', diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts index 139fad04d4..cabe40986f 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts @@ -28,9 +28,6 @@ import { Config } from '@backstage/config'; import { OctokitProvider } from '../github/OctokitProvider'; import { assertError } from '@backstage/errors'; -type Permission = 'pull' | 'push' | 'admin' | 'maintain' | 'triage'; -type Collaborator = { access: Permission; username: string }; - export function createPublishGithubAction(options: { integrations: ScmIntegrationRegistry; config: Config; @@ -50,8 +47,11 @@ export function createPublishGithubAction(options: { defaultBranch?: string; sourcePath?: string; requireCodeOwnerReviews?: boolean; - repoVisibility: 'private' | 'internal' | 'public'; - collaborators: Collaborator[]; + repoVisibility?: 'private' | 'internal' | 'public'; + collaborators?: Array<{ + username: string; + access: 'pull' | 'push' | 'admin' | 'maintain' | 'triage'; + }>; token?: string; topics?: string[]; }>({ diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.test.ts index 20ea4b03da..64d3bc41de 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.test.ts @@ -28,13 +28,18 @@ import { ActionContext, TemplateAction } from '../../types'; import { ClientFactoryInput, createPublishGithubPullRequestAction, - GithubPullRequestActionInput, PullRequestCreator, } from './githubPullRequest'; const root = os.platform() === 'win32' ? 'C:\\root' : '/root'; const workspacePath = resolvePath(root, 'my-workspace'); +type GithubPullRequestActionInput = ReturnType< + typeof createPublishGithubPullRequestAction +> extends TemplateAction + ? U + : never; + describe('createPublishGithubPullRequestAction', () => { let instance: TemplateAction; let fakeClient: PullRequestCreator; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.ts index 80333c4966..c329b6b6f3 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.ts @@ -48,16 +48,6 @@ export type PullRequestCreatorConstructor = ( octokit: Octokit, ) => PullRequestCreator; -export type GithubPullRequestActionInput = { - title: string; - branchName: string; - description: string; - repoUrl: string; - targetPath?: string; - sourcePath?: string; - token?: string; -}; - export type ClientFactoryInput = { integrations: ScmIntegrationRegistry; githubCredentialsProvider?: GithubCredentialsProvider; @@ -122,7 +112,15 @@ export const createPublishGithubPullRequestAction = ({ githubCredentialsProvider, clientFactory = defaultClientFactory, }: CreateGithubPullRequestActionOptions) => { - return createTemplateAction({ + return createTemplateAction<{ + title: string; + branchName: string; + description: string; + repoUrl: string; + targetPath?: string; + sourcePath?: string; + token?: string; + }>({ id: 'publish:github:pull-request', schema: { input: { diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.test.ts index a32fea8830..db4ad5a019 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.test.ts @@ -45,7 +45,7 @@ describe('publish:gitlab', () => { const mockContext = { input: { repoUrl: 'gitlab.com?repo=repo&owner=owner', - repoVisibility: 'private', + repoVisibility: 'private' as const, }, workspacePath: 'lol', logger: getVoidLogger(), diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.ts index 48979306b1..a3c1919b63 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.ts @@ -31,7 +31,7 @@ export function createPublishGitlabAction(options: { return createTemplateAction<{ repoUrl: string; defaultBranch?: string; - repoVisibility: 'private' | 'internal' | 'public'; + repoVisibility?: 'private' | 'internal' | 'public'; sourcePath?: string; token?: string; }>({ diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts index bf687268c3..e04eb5cdb5 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts @@ -24,22 +24,20 @@ import { InputError } from '@backstage/errors'; import { parseRepoUrl } from './util'; import { resolveSafeChildPath } from '@backstage/backend-common'; -export type GitlabMergeRequestActionInput = { - projectid: string; - repoUrl: string; - title: string; - description: string; - branchName: string; - targetPath: string; - token?: string; -}; - export const createPublishGitlabMergeRequestAction = (options: { integrations: ScmIntegrationRegistry; }) => { const { integrations } = options; - return createTemplateAction({ + return createTemplateAction<{ + projectid: string; + repoUrl: string; + title: string; + description: string; + branchName: string; + targetPath: string; + token?: string; + }>({ id: 'publish:gitlab:merge-request', schema: { input: { diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/createTemplateAction.ts b/plugins/scaffolder-backend/src/scaffolder/actions/createTemplateAction.ts index a741900f9d..243f39e070 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/createTemplateAction.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/createTemplateAction.ts @@ -14,11 +14,12 @@ * limitations under the License. */ -import { InputBase, TemplateAction } from './types'; +import { JsonObject } from '@backstage/types'; +import { TemplateAction } from './types'; -export const createTemplateAction = ( - templateAction: TemplateAction, -): TemplateAction => { +export const createTemplateAction = ( + templateAction: TemplateAction, +): TemplateAction => { // TODO(blam): Can add some more validation here to validate the action later on return templateAction; }; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/types.ts b/plugins/scaffolder-backend/src/scaffolder/actions/types.ts index 4b842e8c5c..f1e5dd7b77 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/types.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/types.ts @@ -20,11 +20,7 @@ import { JsonValue, JsonObject } from '@backstage/types'; import { Schema } from 'jsonschema'; import { TaskSecrets, TemplateMetadata } from '../tasks/types'; -type PartialJsonObject = Partial; -type PartialJsonValue = PartialJsonObject | JsonValue | undefined; -export type InputBase = Partial<{ [name: string]: PartialJsonValue }>; - -export type ActionContext = { +export type ActionContext = { /** * Base URL for the location of the task spec, typically the url of the source entity file. */ @@ -51,7 +47,7 @@ export type ActionContext = { metadata?: TemplateMetadata; }; -export type TemplateAction = { +export type TemplateAction = { id: string; description?: string; schema?: {