diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/index.ts b/plugins/scaffolder-backend/src/lib/templating/filters/createDefaultFilters.ts similarity index 100% rename from plugins/scaffolder-backend/src/lib/templating/filters/index.ts rename to plugins/scaffolder-backend/src/lib/templating/filters/createDefaultFilters.ts diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/parseEntityRef/examples.ts b/plugins/scaffolder-backend/src/lib/templating/filters/parseEntityRef/examples.ts index fd6219c998..aef5b451bb 100644 --- a/plugins/scaffolder-backend/src/lib/templating/filters/parseEntityRef/examples.ts +++ b/plugins/scaffolder-backend/src/lib/templating/filters/parseEntityRef/examples.ts @@ -1,5 +1,3 @@ -import { TemplateFilterExample } from '@backstage/plugin-scaffolder-node/alpha'; - /* * Copyright 2025 The Backstage Authors * @@ -15,6 +13,8 @@ import { TemplateFilterExample } from '@backstage/plugin-scaffolder-node/alpha'; * See the License for the specific language governing permissions and * limitations under the License. */ +import { TemplateFilterExample } from '@backstage/plugin-scaffolder-node/alpha'; + export const examples: TemplateFilterExample[] = [ { description: 'Without context', diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/parseEntityRef/filter.ts b/plugins/scaffolder-backend/src/lib/templating/filters/parseEntityRef/filter.ts new file mode 100644 index 0000000000..23ce340370 --- /dev/null +++ b/plugins/scaffolder-backend/src/lib/templating/filters/parseEntityRef/filter.ts @@ -0,0 +1,63 @@ +/* + * Copyright 2025 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 { parseEntityRef as filter } from '@backstage/catalog-model'; +import { createTemplateFilter } from '@backstage/plugin-scaffolder-node/alpha'; +import { examples } from './examples'; + +export const parseEntityRef = createTemplateFilter({ + id: 'parseEntityRef', + description: + 'Extracts the parts of an entity reference, such as the kind, namespace, and name.', + schema: z => + z + .function() + .args( + z.union([ + z.string().describe('compact entity reference'), + z + .object({ + kind: z.string().optional(), + namespace: z.string().optional(), + name: z.string(), + }) + .describe('`CompoundEntityRef`'), + ]), + z + .object({ + defaultKind: z + .string() + .describe('The default kind, if none is given in the reference'), + defaultNamespace: z + .string() + .describe( + 'The default namespace, if none is given in the reference', + ), + }) + .partial() + .optional(), + ) + .returns( + z + .object({ + kind: z.string(), + namespace: z.string(), + name: z.string(), + }) + .describe('`CompoundEntityRef`'), + ), + examples, + filter, +}); diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/parseEntityRef/index.ts b/plugins/scaffolder-backend/src/lib/templating/filters/parseEntityRef/index.ts index 221be44055..b11d925161 100644 --- a/plugins/scaffolder-backend/src/lib/templating/filters/parseEntityRef/index.ts +++ b/plugins/scaffolder-backend/src/lib/templating/filters/parseEntityRef/index.ts @@ -13,49 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { parseEntityRef as filter } from '@backstage/catalog-model'; -import { createTemplateFilter } from '@backstage/plugin-scaffolder-node/alpha'; -import { examples } from './examples'; - -export const parseEntityRef = createTemplateFilter({ - id: 'parseEntityRef', - description: - 'Extracts the parts of an entity reference, such as the kind, namespace, and name.', - schema: z => - z.function( - z.tuple([ - z.union([ - z.string().describe('compact entity reference'), - z - .object({ - kind: z.string().optional(), - namespace: z.string().optional(), - name: z.string(), - }) - .describe('`CompoundEntityRef`'), - ]), - z - .object({ - defaultKind: z - .string() - .describe('The default kind, if none is given in the reference'), - defaultNamespace: z - .string() - .describe( - 'The default namespace, if none is given in the reference', - ), - }) - .partial() - .optional(), - ]), - z - .object({ - kind: z.string(), - namespace: z.string(), - name: z.string(), - }) - .describe('`CompoundEntityRef`'), - ), - examples, - filter, -}); +export { parseEntityRef } from './filter'; diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/parseRepoUrl/filter.ts b/plugins/scaffolder-backend/src/lib/templating/filters/parseRepoUrl/filter.ts new file mode 100644 index 0000000000..8a7daea3bc --- /dev/null +++ b/plugins/scaffolder-backend/src/lib/templating/filters/parseRepoUrl/filter.ts @@ -0,0 +1,52 @@ +/* + * Copyright 2025 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 { ScmIntegrations } from '@backstage/integration'; +import { parseRepoUrl } from '@backstage/plugin-scaffolder-node'; +import { createTemplateFilter } from '@backstage/plugin-scaffolder-node/alpha'; +import { examples } from './examples'; + +export const createParseRepoUrl = (integrations: ScmIntegrations) => + createTemplateFilter({ + id: 'parseRepoUrl', + description: + 'Parses a repository URL into its constituent parts: owner, repository name, etc.', + schema: z => + z + .function() + .args( + z.string().describe('repo URL as collected from repository picker'), + ) + .returns( + z + .object({ + repo: z.string(), + host: z.string(), + }) + .merge( + z + .object({ + owner: z.string(), + organization: z.string(), + workspace: z.string(), + project: z.string(), + }) + .partial(), + ) + .describe('`RepoSpec`'), + ), + examples, + filter: url => parseRepoUrl(url, integrations), + }); diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/parseRepoUrl/index.ts b/plugins/scaffolder-backend/src/lib/templating/filters/parseRepoUrl/index.ts index 1c65852bbb..ed505315b5 100644 --- a/plugins/scaffolder-backend/src/lib/templating/filters/parseRepoUrl/index.ts +++ b/plugins/scaffolder-backend/src/lib/templating/filters/parseRepoUrl/index.ts @@ -13,38 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ScmIntegrations } from '@backstage/integration'; -import { parseRepoUrl } from '@backstage/plugin-scaffolder-node'; -import { createTemplateFilter } from '@backstage/plugin-scaffolder-node/alpha'; -import { examples } from './examples'; - -export const createParseRepoUrl = (integrations: ScmIntegrations) => - createTemplateFilter({ - id: 'parseRepoUrl', - description: - 'Parses a repository URL into its constituent parts: owner, repository name, etc.', - schema: z => - z.function( - z.tuple([ - z.string().describe('repo URL as collected from repository picker'), - ]), - z - .object({ - repo: z.string(), - host: z.string(), - }) - .merge( - z - .object({ - owner: z.string(), - organization: z.string(), - workspace: z.string(), - project: z.string(), - }) - .partial(), - ) - .describe('`RepoSpec`'), - ), - examples, - filter: url => parseRepoUrl(url, integrations), - }); +export { createParseRepoUrl } from './filter'; diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/pick/filter.ts b/plugins/scaffolder-backend/src/lib/templating/filters/pick/filter.ts new file mode 100644 index 0000000000..a38855becc --- /dev/null +++ b/plugins/scaffolder-backend/src/lib/templating/filters/pick/filter.ts @@ -0,0 +1,31 @@ +/* + * Copyright 2025 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 { createTemplateFilter } from '@backstage/plugin-scaffolder-node/alpha'; +import { get as filter } from 'lodash'; +import { examples } from './examples'; + +export const pick = createTemplateFilter({ + id: 'pick', + description: + 'Selects a specific property (e.g. kind, namespace, name) from an object.', + schema: z => + z + .function() + .args(z.any(), z.string().describe('Property')) + .returns(z.any().describe('Selected property')), + examples, + filter, +}); diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/pick/index.ts b/plugins/scaffolder-backend/src/lib/templating/filters/pick/index.ts index 5d8a0d664a..b3ca69bc38 100644 --- a/plugins/scaffolder-backend/src/lib/templating/filters/pick/index.ts +++ b/plugins/scaffolder-backend/src/lib/templating/filters/pick/index.ts @@ -13,19 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { createTemplateFilter } from '@backstage/plugin-scaffolder-node/alpha'; -import { get as filter } from 'lodash'; -import { examples } from './examples'; - -export const pick = createTemplateFilter({ - id: 'pick', - description: - 'Selects a specific property (e.g. kind, namespace, name) from an object.', - schema: z => - z.function( - z.tuple([z.any(), z.string().describe('Property')]), - z.any().describe('Selected property'), - ), - examples, - filter, -}); +export { pick } from './filter'; diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/projectSlug/filter.ts b/plugins/scaffolder-backend/src/lib/templating/filters/projectSlug/filter.ts new file mode 100644 index 0000000000..f6d0eaf681 --- /dev/null +++ b/plugins/scaffolder-backend/src/lib/templating/filters/projectSlug/filter.ts @@ -0,0 +1,37 @@ +/* + * Copyright 2025 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 { ScmIntegrations } from '@backstage/integration'; +import { parseRepoUrl } from '@backstage/plugin-scaffolder-node'; +import { createTemplateFilter } from '@backstage/plugin-scaffolder-node/alpha'; +import { examples } from './examples'; + +export const createProjectSlug = (integrations: ScmIntegrations) => + createTemplateFilter({ + id: 'projectSlug', + description: 'Generates a project slug from a repository URL.', + schema: z => + z + .function() + .args( + z.string().describe('repo URL as collected from repository picker'), + ) + .returns(z.string()), + examples, + filter: repoUrl => { + const { owner, repo } = parseRepoUrl(repoUrl, integrations); + return `${owner}/${repo}`; + }, + }); diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/projectSlug/index.ts b/plugins/scaffolder-backend/src/lib/templating/filters/projectSlug/index.ts index 05bb6d61cd..71a092232c 100644 --- a/plugins/scaffolder-backend/src/lib/templating/filters/projectSlug/index.ts +++ b/plugins/scaffolder-backend/src/lib/templating/filters/projectSlug/index.ts @@ -13,25 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ScmIntegrations } from '@backstage/integration'; -import { parseRepoUrl } from '@backstage/plugin-scaffolder-node'; -import { createTemplateFilter } from '@backstage/plugin-scaffolder-node/alpha'; -import { examples } from './examples'; - -export const createProjectSlug = (integrations: ScmIntegrations) => - createTemplateFilter({ - id: 'projectSlug', - description: 'Generates a project slug from a repository URL.', - schema: z => - z.function( - z.tuple([ - z.string().describe('repo URL as collected from repository picker'), - ]), - z.string(), - ), - examples, - filter: repoUrl => { - const { owner, repo } = parseRepoUrl(repoUrl, integrations); - return `${owner}/${repo}`; - }, - }); +export { createProjectSlug } from './filter'; 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 2e036abc19..8dfa26057b 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.ts @@ -29,7 +29,7 @@ import globby from 'globby'; import fs from 'fs-extra'; import { isBinaryFile } from 'isbinaryfile'; import { SecureTemplater } from '../../../../lib/templating/SecureTemplater'; -import { createDefaultFilters } from '../../../../lib/templating/filters'; +import { createDefaultFilters } from '../../../../lib/templating/filters/createDefaultFilters'; import { examples } from './template.examples'; import { convertFiltersToRecord } from '../../../../util/templating'; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/templateFile.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/templateFile.ts index 9353f5e8d2..2cd4ce883c 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/templateFile.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/templateFile.ts @@ -25,7 +25,7 @@ import { TemplateGlobal, } from '@backstage/plugin-scaffolder-node'; import { SecureTemplater } from '../../../../lib/templating/SecureTemplater'; -import { createDefaultFilters } from '../../../../lib/templating/filters'; +import { createDefaultFilters } from '../../../../lib/templating/filters/createDefaultFilters'; import path from 'path'; import fs from 'fs-extra'; import { convertFiltersToRecord } from '../../../../util/templating'; diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts index e918511354..c352714d9d 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts @@ -55,7 +55,7 @@ import { TemplateFilter, TemplateGlobal, } from '@backstage/plugin-scaffolder-node'; -import { createDefaultFilters } from '../../lib/templating/filters'; +import { createDefaultFilters } from '../../lib/templating/filters/createDefaultFilters'; import { scaffolderActionRules } from '../../service/rules'; import { createCounterMetric, createHistogramMetric } from '../../util/metrics'; import { BackstageLoggerTransport, WinstonLogger } from './logger'; diff --git a/plugins/scaffolder-backend/src/util/templating.test.ts b/plugins/scaffolder-backend/src/util/templating.test.ts index f32e94f95c..61d8637016 100644 --- a/plugins/scaffolder-backend/src/util/templating.test.ts +++ b/plugins/scaffolder-backend/src/util/templating.test.ts @@ -28,7 +28,7 @@ import { extractGlobalValueMetadata, } from './templating'; import { JsonValue } from '@backstage/types'; -import { createDefaultFilters } from '../lib/templating/filters'; +import { createDefaultFilters } from '../lib/templating/filters/createDefaultFilters'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; diff --git a/plugins/scaffolder-node/report-alpha.api.md b/plugins/scaffolder-node/report-alpha.api.md index 6ff02c7ad0..a96f312d2d 100644 --- a/plugins/scaffolder-node/report-alpha.api.md +++ b/plugins/scaffolder-node/report-alpha.api.md @@ -206,7 +206,7 @@ export interface WorkspaceProvider { }): Promise; } -// @alpha +// @alpha (undocumented) export type ZodFunctionSchema< TFunctionArgs extends [z.ZodTypeAny, ...z.ZodTypeAny[]], TReturnType extends z.ZodTypeAny, diff --git a/plugins/scaffolder-node/src/alpha/filters/createTemplateFilter.ts b/plugins/scaffolder-node/src/alpha/filters/createTemplateFilter.ts index 03fb7fd18e..f648658588 100644 --- a/plugins/scaffolder-node/src/alpha/filters/createTemplateFilter.ts +++ b/plugins/scaffolder-node/src/alpha/filters/createTemplateFilter.ts @@ -14,11 +14,8 @@ * limitations under the License. */ -import { - CreatedTemplateFilter, - TemplateFilterExample, - ZodFunctionSchema, -} from './types'; +import { ZodFunctionSchema } from '../types'; +import { CreatedTemplateFilter, TemplateFilterExample } from './types'; import { z } from 'zod'; /** diff --git a/plugins/scaffolder-node/src/alpha/filters/types.ts b/plugins/scaffolder-node/src/alpha/filters/types.ts index 741d4e2ca7..1906ba1c9c 100644 --- a/plugins/scaffolder-node/src/alpha/filters/types.ts +++ b/plugins/scaffolder-node/src/alpha/filters/types.ts @@ -14,6 +14,7 @@ * limitations under the License. */ import { z } from 'zod'; +import { ZodFunctionSchema } from '../types'; export type { TemplateFilter } from '../../types'; @@ -24,21 +25,6 @@ export type TemplateFilterExample = { notes?: string; }; -/** - * Type for template filter schema functions that supports both Zod function definition methods: - * @alpha - */ -export type ZodFunctionSchema< - TFunctionArgs extends [z.ZodTypeAny, ...z.ZodTypeAny[]], - TReturnType extends z.ZodTypeAny, -> = ( - zod: typeof z, -) => - | z.ZodFunction, TReturnType> - | z.ZodType< - (...args: z.infer>) => z.infer - >; - /** @alpha */ export type CreatedTemplateFilter< TFunctionArgs extends [z.ZodTypeAny, ...z.ZodTypeAny[]], diff --git a/plugins/scaffolder-node/src/alpha/globals/createTemplateGlobal.ts b/plugins/scaffolder-node/src/alpha/globals/createTemplateGlobal.ts index a277363f3a..2687b83bb4 100644 --- a/plugins/scaffolder-node/src/alpha/globals/createTemplateGlobal.ts +++ b/plugins/scaffolder-node/src/alpha/globals/createTemplateGlobal.ts @@ -20,7 +20,7 @@ import { CreatedTemplateGlobalValue, TemplateGlobalFunctionExample, } from './types'; -import { ZodFunctionSchema } from '../filters'; +import { ZodFunctionSchema } from '../types'; /** * This function is used to create new template global values in type-safe manner. diff --git a/plugins/scaffolder-node/src/alpha/globals/types.ts b/plugins/scaffolder-node/src/alpha/globals/types.ts index 4754bcaa88..27a3a700e5 100644 --- a/plugins/scaffolder-node/src/alpha/globals/types.ts +++ b/plugins/scaffolder-node/src/alpha/globals/types.ts @@ -15,7 +15,7 @@ */ import { JsonValue } from '@backstage/types'; import { z } from 'zod'; -import { ZodFunctionSchema } from '../filters/types'; +import { ZodFunctionSchema } from '../types'; export type { TemplateGlobal } from '../../types'; diff --git a/plugins/scaffolder-node/src/alpha/index.ts b/plugins/scaffolder-node/src/alpha/index.ts index eb97447a5c..9df968a52d 100644 --- a/plugins/scaffolder-node/src/alpha/index.ts +++ b/plugins/scaffolder-node/src/alpha/index.ts @@ -27,6 +27,7 @@ import { CreatedTemplateGlobal } from './globals'; export * from '../tasks/alpha'; export * from './filters'; export * from './globals'; +export * from './types'; /** * Extension point for managing scaffolder actions. diff --git a/plugins/scaffolder-node/src/alpha/types.ts b/plugins/scaffolder-node/src/alpha/types.ts new file mode 100644 index 0000000000..ca52973775 --- /dev/null +++ b/plugins/scaffolder-node/src/alpha/types.ts @@ -0,0 +1,30 @@ +/* + * Copyright 2025 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 { z } from 'zod'; + +/** + * @alpha + */ +export type ZodFunctionSchema< + TFunctionArgs extends [z.ZodTypeAny, ...z.ZodTypeAny[]], + TReturnType extends z.ZodTypeAny, +> = ( + zod: typeof z, +) => + | z.ZodFunction, TReturnType> + | z.ZodType< + (...args: z.infer>) => z.infer + >;