feat: allow listing file contents with debug:log
This further improves the debug functionality to be able to actually see what is the content of the files generated by the template Signed-off-by: Heikki Hellgren <heikki.hellgren@op.fi>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
---
|
||||
|
||||
Allow listing file contents with `debug:log` scaffolder action
|
||||
@@ -130,7 +130,7 @@ export function createCatalogWriteAction(): TemplateAction_2<
|
||||
export function createDebugLogAction(): TemplateAction_2<
|
||||
{
|
||||
message?: string | undefined;
|
||||
listWorkspace?: boolean | undefined;
|
||||
listWorkspace?: boolean | 'with-contents' | 'with-filenames' | undefined;
|
||||
},
|
||||
JsonObject
|
||||
>;
|
||||
|
||||
@@ -48,4 +48,19 @@ export const examples: TemplateExample[] = [
|
||||
],
|
||||
}),
|
||||
},
|
||||
{
|
||||
description: 'List the workspace directory with file contents',
|
||||
example: yaml.stringify({
|
||||
steps: [
|
||||
{
|
||||
action: 'debug:log',
|
||||
id: 'write-workspace-directory',
|
||||
name: 'List the workspace directory with file contents',
|
||||
input: {
|
||||
listWorkspace: 'with-contents',
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
},
|
||||
];
|
||||
|
||||
@@ -35,8 +35,9 @@ describe('debug:log', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
mockDir.setContent({
|
||||
[`${mockContext.workspacePath}/README.md`]: '',
|
||||
[`${mockContext.workspacePath}/a-directory/index.md`]: '',
|
||||
[`${mockContext.workspacePath}/README.md`]: 'This is a README file',
|
||||
[`${mockContext.workspacePath}/a-directory/index.md`]:
|
||||
'This is a markdown file',
|
||||
});
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
@@ -94,6 +95,34 @@ describe('debug:log', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should log the workspace content with file contents from an example, if active', async () => {
|
||||
const example = action.examples?.find(
|
||||
sample =>
|
||||
sample.description ===
|
||||
'List the workspace directory with file contents',
|
||||
)?.example as string;
|
||||
expect(typeof example).toEqual('string');
|
||||
const context = {
|
||||
...mockContext,
|
||||
...yaml.parse(example).steps[0],
|
||||
};
|
||||
|
||||
await action.handler(context);
|
||||
|
||||
expect(logger.info).toHaveBeenCalledWith(
|
||||
expect.stringContaining('README.md'),
|
||||
);
|
||||
expect(logger.info).toHaveBeenCalledWith(
|
||||
expect.stringContaining(join('a-directory', 'index.md')),
|
||||
);
|
||||
expect(logger.info).toHaveBeenCalledWith(
|
||||
expect.stringContaining('This is a README file'),
|
||||
);
|
||||
expect(logger.info).toHaveBeenCalledWith(
|
||||
expect.stringContaining('This is a markdown file'),
|
||||
);
|
||||
});
|
||||
|
||||
it('should log message from an example', async () => {
|
||||
const example = action.examples?.find(
|
||||
sample => sample.description === 'Write a debug message',
|
||||
|
||||
@@ -15,9 +15,11 @@
|
||||
*/
|
||||
|
||||
import { readdir, stat } from 'fs-extra';
|
||||
import { relative, join } from 'path';
|
||||
import { join, relative } from 'path';
|
||||
import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
|
||||
import { examples } from './log.examples';
|
||||
import fs from 'fs';
|
||||
import { z } from 'zod';
|
||||
|
||||
const id = 'debug:log';
|
||||
|
||||
@@ -32,28 +34,24 @@ const id = 'debug:log';
|
||||
* @public
|
||||
*/
|
||||
export function createDebugLogAction() {
|
||||
return createTemplateAction<{ message?: string; listWorkspace?: boolean }>({
|
||||
return createTemplateAction<{
|
||||
message?: string;
|
||||
listWorkspace?: boolean | 'with-filenames' | 'with-contents';
|
||||
}>({
|
||||
id,
|
||||
description:
|
||||
'Writes a message into the log or lists all files in the workspace.',
|
||||
'Writes a message into the log and/or lists all files in the workspace.',
|
||||
examples,
|
||||
schema: {
|
||||
input: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
message: {
|
||||
title: 'Message to output.',
|
||||
type: 'string',
|
||||
},
|
||||
listWorkspace: {
|
||||
title: 'List all files in the workspace, if true.',
|
||||
type: 'boolean',
|
||||
},
|
||||
extra: {
|
||||
title: 'Extra info',
|
||||
},
|
||||
},
|
||||
},
|
||||
input: z.object({
|
||||
message: z.string({ description: 'Message to output.' }).optional(),
|
||||
listWorkspace: z
|
||||
.union([z.boolean(), z.enum(['with-filenames', 'with-contents'])], {
|
||||
description:
|
||||
'List all files in the workspace. If used with "with-contents", also the file contents are listed.',
|
||||
})
|
||||
.optional(),
|
||||
}),
|
||||
},
|
||||
supportsDryRun: true,
|
||||
async handler(ctx) {
|
||||
@@ -67,7 +65,14 @@ export function createDebugLogAction() {
|
||||
const files = await recursiveReadDir(ctx.workspacePath);
|
||||
ctx.logger.info(
|
||||
`Workspace:\n${files
|
||||
.map(f => ` - ${relative(ctx.workspacePath, f)}`)
|
||||
.map(f => {
|
||||
const relativePath = relative(ctx.workspacePath, f);
|
||||
if (ctx.input?.listWorkspace === 'with-contents') {
|
||||
const content = fs.readFileSync(f, 'utf-8');
|
||||
return ` - ${relativePath}:\n\n ${content}`;
|
||||
}
|
||||
return ` - ${relativePath}`;
|
||||
})
|
||||
.join('\n')}`,
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user