From 0da0c9feef141aa635625736345cb0f4e2d228f8 Mon Sep 17 00:00:00 2001 From: Mathieu Suen Date: Wed, 27 Jan 2021 09:31:09 +0100 Subject: [PATCH] SONAR-14394 Add frontend for bitbucket cloud project binding. --- .../sonar-web/src/main/js/api/alm-settings.ts | 5 ++ .../__tests__/ProjectCreationMenu-test.tsx | 47 ++++++++++++++---- .../AlmSpecificForm.tsx | 22 ++++++++- .../PRDecorationBinding.tsx | 11 +++++ .../__tests__/AlmSpecificForm-test.tsx | 1 + .../__tests__/PRDecorationBinding-test.tsx | 31 +++++++++++- .../AlmSpecificForm-test.tsx.snap | 49 +++++++++++++++++++ .../src/main/js/types/alm-settings.ts | 4 ++ .../resources/org/sonar/l10n/core.properties | 3 ++ 9 files changed, 162 insertions(+), 11 deletions(-) diff --git a/server/sonar-web/src/main/js/api/alm-settings.ts b/server/sonar-web/src/main/js/api/alm-settings.ts index 4c4f6430ad1..9491b1809ec 100644 --- a/server/sonar-web/src/main/js/api/alm-settings.ts +++ b/server/sonar-web/src/main/js/api/alm-settings.ts @@ -26,6 +26,7 @@ import { AzureProjectAlmBindingParams, BitbucketBindingDefinition, BitbucketCloudBindingDefinition, + BitbucketCloudProjectAlmBindingParams, BitbucketProjectAlmBindingParams, GithubBindingDefinition, GithubProjectAlmBindingParams, @@ -132,6 +133,10 @@ export function setProjectBitbucketBinding(data: BitbucketProjectAlmBindingParam return post('/api/alm_settings/set_bitbucket_binding', data).catch(throwGlobalError); } +export function setProjectBitbucketCloudBinding(data: BitbucketCloudProjectAlmBindingParams) { + return post('/api/alm_settings/set_bitbucketcloud_binding', data).catch(throwGlobalError); +} + export function setProjectGithubBinding(data: GithubProjectAlmBindingParams) { return post('/api/alm_settings/set_github_binding', data).catch(throwGlobalError); } diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCreationMenu-test.tsx b/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCreationMenu-test.tsx index 90e7b675473..4488367b066 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCreationMenu-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCreationMenu-test.tsx @@ -53,19 +53,48 @@ it('should not fetch alm bindings if user cannot create projects', async () => { }); it('should filter alm bindings appropriately', async () => { - (getAlmSettings as jest.Mock).mockResolvedValueOnce([ - { alm: AlmKeys.Azure }, - { alm: AlmKeys.BitbucketServer, url: 'b1' }, - { alm: AlmKeys.BitbucketServer, url: 'b2' }, - { alm: AlmKeys.GitHub }, - { alm: AlmKeys.GitLab, url: 'gitlab.com' } - ]); + (getAlmSettings as jest.Mock) + .mockResolvedValueOnce([ + // Only faulty configs. + { alm: AlmKeys.Azure }, // Missing some configuration; will be ignored. + { alm: AlmKeys.BitbucketCloud }, // Bitbucket Cloud isn't supported. + { alm: AlmKeys.GitLab } // Missing some configuration; will be ignored. + ]) + .mockResolvedValueOnce([ + // All correct configs. + { alm: AlmKeys.Azure, url: 'http://ado.example.com' }, + { alm: AlmKeys.BitbucketServer, url: 'b1' }, + { alm: AlmKeys.GitHub }, + { alm: AlmKeys.GitLab, url: 'gitlab.com' } + ]) + .mockResolvedValueOnce([ + // Only duplicate ALMs; should all be ignored. + { alm: AlmKeys.Azure, url: 'http://ado.example.com' }, + { alm: AlmKeys.Azure, url: 'http://ado.example.com' }, + { alm: AlmKeys.BitbucketServer, url: 'b1' }, + { alm: AlmKeys.BitbucketServer, url: 'b1' }, + { alm: AlmKeys.GitHub }, + { alm: AlmKeys.GitHub }, + { alm: AlmKeys.GitLab, url: 'gitlab.com' }, + { alm: AlmKeys.GitLab, url: 'gitlab.com' } + ]); - const wrapper = shallowRender(); + let wrapper = shallowRender(); + await waitAndUpdate(wrapper); + expect(wrapper.state().boundAlms).toEqual([]); + wrapper = shallowRender(); await waitAndUpdate(wrapper); + expect(wrapper.state().boundAlms).toEqual([ + AlmKeys.Azure, + AlmKeys.BitbucketServer, + AlmKeys.GitHub, + AlmKeys.GitLab + ]); - expect(wrapper.state().boundAlms).toEqual([AlmKeys.GitHub, AlmKeys.GitLab]); + wrapper = shallowRender(); + await waitAndUpdate(wrapper); + expect(wrapper.state().boundAlms).toEqual([]); }); function shallowRender(overrides: Partial = {}) { diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/AlmSpecificForm.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/AlmSpecificForm.tsx index 52a985f6fb0..c6d297e1564 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/AlmSpecificForm.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/AlmSpecificForm.tsx @@ -217,7 +217,27 @@ export default function AlmSpecificForm(props: AlmSpecificFormProps) { propKey: 'slug', value: slug || '' })} - {renderMonoRepoFieldWithDocLink(ALM_DOCUMENTATION_PATHS[AlmKeys.Bitbucket])} + {renderMonoRepoFieldWithDocLink(ALM_DOCUMENTATION_PATHS[AlmKeys.BitbucketServer])} + + ); + case AlmKeys.BitbucketCloud: + return ( + <> + {renderField({ + help: true, + helpParams: { + example: ( + <> + {'https://bitbucket.org/{workspace}/'} + {'{repository}'} + + ) + }, + id: 'bitbucketcloud.repository', + onFieldChange: props.onFieldChange, + propKey: 'repository', + value: repository || '' + })} ); case AlmKeys.GitHub: diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/PRDecorationBinding.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/PRDecorationBinding.tsx index 4f4d34a1564..c38e99da161 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/PRDecorationBinding.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/PRDecorationBinding.tsx @@ -26,6 +26,7 @@ import { getProjectAlmBinding, setProjectAzureBinding, setProjectBitbucketBinding, + setProjectBitbucketCloudBinding, setProjectGithubBinding, setProjectGitlabBinding } from '../../../../api/alm-settings'; @@ -193,6 +194,16 @@ export class PRDecorationBinding extends React.PureComponent ({ setProjectBitbucketBinding: jest.fn().mockResolvedValue(undefined), setProjectGithubBinding: jest.fn().mockResolvedValue(undefined), setProjectGitlabBinding: jest.fn().mockResolvedValue(undefined), + setProjectBitbucketCloudBinding: jest.fn().mockResolvedValue(undefined), deleteProjectAlmBinding: jest.fn().mockResolvedValue(undefined) })); @@ -94,7 +96,8 @@ describe('handleSubmit', () => { { key: 'github', alm: AlmKeys.GitHub }, { key: 'azure', alm: AlmKeys.Azure }, { key: 'bitbucket', alm: AlmKeys.BitbucketServer }, - { key: 'gitlab', alm: AlmKeys.GitLab } + { key: 'gitlab', alm: AlmKeys.GitLab }, + { key: 'bitbucketcloud', alm: AlmKeys.BitbucketCloud } ]; it('should work for github', async () => { @@ -187,6 +190,28 @@ describe('handleSubmit', () => { }); expect(wrapper.state().success).toBe(true); }); + + it('should work for bitbucket cloud', async () => { + const wrapper = shallowRender(); + await waitAndUpdate(wrapper); + const bitbucketKey = 'bitbucketcloud'; + const repository = 'repoKey'; + wrapper.setState({ formData: { key: bitbucketKey, repository }, instances: [] }); + wrapper.instance().handleSubmit(); + await waitAndUpdate(wrapper); + expect(setProjectBitbucketCloudBinding).not.toBeCalled(); + + wrapper.setState({ formData: { key: bitbucketKey, repository }, instances }); + wrapper.instance().handleSubmit(); + await waitAndUpdate(wrapper); + + expect(setProjectBitbucketCloudBinding).toBeCalledWith({ + almSetting: bitbucketKey, + project: PROJECT_KEY, + repository + }); + expect(wrapper.state().success).toBe(true); + }); }); describe.each([[500], [404]])('For status %i', status => { @@ -266,6 +291,7 @@ it.each([ [AlmKeys.BitbucketServer, {}], [AlmKeys.BitbucketServer, { slug: 'test' }], [AlmKeys.BitbucketServer, { repository: 'test' }], + [AlmKeys.BitbucketCloud, {}], [AlmKeys.GitHub, {}], [AlmKeys.GitLab, {}] ])('should properly reject promise for %s & %s', async (almKey: AlmKeys, params: {}) => { @@ -290,6 +316,7 @@ it('should validate form', async () => { instances: [ { key: 'azure', alm: AlmKeys.Azure }, { key: 'bitbucket', alm: AlmKeys.BitbucketServer }, + { key: 'bitbucketcloud', alm: AlmKeys.BitbucketCloud }, { key: 'github', alm: AlmKeys.GitHub }, { key: 'gitlab', alm: AlmKeys.GitLab } ] @@ -303,6 +330,8 @@ it('should validate form', async () => { { values: { key: 'github', repository: 'asdf' }, result: true }, { values: { key: 'bitbucket', repository: 'key' }, result: false }, { values: { key: 'bitbucket', repository: 'key', slug: 'slug' }, result: true }, + { values: { key: 'bitbucketcloud', repository: '' }, result: false }, + { values: { key: 'bitbucketcloud', repository: 'key' }, result: true }, { values: { key: 'gitlab' }, result: false }, { values: { key: 'gitlab', repository: 'key' }, result: true } ].forEach(({ values, result }) => { diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/__snapshots__/AlmSpecificForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/__snapshots__/AlmSpecificForm-test.tsx.snap index 64af693dfb7..572d371879f 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/__snapshots__/AlmSpecificForm-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/__snapshots__/AlmSpecificForm-test.tsx.snap @@ -424,6 +424,55 @@ exports[`it should render correctly for bitbucket and monorepo=true 1`] = ` `; +exports[`it should render correctly for bitbucketcloud and monorepo=false 1`] = ` + +
+ + +
+
+`; + exports[`it should render correctly for github and monorepo=false 1`] = `