From: Wouter Admiraal
Date: Tue, 26 Jan 2021 08:30:35 +0000 (+0100)
Subject: SONAR-14393 Add admin form for Bitbucket Cloud integration
X-Git-Tag: 8.7.0.41497~56
X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=eaa3c931777204492328dc49c93e2cfca3d9c307;p=sonarqube.git
SONAR-14393 Add admin form for Bitbucket Cloud integration
---
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 26953bca8a0..4c4f6430ad1 100644
--- a/server/sonar-web/src/main/js/api/alm-settings.ts
+++ b/server/sonar-web/src/main/js/api/alm-settings.ts
@@ -25,6 +25,7 @@ import {
AzureBindingDefinition,
AzureProjectAlmBindingParams,
BitbucketBindingDefinition,
+ BitbucketCloudBindingDefinition,
BitbucketProjectAlmBindingParams,
GithubBindingDefinition,
GithubProjectAlmBindingParams,
@@ -87,6 +88,16 @@ export function updateBitbucketConfiguration(
return post('/api/alm_settings/update_bitbucket', data).catch(throwGlobalError);
}
+export function createBitbucketCloudConfiguration(data: BitbucketCloudBindingDefinition) {
+ return post('/api/alm_settings/create_bitbucketcloud', data).catch(throwGlobalError);
+}
+
+export function updateBitbucketCloudConfiguration(
+ data: BitbucketCloudBindingDefinition & { newKey: string }
+) {
+ return post('/api/alm_settings/update_bitbucketcloud', data).catch(throwGlobalError);
+}
+
export function createGitlabConfiguration(data: GitlabBindingDefinition) {
return post('/api/alm_settings/create_gitlab', data).catch(throwGlobalError);
}
diff --git a/server/sonar-web/src/main/js/apps/create/project/BitbucketProjectCreateRenderer.tsx b/server/sonar-web/src/main/js/apps/create/project/BitbucketProjectCreateRenderer.tsx
index a256fc3202e..0f71610155b 100644
--- a/server/sonar-web/src/main/js/apps/create/project/BitbucketProjectCreateRenderer.tsx
+++ b/server/sonar-web/src/main/js/apps/create/project/BitbucketProjectCreateRenderer.tsx
@@ -101,7 +101,7 @@ export default function BitbucketProjectCreateRenderer(props: BitbucketProjectCr
{loading && }
{!loading && !bitbucketSetting && (
-
+
)}
{!loading &&
diff --git a/server/sonar-web/src/main/js/apps/create/project/CreateProjectModeSelection.tsx b/server/sonar-web/src/main/js/apps/create/project/CreateProjectModeSelection.tsx
index 136fb393e5f..e14ba173049 100644
--- a/server/sonar-web/src/main/js/apps/create/project/CreateProjectModeSelection.tsx
+++ b/server/sonar-web/src/main/js/apps/create/project/CreateProjectModeSelection.tsx
@@ -29,7 +29,12 @@ import { ALM_INTEGRATION } from '../../settings/components/AdditionalCategoryKey
import { CreateProjectModes } from './types';
export interface CreateProjectModeSelectionProps {
- almCounts: { [key in AlmKeys]: number };
+ almCounts: {
+ [AlmKeys.Azure]: number;
+ [AlmKeys.BitbucketServer]: number;
+ [AlmKeys.GitLab]: number;
+ [AlmKeys.GitHub]: number;
+ };
appState: Pick;
loadingBindings: boolean;
onSelectMode: (mode: CreateProjectModes) => void;
@@ -37,7 +42,7 @@ export interface CreateProjectModeSelectionProps {
function renderAlmOption(
props: CreateProjectModeSelectionProps,
- alm: AlmKeys,
+ alm: AlmKeys.Azure | AlmKeys.BitbucketServer | AlmKeys.GitHub | AlmKeys.GitLab,
mode: CreateProjectModes
) {
const {
@@ -145,7 +150,7 @@ export function CreateProjectModeSelection(props: CreateProjectModeSelectionProp
{renderAlmOption(props, AlmKeys.Azure, CreateProjectModes.AzureDevOps)}
- {renderAlmOption(props, AlmKeys.Bitbucket, CreateProjectModes.BitbucketServer)}
+ {renderAlmOption(props, AlmKeys.BitbucketServer, CreateProjectModes.BitbucketServer)}
{renderAlmOption(props, AlmKeys.GitHub, CreateProjectModes.GitHub)}
{renderAlmOption(props, AlmKeys.GitLab, CreateProjectModes.GitLab)}
diff --git a/server/sonar-web/src/main/js/apps/create/project/CreateProjectPage.tsx b/server/sonar-web/src/main/js/apps/create/project/CreateProjectPage.tsx
index c2bdfd909e2..45feaadb2ad 100644
--- a/server/sonar-web/src/main/js/apps/create/project/CreateProjectPage.tsx
+++ b/server/sonar-web/src/main/js/apps/create/project/CreateProjectPage.tsx
@@ -75,7 +75,7 @@ export class CreateProjectPage extends React.PureComponent {
if (this.mounted) {
this.setState({
azureSettings: almSettings.filter(s => s.alm === AlmKeys.Azure),
- bitbucketSettings: almSettings.filter(s => s.alm === AlmKeys.Bitbucket),
+ bitbucketSettings: almSettings.filter(s => s.alm === AlmKeys.BitbucketServer),
githubSettings: almSettings.filter(s => s.alm === AlmKeys.GitHub),
gitlabSettings: almSettings.filter(s => s.alm === AlmKeys.GitLab),
loading: false
@@ -171,7 +171,7 @@ export class CreateProjectPage extends React.PureComponent {
default: {
const almCounts = {
[AlmKeys.Azure]: azureSettings.length,
- [AlmKeys.Bitbucket]: bitbucketSettings.length,
+ [AlmKeys.BitbucketServer]: bitbucketSettings.length,
[AlmKeys.GitHub]: githubSettings.length,
[AlmKeys.GitLab]: gitlabSettings.length
};
diff --git a/server/sonar-web/src/main/js/apps/create/project/PersonalAccessTokenForm.tsx b/server/sonar-web/src/main/js/apps/create/project/PersonalAccessTokenForm.tsx
index 9062a7e84ac..51811a40ac1 100644
--- a/server/sonar-web/src/main/js/apps/create/project/PersonalAccessTokenForm.tsx
+++ b/server/sonar-web/src/main/js/apps/create/project/PersonalAccessTokenForm.tsx
@@ -36,7 +36,7 @@ export interface PersonalAccessTokenFormProps {
}
function getPatUrl(alm: AlmKeys, url: string) {
- if (alm === AlmKeys.Bitbucket) {
+ if (alm === AlmKeys.BitbucketServer) {
return `${url.replace(/\/$/, '')}/plugins/servlet/access-tokens/add`;
} else {
// GitLab
@@ -132,7 +132,7 @@ export default function PersonalAccessTokenForm(props: PersonalAccessTokenFormPr
- {alm === AlmKeys.Bitbucket && (
+ {alm === AlmKeys.BitbucketServer && (
<>
= {}) {
return shallow(
{
function shallowRender(props: Partial = {}) {
return shallow(
{
expect(shallowRender()).toMatchSnapshot('default');
expect(shallowRender({ loadingBindings: true })).toMatchSnapshot('loading instances');
- expect(shallowRender({}, { [AlmKeys.Bitbucket]: 0, [AlmKeys.GitHub]: 2 })).toMatchSnapshot(
+ expect(shallowRender({}, { [AlmKeys.BitbucketServer]: 0, [AlmKeys.GitHub]: 2 })).toMatchSnapshot(
'invalid configs, not admin'
);
expect(
- shallowRender({ appState: { canAdmin: true } }, { [AlmKeys.Bitbucket]: 0, [AlmKeys.GitHub]: 2 })
+ shallowRender(
+ { appState: { canAdmin: true } },
+ { [AlmKeys.BitbucketServer]: 0, [AlmKeys.GitHub]: 2 }
+ )
).toMatchSnapshot('invalid configs, admin');
});
@@ -71,7 +74,7 @@ function shallowRender(
) {
const almCounts = {
[AlmKeys.Azure]: 0,
- [AlmKeys.Bitbucket]: 1,
+ [AlmKeys.BitbucketServer]: 1,
[AlmKeys.GitHub]: 0,
[AlmKeys.GitLab]: 0,
...almCountOverrides
diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/CreateProjectPage-test.tsx b/server/sonar-web/src/main/js/apps/create/project/__tests__/CreateProjectPage-test.tsx
index e59baf2bb09..dd9682364f3 100644
--- a/server/sonar-web/src/main/js/apps/create/project/__tests__/CreateProjectPage-test.tsx
+++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/CreateProjectPage-test.tsx
@@ -26,7 +26,7 @@ import { CreateProjectPage } from '../CreateProjectPage';
import { CreateProjectModes } from '../types';
jest.mock('../../../../api/alm-settings', () => ({
- getAlmSettings: jest.fn().mockResolvedValue([{ alm: AlmKeys.Bitbucket, key: 'foo' }])
+ getAlmSettings: jest.fn().mockResolvedValue([{ alm: AlmKeys.BitbucketServer, key: 'foo' }])
}));
beforeEach(jest.clearAllMocks);
diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/PersonalAccessTokenForm-test.tsx b/server/sonar-web/src/main/js/apps/create/project/__tests__/PersonalAccessTokenForm-test.tsx
index 2f4ee698f96..5e7571a211b 100644
--- a/server/sonar-web/src/main/js/apps/create/project/__tests__/PersonalAccessTokenForm-test.tsx
+++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/PersonalAccessTokenForm-test.tsx
@@ -71,7 +71,7 @@ function shallowRender(props: Partial = {}) {
return shallow(
{
expect(shallowRender({ canAdmin: true })).toMatchSnapshot('for admin');
- expect(shallowRender({ alm: AlmKeys.Bitbucket })).toMatchSnapshot('bitbucket');
+ expect(shallowRender({ alm: AlmKeys.BitbucketServer })).toMatchSnapshot('bitbucket');
expect(shallowRender({ alm: AlmKeys.GitLab })).toMatchSnapshot('gitlab');
});
function shallowRender(props: Partial = {}) {
- return shallow( );
+ return shallow(
+
+ );
}
diff --git a/server/sonar-web/src/main/js/apps/projects/components/ProjectCreationMenu.tsx b/server/sonar-web/src/main/js/apps/projects/components/ProjectCreationMenu.tsx
index 4a406a6a36f..fb282ba3f49 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/ProjectCreationMenu.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/components/ProjectCreationMenu.tsx
@@ -24,6 +24,7 @@ import DropdownIcon from 'sonar-ui-common/components/icons/DropdownIcon';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { getAlmSettings } from '../../../api/alm-settings';
import { withCurrentUser } from '../../../components/hoc/withCurrentUser';
+import { IMPORT_COMPATIBLE_ALMS } from '../../../helpers/constants';
import { hasGlobalPermission } from '../../../helpers/users';
import { AlmKeys, AlmSettingsInstance } from '../../../types/alm-settings';
import ProjectCreationMenuItem from './ProjectCreationMenuItem';
@@ -38,14 +39,11 @@ interface State {
}
const PROJECT_CREATION_PERMISSION = 'provisioning';
-/*
- * ALMs for which the import feature has been implemented
- */
-const IMPORT_COMPATIBLE_ALMS = [AlmKeys.Azure, AlmKeys.Bitbucket, AlmKeys.GitHub, AlmKeys.GitLab];
const almSettingsValidators = {
[AlmKeys.Azure]: (settings: AlmSettingsInstance) => !!settings.url,
- [AlmKeys.Bitbucket]: (_: AlmSettingsInstance) => true,
+ [AlmKeys.BitbucketServer]: (_: AlmSettingsInstance) => true,
+ [AlmKeys.BitbucketCloud]: (_: AlmSettingsInstance) => false,
[AlmKeys.GitHub]: (_: AlmSettingsInstance) => true,
[AlmKeys.GitLab]: (settings: AlmSettingsInstance) => !!settings.url
};
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 5b2825de4b2..90e7b675473 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
@@ -55,8 +55,8 @@ 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.Bitbucket, url: 'b1' },
- { alm: AlmKeys.Bitbucket, url: 'b2' },
+ { alm: AlmKeys.BitbucketServer, url: 'b1' },
+ { alm: AlmKeys.BitbucketServer, url: 'b2' },
{ alm: AlmKeys.GitHub },
{ alm: AlmKeys.GitLab, url: 'gitlab.com' }
]);
diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCreationMenuItem-test.tsx b/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCreationMenuItem-test.tsx
index 65325429a39..2825b03ba1f 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCreationMenuItem-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCreationMenuItem-test.tsx
@@ -28,5 +28,5 @@ it('should render correctly', () => {
});
function shallowRender(overrides: Partial = {}) {
- return shallow( );
+ return shallow( );
}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionBox.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionBox.tsx
index c83889511c9..9f1d81371f9 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionBox.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionBox.tsx
@@ -29,6 +29,7 @@ import EditIcon from 'sonar-ui-common/components/icons/EditIcon';
import { Alert } from 'sonar-ui-common/components/ui/Alert';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { getEdition, getEditionUrl } from '../../../../helpers/editions';
+import { IMPORT_COMPATIBLE_ALMS } from '../../../../helpers/constants';
import {
AlmBindingDefinition,
AlmKeys,
@@ -140,12 +141,12 @@ function getImportFeatureStatus(
export default function AlmBindingDefinitionBox(props: AlmBindingDefinitionBoxProps) {
const { alm, branchesEnabled, definition, multipleDefinitions, status = DEFAULT_STATUS } = props;
- const importFeatureTitle =
+ const prDecoFeatureTitle =
alm === AlmKeys.GitLab
? translate('settings.almintegration.feature.mr_decoration.title')
: translate('settings.almintegration.feature.pr_decoration.title');
- const importFeatureDescription =
+ const prDecoFeatureDescription =
alm === AlmKeys.GitLab
? translate('settings.almintegration.feature.mr_decoration.description')
: translate('settings.almintegration.feature.pr_decoration.description');
@@ -178,20 +179,24 @@ export default function AlmBindingDefinitionBox(props: AlmBindingDefinitionBoxPr
{status.type !== AlmSettingsBindingStatusType.Warning && (
-
- {importFeatureTitle}
+
+ {prDecoFeatureTitle}
{getPRDecorationFeatureStatus(branchesEnabled, status.type)}
-
-
- {translate('settings.almintegration.feature.alm_repo_import.title')}
-
- {getImportFeatureStatus(definition, multipleDefinitions, status.type)}
-
+ {IMPORT_COMPATIBLE_ALMS.includes(alm) && (
+
+
+
+ {translate('settings.almintegration.feature.alm_repo_import.title')}
+
+
+ {getImportFeatureStatus(definition, multipleDefinitions, status.type)}
+
+ )}
)}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionFormModalRenderer.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionFormModalRenderer.tsx
index 2c0ac91f58d..c3600b8bfe8 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionFormModalRenderer.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionFormModalRenderer.tsx
@@ -58,10 +58,12 @@ export default function AlmBindingDefinitionFormModalRenderer(
{children}
- {help && (
+ {help ? (
{help}
+ ) : (
+
)}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmIntegration.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmIntegration.tsx
index 254cffa1d76..7845f393fb3 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmIntegration.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmIntegration.tsx
@@ -62,7 +62,8 @@ export class AlmIntegration extends React.PureComponent {
currentAlm: props.location.query.alm || AlmKeys.GitHub,
definitions: {
[AlmKeys.Azure]: [],
- [AlmKeys.Bitbucket]: [],
+ [AlmKeys.BitbucketServer]: [],
+ [AlmKeys.BitbucketCloud]: [],
[AlmKeys.GitHub]: [],
[AlmKeys.GitLab]: []
},
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmIntegrationRenderer.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmIntegrationRenderer.tsx
index 2583b5c064e..92ced87796c 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmIntegrationRenderer.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmIntegrationRenderer.tsx
@@ -68,7 +68,7 @@ const tabs = [
requiresBranchesEnabled: false
},
{
- key: AlmKeys.Bitbucket,
+ key: AlmKeys.BitbucketServer,
label: (
<>
- Bitbucket Server
+ Bitbucket
>
),
requiresBranchesEnabled: false
@@ -156,10 +156,10 @@ export default function AlmIntegrationRenderer(props: AlmIntegrationRendererProp
onUpdateDefinitions={props.onUpdateDefinitions}
/>
)}
- {currentAlm === AlmKeys.Bitbucket && (
+ {currentAlm === AlmKeys.BitbucketServer && (
extends React.PureCo
}
handleCancel = () => {
- this.setState({
- editedDefinition: undefined,
- success: false
- });
+ this.setState({ editedDefinition: undefined, success: false });
};
handleCreate = () => {
@@ -93,7 +90,11 @@ export default class AlmTab extends React.PureCo
return call
.then(() => {
if (this.mounted) {
- this.setState({ editedDefinition: undefined, submitting: false, success: true });
+ this.setState({
+ editedDefinition: undefined,
+ submitting: false,
+ success: true
+ });
}
})
.then(this.props.onUpdateDefinitions)
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmTabRenderer.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmTabRenderer.tsx
index c7c1cbd5a7f..e0f13c920db 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmTabRenderer.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmTabRenderer.tsx
@@ -24,7 +24,8 @@ import { translate } from 'sonar-ui-common/helpers/l10n';
import {
AlmBindingDefinition,
AlmKeys,
- AlmSettingsBindingStatus
+ AlmSettingsBindingStatus,
+ isBitbucketCloudBindingDefinition
} from '../../../../types/alm-settings';
import AlmBindingDefinitionBox from './AlmBindingDefinitionBox';
import AlmBindingDefinitionForm, {
@@ -93,7 +94,7 @@ export default function AlmTabRenderer(
{definitions.map(def => (
void;
- readOnly?: boolean;
+ formData: BitbucketBindingDefinition | BitbucketCloudBindingDefinition;
+ isCreating: boolean;
+ onFieldChange: (
+ fieldId: keyof (BitbucketBindingDefinition & BitbucketCloudBindingDefinition),
+ value: string
+ ) => void;
+ onSelectVariant: (variant: AlmKeys.BitbucketServer | AlmKeys.BitbucketCloud) => void;
+ variant?: AlmKeys.BitbucketServer | AlmKeys.BitbucketCloud;
}
export default function BitbucketForm(props: BitbucketFormProps) {
- const { formData, hideKeyField, onFieldChange, readOnly } = props;
+ const { formData, isCreating, variant } = props;
return (
- <>
- {!hideKeyField && (
-
+
+ {isCreating && (
+ <>
+
{translate('settings.almintegration.form.choose_bitbucket_variant')}
+
+ >
)}
-
+
+
+ }
+ id="url.bitbucket"
+ maxLength={2000}
+ onFieldChange={props.onFieldChange}
+ propKey="url"
+ value={formData.url}
/>
- }
- id="url.bitbucket"
- maxLength={2000}
- onFieldChange={onFieldChange}
- propKey="url"
- readOnly={readOnly}
- value={formData.url}
- />
-
- >
+
+
+ )}
+
+ {variant === AlmKeys.BitbucketCloud && isBitbucketCloudBindingDefinition(formData) && (
+
+
+
+ {'https://bitbucket.org/'}
+ {'{workspace}'}
+ {'/{repository}'}
+ >
+ )
+ }}
+ />
+ }
+ id="workspace.bitbucketcloud"
+ maxLength={2000}
+ onFieldChange={props.onFieldChange}
+ propKey="workspace"
+ value={formData.workspace}
+ />
+
+
+
+ )}
+
);
}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketTab.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketTab.tsx
index 1ea3352965b..df05024ece7 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketTab.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketTab.tsx
@@ -18,24 +18,24 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import { Link } from 'react-router';
-import { translate } from 'sonar-ui-common/helpers/l10n';
import {
+ createBitbucketCloudConfiguration,
createBitbucketConfiguration,
+ updateBitbucketCloudConfiguration,
updateBitbucketConfiguration
} from '../../../../api/alm-settings';
-import { ALM_DOCUMENTATION_PATHS } from '../../../../helpers/constants';
import {
AlmKeys,
AlmSettingsBindingStatus,
- BitbucketBindingDefinition
+ BitbucketBindingDefinition,
+ BitbucketCloudBindingDefinition,
+ isBitbucketBindingDefinition
} from '../../../../types/alm-settings';
-import AlmTab from './AlmTab';
-import BitbucketForm from './BitbucketForm';
+import BitbucketTabRenderer from './BitbucketTabRenderer';
-export interface BitbucketTabProps {
+interface Props {
branchesEnabled: boolean;
- definitions: BitbucketBindingDefinition[];
+ definitions: Array;
definitionStatus: T.Dict;
loadingAlmDefinitions: boolean;
loadingProjectCount: boolean;
@@ -45,54 +45,142 @@ export interface BitbucketTabProps {
onUpdateDefinitions: () => void;
}
-export default function BitbucketTab(props: BitbucketTabProps) {
- const {
- branchesEnabled,
- multipleAlmEnabled,
- definitions,
- definitionStatus,
- loadingAlmDefinitions,
- loadingProjectCount
- } = props;
-
- return (
-
-
{
+ mounted = false;
+ state: State = { isCreating: false, submitting: false, success: false };
+
+ componentDidMount() {
+ this.mounted = true;
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ handleCancel = () => {
+ this.setState({
+ editedDefinition: undefined,
+ isCreating: false,
+ success: false,
+ variant: undefined
+ });
+ };
+
+ handleCreate = () => {
+ this.setState({
+ editedDefinition: DEFAULT_SERVER_BINDING, // Default to Bitbucket Server.
+ isCreating: true,
+ success: false,
+ variant: undefined
+ });
+ };
+
+ handleSelectVariant = (variant: AlmKeys.BitbucketServer | AlmKeys.BitbucketCloud) => {
+ this.setState({
+ variant,
+ editedDefinition:
+ variant === AlmKeys.BitbucketServer ? DEFAULT_SERVER_BINDING : DEFAULT_CLOUD_BINDING
+ });
+ };
+
+ handleEdit = (definitionKey: string) => {
+ const editedDefinition = this.props.definitions.find(d => d.key === definitionKey);
+ const variant = isBitbucketBindingDefinition(editedDefinition)
+ ? AlmKeys.BitbucketServer
+ : AlmKeys.BitbucketCloud;
+ this.setState({ editedDefinition, variant, success: false });
+ };
+
+ handleSubmit = (
+ config: BitbucketBindingDefinition | BitbucketCloudBindingDefinition,
+ originalKey: string
+ ) => {
+ const call = originalKey
+ ? this.updateConfiguration({ newKey: config.key, ...config, key: originalKey })
+ : this.createConfiguration({ ...config });
+
+ this.setState({ submitting: true });
+ return call
+ .then(() => {
+ if (this.mounted) {
+ this.setState({
+ editedDefinition: undefined,
+ isCreating: false,
+ submitting: false,
+ success: true
+ });
+ }
+ })
+ .then(this.props.onUpdateDefinitions)
+ .then(() => {
+ this.props.onCheck(config.key);
+ })
+ .catch(() => {
+ if (this.mounted) {
+ this.setState({ submitting: false, success: false });
+ }
+ });
+ };
+
+ updateConfiguration = (
+ config: (BitbucketBindingDefinition | BitbucketCloudBindingDefinition) & { newKey: string }
+ ) => {
+ if (isBitbucketBindingDefinition(config)) {
+ return updateBitbucketConfiguration(config);
+ }
+ return updateBitbucketCloudConfiguration(config);
+ };
+
+ createConfiguration = (config: BitbucketBindingDefinition | BitbucketCloudBindingDefinition) => {
+ if (isBitbucketBindingDefinition(config)) {
+ return createBitbucketConfiguration(config);
+ }
+ return createBitbucketCloudConfiguration(config);
+ };
+
+ render() {
+ const {
+ branchesEnabled,
+ definitions,
+ definitionStatus,
+ loadingAlmDefinitions,
+ loadingProjectCount,
+ multipleAlmEnabled
+ } = this.props;
+ const { editedDefinition, isCreating, submitting, success, variant } = this.state;
+
+ return (
+ }
- help={
- <>
- {translate('onboarding.create_project.pat_help.title')}
-
-
- {translate('settings.almintegration.bitbucket.help_1')}
-
-
-
- {translate('settings.almintegration.bitbucket.help_2')}
- {translate('settings.almintegration.bitbucket.help_3')}
-
-
-
-
- {translate('learn_more')}
-
-
- >
- }
+ editedDefinition={editedDefinition}
+ isCreating={isCreating}
loadingAlmDefinitions={loadingAlmDefinitions}
loadingProjectCount={loadingProjectCount}
multipleAlmEnabled={multipleAlmEnabled}
- onCheck={props.onCheck}
- onDelete={props.onDelete}
- onUpdateDefinitions={props.onUpdateDefinitions}
- updateConfiguration={updateBitbucketConfiguration}
+ onCancel={this.handleCancel}
+ onCheck={this.props.onCheck}
+ onCreate={this.handleCreate}
+ onDelete={this.props.onDelete}
+ onEdit={this.handleEdit}
+ onSelectVariant={this.handleSelectVariant}
+ onSubmit={this.handleSubmit}
+ submitting={submitting}
+ success={success}
+ variant={variant}
/>
-
- );
+ );
+ }
}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketTabRenderer.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketTabRenderer.tsx
new file mode 100644
index 00000000000..e586f2b8d36
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketTabRenderer.tsx
@@ -0,0 +1,140 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { FormattedMessage } from 'react-intl';
+import { Link } from 'react-router';
+import { translate } from 'sonar-ui-common/helpers/l10n';
+import { ALM_DOCUMENTATION_PATHS } from '../../../../helpers/constants';
+import {
+ AlmKeys,
+ AlmSettingsBindingStatus,
+ BitbucketBindingDefinition,
+ BitbucketCloudBindingDefinition
+} from '../../../../types/alm-settings';
+import AlmTabRenderer from './AlmTabRenderer';
+import BitbucketForm from './BitbucketForm';
+
+export interface BitbucketTabRendererProps {
+ branchesEnabled: boolean;
+ definitionStatus: T.Dict;
+ editedDefinition?: BitbucketBindingDefinition | BitbucketCloudBindingDefinition;
+ definitions: Array;
+ isCreating: boolean;
+ loadingAlmDefinitions: boolean;
+ loadingProjectCount: boolean;
+ multipleAlmEnabled: boolean;
+ onCancel: () => void;
+ onCheck: (definitionKey: string) => void;
+ onCreate: () => void;
+ onDelete: (definitionKey: string) => void;
+ onEdit: (definitionKey: string) => void;
+ onSelectVariant: (variant: AlmKeys.BitbucketServer | AlmKeys.BitbucketCloud) => void;
+ onSubmit: (
+ config: BitbucketBindingDefinition | BitbucketCloudBindingDefinition,
+ originalKey: string
+ ) => void;
+ submitting: boolean;
+ success: boolean;
+ variant?: AlmKeys.BitbucketServer | AlmKeys.BitbucketCloud;
+}
+
+export default function BitbucketTabRenderer(props: BitbucketTabRendererProps) {
+ const {
+ branchesEnabled,
+ editedDefinition,
+ definitions,
+ definitionStatus,
+ isCreating,
+ loadingAlmDefinitions,
+ loadingProjectCount,
+ multipleAlmEnabled,
+ submitting,
+ success,
+ variant
+ } = props;
+
+ let help;
+ if (variant === AlmKeys.BitbucketServer) {
+ help = (
+ <>
+ {translate('onboarding.create_project.pat_help.title')}
+
+ {translate('settings.almintegration.bitbucket.help_1')}
+
+
+ {translate('settings.almintegration.bitbucket.help_2')}
+ {translate('settings.almintegration.bitbucket.help_3')}
+
+
+
+
+ {translate('learn_more')}
+
+
+ >
+ );
+ } else if (variant === AlmKeys.BitbucketCloud) {
+ help = (
+
+ {translate('learn_more')}
+
+ )
+ }}
+ />
+ );
+ }
+
+ return (
+
+
(
+
+ )}
+ help={help}
+ loadingAlmDefinitions={loadingAlmDefinitions}
+ loadingProjectCount={loadingProjectCount}
+ multipleAlmEnabled={multipleAlmEnabled}
+ onCancel={props.onCancel}
+ onCheck={props.onCheck}
+ onCreate={props.onCreate}
+ onDelete={props.onDelete}
+ onEdit={props.onEdit}
+ onSubmit={props.onSubmit}
+ submitting={submitting}
+ success={success}
+ />
+
+ );
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/GithubForm.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/GithubForm.tsx
index fe097ae0d60..87cb47d8652 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/GithubForm.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/GithubForm.tsx
@@ -74,7 +74,7 @@ export default function GithubForm(props: GithubFormProps) {
value={formData.appId}
/>
{
shallowRender({ alm: AlmKeys.Azure, definition: mockAzureBindingDefinition() })
).toMatchSnapshot('Azure DevOps');
+ expect(
+ shallowRender({
+ status: mockAlmSettingsBindingStatus({
+ type: AlmSettingsBindingStatusType.Success
+ }),
+ alm: AlmKeys.GitLab,
+ definition: mockGitlabBindingDefinition()
+ })
+ ).toMatchSnapshot('success for GitLab');
+
+ expect(
+ shallowRender({
+ status: mockAlmSettingsBindingStatus({
+ type: AlmSettingsBindingStatusType.Success
+ }),
+ alm: AlmKeys.BitbucketCloud,
+ definition: mockBitbucketCloudBindingDefinition()
+ })
+ ).toMatchSnapshot('success for Bitbucket Cloud');
+
expect(
shallowRender({
branchesEnabled: false,
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmIntegration-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmIntegration-test.tsx
index fe7e883bf6a..59d81720e26 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmIntegration-test.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmIntegration-test.tsx
@@ -35,7 +35,7 @@ jest.mock('../../../../../api/alm-settings', () => ({
deleteConfiguration: jest.fn().mockResolvedValue(undefined),
getAlmDefinitions: jest
.fn()
- .mockResolvedValue({ azure: [], bitbucket: [], github: [], gitlab: [] }),
+ .mockResolvedValue({ azure: [], bitbucket: [], bitbucketcloud: [], github: [], gitlab: [] }),
validateAlmSettings: jest.fn().mockResolvedValue('')
}));
@@ -50,7 +50,8 @@ it('should render correctly', () => {
it('should validate existing configurations', async () => {
(getAlmDefinitions as jest.Mock).mockResolvedValueOnce({
[AlmKeys.Azure]: [{ key: 'a1' }],
- [AlmKeys.Bitbucket]: [{ key: 'b1' }],
+ [AlmKeys.BitbucketServer]: [{ key: 'b1' }],
+ [AlmKeys.BitbucketCloud]: [{ key: 'bc1' }],
[AlmKeys.GitHub]: [{ key: 'gh1' }, { key: 'gh2' }],
[AlmKeys.GitLab]: [{ key: 'gl1' }]
});
@@ -59,9 +60,10 @@ it('should validate existing configurations', async () => {
await waitAndUpdate(wrapper);
- expect(validateAlmSettings).toBeCalledTimes(5);
+ expect(validateAlmSettings).toBeCalledTimes(6);
expect(validateAlmSettings).toBeCalledWith('a1');
expect(validateAlmSettings).toBeCalledWith('b1');
+ expect(validateAlmSettings).toBeCalledWith('bc1');
expect(validateAlmSettings).toBeCalledWith('gh1');
expect(validateAlmSettings).toBeCalledWith('gh2');
expect(validateAlmSettings).toBeCalledWith('gl1');
@@ -111,6 +113,7 @@ it('should validate a configuration', async () => {
(validateAlmSettings as jest.Mock)
.mockRejectedValueOnce(undefined)
.mockResolvedValueOnce(failureMessage)
+ .mockResolvedValueOnce('')
.mockResolvedValueOnce('');
await wrapper.instance().handleCheck(definitionKey);
@@ -141,7 +144,8 @@ it('should validate a configuration', async () => {
it('should fetch settings', async () => {
const definitions = {
[AlmKeys.Azure]: [{ key: 'a1' }],
- [AlmKeys.Bitbucket]: [{ key: 'b1' }],
+ [AlmKeys.BitbucketServer]: [{ key: 'b1' }],
+ [AlmKeys.BitbucketCloud]: [{ key: 'bc1' }],
[AlmKeys.GitHub]: [{ key: 'gh1' }],
[AlmKeys.GitLab]: [{ key: 'gl1' }]
};
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmIntegrationRenderer-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmIntegrationRenderer-test.tsx
index cc4a11a4942..6b33832d728 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmIntegrationRenderer-test.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmIntegrationRenderer-test.tsx
@@ -31,7 +31,8 @@ it('should render correctly', () => {
'delete modal'
);
expect(shallowRender({ currentAlm: AlmKeys.Azure })).toMatchSnapshot('azure');
- expect(shallowRender({ currentAlm: AlmKeys.Bitbucket })).toMatchSnapshot('bitbucket');
+ expect(shallowRender({ currentAlm: AlmKeys.BitbucketServer })).toMatchSnapshot('bitbucket');
+ expect(shallowRender({ currentAlm: AlmKeys.BitbucketCloud })).toMatchSnapshot('bitbucketcloud');
expect(shallowRender({ currentAlm: AlmKeys.GitLab })).toMatchSnapshot('gitlab');
});
@@ -40,7 +41,7 @@ function shallowRender(props: Partial = {}) {
{
defaultBinding: mockGithubBindingDefinition(),
definitions: [mockGithubBindingDefinition()]
};
- expect(shallowRender(githubProps)).toMatchSnapshot();
+ expect(shallowRender(githubProps)).toMatchSnapshot('default');
expect(shallowRender({ ...githubProps, definitions: [] })).toMatchSnapshot('empty');
expect(
@@ -77,6 +78,13 @@ it('should render correctly with validation', () => {
editedDefinition: mockGithubBindingDefinition()
})
).toMatchSnapshot('create a first');
+
+ expect(
+ shallowRender({
+ alm: AlmKeys.BitbucketServer, // BitbucketServer will be passed for both Bitbucket variants.
+ definitions: [mockBitbucketCloudBindingDefinition()]
+ })
+ ).toMatchSnapshot('pass the correct key for bitbucket cloud');
});
function shallowRenderAzure(props: Partial> = {}) {
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/BitbucketForm-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/BitbucketForm-test.tsx
index 8c758f307b9..daa8f83f497 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/BitbucketForm-test.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/BitbucketForm-test.tsx
@@ -19,19 +19,41 @@
*/
import { shallow } from 'enzyme';
import * as React from 'react';
-import { mockBitbucketBindingDefinition } from '../../../../../helpers/mocks/alm-settings';
+import {
+ mockBitbucketBindingDefinition,
+ mockBitbucketCloudBindingDefinition
+} from '../../../../../helpers/mocks/alm-settings';
+import { AlmKeys } from '../../../../../types/alm-settings';
import BitbucketForm, { BitbucketFormProps } from '../BitbucketForm';
it('should render correctly', () => {
- expect(shallowRender()).toMatchSnapshot();
- expect(shallowRender({ formData: mockBitbucketBindingDefinition() })).toMatchSnapshot();
+ expect(shallowRender({ isCreating: true })).toMatchSnapshot('variant select');
+ expect(shallowRender()).toMatchSnapshot('bitbucket server, empty');
+ expect(shallowRender({ formData: mockBitbucketBindingDefinition() })).toMatchSnapshot(
+ 'bitbucket server, edit'
+ );
+ expect(
+ shallowRender({
+ formData: { key: '', clientId: '', clientSecret: '', workspace: '' },
+ variant: AlmKeys.BitbucketCloud
+ })
+ ).toMatchSnapshot('bitbucket cloud, empty');
+ expect(
+ shallowRender({
+ variant: AlmKeys.BitbucketCloud,
+ formData: mockBitbucketCloudBindingDefinition()
+ })
+ ).toMatchSnapshot('bitbucket cloud, edit');
});
function shallowRender(props: Partial = {}) {
return shallow(
);
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/BitbucketTab-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/BitbucketTab-test.tsx
index 28551069145..5a95099ac5f 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/BitbucketTab-test.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/BitbucketTab-test.tsx
@@ -19,15 +19,123 @@
*/
import { shallow } from 'enzyme';
import * as React from 'react';
-import { mockBitbucketBindingDefinition } from '../../../../../helpers/mocks/alm-settings';
-import BitbucketTab, { BitbucketTabProps } from '../BitbucketTab';
+import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
+import {
+ createBitbucketCloudConfiguration,
+ createBitbucketConfiguration,
+ updateBitbucketCloudConfiguration,
+ updateBitbucketConfiguration
+} from '../../../../../api/alm-settings';
+import {
+ mockBitbucketBindingDefinition,
+ mockBitbucketCloudBindingDefinition
+} from '../../../../../helpers/mocks/alm-settings';
+import { AlmKeys } from '../../../../../types/alm-settings';
+import BitbucketTab, { DEFAULT_CLOUD_BINDING, DEFAULT_SERVER_BINDING } from '../BitbucketTab';
+
+jest.mock('../../../../../api/alm-settings', () => ({
+ createBitbucketConfiguration: jest.fn().mockResolvedValue(null),
+ createBitbucketCloudConfiguration: jest.fn().mockResolvedValue(null),
+ updateBitbucketConfiguration: jest.fn().mockResolvedValue(null),
+ updateBitbucketCloudConfiguration: jest.fn().mockResolvedValue(null)
+}));
it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot();
});
-function shallowRender(props: Partial = {}) {
- return shallow(
+it('should handle cancel', async () => {
+ const wrapper = shallowRender();
+
+ wrapper.setState({
+ editedDefinition: mockBitbucketBindingDefinition()
+ });
+
+ wrapper.instance().handleCancel();
+
+ await waitAndUpdate(wrapper);
+
+ expect(wrapper.state().editedDefinition).toBeUndefined();
+});
+
+it('should handle edit', async () => {
+ const config = mockBitbucketBindingDefinition();
+ const wrapper = shallowRender({ definitions: [config] });
+ wrapper.instance().handleEdit(config.key);
+ await waitAndUpdate(wrapper);
+ expect(wrapper.state().editedDefinition).toEqual(config);
+});
+
+it('should create config for Bitbucket Server', async () => {
+ const onUpdateDefinitions = jest.fn();
+ const config = mockBitbucketBindingDefinition();
+ const wrapper = shallowRender({ onUpdateDefinitions });
+
+ wrapper.instance().handleCreate();
+ wrapper.instance().handleSelectVariant(AlmKeys.BitbucketServer);
+ expect(wrapper.state().editedDefinition).toBe(DEFAULT_SERVER_BINDING);
+
+ wrapper.setState({ editedDefinition: config });
+ await wrapper.instance().handleSubmit(config, '');
+
+ expect(createBitbucketConfiguration).toBeCalledWith(config);
+ expect(onUpdateDefinitions).toBeCalled();
+ expect(wrapper.state().editedDefinition).toBeUndefined();
+});
+
+it('should create config for Bitbucket Cloud', async () => {
+ const onUpdateDefinitions = jest.fn();
+ const config = mockBitbucketCloudBindingDefinition();
+ const wrapper = shallowRender({ onUpdateDefinitions });
+
+ wrapper.instance().handleCreate();
+ wrapper.instance().handleSelectVariant(AlmKeys.BitbucketCloud);
+ expect(wrapper.state().editedDefinition).toBe(DEFAULT_CLOUD_BINDING);
+
+ wrapper.setState({ editedDefinition: config });
+ await wrapper.instance().handleSubmit(config, '');
+
+ expect(createBitbucketCloudConfiguration).toBeCalledWith(config);
+ expect(onUpdateDefinitions).toBeCalled();
+ expect(wrapper.state().editedDefinition).toBeUndefined();
+});
+
+it('should update config for Bitbucket Server', async () => {
+ const onUpdateDefinitions = jest.fn();
+ const config = mockBitbucketBindingDefinition();
+ const wrapper = shallowRender({ onUpdateDefinitions });
+ wrapper.setState({ editedDefinition: config });
+
+ await wrapper.instance().handleSubmit(config, 'originalKey');
+
+ expect(updateBitbucketConfiguration).toBeCalledWith({
+ newKey: 'key',
+ ...config,
+ key: 'originalKey'
+ });
+ expect(onUpdateDefinitions).toBeCalled();
+ expect(wrapper.state().editedDefinition).toBeUndefined();
+});
+
+it('should update config for Bitbucket Cloud', async () => {
+ const onUpdateDefinitions = jest.fn();
+ const config = mockBitbucketCloudBindingDefinition();
+ const wrapper = shallowRender({ onUpdateDefinitions });
+ wrapper.setState({ editedDefinition: config });
+
+ await wrapper.instance().handleSubmit(config, 'originalKey');
+
+ expect(updateBitbucketCloudConfiguration).toBeCalledWith({
+ newKey: 'key',
+ ...config,
+ key: 'originalKey'
+ });
+ expect(onUpdateDefinitions).toBeCalled();
+ expect(wrapper.state().editedDefinition).toBeUndefined();
+});
+
+function shallowRender(props: Partial = {}) {
+ return shallow(
{
+ expect(shallowRender()).toMatchSnapshot('default');
+ expect(shallowRender({ variant: AlmKeys.BitbucketServer })).toMatchSnapshot('bitbucket server');
+ expect(shallowRender({ variant: AlmKeys.BitbucketCloud })).toMatchSnapshot('bitbucket cloud');
+
+ const almTab = shallowRender().find>(
+ AlmTabRenderer
+ );
+ expect(
+ almTab.props().form({ formData: mockBitbucketBindingDefinition(), onFieldChange: jest.fn() })
+ ).toMatchSnapshot('bitbucket form');
+});
+
+function shallowRender(props: Partial = {}) {
+ return shallow(
+
+ );
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionBox-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionBox-test.tsx.snap
index 07cd7a44076..4fce50260a7 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionBox-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionBox-test.tsx.snap
@@ -283,6 +283,152 @@ exports[`should render correctly: success 1`] = `
`;
+exports[`should render correctly: success for Bitbucket Cloud 1`] = `
+
+
+
+
+ edit
+
+
+
+ delete
+
+
+
+
+ key
+
+
+
+
+
+
+ settings.almintegration.feature.pr_decoration.title
+
+
+
+
+
+
+
+ settings.almintegration.check_configuration
+
+
+`;
+
+exports[`should render correctly: success for GitLab 1`] = `
+
+
+
+
+ edit
+
+
+
+ delete
+
+
+
+
+ foo
+
+
+
+
+
+
+ settings.almintegration.feature.mr_decoration.title
+
+
+
+
+
+
+
+ settings.almintegration.feature.alm_repo_import.title
+
+
+
+
+ settings.almintegration.feature.alm_repo_import.disabled
+
+
+
+
+
+
+
+ settings.almintegration.check_configuration
+
+
+`;
+
exports[`should render correctly: success with alert 1`] = `
+
+
- Bitbucket Server
+ Bitbucket
,
"requiresBranchesEnabled": false,
},
@@ -133,7 +133,7 @@ exports[`should render correctly: bitbucket 1`] = `
height={16}
src="/images/alm/bitbucket.svg"
/>
- Bitbucket Server
+ Bitbucket
,
"requiresBranchesEnabled": false,
},
@@ -180,6 +180,85 @@ exports[`should render correctly: bitbucket 1`] = `
`;
+exports[`should render correctly: bitbucketcloud 1`] = `
+
+
+
+ settings.almintegration.title
+
+
+
+ settings.almintegration.description
+
+
+
+ GitHub
+ ,
+ "requiresBranchesEnabled": false,
+ },
+ Object {
+ "key": "bitbucket",
+ "label":
+
+ Bitbucket
+ ,
+ "requiresBranchesEnabled": false,
+ },
+ Object {
+ "key": "azure",
+ "label":
+
+ Azure DevOps
+ ,
+ "requiresBranchesEnabled": false,
+ },
+ Object {
+ "key": "gitlab",
+ "label":
+
+ GitLab
+ ,
+ "requiresBranchesEnabled": false,
+ },
+ ]
+ }
+ />
+
+`;
+
exports[`should render correctly: default 1`] = `
- Bitbucket Server
+ Bitbucket
,
"requiresBranchesEnabled": false,
},
@@ -313,7 +392,7 @@ exports[`should render correctly: delete modal 1`] = `
height={16}
src="/images/alm/bitbucket.svg"
/>
- Bitbucket Server
+ Bitbucket
,
"requiresBranchesEnabled": false,
},
@@ -408,7 +487,7 @@ exports[`should render correctly: gitlab 1`] = `
height={16}
src="/images/alm/bitbucket.svg"
/>
- Bitbucket Server
+ Bitbucket
,
"requiresBranchesEnabled": false,
},
@@ -498,7 +577,7 @@ exports[`should render correctly: loading 1`] = `
height={16}
src="/images/alm/bitbucket.svg"
/>
- Bitbucket Server
+ Bitbucket
,
"requiresBranchesEnabled": false,
},
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmTab-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmTab-test.tsx.snap
index 76720ff1334..9822401deaf 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmTab-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmTab-test.tsx.snap
@@ -4,13 +4,6 @@ exports[`should render correctly 1`] = `
`;
-exports[`should render correctly with validation 1`] = `
+exports[`should render correctly with validation: create a first 1`] = `
+
+ settings.almintegration.empty.github
+
-
+ help={
}
+ isSecondInstance={false}
+ onCancel={[MockFunction]}
+ onSubmit={[MockFunction]}
+ >
+
+
`;
-exports[`should render correctly with validation: create a first 1`] = `
+exports[`should render correctly with validation: create a second 1`] = `
-
- settings.almintegration.empty.github
-
+
}
- isSecondInstance={false}
+ isSecondInstance={true}
onCancel={[MockFunction]}
onSubmit={[MockFunction]}
>
@@ -446,7 +464,7 @@ exports[`should render correctly with validation: create a first 1`] = `
`;
-exports[`should render correctly with validation: create a second 1`] = `
+exports[`should render correctly with validation: default 1`] = `
@@ -488,24 +506,6 @@ exports[`should render correctly with validation: create a second 1`] = `
onDelete={[MockFunction]}
onEdit={[MockFunction]}
/>
-
}
- isSecondInstance={true}
- onCancel={[MockFunction]}
- onSubmit={[MockFunction]}
- >
-
-
`;
@@ -541,3 +541,47 @@ exports[`should render correctly with validation: empty 1`] = `
`;
+
+exports[`should render correctly with validation: pass the correct key for bitbucket cloud 1`] = `
+
+
+
+
+
+ settings.almintegration.create
+
+
+
+
+
+
+`;
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketForm-test.tsx.snap
index e19b6f4af80..be3c262eca1 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketForm-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketForm-test.tsx.snap
@@ -1,81 +1,255 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`should render correctly 1`] = `
-
-
-
+
+
+
+ https://bitbucket.org/
+
+ {workspace}
+
+ /{repository}
+ ,
+ }
}
- }
- />
- }
- id="url.bitbucket"
- maxLength={2000}
- onFieldChange={[MockFunction]}
- propKey="url"
- value=""
- />
-
-
+ />
+ }
+ id="workspace.bitbucketcloud"
+ maxLength={2000}
+ onFieldChange={[MockFunction]}
+ propKey="workspace"
+ value="workspace"
+ />
+
+
+
+
`;
-exports[`should render correctly 2`] = `
-
-
-
+
+
+
+ https://bitbucket.org/
+
+ {workspace}
+
+ /{repository}
+ ,
+ }
+ }
+ />
+ }
+ id="workspace.bitbucketcloud"
+ maxLength={2000}
+ onFieldChange={[MockFunction]}
+ propKey="workspace"
+ value=""
+ />
+
+
+
+
+`;
+
+exports[`should render correctly: bitbucket server, edit 1`] = `
+
+
+
+
+ />
+ }
+ id="url.bitbucket"
+ maxLength={2000}
+ onFieldChange={[MockFunction]}
+ propKey="url"
+ value="http://bbs.enterprise.com"
+ />
+
+
+
+`;
+
+exports[`should render correctly: bitbucket server, empty 1`] = `
+
+
+
+
+ }
+ id="url.bitbucket"
+ maxLength={2000}
+ onFieldChange={[MockFunction]}
+ propKey="url"
+ value=""
+ />
+
+
+
+`;
+
+exports[`should render correctly: variant select 1`] = `
+
+
+ settings.almintegration.form.choose_bitbucket_variant
+
+
-
-
+
+
+
+ }
+ id="url.bitbucket"
+ maxLength={2000}
+ onFieldChange={[MockFunction]}
+ propKey="url"
+ value=""
+ />
+
+
+
`;
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketTab-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketTab-test.tsx.snap
index e7b2a23b1da..8100d78442d 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketTab-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketTab-test.tsx.snap
@@ -1,72 +1,30 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should render correctly 1`] = `
-
-
-
- onboarding.create_project.pat_help.title
-
-
- settings.almintegration.bitbucket.help_1
-
-
-
- settings.almintegration.bitbucket.help_2
-
-
- settings.almintegration.bitbucket.help_3
-
-
-
-
- learn_more
-
-
-
- }
- loadingAlmDefinitions={false}
- loadingProjectCount={false}
- multipleAlmEnabled={true}
- onCheck={[MockFunction]}
- onDelete={[MockFunction]}
- onUpdateDefinitions={[MockFunction]}
- updateConfiguration={[Function]}
- />
-
+ "key": "key",
+ "personalAccessToken": "asdf1234",
+ "url": "http://bbs.enterprise.com",
+ },
+ ]
+ }
+ isCreating={false}
+ loadingAlmDefinitions={false}
+ loadingProjectCount={false}
+ multipleAlmEnabled={true}
+ onCancel={[Function]}
+ onCheck={[MockFunction]}
+ onCreate={[Function]}
+ onDelete={[MockFunction]}
+ onEdit={[Function]}
+ onSelectVariant={[Function]}
+ onSubmit={[Function]}
+ submitting={false}
+ success={false}
+/>
`;
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketTabRenderer-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketTabRenderer-test.tsx.snap
new file mode 100644
index 00000000000..e742c9c3f31
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketTabRenderer-test.tsx.snap
@@ -0,0 +1,143 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly: bitbucket cloud 1`] = `
+
+
+ learn_more
+ ,
+ }
+ }
+ />
+ }
+ loadingAlmDefinitions={false}
+ loadingProjectCount={false}
+ multipleAlmEnabled={true}
+ onCancel={[MockFunction]}
+ onCheck={[MockFunction]}
+ onCreate={[MockFunction]}
+ onDelete={[MockFunction]}
+ onEdit={[MockFunction]}
+ onSubmit={[MockFunction]}
+ submitting={true}
+ success={false}
+ />
+
+`;
+
+exports[`should render correctly: bitbucket form 1`] = `
+
+`;
+
+exports[`should render correctly: bitbucket server 1`] = `
+
+
+
+ onboarding.create_project.pat_help.title
+
+
+ settings.almintegration.bitbucket.help_1
+
+
+
+ settings.almintegration.bitbucket.help_2
+
+
+ settings.almintegration.bitbucket.help_3
+
+
+
+
+ learn_more
+
+
+
+ }
+ loadingAlmDefinitions={false}
+ loadingProjectCount={false}
+ multipleAlmEnabled={true}
+ onCancel={[MockFunction]}
+ onCheck={[MockFunction]}
+ onCreate={[MockFunction]}
+ onDelete={[MockFunction]}
+ onEdit={[MockFunction]}
+ onSubmit={[MockFunction]}
+ submitting={true}
+ success={false}
+ />
+
+`;
+
+exports[`should render correctly: default 1`] = `
+
+`;
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GithubForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GithubForm-test.tsx.snap
index 6ae40e3ac21..79359f8817a 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GithubForm-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GithubForm-test.tsx.snap
@@ -41,14 +41,14 @@ exports[`should render correctly 1`] = `
value=""
/>
);
- case AlmKeys.Bitbucket:
+ case AlmKeys.BitbucketServer:
return (
<>
{renderField({
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 3d9a226923e..4f4d34a1564 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
@@ -65,7 +65,8 @@ const REQUIRED_FIELDS_BY_ALM: {
[almKey in AlmKeys]: Array>;
} = {
[AlmKeys.Azure]: ['repository', 'slug'],
- [AlmKeys.Bitbucket]: ['repository', 'slug'],
+ [AlmKeys.BitbucketServer]: ['repository', 'slug'],
+ [AlmKeys.BitbucketCloud]: ['repository'],
[AlmKeys.GitHub]: ['repository'],
[AlmKeys.GitLab]: ['repository']
};
@@ -180,7 +181,7 @@ export class PRDecorationBinding extends React.PureComponent {
const instances: AlmSettingsInstance[] = [
{ key: 'github', alm: AlmKeys.GitHub },
{ key: 'azure', alm: AlmKeys.Azure },
- { key: 'bitbucket', alm: AlmKeys.Bitbucket },
+ { key: 'bitbucket', alm: AlmKeys.BitbucketServer },
{ key: 'gitlab', alm: AlmKeys.GitLab }
];
@@ -263,9 +263,9 @@ it.each([
[AlmKeys.Azure, {}],
[AlmKeys.Azure, { slug: 'test' }],
[AlmKeys.Azure, { repository: 'test' }],
- [AlmKeys.Bitbucket, {}],
- [AlmKeys.Bitbucket, { slug: 'test' }],
- [AlmKeys.Bitbucket, { repository: 'test' }],
+ [AlmKeys.BitbucketServer, {}],
+ [AlmKeys.BitbucketServer, { slug: 'test' }],
+ [AlmKeys.BitbucketServer, { repository: 'test' }],
[AlmKeys.GitHub, {}],
[AlmKeys.GitLab, {}]
])('should properly reject promise for %s & %s', async (almKey: AlmKeys, params: {}) => {
@@ -289,7 +289,7 @@ it('should validate form', async () => {
wrapper.setState({
instances: [
{ key: 'azure', alm: AlmKeys.Azure },
- { key: 'bitbucket', alm: AlmKeys.Bitbucket },
+ { key: 'bitbucket', alm: AlmKeys.BitbucketServer },
{ key: 'github', alm: AlmKeys.GitHub },
{ key: 'gitlab', alm: AlmKeys.GitLab }
]
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/PRDecorationBindingRenderer-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/PRDecorationBindingRenderer-test.tsx
index 9bb9c158a99..b0520110cf0 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/PRDecorationBindingRenderer-test.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/PRDecorationBindingRenderer-test.tsx
@@ -59,7 +59,7 @@ it('should render multiple instances correctly', () => {
url: urls[0]
},
{
- alm: AlmKeys.Bitbucket,
+ alm: AlmKeys.BitbucketServer,
key: 'i3',
url: urls[1]
},
diff --git a/server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx b/server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx
index 3c4cc3ac579..40674894fd5 100644
--- a/server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx
+++ b/server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx
@@ -45,7 +45,7 @@ export default function TutorialSelectionRenderer(props: TutorialSelectionRender
}
const jenkinsAvailable =
- projectBinding && [AlmKeys.Bitbucket, AlmKeys.GitHub].includes(projectBinding.alm);
+ projectBinding && [AlmKeys.BitbucketServer, AlmKeys.GitHub].includes(projectBinding.alm);
return (
<>
diff --git a/server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelection-test.tsx b/server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelection-test.tsx
index 5c593a74ac8..76b4dbe9d79 100644
--- a/server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelection-test.tsx
+++ b/server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelection-test.tsx
@@ -50,7 +50,7 @@ it('should select manual if project is not bound', async () => {
});
it('should not select anything if project is bound', async () => {
- (getProjectAlmBinding as jest.Mock).mockResolvedValueOnce({ alm: AlmKeys.Bitbucket });
+ (getProjectAlmBinding as jest.Mock).mockResolvedValueOnce({ alm: AlmKeys.BitbucketServer });
const wrapper = shallowRender();
await waitAndUpdate(wrapper);
expect(wrapper.state().forceManual).toBe(false);
@@ -59,9 +59,9 @@ it('should not select anything if project is bound', async () => {
it('should correctly find the global ALM binding definition', async () => {
const key = 'foo';
const almBinding = mockBitbucketBindingDefinition({ key });
- (getProjectAlmBinding as jest.Mock).mockResolvedValueOnce({ alm: AlmKeys.Bitbucket, key });
+ (getProjectAlmBinding as jest.Mock).mockResolvedValueOnce({ alm: AlmKeys.BitbucketServer, key });
(getAlmDefinitionsNoCatch as jest.Mock).mockResolvedValueOnce({
- [AlmKeys.Bitbucket]: [almBinding]
+ [AlmKeys.BitbucketServer]: [almBinding]
});
const wrapper = shallowRender();
await waitAndUpdate(wrapper);
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStep.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStep.tsx
index a3373234346..2349c1f90e8 100644
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStep.tsx
+++ b/server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStep.tsx
@@ -46,7 +46,7 @@ function renderAlmSpecificInstructions(props: WebhookStepProps) {
const { almBinding, branchesEnabled, projectBinding } = props;
switch (projectBinding.alm) {
- case AlmKeys.Bitbucket:
+ case AlmKeys.BitbucketServer:
return (
{
function shallowRender(props: Partial = {}) {
return shallow(
= {}
+): BitbucketCloudBindingDefinition {
+ return {
+ key: 'key',
+ clientId: 'client1',
+ clientSecret: '**clientsecret**',
+ workspace: 'workspace',
+ ...overrides
+ };
+}
+
export function mockGithubBindingDefinition(
overrides: Partial = {}
): GithubBindingDefinition {
@@ -102,7 +115,7 @@ export function mockProjectBitbucketBindingResponse(
overrides: Partial = {}
): ProjectBitbucketBindingResponse {
return {
- alm: AlmKeys.Bitbucket,
+ alm: AlmKeys.BitbucketServer,
key: 'foo',
repository: 'PROJECT_KEY',
slug: 'repo-slug',
diff --git a/server/sonar-web/src/main/js/types/alm-settings.ts b/server/sonar-web/src/main/js/types/alm-settings.ts
index ce3c5a0cb90..0e81f6d70a3 100644
--- a/server/sonar-web/src/main/js/types/alm-settings.ts
+++ b/server/sonar-web/src/main/js/types/alm-settings.ts
@@ -19,7 +19,8 @@
*/
export const enum AlmKeys {
Azure = 'azure',
- Bitbucket = 'bitbucket',
+ BitbucketServer = 'bitbucket',
+ BitbucketCloud = 'bitbucketcloud',
GitHub = 'github',
GitLab = 'gitlab'
}
@@ -39,6 +40,12 @@ export interface BitbucketBindingDefinition extends AlmBindingDefinition {
url: string;
}
+export interface BitbucketCloudBindingDefinition extends AlmBindingDefinition {
+ clientId: string;
+ clientSecret: string;
+ workspace: string;
+}
+
export interface GithubBindingDefinition extends AlmBindingDefinition {
appId: string;
clientId: string;
@@ -70,7 +77,7 @@ export interface ProjectAzureBindingResponse extends ProjectAlmBindingResponse {
}
export interface ProjectBitbucketBindingResponse extends ProjectAlmBindingResponse {
- alm: AlmKeys.Bitbucket;
+ alm: AlmKeys.BitbucketServer;
repository: string;
slug: string;
monorepo: boolean;
@@ -125,7 +132,8 @@ export interface AlmSettingsInstance {
export interface AlmSettingsBindingDefinitions {
[AlmKeys.Azure]: AzureBindingDefinition[];
- [AlmKeys.Bitbucket]: BitbucketBindingDefinition[];
+ [AlmKeys.BitbucketServer]: BitbucketBindingDefinition[];
+ [AlmKeys.BitbucketCloud]: BitbucketCloudBindingDefinition[];
[AlmKeys.GitHub]: GithubBindingDefinition[];
[AlmKeys.GitLab]: GitlabBindingDefinition[];
}
@@ -146,7 +154,7 @@ export enum AlmSettingsBindingStatusType {
export function isProjectBitbucketBindingResponse(
binding: ProjectAlmBindingResponse
): binding is ProjectBitbucketBindingResponse {
- return binding.alm === AlmKeys.Bitbucket;
+ return binding.alm === AlmKeys.BitbucketServer;
}
export function isProjectGitHubBindingResponse(
@@ -168,20 +176,19 @@ export function isProjectAzureBindingResponse(
}
export function isBitbucketBindingDefinition(
- binding?: AlmBindingDefinition & { url?: string; personalAccessToken?: string }
+ binding?: AlmBindingDefinition & { url?: string }
): binding is BitbucketBindingDefinition {
- return (
- binding !== undefined && binding.url !== undefined && binding.personalAccessToken !== undefined
- );
+ return binding !== undefined && binding.url !== undefined;
+}
+
+export function isBitbucketCloudBindingDefinition(
+ binding?: AlmBindingDefinition & { clientId?: string; workspace?: string }
+): binding is BitbucketCloudBindingDefinition {
+ return binding !== undefined && binding.clientId !== undefined && binding.workspace !== undefined;
}
export function isGithubBindingDefinition(
- binding?: AlmBindingDefinition & { appId?: string; privateKey?: string; url?: string }
+ binding?: AlmBindingDefinition & { appId?: string; url?: string }
): binding is GithubBindingDefinition {
- return (
- binding !== undefined &&
- binding.appId !== undefined &&
- binding.privateKey !== undefined &&
- binding.url !== undefined
- );
+ return binding !== undefined && binding.appId !== undefined && binding.url !== undefined;
}
diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
index 3aff37f6d0a..779baa23258 100644
--- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties
+++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
@@ -361,10 +361,10 @@ Sa=Sa
alm.azure=Azure DevOps
alm.azure.short=Azure DevOps
-alm.bitbucket=Bitbucket Server
+alm.bitbucket=Bitbucket
alm.bitbucket.short=Bitbucket
-alm.github=Github
-alm.github.short=Github
+alm.github=GitHub
+alm.github.short=GitHub
alm.gitlab=GitLab
alm.gitlab.short=GitLab
@@ -1075,8 +1075,10 @@ settings.almintegration.gitlab.info=Accounts that will be used to decorate Merge
settings.almintegration.bitbucket.help_1=SonarQube needs a Personal Access Token to communicate with Bitbucket Server. This token will be used to decorate Pull Requests.
settings.almintegration.bitbucket.help_2=The account used for integration needs write permission.
settings.almintegration.bitbucket.help_3=We recommend to integrate with SonarQube using a Bitbucket Server Service Account.
+settings.almintegration.bitbucketcloud.info=You need to create an OAuth consumer in your Bitbucket Cloud workspace settings to decorate your Pull Requests. It needs to be a private consumer with Pull requests: Read permission. Bitbucket requires an OAuth callback URL, but it's not used by SonarQube so any URL works. {link}
settings.almintegration.empty.azure=Create your first Azure DevOps configuration to start analyzing your repositories on SonarQube.
settings.almintegration.empty.bitbucket=Create your first Bitbucket configuration to start analyzing your repositories on SonarQube.
+settings.almintegration.empty.bitbucketcloud=Create your first Bitbucket Cloud configuration to start analyzing your repositories on SonarQube.
settings.almintegration.empty.github=Create your first GitHub configuration to start analyzing your repositories on SonarQube.
settings.almintegration.empty.gitlab=Create your first GitLab configuration to start analyzing your repositories on SonarQube.
settings.almintegration.create=Create configuration
@@ -1095,12 +1097,17 @@ settings.almintegration.form.header.edit=Edit the configuration
settings.almintegration.form.second_instance_warning=Binding more than one instance of an ALM will deactivate the import of repositories from that ALM.
settings.almintegration.form.name.azure=Configuration name
settings.almintegration.form.name.azure.help=Give your configuration a clear and succinct name. This name will be used at project level to identify the correct configured Azure instance for a project.
+settings.almintegration.form.choose_bitbucket_variant=Select which variant you want to configure
settings.almintegration.form.name.bitbucket=Configuration name
settings.almintegration.form.name.bitbucket.help=Give your configuration a clear and succinct name. This name will be used at project level to identify the correct configured Bitbucket instance for a project.
+settings.almintegration.form.name.bitbucketcloud=Configuration name
+settings.almintegration.form.name.bitbucketcloud.help=Give your configuration a clear and succinct name. This name will be used at project level to identify the correct configured Bitbucket Cloud instance for a project.
settings.almintegration.form.name.github=Configuration name
settings.almintegration.form.name.github.help=Give your configuration a clear and succinct name. This name will be used at project level to identify the correct configured GitHub App for a project.
settings.almintegration.form.name.gitlab=Configuration name
settings.almintegration.form.name.gitlab.help=Give your configuration a clear and succinct name. This name will be used at project level to identify the correct configured GitLab instance for a project.
+settings.almintegration.form.workspace.bitbucketcloud=Workspace ID
+settings.almintegration.form.workspace.bitbucketcloud.help=The Workspace ID
settings.almintegration.form.url.azure=Azure DevOps URL
settings.almintegration.form.url.azure.help1=For Azure DevOps Server, provide the full collection URL:
settings.almintegration.form.url.azure.help2=For Azure DevOps Services, provide the full organization URL:
@@ -1112,8 +1119,10 @@ settings.almintegration.form.url.github.help2=If using GitHub.com:
settings.almintegration.form.url.gitlab=GitLab API URL
settings.almintegration.form.url.gitlab.help=Provide the GitLab API URL. For example:
settings.almintegration.form.app_id=GitHub App ID
-settings.almintegration.form.client_id=GitHub Client ID
-settings.almintegration.form.client_secret=GitHub Client Secret
+settings.almintegration.form.client_id.github=Client ID
+settings.almintegration.form.client_secret.github=Client Secret
+settings.almintegration.form.client_id.bitbucketcloud=OAuth Key
+settings.almintegration.form.client_secret.bitbucketcloud=OAuth Secret
settings.almintegration.form.private_key=Private Key
settings.almintegration.form.personal_access_token=Personal Access token
settings.almintegration.form.personal_access_token.azure.help=Token of the user that will be used to decorate the Pull Requests. Needs authorized scope: "Code (read and write)".