Merge pull request #28777 from gavinclarkeuk/globbing

Add support for file globbing to fs:delete
This commit is contained in:
Fredrik Adelöw
2025-02-11 12:04:12 +01:00
committed by GitHub
5 changed files with 65 additions and 7 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder-backend': minor
---
Support file globbing in fs:delete
@@ -157,6 +157,7 @@ Gitiles
gitlab
GitLab
globals
globbing
Gource
Grafana
graphql
@@ -33,4 +33,19 @@ export const examples: TemplateExample[] = [
],
}),
},
{
description: 'Delete files with wildcard',
example: yaml.stringify({
steps: [
{
action: 'fs:delete',
id: 'deleteFiles',
name: 'Delete files',
input: {
files: ['*.txt'],
},
},
],
}),
},
];
@@ -95,6 +95,15 @@ describe('fs:delete', () => {
).rejects.toThrow(
/Relative path is not allowed to refer to a directory outside its parent/,
);
await expect(
action.handler({
...mockContext,
input: { files: ['../../../**/index.js'] },
}),
).rejects.toThrow(
/Relative path is not allowed to refer to a directory outside its parent/,
);
});
it('should call fs.rm with the correct values', async () => {
@@ -114,4 +123,25 @@ describe('fs:delete', () => {
expect(fileExists).toBe(false);
});
});
it('should handle wildcards', async () => {
const files = ['unit-test-a.js', 'unit-test-b.js'];
files.forEach(file => {
const filePath = resolvePath(workspacePath, file);
const fileExists = fs.existsSync(filePath);
expect(fileExists).toBe(true);
});
await action.handler({
...mockContext,
input: { files: ['unit-*.js'] },
});
files.forEach(file => {
const filePath = resolvePath(workspacePath, file);
const fileExists = fs.existsSync(filePath);
expect(fileExists).toBe(false);
});
});
});
@@ -18,6 +18,7 @@ import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
import { InputError } from '@backstage/errors';
import { resolveSafeChildPath } from '@backstage/backend-plugin-api';
import fs from 'fs-extra';
import globby from 'globby';
import { examples } from './delete.examples';
/**
@@ -52,14 +53,20 @@ export const createFilesystemDeleteAction = () => {
}
for (const file of ctx.input.files) {
const filepath = resolveSafeChildPath(ctx.workspacePath, file);
const safeFilepath = resolveSafeChildPath(ctx.workspacePath, file);
const resolvedPaths = await globby(safeFilepath, {
cwd: ctx.workspacePath,
absolute: true,
});
try {
await fs.remove(filepath);
ctx.logger.info(`File ${filepath} deleted successfully`);
} catch (err) {
ctx.logger.error(`Failed to delete file ${filepath}:`, err);
throw err;
for (const filepath of resolvedPaths) {
try {
await fs.remove(filepath);
ctx.logger.info(`File ${filepath} deleted successfully`);
} catch (err) {
ctx.logger.error(`Failed to delete file ${filepath}:`, err);
throw err;
}
}
}
},