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 755b435149..cf1662307c 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 @@ -33,6 +33,17 @@ jest.mock('./helpers', () => ({ fetchContents: jest.fn(), })); +const realFiles = Object.fromEntries( + [ + require.resolve('vm2/lib/fixasync'), + resolvePackagePath( + '@backstage/plugin-scaffolder-backend', + 'assets', + 'nunjucks.js.txt', + ), + ].map(k => [k, mockFs.load(k)]), +); + const aBinaryFile = fs.readFileSync( resolvePackagePath( '@backstage/plugin-scaffolder-backend', @@ -76,7 +87,9 @@ describe('fetch:template', () => { }); beforeEach(() => { - mockFs(); + mockFs({ + ...realFiles, + }); action = createFetchTemplateAction({ reader: Symbol('UrlReader') as unknown as UrlReader, @@ -150,6 +163,7 @@ describe('fetch:template', () => { mockFetchContents.mockImplementation(({ outputPath }) => { mockFs({ + ...realFiles, [outputPath]: { 'an-executable.sh': mockFs.file({ content: '#!/usr/bin/env bash', @@ -259,6 +273,7 @@ describe('fetch:template', () => { mockFetchContents.mockImplementation(({ outputPath }) => { mockFs({ + ...realFiles, [outputPath]: { processed: { 'templated-content-${{ values.name }}.txt': @@ -312,6 +327,7 @@ describe('fetch:template', () => { mockFetchContents.mockImplementation(({ outputPath }) => { mockFs({ + ...realFiles, [outputPath]: { '{{ cookiecutter.name }}.txt': 'static content', subdir: { @@ -366,6 +382,7 @@ describe('fetch:template', () => { mockFetchContents.mockImplementation(({ outputPath }) => { mockFs({ + ...realFiles, [outputPath]: { 'empty-dir-${{ values.count }}': {}, 'static.txt': 'static content', @@ -447,6 +464,7 @@ describe('fetch:template', () => { mockFetchContents.mockImplementation(({ outputPath }) => { mockFs({ + ...realFiles, [outputPath]: { '${{ values.name }}.njk': '${{ values.name }}: ${{ values.count }}', '${{ values.name }}.txt.jinja2': diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts index b2e2e85a6c..b933990953 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts @@ -17,13 +17,24 @@ import mockFs from 'mock-fs'; import * as winston from 'winston'; -import { getVoidLogger } from '@backstage/backend-common'; +import { getVoidLogger, resolvePackagePath } from '@backstage/backend-common'; import { NunjucksWorkflowRunner } from './NunjucksWorkflowRunner'; import { TemplateActionRegistry } from '../actions'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import { TaskContext, TaskSpec } from './types'; +const realFiles = Object.fromEntries( + [ + require.resolve('vm2/lib/fixasync'), + resolvePackagePath( + '@backstage/plugin-scaffolder-backend', + 'assets', + 'nunjucks.js.txt', + ), + ].map(k => [k, mockFs.load(k)]), +); + describe('DefaultWorkflowRunner', () => { const logger = getVoidLogger(); let actionRegistry = new TemplateActionRegistry(); @@ -50,6 +61,7 @@ describe('DefaultWorkflowRunner', () => { winston.format.simple(); // put logform the require cache before mocking fs mockFs({ '/tmp': mockFs.directory(), + ...realFiles, }); jest.resetAllMocks(); diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts index 5ed55d9630..37d302e8b2 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts @@ -26,6 +26,7 @@ import { import * as winston from 'winston'; import fs from 'fs-extra'; import path from 'path'; +import nunjucks from 'nunjucks'; import { JsonObject, JsonValue } from '@backstage/types'; import { InputError } from '@backstage/errors'; import { PassThrough } from 'stream'; @@ -102,7 +103,17 @@ export class NunjucksWorkflowRunner implements WorkflowRunner { } private isSingleTemplateString(input: string) { - const { parser, nodes } = require('nunjucks'); + const { parser, nodes } = nunjucks as unknown as { + parser: { + parse( + template: string, + ctx: object, + options: nunjucks.ConfigureOptions, + ): { children: { children?: unknown[] }[] }; + }; + nodes: { TemplateData: Function }; + }; + const parsed = parser.parse( input, {},