Switch to a clearer enum setup and default to ex
clude Signed-off-by: Marcus Crane <marcus.crane@lightspeedhq.com>
This commit is contained in:
@@ -93,8 +93,9 @@ catalog:
|
||||
filters:
|
||||
branch: 'main' # string
|
||||
repository: '.*' # Regex
|
||||
topic: 'backstage-include' # optional string
|
||||
topicIncludesIfMatch: true # optional boolean (default: false)
|
||||
topic:
|
||||
name: 'backstage-include' # optional string
|
||||
type: 'INCLUDES' # optional enum (INCLUDES or EXCLUDES)
|
||||
```
|
||||
|
||||
This provider supports multiple organizations via unique provider IDs.
|
||||
@@ -112,11 +113,13 @@ This provider supports multiple organizations via unique provider IDs.
|
||||
- **repository** _(optional)_:
|
||||
Regular expression used to filter results based on the repository name.
|
||||
- **topic** _(optional)_:
|
||||
String used to filter results based on repository topics. By default, repositories that match the topic filter will be **ignored**. See below for the inverse.
|
||||
This is useful for excluding excess locations from being registered such as experiments, practical tests, non-production tooling and so on.
|
||||
- **topicIncludesIfMatch** _(optional)_:
|
||||
Default: `false`
|
||||
If set to `true` and a topic filter is set, **ONLY** repositories matching the topic filter will have a location registered.
|
||||
- **name** _(optional)_:
|
||||
String used to filter results based on repository topics. If configured, only repositories that match the topic filter will be registered. See below for the reverse.
|
||||
This is useful for excluding excess locations from being registered such as experiments, practical tests, non-production tooling and so on.
|
||||
- **type** _(optional)_:
|
||||
Default: `INCLUDES`
|
||||
When set to `INCLUDES`, locations matching the topic filter will be registered and other repositories will be ignored
|
||||
When set to `EXCLUDES`, locations matching the topic filter will not be registered and other repositories will be registered
|
||||
- **organization**:
|
||||
Name of your organization account/workspace.
|
||||
If you want to add multiple organizations, you need to add one provider config each.
|
||||
|
||||
@@ -200,7 +200,9 @@ describe('GitHubEntityProvider', () => {
|
||||
filters: {
|
||||
branch: 'main',
|
||||
repository: 'test-.*',
|
||||
topic: 'blah',
|
||||
topic: {
|
||||
name: 'blah',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -268,8 +270,10 @@ describe('GitHubEntityProvider', () => {
|
||||
filters: {
|
||||
branch: 'main',
|
||||
repository: 'test-.*',
|
||||
topic: 'backstage-include',
|
||||
topicIncludesIfMatch: true,
|
||||
topic: {
|
||||
name: 'backstage-include',
|
||||
type: 'INCLUDES',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -36,6 +36,7 @@ import { Logger } from 'winston';
|
||||
import {
|
||||
readProviderConfigs,
|
||||
GitHubEntityProviderConfig,
|
||||
TopicTypes,
|
||||
} from './GitHubEntityProviderConfig';
|
||||
import { getOrganizationRepositories, Repository } from '../lib/github';
|
||||
|
||||
@@ -184,17 +185,29 @@ export class GitHubEntityProvider implements EntityProvider {
|
||||
private matchesFilters(repositories: Repository[]) {
|
||||
const repositoryFilter = this.config.filters?.repository;
|
||||
const topicFilter = this.config.filters?.topic;
|
||||
const topicIncludesIfMatch = this.config.filters?.topicIncludesIfMatch;
|
||||
|
||||
const matchingRepositories = repositories.filter(r => {
|
||||
const topics: string[] = r.repositoryTopics.nodes.map(
|
||||
const repoTopics: string[] = r.repositoryTopics.nodes.map(
|
||||
node => node.topic.name,
|
||||
);
|
||||
const satisfiesTopicFilter = (
|
||||
topics: string[],
|
||||
filter: typeof topicFilter,
|
||||
) => {
|
||||
if (!filter || !filter.name) return true;
|
||||
if (filter.type === TopicTypes.Includes && topics.includes(filter.name))
|
||||
return true;
|
||||
if (
|
||||
filter.type === TopicTypes.Excludes &&
|
||||
!topics.includes(filter.name)
|
||||
)
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
return (
|
||||
!r.isArchived &&
|
||||
(!repositoryFilter || repositoryFilter.test(r.name)) &&
|
||||
(!topicFilter ||
|
||||
(topics.includes(topicFilter) && topicIncludesIfMatch)) &&
|
||||
satisfiesTopicFilter(repoTopics, topicFilter) &&
|
||||
r.defaultBranchRef?.name
|
||||
);
|
||||
});
|
||||
|
||||
+31
-15
@@ -71,14 +71,18 @@ describe('readProviderConfigs', () => {
|
||||
providerWithTopicFilter: {
|
||||
organization: 'test-org5',
|
||||
filters: {
|
||||
topic: 'backstage-exclude',
|
||||
topic: {
|
||||
name: 'backstage-exclude',
|
||||
},
|
||||
},
|
||||
},
|
||||
providerWithTopicFilterAndInclusion: {
|
||||
organization: 'test-org6',
|
||||
filters: {
|
||||
topic: 'backstage-include',
|
||||
topicIncludesIfMatch: false,
|
||||
topic: {
|
||||
name: 'backstage-include',
|
||||
type: 'INCLUDES',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -95,8 +99,10 @@ describe('readProviderConfigs', () => {
|
||||
filters: {
|
||||
repository: undefined,
|
||||
branch: undefined,
|
||||
topic: undefined,
|
||||
topicIncludesIfMatch: false,
|
||||
topic: {
|
||||
name: undefined,
|
||||
type: 'EXCLUDES',
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(providerConfigs[1]).toEqual({
|
||||
@@ -106,8 +112,10 @@ describe('readProviderConfigs', () => {
|
||||
filters: {
|
||||
repository: undefined,
|
||||
branch: undefined,
|
||||
topic: undefined,
|
||||
topicIncludesIfMatch: false,
|
||||
topic: {
|
||||
name: undefined,
|
||||
type: 'EXCLUDES',
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(providerConfigs[2]).toEqual({
|
||||
@@ -117,8 +125,10 @@ describe('readProviderConfigs', () => {
|
||||
filters: {
|
||||
repository: /^repository.*filter$/, // repo
|
||||
branch: undefined, // branch
|
||||
topic: undefined,
|
||||
topicIncludesIfMatch: false,
|
||||
topic: {
|
||||
name: undefined,
|
||||
type: 'EXCLUDES',
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(providerConfigs[3]).toEqual({
|
||||
@@ -128,8 +138,10 @@ describe('readProviderConfigs', () => {
|
||||
filters: {
|
||||
repository: undefined,
|
||||
branch: 'branch-name',
|
||||
topic: undefined,
|
||||
topicIncludesIfMatch: false,
|
||||
topic: {
|
||||
name: undefined,
|
||||
type: 'EXCLUDES',
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(providerConfigs[4]).toEqual({
|
||||
@@ -139,8 +151,10 @@ describe('readProviderConfigs', () => {
|
||||
filters: {
|
||||
repository: undefined,
|
||||
branch: undefined,
|
||||
topic: 'backstage-exclude',
|
||||
topicIncludesIfMatch: false,
|
||||
topic: {
|
||||
name: 'backstage-exclude',
|
||||
type: 'EXCLUDES',
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(providerConfigs[5]).toEqual({
|
||||
@@ -150,8 +164,10 @@ describe('readProviderConfigs', () => {
|
||||
filters: {
|
||||
repository: undefined,
|
||||
branch: undefined,
|
||||
topic: 'backstage-include',
|
||||
topicIncludesIfMatch: false,
|
||||
topic: {
|
||||
name: 'backstage-include',
|
||||
type: 'INCLUDES',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,9 +16,17 @@
|
||||
|
||||
import { Config } from '@backstage/config';
|
||||
|
||||
export enum TopicTypes {
|
||||
Includes = 'INCLUDES',
|
||||
Excludes = 'EXCLUDES',
|
||||
}
|
||||
|
||||
const isValidTopicType = (topicType: string) =>
|
||||
(Object.values(TopicTypes) as string[]).includes(topicType);
|
||||
|
||||
const DEFAULT_CATALOG_PATH = '/catalog-info.yaml';
|
||||
const DEFAULT_PROVIDER_ID = 'default';
|
||||
const DEFAULT_TOPIC_INCLUSION = false;
|
||||
const DEFAULT_TOPIC_FILTER_TYPE: TopicTypes = TopicTypes.Excludes;
|
||||
|
||||
export type GitHubEntityProviderConfig = {
|
||||
id: string;
|
||||
@@ -27,8 +35,10 @@ export type GitHubEntityProviderConfig = {
|
||||
filters?: {
|
||||
repository?: RegExp;
|
||||
branch?: string;
|
||||
topic?: string;
|
||||
topicIncludesIfMatch: boolean;
|
||||
topic?: {
|
||||
name?: string;
|
||||
type: TopicTypes;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -61,10 +71,9 @@ function readProviderConfig(
|
||||
config.getOptionalString('catalogPath') ?? DEFAULT_CATALOG_PATH;
|
||||
const repositoryPattern = config.getOptionalString('filters.repository');
|
||||
const branchPattern = config.getOptionalString('filters.branch');
|
||||
const topicPattern = config.getOptionalString('filters.topic');
|
||||
const topicIncludesIfMatch =
|
||||
config.getOptionalBoolean('filters.topicIncludesIfMatch') ??
|
||||
DEFAULT_TOPIC_INCLUSION;
|
||||
const topicFilterConfig = config.getOptionalConfig('filters.topic');
|
||||
const topicFilterName = topicFilterConfig?.getOptionalString('name');
|
||||
const topicFilterType = topicFilterConfig?.getOptionalString('type');
|
||||
|
||||
return {
|
||||
id,
|
||||
@@ -75,8 +84,13 @@ function readProviderConfig(
|
||||
? compileRegExp(repositoryPattern)
|
||||
: undefined,
|
||||
branch: branchPattern || undefined,
|
||||
topic: topicPattern || undefined,
|
||||
topicIncludesIfMatch,
|
||||
topic: {
|
||||
name: topicFilterName || undefined,
|
||||
type:
|
||||
topicFilterType && isValidTopicType(topicFilterType)
|
||||
? (topicFilterType as TopicTypes)
|
||||
: DEFAULT_TOPIC_FILTER_TYPE,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user