interface GetOrganizationNavigation {
adminPages: T.Extension[];
- alm?: { key: string; membersSync: boolean; url: string };
+ alm?: { key: string; membersSync: boolean; personal: boolean; url: string };
canUpdateProjectsVisibilityToPrivate: boolean;
isDefault: boolean;
pages: T.Extension[];
export interface AlmOrganization extends OrganizationBase {
almUrl: string;
key: string;
+ personal: boolean;
privateRepos: number;
publicRepos: number;
}
export interface Organization extends OrganizationBase {
actions?: OrganizationActions;
- alm?: { key: string; membersSync: boolean; url: string };
+ alm?: { key: string; membersSync: boolean; personal: boolean; url: string };
adminPages?: Extension[];
canUpdateProjectsVisibilityToPrivate?: boolean;
isDefault?: boolean;
"alm": Object {
"key": "github",
"membersSync": false,
+ "personal": false,
"url": "https://github.com/foo",
},
"key": "bar",
alm: {
key: almApplication.key,
membersSync: true,
+ personal: almOrganization.personal,
url: almOrganization.almUrl
},
installationId: this.props.almInstallId
wrapper.setProps({ organization });
wrapper.find('PlanStep').prop<Function>('createOrganization')();
- const alm = {
+ const alm: T.Organization['alm'] = {
key: 'github',
membersSync: true,
+ personal: false,
url: 'http://github.com/thing'
};
expect(createOrganization).toBeCalledWith({ ...organization, alm, installationId: 'id-foo' });
"description": "description-foo",
"key": "foo",
"name": "foo",
+ "personal": false,
"privateRepos": 0,
"publicRepos": 3,
"url": "http://example.com/foo",
"description": "description-foo",
"key": "foo",
"name": "foo",
+ "personal": false,
"privateRepos": 0,
"publicRepos": 3,
"url": "http://example.com/foo",
"description": "description-foo",
"key": "foo",
"name": "foo",
+ "personal": false,
"privateRepos": 0,
"publicRepos": 3,
"url": "http://example.com/foo",
"description": "description-foo",
"key": "foo",
"name": "foo",
+ "personal": false,
"privateRepos": 0,
"publicRepos": 3,
"url": "http://example.com/foo",
"description": "description-foo",
"key": "foo",
"name": "foo",
+ "personal": false,
"privateRepos": 5,
"publicRepos": 0,
"url": "http://example.com/foo",
await promise;
expect(syncMembers).toHaveBeenCalledWith(org.key);
});
+
+ it('should not sync members for personal Github orgs', async () => {
+ const { alm, ...org } = mockOrganizationWithAlm(
+ {},
+ { key: 'github', membersSync: true, personal: true, url: 'https://github.com/foo' }
+ );
+
+ (createOrganization as jest.Mock).mockResolvedValueOnce(org);
+ const promise = actions.createOrganization({ alm, ...org })(dispatch);
+
+ expect(createOrganization).toHaveBeenCalledWith(org);
+ await promise;
+ expect(syncMembers).not.toBeCalled();
+ });
});
.createOrganization({ ...organization, name: organization.name || organization.key })
.then((newOrganization: T.Organization) => {
dispatch(actions.createOrganization({ ...newOrganization, alm }));
- if (alm && alm.membersSync && isGithub(alm.key)) {
+ if (alm && alm.membersSync && !alm.personal && isGithub(alm.key)) {
api.syncMembers(newOrganization.key);
}
return newOrganization.key;
"alm": Object {
"key": "github",
"membersSync": false,
+ "personal": false,
"url": "https://github.com/foo",
},
"key": "foo",
"alm": Object {
"key": "github",
"membersSync": false,
+ "personal": false,
"url": "https://github.com/foo",
},
"key": "bar",
"alm": Object {
"key": "github",
"membersSync": false,
+ "personal": false,
"url": "https://github.com/foo",
},
"key": "foo",
"alm": Object {
"key": "github",
"membersSync": false,
+ "personal": false,
"url": "https://github.com/foo",
},
"key": "bar",
"alm": Object {
"key": "github",
"membersSync": false,
+ "personal": false,
"url": "https://github.com/foo",
},
"key": "bar",
"alm": Object {
"key": "github",
"membersSync": false,
+ "personal": false,
"url": "https://github.com/foo",
},
"key": "bar",
"alm": Object {
"key": "github",
"membersSync": false,
+ "personal": false,
"url": "https://github.com/foo",
},
"key": "bar",
"alm": Object {
"key": "github",
"membersSync": false,
+ "personal": false,
"url": "https://github.com/foo",
},
"key": "foo",
"alm": Object {
"key": "github",
"membersSync": false,
+ "personal": false,
"url": "https://github.com/foo",
},
"key": "foo",
"alm": Object {
"key": "github",
"membersSync": false,
+ "personal": false,
"url": "https://github.com/foo",
},
"key": "foo",
const almKey = organization.alm && sanitizeAlmId(organization.alm.key);
const hasMemberSync = organization.alm && organization.alm.membersSync;
const showSyncNotif = isAdmin && organization.alm && !hasMemberSync;
+ const isSyncEligible =
+ almKey && isGithub(almKey) && organization.alm && !organization.alm.personal;
return (
<header className="page-header">
<DeferredSpinner loading={props.loading} />
{isAdmin && (
<div className="page-actions text-right">
- {almKey && isGithub(almKey) && !showSyncNotif && (
+ {isSyncEligible && !showSyncNotif && (
<SyncMemberForm
buttonText={translate('organization.members.config_synchro')}
hasOtherMembers={members && members.length > 1}
)
}}
/>
- {almKey && isGithub(almKey) && showSyncNotif && (
+ {almKey && isSyncEligible && showSyncNotif && (
<Alert className="spacer-top" display="inline" variant="info">
{translateWithParameters(
'organization.members.auto_sync_members_from_org_x',
expect(shallowRender({ organization })).toMatchSnapshot();
});
+it('should render for personal GitHub bound organization without sync', () => {
+ const organization = mockOrganizationWithAlm(mockOrganizationWithAdminActions(), {
+ personal: true
+ });
+ expect(shallowRender({ organization })).toMatchSnapshot();
+});
+
it('should render for bound organization with sync', () => {
const organization = mockOrganizationWithAlm(mockOrganizationWithAdminActions(), {
membersSync: true
"alm": Object {
"key": "bitbucket",
"membersSync": false,
+ "personal": false,
"url": "https://github.com/foo",
},
"key": "foo",
"alm": Object {
"key": "github",
"membersSync": false,
+ "personal": false,
"url": "https://github.com/foo",
},
"key": "foo",
"alm": Object {
"key": "github",
"membersSync": false,
+ "personal": false,
"url": "https://github.com/foo",
},
"key": "foo",
</div>
</header>
`;
+
+exports[`should render for personal GitHub bound organization without sync 1`] = `
+<header
+ className="page-header"
+>
+ <h1
+ className="page-title"
+ >
+ organization.members.page
+ </h1>
+ <DeferredSpinner
+ loading={false}
+ timeout={100}
+ />
+ <div
+ className="page-actions text-right"
+ >
+ <div
+ className="display-inline-block spacer-left spacer-bottom"
+ >
+ <AddMemberForm
+ addMember={[MockFunction]}
+ memberLogins={Array []}
+ organization={
+ Object {
+ "actions": Object {
+ "admin": true,
+ },
+ "alm": Object {
+ "key": "github",
+ "membersSync": false,
+ "personal": true,
+ "url": "https://github.com/foo",
+ },
+ "key": "foo",
+ "name": "Foo",
+ }
+ }
+ />
+ <DocTooltip
+ className="spacer-left"
+ doc={Promise {}}
+ />
+ </div>
+ </div>
+ <div
+ className="page-description"
+ >
+ <FormattedMessage
+ defaultMessage="organization.members.page.description"
+ id="organization.members.page.description"
+ values={
+ Object {
+ "link": <Link
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ target="_blank"
+ to="/documentation/organizations/manage-team/"
+ >
+ organization.members.manage_a_team
+ </Link>,
+ }
+ }
+ />
+ </div>
+</header>
+`;
"alm": Object {
"key": "github",
"membersSync": false,
+ "personal": false,
"url": "https://github.com/foo",
},
"key": "foo",
description: 'description-foo',
key: 'foo',
name: 'foo',
+ personal: false,
privateRepos: 0,
publicRepos: 3,
url: 'http://example.com/foo',
almOverrides: Partial<T.Organization['alm']> = {}
): T.Organization {
return mockOrganization({
- alm: { key: 'github', membersSync: false, url: 'https://github.com/foo', ...almOverrides },
+ alm: {
+ key: 'github',
+ membersSync: false,
+ personal: false,
+ url: 'https://github.com/foo',
+ ...almOverrides
+ },
...overrides
});
}