diff options
19 files changed, 127 insertions, 7 deletions
diff --git a/server/sonar-web/src/main/js/api/organizations.ts b/server/sonar-web/src/main/js/api/organizations.ts index cc2d8c0f205..140ed739887 100644 --- a/server/sonar-web/src/main/js/api/organizations.ts +++ b/server/sonar-web/src/main/js/api/organizations.ts @@ -39,7 +39,7 @@ export function getOrganization(key: string): Promise<T.Organization | undefined 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[]; diff --git a/server/sonar-web/src/main/js/app/types.d.ts b/server/sonar-web/src/main/js/app/types.d.ts index 2f0712d6aeb..93a3e9383b4 100644 --- a/server/sonar-web/src/main/js/app/types.d.ts +++ b/server/sonar-web/src/main/js/app/types.d.ts @@ -37,6 +37,7 @@ declare namespace T { export interface AlmOrganization extends OrganizationBase { almUrl: string; key: string; + personal: boolean; privateRepos: number; publicRepos: number; } @@ -514,7 +515,7 @@ declare namespace T { 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; diff --git a/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/OrganizationSelect-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/OrganizationSelect-test.tsx.snap index 8e373bfac39..46e9dbfcba1 100644 --- a/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/OrganizationSelect-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/OrganizationSelect-test.tsx.snap @@ -15,6 +15,7 @@ exports[`should render correctly 1`] = ` "alm": Object { "key": "github", "membersSync": false, + "personal": false, "url": "https://github.com/foo", }, "key": "bar", diff --git a/server/sonar-web/src/main/js/apps/create/organization/AutoOrganizationCreate.tsx b/server/sonar-web/src/main/js/apps/create/organization/AutoOrganizationCreate.tsx index 99c5c5028e7..d0fb9543cff 100644 --- a/server/sonar-web/src/main/js/apps/create/organization/AutoOrganizationCreate.tsx +++ b/server/sonar-web/src/main/js/apps/create/organization/AutoOrganizationCreate.tsx @@ -86,6 +86,7 @@ export default class AutoOrganizationCreate extends React.PureComponent<Props, S alm: { key: almApplication.key, membersSync: true, + personal: almOrganization.personal, url: almOrganization.almUrl }, installationId: this.props.almInstallId diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/AutoOrganizationCreate-test.tsx b/server/sonar-web/src/main/js/apps/create/organization/__tests__/AutoOrganizationCreate-test.tsx index 0deff24f195..bce78581887 100644 --- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/AutoOrganizationCreate-test.tsx +++ b/server/sonar-web/src/main/js/apps/create/organization/__tests__/AutoOrganizationCreate-test.tsx @@ -50,9 +50,10 @@ it('should render prefilled and create org', async () => { 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' }); diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/AutoOrganizationCreate-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/AutoOrganizationCreate-test.tsx.snap index 21741e56c96..9b74fb68d47 100644 --- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/AutoOrganizationCreate-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/AutoOrganizationCreate-test.tsx.snap @@ -73,6 +73,7 @@ exports[`should display choice between import or creation 1`] = ` "description": "description-foo", "key": "foo", "name": "foo", + "personal": false, "privateRepos": 0, "publicRepos": 3, "url": "http://example.com/foo", @@ -162,6 +163,7 @@ exports[`should render prefilled and create org 1`] = ` "description": "description-foo", "key": "foo", "name": "foo", + "personal": false, "privateRepos": 0, "publicRepos": 3, "url": "http://example.com/foo", @@ -187,6 +189,7 @@ exports[`should render prefilled and create org 1`] = ` "description": "description-foo", "key": "foo", "name": "foo", + "personal": false, "privateRepos": 0, "publicRepos": 3, "url": "http://example.com/foo", diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/CreateOrganization-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/CreateOrganization-test.tsx.snap index 3e5bdda098a..46829d9e422 100644 --- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/CreateOrganization-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/CreateOrganization-test.tsx.snap @@ -361,6 +361,7 @@ exports[`should render with organization bind page 2`] = ` "description": "description-foo", "key": "foo", "name": "foo", + "personal": false, "privateRepos": 0, "publicRepos": 3, "url": "http://example.com/foo", diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/PlanStep-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/PlanStep-test.tsx.snap index 0d38c7b12b9..ca7cb711940 100644 --- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/PlanStep-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/PlanStep-test.tsx.snap @@ -30,6 +30,7 @@ exports[`should preselect paid plan 1`] = ` "description": "description-foo", "key": "foo", "name": "foo", + "personal": false, "privateRepos": 5, "publicRepos": 0, "url": "http://example.com/foo", diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/actions-test.ts b/server/sonar-web/src/main/js/apps/create/organization/__tests__/actions-test.ts index eb0a5cb17fc..0a3bb15ea84 100644 --- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/actions-test.ts +++ b/server/sonar-web/src/main/js/apps/create/organization/__tests__/actions-test.ts @@ -62,4 +62,18 @@ describe('#createOrganization', () => { 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(); + }); }); diff --git a/server/sonar-web/src/main/js/apps/create/organization/actions.ts b/server/sonar-web/src/main/js/apps/create/organization/actions.ts index 950156f2876..8184ad205b2 100644 --- a/server/sonar-web/src/main/js/apps/create/organization/actions.ts +++ b/server/sonar-web/src/main/js/apps/create/organization/actions.ts @@ -31,7 +31,7 @@ export function createOrganization({ .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; diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/AutoProjectCreate-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/AutoProjectCreate-test.tsx.snap index 61c5ce222bb..9e3f0583a8b 100644 --- a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/AutoProjectCreate-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/AutoProjectCreate-test.tsx.snap @@ -15,6 +15,7 @@ exports[`should display the bound organizations dropdown with the remote reposit "alm": Object { "key": "github", "membersSync": false, + "personal": false, "url": "https://github.com/foo", }, "key": "foo", @@ -25,6 +26,7 @@ exports[`should display the bound organizations dropdown with the remote reposit "alm": Object { "key": "github", "membersSync": false, + "personal": false, "url": "https://github.com/foo", }, "key": "bar", @@ -54,6 +56,7 @@ exports[`should display the bound organizations dropdown with the remote reposit "alm": Object { "key": "github", "membersSync": false, + "personal": false, "url": "https://github.com/foo", }, "key": "foo", diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/CreateProjectPageSonarCloud-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/CreateProjectPageSonarCloud-test.tsx.snap index e2fc083cdee..71566a53266 100644 --- a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/CreateProjectPageSonarCloud-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/CreateProjectPageSonarCloud-test.tsx.snap @@ -87,6 +87,7 @@ exports[`should render correctly 2`] = ` "alm": Object { "key": "github", "membersSync": false, + "personal": false, "url": "https://github.com/foo", }, "key": "bar", @@ -152,6 +153,7 @@ exports[`should render with Custom creation only 1`] = ` "alm": Object { "key": "github", "membersSync": false, + "personal": false, "url": "https://github.com/foo", }, "key": "bar", @@ -222,6 +224,7 @@ exports[`should switch tabs 1`] = ` "alm": Object { "key": "github", "membersSync": false, + "personal": false, "url": "https://github.com/foo", }, "key": "bar", diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/OrganizationInput-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/OrganizationInput-test.tsx.snap index a655ac75dbe..7f2483a621e 100644 --- a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/OrganizationInput-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/OrganizationInput-test.tsx.snap @@ -34,6 +34,7 @@ exports[`should render correctly 1`] = ` "alm": Object { "key": "github", "membersSync": false, + "personal": false, "url": "https://github.com/foo", }, "key": "bar", diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/RemoteRepositories-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/RemoteRepositories-test.tsx.snap index d5f81a64131..ffd95a3904c 100644 --- a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/RemoteRepositories-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/RemoteRepositories-test.tsx.snap @@ -39,6 +39,7 @@ exports[`should display the list of repositories 1`] = ` "alm": Object { "key": "github", "membersSync": false, + "personal": false, "url": "https://github.com/foo", }, "key": "foo", @@ -140,6 +141,7 @@ exports[`should display the list of repositories 2`] = ` "alm": Object { "key": "github", "membersSync": false, + "personal": false, "url": "https://github.com/foo", }, "key": "foo", @@ -166,6 +168,7 @@ exports[`should display the organization upgrade box 1`] = ` "alm": Object { "key": "github", "membersSync": false, + "personal": false, "url": "https://github.com/foo", }, "key": "foo", diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/MembersPageHeader.tsx b/server/sonar-web/src/main/js/apps/organizationMembers/MembersPageHeader.tsx index a520f22a579..0fbc42ebcf3 100644 --- a/server/sonar-web/src/main/js/apps/organizationMembers/MembersPageHeader.tsx +++ b/server/sonar-web/src/main/js/apps/organizationMembers/MembersPageHeader.tsx @@ -43,6 +43,8 @@ export default function MembersPageHeader(props: Props) { 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"> @@ -50,7 +52,7 @@ export default function MembersPageHeader(props: Props) { <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} @@ -85,7 +87,7 @@ export default function MembersPageHeader(props: Props) { ) }} /> - {almKey && isGithub(almKey) && showSyncNotif && ( + {almKey && isSyncEligible && showSyncNotif && ( <Alert className="spacer-top" display="inline" variant="info"> {translateWithParameters( 'organization.members.auto_sync_members_from_org_x', diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/MembersPageHeader-test.tsx b/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/MembersPageHeader-test.tsx index 43921cdcace..98cae6d4a69 100644 --- a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/MembersPageHeader-test.tsx +++ b/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/MembersPageHeader-test.tsx @@ -48,6 +48,13 @@ it('should render for GitHub bound organization without sync', () => { 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 diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/MembersPageHeader-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/MembersPageHeader-test.tsx.snap index 9cc1eb93b37..fe3b38ed772 100644 --- a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/MembersPageHeader-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/MembersPageHeader-test.tsx.snap @@ -66,6 +66,7 @@ exports[`should render for Bitbucket bound organization 1`] = ` "alm": Object { "key": "bitbucket", "membersSync": false, + "personal": false, "url": "https://github.com/foo", }, "key": "foo", @@ -132,6 +133,7 @@ exports[`should render for GitHub bound organization without sync 1`] = ` "alm": Object { "key": "github", "membersSync": false, + "personal": false, "url": "https://github.com/foo", }, "key": "foo", @@ -184,6 +186,7 @@ exports[`should render for GitHub bound organization without sync 1`] = ` "alm": Object { "key": "github", "membersSync": false, + "personal": false, "url": "https://github.com/foo", }, "key": "foo", @@ -258,3 +261,70 @@ exports[`should render for admin 1`] = ` </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> +`; diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationHeader-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationHeader-test.tsx.snap index 828f54920e8..0394cb0be1d 100644 --- a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationHeader-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationHeader-test.tsx.snap @@ -116,6 +116,7 @@ exports[`renders with alm integration 1`] = ` "alm": Object { "key": "github", "membersSync": false, + "personal": false, "url": "https://github.com/foo", }, "key": "foo", diff --git a/server/sonar-web/src/main/js/helpers/testMocks.ts b/server/sonar-web/src/main/js/helpers/testMocks.ts index 7e9b7eb4d1e..a9b33558b36 100644 --- a/server/sonar-web/src/main/js/helpers/testMocks.ts +++ b/server/sonar-web/src/main/js/helpers/testMocks.ts @@ -43,6 +43,7 @@ export function mockAlmOrganization(overrides: Partial<T.AlmOrganization> = {}): description: 'description-foo', key: 'foo', name: 'foo', + personal: false, privateRepos: 0, publicRepos: 3, url: 'http://example.com/foo', @@ -491,7 +492,13 @@ export function mockOrganizationWithAlm( 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 }); } |