feat: small refactor to move some logic out of the index files and move to using .args() and .returns() as it's cleaner

Signed-off-by: benjdlambert <ben@blam.sh>
This commit is contained in:
benjdlambert
2025-03-21 11:07:00 +01:00
parent d48525c9f8
commit 3cfc7f06d1
21 changed files with 230 additions and 148 deletions
@@ -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',
@@ -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,
});
@@ -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';
@@ -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),
});
@@ -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';
@@ -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,
});
@@ -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';
@@ -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}`;
},
});
@@ -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';
@@ -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';
@@ -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';
@@ -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';
@@ -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';
+1 -1
View File
@@ -206,7 +206,7 @@ export interface WorkspaceProvider {
}): Promise<void>;
}
// @alpha
// @alpha (undocumented)
export type ZodFunctionSchema<
TFunctionArgs extends [z.ZodTypeAny, ...z.ZodTypeAny[]],
TReturnType extends z.ZodTypeAny,
@@ -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';
/**
@@ -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<z.ZodTuple<TFunctionArgs, null>, TReturnType>
| z.ZodType<
(...args: z.infer<z.ZodTuple<TFunctionArgs>>) => z.infer<TReturnType>
>;
/** @alpha */
export type CreatedTemplateFilter<
TFunctionArgs extends [z.ZodTypeAny, ...z.ZodTypeAny[]],
@@ -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.
@@ -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';
@@ -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.
@@ -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<z.ZodTuple<TFunctionArgs, null>, TReturnType>
| z.ZodType<
(...args: z.infer<z.ZodTuple<TFunctionArgs>>) => z.infer<TReturnType>
>;