catalog-github: add default namespace support to GithubMultiOrgEntityProvider
Signed-off-by: Vincenzo Scamporlino <vincenzos@spotify.com>
This commit is contained in:
+303
-15
@@ -68,26 +68,24 @@ describe('GithubMultiOrgEntityProvider', () => {
|
||||
headers: { token: 'blah' },
|
||||
type: 'app',
|
||||
});
|
||||
|
||||
const githubCredentialsProvider: GithubCredentialsProvider = {
|
||||
getCredentials: mockGetCredentials,
|
||||
};
|
||||
|
||||
entityProvider = new GithubMultiOrgEntityProvider({
|
||||
id: 'my-id',
|
||||
gitHubConfig,
|
||||
githubCredentialsProvider,
|
||||
githubUrl: 'https://github.com',
|
||||
logger,
|
||||
orgs: ['orgA', 'orgB'], // only include for tests that require it
|
||||
});
|
||||
|
||||
entityProvider.connect(entityProviderConnection);
|
||||
});
|
||||
|
||||
afterEach(() => jest.resetAllMocks());
|
||||
|
||||
it('should read specified orgs', async () => {
|
||||
entityProvider = new GithubMultiOrgEntityProvider({
|
||||
id: 'my-id',
|
||||
gitHubConfig,
|
||||
githubCredentialsProvider: {
|
||||
getCredentials: mockGetCredentials,
|
||||
},
|
||||
githubUrl: 'https://github.com',
|
||||
logger,
|
||||
orgs: ['orgA', 'orgB'],
|
||||
});
|
||||
|
||||
await entityProvider.connect(entityProviderConnection);
|
||||
|
||||
mockClient
|
||||
.mockResolvedValueOnce({
|
||||
organization: {
|
||||
@@ -348,6 +346,19 @@ describe('GithubMultiOrgEntityProvider', () => {
|
||||
});
|
||||
|
||||
it('should read every accessible org', async () => {
|
||||
entityProvider = new GithubMultiOrgEntityProvider({
|
||||
id: 'my-id',
|
||||
gitHubConfig,
|
||||
githubCredentialsProvider: {
|
||||
getCredentials: mockGetCredentials,
|
||||
},
|
||||
githubUrl: 'https://github.com',
|
||||
logger,
|
||||
orgs: ['orgA', 'orgB'],
|
||||
});
|
||||
|
||||
await entityProvider.connect(entityProviderConnection);
|
||||
|
||||
getAllInstallationsMock.mockResolvedValue([
|
||||
{
|
||||
target_type: 'Organization',
|
||||
@@ -636,7 +647,284 @@ describe('GithubMultiOrgEntityProvider', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should use the default namespace if options.defaultNamespace is provided', async () => {
|
||||
mockClient
|
||||
.mockResolvedValueOnce({
|
||||
organization: {
|
||||
membersWithRole: {
|
||||
pageInfo: { hasNextPage: false },
|
||||
nodes: [
|
||||
{
|
||||
login: 'a',
|
||||
name: 'b',
|
||||
bio: 'c',
|
||||
email: 'd',
|
||||
avatarUrl: 'e',
|
||||
},
|
||||
{
|
||||
login: 'x',
|
||||
name: 'y',
|
||||
bio: 'z',
|
||||
email: 'w',
|
||||
avatarUrl: 'v',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
organization: {
|
||||
teams: {
|
||||
pageInfo: { hasNextPage: false },
|
||||
nodes: [
|
||||
{
|
||||
slug: 'team',
|
||||
combinedSlug: 'orgC/team',
|
||||
name: 'Team',
|
||||
description: 'The one and only team',
|
||||
avatarUrl: 'http://example.com/team.jpeg',
|
||||
parentTeam: {
|
||||
slug: 'parent',
|
||||
combinedSlug: '',
|
||||
members: { pageInfo: { hasNextPage: false }, nodes: [] },
|
||||
},
|
||||
members: {
|
||||
pageInfo: { hasNextPage: false },
|
||||
nodes: [{ login: 'a' }, { login: 'x' }],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
organization: {
|
||||
membersWithRole: {
|
||||
pageInfo: { hasNextPage: false },
|
||||
nodes: [
|
||||
{
|
||||
login: 'a',
|
||||
name: 'b',
|
||||
bio: 'c',
|
||||
email: 'd',
|
||||
avatarUrl: 'e',
|
||||
},
|
||||
{
|
||||
login: 'x',
|
||||
name: 'y',
|
||||
bio: 'z',
|
||||
email: 'w',
|
||||
avatarUrl: 'v',
|
||||
},
|
||||
{
|
||||
login: 'q',
|
||||
name: 'r',
|
||||
bio: 's',
|
||||
email: 't',
|
||||
avatarUrl: 'u',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
organization: {
|
||||
teams: {
|
||||
pageInfo: { hasNextPage: false },
|
||||
nodes: [
|
||||
{
|
||||
slug: 'team',
|
||||
combinedSlug: 'orgD/team',
|
||||
name: 'Team',
|
||||
description: 'The one and only team',
|
||||
avatarUrl: 'http://example.com/team.jpeg',
|
||||
parentTeam: {
|
||||
slug: 'parent',
|
||||
combinedSlug: '',
|
||||
members: { pageInfo: { hasNextPage: false }, nodes: [] },
|
||||
},
|
||||
members: {
|
||||
pageInfo: { hasNextPage: false },
|
||||
nodes: [{ login: 'a' }, { login: 'q' }],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
(graphql.defaults as jest.Mock).mockReturnValue(mockClient);
|
||||
|
||||
entityProvider = new GithubMultiOrgEntityProvider({
|
||||
id: 'my-id',
|
||||
gitHubConfig,
|
||||
githubCredentialsProvider: {
|
||||
getCredentials: mockGetCredentials,
|
||||
},
|
||||
githubUrl: 'https://github.com',
|
||||
logger,
|
||||
orgs: ['orgA', 'orgB'],
|
||||
defaultNamespace: true,
|
||||
});
|
||||
|
||||
await entityProvider.connect(entityProviderConnection);
|
||||
await entityProvider.read();
|
||||
|
||||
expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({
|
||||
entities: [
|
||||
{
|
||||
entity: {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'User',
|
||||
metadata: {
|
||||
annotations: {
|
||||
'backstage.io/managed-by-location':
|
||||
'url:https://github.com/a',
|
||||
'backstage.io/managed-by-origin-location':
|
||||
'url:https://github.com/a',
|
||||
'github.com/user-login': 'a',
|
||||
},
|
||||
description: 'c',
|
||||
name: 'a',
|
||||
},
|
||||
spec: {
|
||||
memberOf: ['team'],
|
||||
profile: {
|
||||
displayName: 'b',
|
||||
email: 'd',
|
||||
picture: 'e',
|
||||
},
|
||||
},
|
||||
},
|
||||
locationKey: 'github-multi-org-provider:my-id',
|
||||
},
|
||||
{
|
||||
entity: {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'User',
|
||||
metadata: {
|
||||
annotations: {
|
||||
'backstage.io/managed-by-location':
|
||||
'url:https://github.com/x',
|
||||
'backstage.io/managed-by-origin-location':
|
||||
'url:https://github.com/x',
|
||||
'github.com/user-login': 'x',
|
||||
},
|
||||
description: 'z',
|
||||
name: 'x',
|
||||
},
|
||||
spec: {
|
||||
memberOf: ['team'],
|
||||
profile: {
|
||||
displayName: 'y',
|
||||
email: 'w',
|
||||
picture: 'v',
|
||||
},
|
||||
},
|
||||
},
|
||||
locationKey: 'github-multi-org-provider:my-id',
|
||||
},
|
||||
{
|
||||
entity: {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'User',
|
||||
metadata: {
|
||||
annotations: {
|
||||
'backstage.io/managed-by-location':
|
||||
'url:https://github.com/q',
|
||||
'backstage.io/managed-by-origin-location':
|
||||
'url:https://github.com/q',
|
||||
'github.com/user-login': 'q',
|
||||
},
|
||||
description: 's',
|
||||
name: 'q',
|
||||
},
|
||||
spec: {
|
||||
memberOf: ['team'],
|
||||
profile: {
|
||||
displayName: 'r',
|
||||
email: 't',
|
||||
picture: 'u',
|
||||
},
|
||||
},
|
||||
},
|
||||
locationKey: 'github-multi-org-provider:my-id',
|
||||
},
|
||||
{
|
||||
entity: {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'Group',
|
||||
metadata: {
|
||||
annotations: {
|
||||
'backstage.io/managed-by-location':
|
||||
'url:https://github.com/orgs/orgC/teams/team',
|
||||
'backstage.io/managed-by-origin-location':
|
||||
'url:https://github.com/orgs/orgC/teams/team',
|
||||
'github.com/team-slug': 'orgC/team',
|
||||
},
|
||||
name: 'team',
|
||||
description: 'The one and only team',
|
||||
},
|
||||
spec: {
|
||||
children: [],
|
||||
parent: 'parent',
|
||||
profile: {
|
||||
displayName: 'Team',
|
||||
picture: 'http://example.com/team.jpeg',
|
||||
},
|
||||
type: 'team',
|
||||
members: ['default/a', 'default/x'],
|
||||
},
|
||||
},
|
||||
locationKey: 'github-multi-org-provider:my-id',
|
||||
},
|
||||
{
|
||||
entity: {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'Group',
|
||||
metadata: {
|
||||
annotations: {
|
||||
'backstage.io/managed-by-location':
|
||||
'url:https://github.com/orgs/orgD/teams/team',
|
||||
'backstage.io/managed-by-origin-location':
|
||||
'url:https://github.com/orgs/orgD/teams/team',
|
||||
'github.com/team-slug': 'orgD/team',
|
||||
},
|
||||
name: 'team',
|
||||
description: 'The one and only team',
|
||||
},
|
||||
spec: {
|
||||
children: [],
|
||||
parent: 'parent',
|
||||
profile: {
|
||||
displayName: 'Team',
|
||||
picture: 'http://example.com/team.jpeg',
|
||||
},
|
||||
type: 'team',
|
||||
members: ['default/a', 'default/q'],
|
||||
},
|
||||
},
|
||||
locationKey: 'github-multi-org-provider:my-id',
|
||||
},
|
||||
],
|
||||
type: 'full',
|
||||
});
|
||||
});
|
||||
|
||||
it('should not call applyMutation if an error is thrown', async () => {
|
||||
entityProvider = new GithubMultiOrgEntityProvider({
|
||||
id: 'my-id',
|
||||
gitHubConfig,
|
||||
githubCredentialsProvider: {
|
||||
getCredentials: mockGetCredentials,
|
||||
},
|
||||
githubUrl: 'https://github.com',
|
||||
logger,
|
||||
orgs: ['orgA', 'orgB'],
|
||||
});
|
||||
|
||||
await entityProvider.connect(entityProviderConnection);
|
||||
|
||||
mockClient.mockImplementationOnce(() => {
|
||||
throw new Error('Network Error');
|
||||
});
|
||||
|
||||
+15
-1
@@ -143,6 +143,15 @@ export interface GithubMultiOrgEntityProviderOptions {
|
||||
*/
|
||||
githubCredentialsProvider?: GithubCredentialsProvider;
|
||||
|
||||
/**
|
||||
* Use the default namespace for groups. By default, groups will be namespaced according to their GitHub org.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* If set to true, groups with the same name across different orgs will be considered the same group.
|
||||
*/
|
||||
defaultNamespace?: boolean;
|
||||
|
||||
/**
|
||||
* Optionally include a user transformer for transforming from GitHub users to User Entities
|
||||
*/
|
||||
@@ -198,6 +207,7 @@ export class GithubMultiOrgEntityProvider implements EntityProvider {
|
||||
userTransformer: options.userTransformer,
|
||||
teamTransformer: options.teamTransformer,
|
||||
events: options.events,
|
||||
defaultNamespace: options.defaultNamespace,
|
||||
});
|
||||
|
||||
provider.schedule(options.schedule);
|
||||
@@ -216,6 +226,7 @@ export class GithubMultiOrgEntityProvider implements EntityProvider {
|
||||
orgs?: string[];
|
||||
userTransformer?: UserTransformer;
|
||||
teamTransformer?: TeamTransformer;
|
||||
defaultNamespace?: boolean;
|
||||
},
|
||||
) {}
|
||||
|
||||
@@ -846,7 +857,10 @@ export class GithubMultiOrgEntityProvider implements EntityProvider {
|
||||
const result = await defaultOrganizationTeamTransformer(team, ctx);
|
||||
|
||||
if (result && result.spec) {
|
||||
result.metadata.namespace = ctx.org.toLocaleLowerCase('en-US');
|
||||
if (!this.options.defaultNamespace) {
|
||||
result.metadata.namespace = ctx.org.toLocaleLowerCase('en-US');
|
||||
}
|
||||
|
||||
// Group `spec.members` inherits the namespace of it's group so need to explicitly specify refs here
|
||||
result.spec.members = team.members.map(
|
||||
user => `${DEFAULT_NAMESPACE}/${user.login}`,
|
||||
|
||||
Reference in New Issue
Block a user