Merge pull request #19231 from steff-petro/scaffolderFileSystemExamples

Scaffolder file system action examples
This commit is contained in:
Fredrik Adelöw
2023-08-07 16:29:37 +02:00
committed by GitHub
7 changed files with 268 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder-backend': patch
---
Added examples for the fs:delete and fs:rename actions
@@ -0,0 +1,79 @@
/*
* Copyright 2021 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 { createFilesystemDeleteAction } from './delete';
import { getVoidLogger } from '@backstage/backend-common';
import { PassThrough } from 'stream';
import { resolve as resolvePath } from 'path';
import * as os from 'os';
import mockFs from 'mock-fs';
import fs from 'fs-extra';
import yaml from 'yaml';
import { examples } from './delete.examples';
const root = os.platform() === 'win32' ? 'C:\\rootDir' : '/rootDir';
const workspacePath = resolvePath(root, 'my-workspace');
describe('fs:delete examples', () => {
const action = createFilesystemDeleteAction();
const files: string[] = yaml.parse(examples[0].example).steps[0].input.files;
const mockContext = {
input: {
files: files,
},
workspacePath,
logger: getVoidLogger(),
logStream: new PassThrough(),
output: jest.fn(),
createTemporaryDirectory: jest.fn(),
};
beforeEach(() => {
jest.restoreAllMocks();
mockFs({
[workspacePath]: {
[files[0]]: 'hello',
[files[1]]: 'world',
'a-folder': {
'unit-test-in-a-folder.js2': 'content',
},
},
});
});
afterEach(() => {
mockFs.restore();
});
it('should call fs.rm with the correct values', async () => {
files.forEach(file => {
const filePath = resolvePath(workspacePath, file);
const fileExists = fs.existsSync(filePath);
expect(fileExists).toBe(true);
});
await action.handler(mockContext);
files.forEach(file => {
const filePath = resolvePath(workspacePath, file);
const fileExists = fs.existsSync(filePath);
expect(fileExists).toBe(false);
});
});
});
@@ -0,0 +1,36 @@
/*
* Copyright 2021 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 { TemplateExample } from '@backstage/plugin-scaffolder-node';
import * as yaml from 'yaml';
export const examples: TemplateExample[] = [
{
description: 'Delete specified files',
example: yaml.stringify({
steps: [
{
action: 'fs:delete',
id: 'deleteFiles',
name: 'Delete files',
input: {
files: ['file1.txt', 'file2.txt'],
},
},
],
}),
},
];
@@ -18,6 +18,7 @@ import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
import { InputError } from '@backstage/errors';
import { resolveSafeChildPath } from '@backstage/backend-common';
import fs from 'fs-extra';
import { examples } from './delete.examples';
/**
* Creates new action that enables deletion of files and directories in the workspace.
@@ -27,6 +28,7 @@ export const createFilesystemDeleteAction = () => {
return createTemplateAction<{ files: string[] }>({
id: 'fs:delete',
description: 'Deletes files and directories from the workspace',
examples,
schema: {
input: {
required: ['files'],
@@ -0,0 +1,104 @@
/*
* Copyright 2021 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 * as os from 'os';
import mockFs from 'mock-fs';
import { resolve as resolvePath } from 'path';
import { createFilesystemRenameAction } from './rename';
import { getVoidLogger } from '@backstage/backend-common';
import { PassThrough } from 'stream';
import fs from 'fs-extra';
import yaml from 'yaml';
import { examples } from './rename.examples';
const root = os.platform() === 'win32' ? 'C:\\rootDir' : '/rootDir';
const workspacePath = resolvePath(root, 'my-workspace');
describe('fs:rename examples', () => {
const action = createFilesystemRenameAction();
const files: { from: string; to: string }[] = yaml.parse(examples[0].example)
.steps[0].input.files;
const mockContext = {
input: {
files: files,
},
workspacePath,
logger: getVoidLogger(),
logStream: new PassThrough(),
output: jest.fn(),
createTemporaryDirectory: jest.fn(),
};
beforeEach(() => {
jest.restoreAllMocks();
mockFs({
[workspacePath]: {
[files[0].from]: 'hello',
[files[1].from]: 'world',
[files[2].from]: '!!!',
'file3Renamed.txt': 'I will be overwritten :(',
'a-folder': {
'file.md': 'content',
},
},
});
});
afterEach(() => {
mockFs.restore();
});
it('should call fs.move with the correct values', async () => {
mockContext.input.files.forEach(file => {
const filePath = resolvePath(workspacePath, file.from);
const fileExists = fs.existsSync(filePath);
expect(fileExists).toBe(true);
});
await action.handler(mockContext);
mockContext.input.files.forEach(file => {
const filePath = resolvePath(workspacePath, file.from);
const fileExists = fs.existsSync(filePath);
expect(fileExists).toBe(false);
});
});
it('should override when requested', async () => {
const sourceFile = files[2].from;
const destFile = files[2].to;
const sourceFilePath = resolvePath(workspacePath, sourceFile);
const destFilePath = resolvePath(workspacePath, destFile);
const sourceBeforeContent = fs.readFileSync(sourceFilePath, 'utf-8');
const destBeforeContent = fs.readFileSync(destFilePath, 'utf-8');
expect(sourceBeforeContent).not.toEqual(destBeforeContent);
await action.handler({
...mockContext,
input: {
files,
},
});
const destAfterContent = fs.readFileSync(destFilePath, 'utf-8');
expect(sourceBeforeContent).toEqual(destAfterContent);
});
});
@@ -0,0 +1,40 @@
/*
* Copyright 2021 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 { TemplateExample } from '@backstage/plugin-scaffolder-node';
import * as yaml from 'yaml';
export const examples: TemplateExample[] = [
{
description: 'Rename specified files ',
example: yaml.stringify({
steps: [
{
action: 'fs:rename',
id: 'renameFiles',
name: 'Rename files',
input: {
files: [
{ from: 'file1.txt', to: 'file1Renamed.txt' },
{ from: 'file2.txt', to: 'file2Renamed.txt' },
{ from: 'file3.txt', to: 'file3Renamed.txt', overwrite: true },
],
},
},
],
}),
},
];
@@ -18,6 +18,7 @@ import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
import { resolveSafeChildPath } from '@backstage/backend-common';
import { InputError } from '@backstage/errors';
import fs from 'fs-extra';
import { examples } from './rename.examples';
/**
* Creates a new action that allows renames of files and directories in the workspace.
@@ -33,6 +34,7 @@ export const createFilesystemRenameAction = () => {
}>({
id: 'fs:rename',
description: 'Renames files and directories within the workspace',
examples,
schema: {
input: {
required: ['files'],