From 0ad2427584c654389e6e8112a869b3f25e32eb8d Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Tue, 22 Oct 2019 14:29:27 +0200 Subject: [PATCH] SONAR-12514 UI for project-level form - Bitbucket --- .../sonar-web/src/main/js/api/almSettings.ts | 4 + .../PRDecorationTabs-test.tsx.snap | 16 +++ .../PRDecorationBinding.tsx | 20 +++- .../PRDecorationBindingRenderer.tsx | 104 +++++++++++++++--- .../__tests__/PRDecorationBinding-test.tsx | 38 ++++++- .../PRDecorationBindingRenderer-test.tsx.snap | 15 +++ .../src/main/js/types/alm-settings.d.ts | 13 ++- .../resources/org/sonar/l10n/core.properties | 4 + 8 files changed, 189 insertions(+), 25 deletions(-) diff --git a/server/sonar-web/src/main/js/api/almSettings.ts b/server/sonar-web/src/main/js/api/almSettings.ts index 2d20b9f0511..487e12ed19b 100644 --- a/server/sonar-web/src/main/js/api/almSettings.ts +++ b/server/sonar-web/src/main/js/api/almSettings.ts @@ -78,6 +78,10 @@ export function setProjectAzureBinding(data: T.AzureProjectAlmBinding) { return post('/api/alm_settings/set_azure_binding', data).catch(throwGlobalError); } +export function setProjectBitbucketBinding(data: T.BitbucketProjectAlmBinding) { + return post('/api/alm_settings/set_bitbucket_binding', data).catch(throwGlobalError); +} + export function setProjectGithubBinding(data: T.GithubProjectAlmBinding) { return post('/api/alm_settings/set_github_binding', data).catch(throwGlobalError); } diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/PRDecorationTabs-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/PRDecorationTabs-test.tsx.snap index d04c62f26d3..7d8a26c3d7c 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/PRDecorationTabs-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/PRDecorationTabs-test.tsx.snap @@ -25,6 +25,10 @@ exports[`should render correctly 1`] = ` "key": "github", "label": "Github Enterprise", }, + Object { + "key": "bitbucket", + "label": "Bitbucket Server", + }, Object { "key": "azure", "label": "Azure DevOps Server", @@ -70,6 +74,10 @@ exports[`should render correctly 2`] = ` "key": "github", "label": "Github Enterprise", }, + Object { + "key": "bitbucket", + "label": "Bitbucket Server", + }, Object { "key": "azure", "label": "Azure DevOps Server", @@ -120,6 +128,10 @@ exports[`should render correctly 3`] = ` "key": "github", "label": "Github Enterprise", }, + Object { + "key": "bitbucket", + "label": "Bitbucket Server", + }, Object { "key": "azure", "label": "Azure DevOps Server", @@ -165,6 +177,10 @@ exports[`should render correctly 4`] = ` "key": "github", "label": "Github Enterprise", }, + Object { + "key": "bitbucket", + "label": "Bitbucket Server", + }, Object { "key": "azure", "label": "Azure DevOps Server", 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 6c31725727a..70ff66b5a83 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 @@ -23,6 +23,7 @@ import { getAlmSettings, getProjectAlmBinding, setProjectAzureBinding, + setProjectBitbucketBinding, setProjectGithubBinding } from '../../../../api/almSettings'; import throwGlobalError from '../../../../app/utils/throwGlobalError'; @@ -43,8 +44,11 @@ interface State { success: boolean; } -const FIELDS_BY_ALM: { [almKey: string]: Array<'repository'> } = { +const FIELDS_BY_ALM: { + [almKey: string]: Array<'repository' | 'repositoryKey' | 'repositorySlug'>; +} = { [ALM_KEYS.AZURE]: [], + [ALM_KEYS.BITBUCKET]: ['repositoryKey', 'repositorySlug'], [ALM_KEYS.GITHUB]: ['repository'] }; @@ -138,7 +142,7 @@ export default class PRDecorationBinding extends React.PureComponent { const almSetting = key; const project = this.props.component.key; @@ -149,6 +153,18 @@ export default class PRDecorationBinding extends React.PureComponent void; + propKey: keyof T.ProjectAlmBinding; + value: string; +}) { + const { help, helpParams, id, propKey, value, onFieldChange } = props; + return ( +
+ + onFieldChange(propKey, e.currentTarget.value)} + type="text" + value={value} + /> +
+ ); +} + export default function PRDecorationBindingRenderer(props: PRDecorationBindingRendererProps) { const { - formData: { repository, key }, + formData: { key, repository, repositoryKey, repositorySlug }, hasBinding, instances, isValid, @@ -114,24 +155,53 @@ export default function PRDecorationBindingRenderer(props: PRDecorationBindingRe /> - {alm === ALM_KEYS.GITHUB && ( -
- - props.onFieldChange('repository', e.currentTarget.value)} - type="text" - value={repository} - /> -
+ {alm === ALM_KEYS.BITBUCKET && ( + <> + {renderField({ + help: true, + helpParams: { + example: ( + <> + {'.../projects/'} + {'{KEY}'} + {'/repos/{SLUG}/browse'} + + ) + }, + id: 'repository_key', + onFieldChange: props.onFieldChange, + propKey: 'repositoryKey', + value: repositoryKey || '' + })} + {renderField({ + help: true, + helpParams: { + example: ( + <> + {'.../projects/{KEY}/repos/'} + {'{SLUG}'} + {'/browse'} + + ) + }, + id: 'repository_slug', + onFieldChange: props.onFieldChange, + propKey: 'repositorySlug', + value: repositorySlug || '' + })} + )} + {alm === ALM_KEYS.GITHUB && + renderField({ + help: true, + helpParams: { example: 'SonarSource/sonarqube' }, + id: 'repository', + onFieldChange: props.onFieldChange, + propKey: 'repository', + value: repository || '' + })} +
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/PRDecorationBinding-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/PRDecorationBinding-test.tsx index e0e1b899c4a..b1eaaf1346c 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/PRDecorationBinding-test.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/PRDecorationBinding-test.tsx @@ -25,6 +25,7 @@ import { getAlmSettings, getProjectAlmBinding, setProjectAzureBinding, + setProjectBitbucketBinding, setProjectGithubBinding } from '../../../../../api/almSettings'; import { mockComponent } from '../../../../../helpers/testMocks'; @@ -35,6 +36,7 @@ jest.mock('../../../../../api/almSettings', () => ({ getAlmSettings: jest.fn().mockResolvedValue([]), getProjectAlmBinding: jest.fn().mockResolvedValue(undefined), setProjectAzureBinding: jest.fn().mockResolvedValue(undefined), + setProjectBitbucketBinding: jest.fn().mockResolvedValue(undefined), setProjectGithubBinding: jest.fn().mockResolvedValue(undefined), deleteProjectAlmBinding: jest.fn().mockResolvedValue(undefined) })); @@ -99,12 +101,13 @@ it('should handle reset', async () => { expect(wrapper.state().hasBinding).toBe(false); }); -it('should handle submit to github or azure', async () => { +it('should handle submit to github, azure or bitbucket', async () => { const wrapper = shallowRender(); await waitAndUpdate(wrapper); const instances = [ { key: 'github', alm: ALM_KEYS.GITHUB }, - { key: 'azure', alm: ALM_KEYS.AZURE } + { key: 'azure', alm: ALM_KEYS.AZURE }, + { key: 'bitbucket', alm: ALM_KEYS.BITBUCKET } ]; // Github @@ -134,6 +137,23 @@ it('should handle submit to github or azure', async () => { }); expect(wrapper.state().hasBinding).toBe(true); expect(wrapper.state().success).toBe(true); + + // bitbucket + const bitbucketKey = 'bitbucket'; + const repositoryKey = 'repoKey'; + const repositorySlug = 'repoSlug'; + wrapper.setState({ formData: { key: bitbucketKey, repositoryKey, repositorySlug } }); + wrapper.instance().handleSubmit(); + await waitAndUpdate(wrapper); + + expect(setProjectBitbucketBinding).toBeCalledWith({ + almSetting: bitbucketKey, + project: PROJECT_KEY, + repositoryKey, + repositorySlug + }); + expect(wrapper.state().hasBinding).toBe(true); + expect(wrapper.state().success).toBe(true); }); it('should handle failures gracefully', async () => { @@ -185,11 +205,23 @@ it('should validate form', async () => { expect(wrapper.instance().validateForm({ key: '', repository: 'c' })).toBe(false); wrapper.setState({ - instances: [{ key: 'azure', alm: ALM_KEYS.AZURE }, { key: 'github', alm: ALM_KEYS.GITHUB }] + instances: [ + { key: 'azure', alm: ALM_KEYS.AZURE }, + { key: 'bitbucket', alm: ALM_KEYS.BITBUCKET }, + { key: 'github', alm: ALM_KEYS.GITHUB } + ] }); expect(wrapper.instance().validateForm({ key: 'azure' })).toBe(true); + expect(wrapper.instance().validateForm({ key: 'github', repository: '' })).toBe(false); expect(wrapper.instance().validateForm({ key: 'github', repository: 'asdf' })).toBe(true); + + expect(wrapper.instance().validateForm({ key: 'bitbucket', repositoryKey: 'key' })).toBe(false); + expect( + wrapper + .instance() + .validateForm({ key: 'bitbucket', repositoryKey: 'key', repositorySlug: 'slug' }) + ).toBe(true); }); function shallowRender(props: Partial = {}) { diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/__snapshots__/PRDecorationBindingRenderer-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/__snapshots__/PRDecorationBindingRenderer-test.tsx.snap index a57c9bfa856..5fd4b3eca00 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/__snapshots__/PRDecorationBindingRenderer-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/__snapshots__/PRDecorationBindingRenderer-test.tsx.snap @@ -380,6 +380,7 @@ exports[`should render multiple instances correctly 2`] = ` className="form-field" >