diff --git a/.changeset/perfect-cheetahs-serve.md b/.changeset/perfect-cheetahs-serve.md new file mode 100644 index 0000000000..08f7c1da21 --- /dev/null +++ b/.changeset/perfect-cheetahs-serve.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': minor +--- + +Added the option to overwrite files in the `targetPath` of the `template:fetch` action diff --git a/plugins/scaffolder-backend/api-report.md b/plugins/scaffolder-backend/api-report.md index 1a3c1db03f..7f8ab0ad79 100644 --- a/plugins/scaffolder-backend/api-report.md +++ b/plugins/scaffolder-backend/api-report.md @@ -127,6 +127,7 @@ export function createFetchTemplateAction(options: { copyWithoutRender?: string[] | undefined; copyWithoutTemplating?: string[] | undefined; cookiecutterCompat?: boolean | undefined; + replace?: boolean | undefined; }>; // @public 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 6b03290e1e..6658e1915d 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 @@ -669,4 +669,81 @@ describe('fetch:template', () => { ).resolves.toEqual('test-project: 1234'); }); }); + + describe('with replacement of existing files', () => { + let context: ActionContext; + + beforeEach(async () => { + context = mockContext({ + values: { + name: 'test-project', + count: 1234, + }, + replace: true, + }); + + mockFetchContents.mockImplementation(({ outputPath }) => { + mockFs({ + ...realFiles, + [joinPath(workspacePath, 'target')]: { + 'static-content.txt': 'static-content', + }, + [outputPath]: { + 'static-content.txt': '${{ values.name }}: ${{ values.count }}', + }, + }); + + return Promise.resolve(); + }); + + await action.handler(context); + }); + + afterEach(() => { + mockFs.restore(); + }); + + it('overwrites existing file', async () => { + await expect( + fs.readFile(`${workspacePath}/target/static-content.txt`, 'utf-8'), + ).resolves.toEqual('test-project: 1234'); + }); + }); + + describe('without replacement of existing files', () => { + let context: ActionContext; + + beforeEach(async () => { + context = mockContext({ + values: { + name: 'test-project', + count: 1234, + }, + targetPath: './target', + replace: false, + }); + + mockFetchContents.mockImplementation(({ outputPath }) => { + mockFs({ + ...realFiles, + [joinPath(workspacePath, 'target')]: { + 'static-content.txt': 'static-content', + }, + [outputPath]: { + 'static-content.txt': '${{ values.name }}: ${{ values.count }}', + }, + }); + + return Promise.resolve(); + }); + + await action.handler(context); + }); + + it('keeps existing file', async () => { + await expect( + fs.readFile(`${workspacePath}/target/static-content.txt`, 'utf-8'), + ).resolves.toEqual('static-content'); + }); + }); }); 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 10a9d0c055..81b3f4577c 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.ts @@ -62,6 +62,7 @@ export function createFetchTemplateAction(options: { copyWithoutRender?: string[]; copyWithoutTemplating?: string[]; cookiecutterCompat?: boolean; + replace?: boolean; }>({ id: 'fetch:template', description: @@ -118,6 +119,12 @@ export function createFetchTemplateAction(options: { 'If set, only files with the given extension will be templated. If set to `true`, the default extension `.njk` is used.', type: ['string', 'boolean'], }, + replace: { + title: 'Replace files', + description: + 'If set, replace files in targetPath instead of skipping existing ones.', + type: 'boolean', + }, }, }, }, @@ -261,7 +268,7 @@ export function createFetchTemplateAction(options: { } const outputPath = resolveSafeChildPath(outputDir, localOutputPath); - if (fs.existsSync(outputPath)) { + if (fs.existsSync(outputPath) && !ctx.input.replace) { continue; }