Merge pull request #29183 from JohannesWill/gitlab-add-filter

GitlabDiscoveryEntityProvider add additional filtering options
This commit is contained in:
Fredrik Adelöw
2025-03-25 10:59:56 +01:00
committed by GitHub
8 changed files with 238 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend-module-gitlab': patch
---
add filter for repos by membership and topics
+12
View File
@@ -72,6 +72,18 @@ export interface Config {
* Should be in the format group/subgroup/repo, with no leading or trailing slashes.
*/
excludeRepos?: string[];
/**
* (Optional) If true, limit by repositories that the current user is a member of.
* See: https://docs.gitlab.com/api/projects/#list-projects
*/
membership?: boolean;
/**
* (Optional) List of topic names. Limit results to repositories that match all of given topics.
* See: https://docs.gitlab.com/api/projects/#list-projects
*/
topics?: string;
};
};
};
@@ -120,6 +120,8 @@ export type GitlabProviderConfig = {
includeArchivedRepos?: boolean;
excludeRepos?: string[];
includeUsersWithoutSeat?: boolean;
membership?: boolean;
topics?: string;
};
// @public
@@ -41,6 +41,8 @@ export type CommonListOptions = {
interface ListProjectOptions extends CommonListOptions {
archived?: boolean;
group?: string;
membership?: boolean;
topics?: string;
}
interface UserListOptions extends CommonListOptions {
@@ -248,6 +248,18 @@ export type GitlabProviderConfig = {
* Defaults to `false`
*/
includeUsersWithoutSeat?: boolean;
/**
* If true, the membership parameter is set to true in the GitLab API request.
* See: https://docs.gitlab.com/api/projects/#list-projects
*/
membership?: boolean;
/**
* Optional comma seperated list of topics to filter projects by, as specified in the GitLab API documentation:
* https://docs.gitlab.com/api/projects/#list-projects
*/
topics?: string;
};
/**
@@ -214,6 +214,8 @@ export class GitlabDiscoveryEntityProvider implements EntityProvider {
page: 1,
per_page: 50,
...(!this.config.includeArchivedRepos && { archived: false }),
...(this.config.membership && { membership: true }),
...(this.config.topics && { topics: this.config.topics }),
},
);
@@ -65,6 +65,8 @@ describe('config', () => {
excludeRepos: [],
restrictUsersToGroup: false,
includeUsersWithoutSeat: false,
membership: undefined,
topics: undefined,
}),
);
});
@@ -109,6 +111,8 @@ describe('config', () => {
excludeRepos: [],
restrictUsersToGroup: false,
includeUsersWithoutSeat: true,
membership: undefined,
topics: undefined,
}),
);
});
@@ -153,6 +157,8 @@ describe('config', () => {
skipForkedRepos: true,
includeArchivedRepos: false,
includeUsersWithoutSeat: false,
membership: undefined,
topics: undefined,
}),
);
});
@@ -197,6 +203,8 @@ describe('config', () => {
skipForkedRepos: false,
includeArchivedRepos: true,
includeUsersWithoutSeat: false,
membership: undefined,
topics: undefined,
}),
);
});
@@ -242,6 +250,8 @@ describe('config', () => {
includeArchivedRepos: false,
excludeRepos: ['foo/bar', 'quz/qux'],
includeUsersWithoutSeat: false,
membership: undefined,
topics: undefined,
}),
);
});
@@ -287,6 +297,8 @@ describe('config', () => {
restrictUsersToGroup: false,
excludeRepos: [],
includeUsersWithoutSeat: false,
membership: undefined,
topics: undefined,
schedule: {
frequency: { minutes: 30 },
timeout: {
@@ -336,4 +348,188 @@ describe('config', () => {
expect(result).toHaveLength(1);
expect(result[0].group).toEqual('');
});
it('valid config with membership', () => {
const config = new ConfigReader({
catalog: {
providers: {
gitlab: {
test: {
group: 'group',
host: 'host',
branch: 'not-master',
fallbackBranch: 'main',
entityFilename: 'custom-file.yaml',
membership: true,
},
},
},
},
});
const result = readGitlabConfigs(config);
expect(result).toHaveLength(1);
result.forEach(r =>
expect(r).toStrictEqual({
id: 'test',
group: 'group',
branch: 'not-master',
fallbackBranch: 'main',
host: 'host',
catalogFile: 'custom-file.yaml',
projectPattern: /[\s\S]*/,
groupPattern: /[\s\S]*/,
userPattern: /[\s\S]*/,
orgEnabled: false,
allowInherited: false,
relations: [],
schedule: undefined,
restrictUsersToGroup: false,
excludeRepos: [],
skipForkedRepos: false,
includeUsersWithoutSeat: false,
includeArchivedRepos: false,
membership: true,
topics: undefined,
}),
);
});
it('valid config with empyt topics', () => {
const config = new ConfigReader({
catalog: {
providers: {
gitlab: {
test: {
group: 'group',
host: 'host',
branch: 'not-master',
fallbackBranch: 'main',
entityFilename: 'custom-file.yaml',
topics: [],
},
},
},
},
});
const result = readGitlabConfigs(config);
expect(result).toHaveLength(1);
result.forEach(r =>
expect(r).toStrictEqual({
id: 'test',
group: 'group',
branch: 'not-master',
fallbackBranch: 'main',
host: 'host',
catalogFile: 'custom-file.yaml',
projectPattern: /[\s\S]*/,
groupPattern: /[\s\S]*/,
userPattern: /[\s\S]*/,
orgEnabled: false,
allowInherited: false,
relations: [],
schedule: undefined,
restrictUsersToGroup: false,
excludeRepos: [],
skipForkedRepos: false,
includeUsersWithoutSeat: false,
includeArchivedRepos: false,
membership: undefined,
topics: undefined,
}),
);
});
it('valid config with single topics', () => {
const config = new ConfigReader({
catalog: {
providers: {
gitlab: {
test: {
group: 'group',
host: 'host',
branch: 'not-master',
fallbackBranch: 'main',
entityFilename: 'custom-file.yaml',
topics: ['topic1'],
},
},
},
},
});
const result = readGitlabConfigs(config);
expect(result).toHaveLength(1);
result.forEach(r =>
expect(r).toStrictEqual({
id: 'test',
group: 'group',
branch: 'not-master',
fallbackBranch: 'main',
host: 'host',
catalogFile: 'custom-file.yaml',
projectPattern: /[\s\S]*/,
groupPattern: /[\s\S]*/,
userPattern: /[\s\S]*/,
orgEnabled: false,
allowInherited: false,
relations: [],
schedule: undefined,
restrictUsersToGroup: false,
excludeRepos: [],
skipForkedRepos: false,
includeUsersWithoutSeat: false,
includeArchivedRepos: false,
membership: undefined,
topics: 'topic1',
}),
);
});
it('valid config with multiple topics', () => {
const config = new ConfigReader({
catalog: {
providers: {
gitlab: {
test: {
group: 'group',
host: 'host',
branch: 'not-master',
fallbackBranch: 'main',
entityFilename: 'custom-file.yaml',
topics: ['topic1', 'topic2', 'topic3'],
},
},
},
},
});
const result = readGitlabConfigs(config);
expect(result).toHaveLength(1);
result.forEach(r =>
expect(r).toStrictEqual({
id: 'test',
group: 'group',
branch: 'not-master',
fallbackBranch: 'main',
host: 'host',
catalogFile: 'custom-file.yaml',
projectPattern: /[\s\S]*/,
groupPattern: /[\s\S]*/,
userPattern: /[\s\S]*/,
orgEnabled: false,
allowInherited: false,
relations: [],
schedule: undefined,
restrictUsersToGroup: false,
excludeRepos: [],
skipForkedRepos: false,
includeUsersWithoutSeat: false,
includeArchivedRepos: false,
membership: undefined,
topics: 'topic1,topic2,topic3',
}),
);
});
});
@@ -66,6 +66,11 @@ function readGitlabConfig(id: string, config: Config): GitlabProviderConfig {
const includeUsersWithoutSeat =
config.getOptionalBoolean('includeUsersWithoutSeat') ?? false;
const membership = config.getOptionalBoolean('membership');
const topicsArray = config.getOptionalStringArray('topics');
const topics = topicsArray?.length ? topicsArray.join(',') : undefined;
return {
id,
group,
@@ -85,6 +90,8 @@ function readGitlabConfig(id: string, config: Config): GitlabProviderConfig {
excludeRepos,
restrictUsersToGroup,
includeUsersWithoutSeat,
membership,
topics,
};
}