Merge pull request #26684 from MarkForesta/include_dry_run_template_metadata
Include templateMetadata in Dry Run
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
---
|
||||
|
||||
Modified `createDryRunner` and corresponding route to include `templateMetaData` inside the `templateInfo`. This allows custom action writers to access things like `templateInfo.entity.metadata.name` via the action context while executing templates using the dry run framework.
|
||||
@@ -15,10 +15,9 @@
|
||||
*/
|
||||
|
||||
import { ScmIntegrations } from '@backstage/integration';
|
||||
import { TaskSpec } from '@backstage/plugin-scaffolder-common';
|
||||
import { TaskSpec, TemplateInfo } from '@backstage/plugin-scaffolder-common';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { pathToFileURL } from 'url';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { Logger } from 'winston';
|
||||
import {
|
||||
createTemplateAction,
|
||||
@@ -29,19 +28,19 @@ import {
|
||||
SerializedFile,
|
||||
serializeDirectoryContents,
|
||||
} from '@backstage/plugin-scaffolder-node';
|
||||
import path from 'path';
|
||||
import { TemplateActionRegistry } from '../actions';
|
||||
import { NunjucksWorkflowRunner } from '../tasks/NunjucksWorkflowRunner';
|
||||
import { DecoratedActionsRegistry } from './DecoratedActionsRegistry';
|
||||
import fs from 'fs-extra';
|
||||
import { PermissionEvaluator } from '@backstage/plugin-permission-common';
|
||||
import {
|
||||
BackstageCredentials,
|
||||
resolveSafeChildPath,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { BackstageCredentials } from '@backstage/backend-plugin-api';
|
||||
import type { UserEntity } from '@backstage/catalog-model';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
interface DryRunInput {
|
||||
spec: TaskSpec;
|
||||
templateInfo: TemplateInfo;
|
||||
secrets?: TaskSecrets;
|
||||
directoryContents: SerializedFile[];
|
||||
credentials: BackstageCredentials;
|
||||
@@ -94,18 +93,21 @@ export function createDryRunner(options: TemplateTesterCreateOptions) {
|
||||
]),
|
||||
});
|
||||
|
||||
// Extracting contentsPath and dryRunId from the baseUrl
|
||||
const baseUrl = input.templateInfo.baseUrl;
|
||||
if (!baseUrl) {
|
||||
throw new Error('baseUrl is required');
|
||||
}
|
||||
const basePath = fileURLToPath(new URL(baseUrl));
|
||||
const contentsPath = path.dirname(basePath);
|
||||
const dryRunId = uuid();
|
||||
|
||||
const log = new Array<{ body: JsonObject }>();
|
||||
const contentsPath = resolveSafeChildPath(
|
||||
options.workingDirectory,
|
||||
`dry-run-content-${dryRunId}`,
|
||||
);
|
||||
|
||||
try {
|
||||
await deserializeDirectoryContents(contentsPath, input.directoryContents);
|
||||
|
||||
const abortSignal = new AbortController().signal;
|
||||
|
||||
const result = await workflowRunner.execute({
|
||||
spec: {
|
||||
...input.spec,
|
||||
@@ -117,12 +119,7 @@ export function createDryRunner(options: TemplateTesterCreateOptions) {
|
||||
action: 'dry-run:extract',
|
||||
},
|
||||
],
|
||||
templateInfo: {
|
||||
entityRef: 'template:default/dry-run',
|
||||
baseUrl: pathToFileURL(
|
||||
resolveSafeChildPath(contentsPath, 'template.yaml'),
|
||||
).toString(),
|
||||
},
|
||||
templateInfo: input.templateInfo,
|
||||
},
|
||||
secrets: input.secrets,
|
||||
getInitiatorCredentials: () => Promise.resolve(input.credentials),
|
||||
|
||||
@@ -1331,6 +1331,39 @@ describe('NunjucksWorkflowRunner', () => {
|
||||
|
||||
expect(fakeActionHandler.mock.calls[0][0].isDryRun).toEqual(true);
|
||||
});
|
||||
|
||||
it('should have metadata in action context during dry run', async () => {
|
||||
const task = createMockTaskWithSpec(
|
||||
{
|
||||
apiVersion: 'scaffolder.backstage.io/v1beta3',
|
||||
templateInfo: {
|
||||
entityRef: 'dryRun-Entity',
|
||||
entity: { metadata: { name: 'test-template' } },
|
||||
},
|
||||
parameters: {},
|
||||
output: {},
|
||||
steps: [
|
||||
{
|
||||
id: 'test',
|
||||
name: 'name',
|
||||
action: 'jest-validated-action',
|
||||
input: { foo: 1 },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
backstageToken: token,
|
||||
},
|
||||
true,
|
||||
);
|
||||
|
||||
await runner.execute(task);
|
||||
|
||||
expect(fakeActionHandler.mock.calls[0][0].isDryRun).toEqual(true);
|
||||
expect(
|
||||
fakeActionHandler.mock.calls[0][0].templateInfo.entity.metadata.name,
|
||||
).toEqual('test-template');
|
||||
});
|
||||
});
|
||||
|
||||
describe('permissions', () => {
|
||||
|
||||
@@ -94,6 +94,7 @@ import {
|
||||
PermissionsService,
|
||||
SchedulerService,
|
||||
UrlReaderService,
|
||||
resolveSafeChildPath,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import {
|
||||
IdentityApi,
|
||||
@@ -105,6 +106,8 @@ import {
|
||||
AutocompleteHandler,
|
||||
WorkspaceProvider,
|
||||
} from '@backstage/plugin-scaffolder-node/alpha';
|
||||
import { pathToFileURL } from 'url';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -814,6 +817,22 @@ export async function createRouter(
|
||||
name: step.name ?? step.action,
|
||||
}));
|
||||
|
||||
const dryRunId = uuid();
|
||||
const contentsPath = resolveSafeChildPath(
|
||||
workingDirectory,
|
||||
`dry-run-content-${dryRunId}`,
|
||||
);
|
||||
|
||||
const templateInfo = {
|
||||
entityRef: stringifyEntityRef(template),
|
||||
entity: {
|
||||
metadata: template.metadata,
|
||||
},
|
||||
baseUrl: pathToFileURL(
|
||||
resolveSafeChildPath(contentsPath, 'template.yaml'),
|
||||
).toString(),
|
||||
};
|
||||
|
||||
const result = await dryRunner({
|
||||
spec: {
|
||||
apiVersion: template.apiVersion,
|
||||
@@ -825,6 +844,7 @@ export async function createRouter(
|
||||
ref: userEntityRef,
|
||||
},
|
||||
},
|
||||
templateInfo: templateInfo,
|
||||
directoryContents: (body.directoryContents ?? []).map(file => ({
|
||||
path: file.path,
|
||||
content: Buffer.from(file.base64Content, 'base64'),
|
||||
|
||||
Reference in New Issue
Block a user