Merge pull request #9564 from kim5566/feature/todo-exclude-folders
[TODO] filter out certain folders from plugin
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
---
|
||||
'@backstage/plugin-todo-backend': patch
|
||||
---
|
||||
|
||||
Add support to exclude certain folders in `todo` plugin.
|
||||
|
||||
You can add function by configuring your own exclusion logic, for example:
|
||||
|
||||
```ts
|
||||
import {
|
||||
TodoScmReader,
|
||||
createTodoParser,
|
||||
} from '@backstage/plugin-todo-backend';
|
||||
|
||||
// ...
|
||||
|
||||
const todoReader = TodoScmReader.fromConfig(config, {
|
||||
logger,
|
||||
reader,
|
||||
filePathFilter: (filePath: string): boolean => {
|
||||
...
|
||||
YOUR LOGIC HERE
|
||||
},
|
||||
});
|
||||
```
|
||||
@@ -131,6 +131,7 @@ export type TodoScmReaderOptions = {
|
||||
reader: UrlReader;
|
||||
integrations: ScmIntegrations;
|
||||
parser?: TodoParser;
|
||||
filePathFilter?: (filePath: string) => boolean;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
|
||||
@@ -189,4 +189,91 @@ describe('TodoScmReader', () => {
|
||||
'Failed to parse TODO in https://github.com/o/r/catalog-info.yaml at my-file.sh, Error: failed to parse',
|
||||
);
|
||||
});
|
||||
|
||||
it('should not filter out exclude folders', async () => {
|
||||
const reader = mockReader();
|
||||
const filePathFilter = jest.fn(() => true);
|
||||
|
||||
const todoReader = new TodoScmReader({
|
||||
logger: getVoidLogger(),
|
||||
reader,
|
||||
integrations: ScmIntegrations.fromConfig(new ConfigReader({})),
|
||||
filePathFilter,
|
||||
});
|
||||
reader.readTree.mockResolvedValueOnce({
|
||||
files: async () => [
|
||||
{
|
||||
content: async () => Buffer.from('// TODO: my-todo', 'utf8'),
|
||||
path: 'my-folder/my-file.js',
|
||||
},
|
||||
],
|
||||
} as ReadTreeResponse);
|
||||
await expect(
|
||||
todoReader.readTodos({
|
||||
url: 'https://github.com/backstage/backstage/catalog-info.yaml',
|
||||
}),
|
||||
).resolves.toEqual({
|
||||
items: [
|
||||
{
|
||||
text: 'my-todo',
|
||||
tag: 'TODO',
|
||||
lineNumber: 1,
|
||||
repoFilePath: 'my-folder/my-file.js',
|
||||
viewUrl:
|
||||
'https://github.com/backstage/backstage/my-folder/my-file.js#L1',
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(reader.readTree).toHaveBeenCalledTimes(1);
|
||||
expect(reader.readTree).toHaveBeenCalledWith(
|
||||
'https://github.com/backstage/backstage/catalog-info.yaml',
|
||||
{
|
||||
etag: undefined,
|
||||
filter: expect.any(Function),
|
||||
},
|
||||
);
|
||||
// Filter function should filter out exclude folders
|
||||
const filterFunc = reader.readTree.mock.calls[0][1]!.filter!;
|
||||
expect(filterFunc('my-file.js')).toBe(true);
|
||||
expect(filterFunc('my-folder/my-file.js')).toBe(true);
|
||||
});
|
||||
|
||||
it('should filter out exclude folders', async () => {
|
||||
const reader = mockReader();
|
||||
const filePathFilter = jest.fn(() => false);
|
||||
|
||||
const todoReader = new TodoScmReader({
|
||||
logger: getVoidLogger(),
|
||||
reader,
|
||||
integrations: ScmIntegrations.fromConfig(new ConfigReader({})),
|
||||
filePathFilter,
|
||||
});
|
||||
reader.readTree.mockResolvedValueOnce({
|
||||
files: async () => [
|
||||
{
|
||||
content: async () => Buffer.from('// TODO: my-todo', 'utf8'),
|
||||
path: '',
|
||||
},
|
||||
],
|
||||
} as ReadTreeResponse);
|
||||
await expect(
|
||||
todoReader.readTodos({
|
||||
url: 'https://github.com/backstage/backstage/catalog-info.yaml',
|
||||
}),
|
||||
).resolves.toEqual({
|
||||
items: [],
|
||||
});
|
||||
expect(reader.readTree).toHaveBeenCalledTimes(1);
|
||||
expect(reader.readTree).toHaveBeenCalledWith(
|
||||
'https://github.com/backstage/backstage/catalog-info.yaml',
|
||||
{
|
||||
etag: undefined,
|
||||
filter: expect.any(Function),
|
||||
},
|
||||
);
|
||||
// Filter function should filter out exclude folders
|
||||
const filterFunc = reader.readTree.mock.calls[0][1]!.filter!;
|
||||
expect(filterFunc('my-file.js')).toBe(false);
|
||||
expect(filterFunc('my-folder/my-file.js')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -47,6 +47,7 @@ export type TodoScmReaderOptions = {
|
||||
reader: UrlReader;
|
||||
integrations: ScmIntegrations;
|
||||
parser?: TodoParser;
|
||||
filePathFilter?: (filePath: string) => boolean;
|
||||
};
|
||||
|
||||
type CacheItem = {
|
||||
@@ -60,6 +61,7 @@ export class TodoScmReader implements TodoReader {
|
||||
private readonly reader: UrlReader;
|
||||
private readonly parser: TodoParser;
|
||||
private readonly integrations: ScmIntegrations;
|
||||
private readonly filePathFilter: (filePath: string) => boolean;
|
||||
|
||||
private readonly cache = new Map<string, CacheItem>();
|
||||
private readonly inFlightReads = new Map<string, Promise<CacheItem>>();
|
||||
@@ -79,6 +81,7 @@ export class TodoScmReader implements TodoReader {
|
||||
this.reader = options.reader;
|
||||
this.parser = options.parser ?? createTodoParser();
|
||||
this.integrations = options.integrations;
|
||||
this.filePathFilter = options.filePathFilter ?? (() => true);
|
||||
}
|
||||
|
||||
async readTodos(options: ReadTodosOptions): Promise<ReadTodosResult> {
|
||||
@@ -111,6 +114,7 @@ export class TodoScmReader implements TodoReader {
|
||||
etag?: string,
|
||||
): Promise<CacheItem> {
|
||||
const { url } = options;
|
||||
const filePathFilter = this.filePathFilter;
|
||||
const tree = await this.reader.readTree(url, {
|
||||
etag,
|
||||
filter(filePath, info) {
|
||||
@@ -121,7 +125,8 @@ export class TodoScmReader implements TodoReader {
|
||||
return (
|
||||
!filePath.startsWith('.') &&
|
||||
!filePath.includes('/.') &&
|
||||
!excludedExtensions.includes(extname)
|
||||
!excludedExtensions.includes(extname) &&
|
||||
filePathFilter(filePath)
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user