Merge pull request #9564 from kim5566/feature/todo-exclude-folders

[TODO] filter out certain folders from plugin
This commit is contained in:
Fredrik Adelöw
2022-02-21 11:17:36 +01:00
committed by GitHub
4 changed files with 119 additions and 1 deletions
+25
View File
@@ -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
},
});
```
+1
View File
@@ -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)
);
},
});