AzureBindingDefinition,
AzureProjectAlmBindingParams,
BitbucketBindingDefinition,
+ BitbucketCloudBindingDefinition,
BitbucketProjectAlmBindingParams,
GithubBindingDefinition,
GithubProjectAlmBindingParams,
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);
}
{loading && <i className="spinner" />}
{!loading && !bitbucketSetting && (
- <WrongBindingCountAlert alm={AlmKeys.Bitbucket} canAdmin={!!canAdmin} />
+ <WrongBindingCountAlert alm={AlmKeys.BitbucketServer} canAdmin={!!canAdmin} />
)}
{!loading &&
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<T.AppState, 'canAdmin'>;
loadingBindings: boolean;
onSelectMode: (mode: CreateProjectModes) => void;
function renderAlmOption(
props: CreateProjectModeSelectionProps,
- alm: AlmKeys,
+ alm: AlmKeys.Azure | AlmKeys.BitbucketServer | AlmKeys.GitHub | AlmKeys.GitLab,
mode: CreateProjectModes
) {
const {
</button>
{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)}
</div>
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
default: {
const almCounts = {
[AlmKeys.Azure]: azureSettings.length,
- [AlmKeys.Bitbucket]: bitbucketSettings.length,
+ [AlmKeys.BitbucketServer]: bitbucketSettings.length,
[AlmKeys.GitHub]: githubSettings.length,
[AlmKeys.GitLab]: gitlabSettings.length
};
}
function getPatUrl(alm: AlmKeys, url: string) {
- if (alm === AlmKeys.Bitbucket) {
+ if (alm === AlmKeys.BitbucketServer) {
return `${url.replace(/\/$/, '')}/plugins/servlet/access-tokens/add`;
} else {
// GitLab
</p>
<ul>
- {alm === AlmKeys.Bitbucket && (
+ {alm === AlmKeys.BitbucketServer && (
<>
<li>
<FormattedMessage
return shallow<BitbucketProjectCreate>(
<BitbucketProjectCreate
canAdmin={false}
- bitbucketSettings={[mockAlmSettingsInstance({ alm: AlmKeys.Bitbucket, key: 'foo' })]}
+ bitbucketSettings={[mockAlmSettingsInstance({ alm: AlmKeys.BitbucketServer, key: 'foo' })]}
loadingBindings={false}
location={mockLocation()}
onProjectCreate={jest.fn()}
function shallowRender(props: Partial<BitbucketProjectCreateRendererProps> = {}) {
return shallow<BitbucketProjectCreateRendererProps>(
<BitbucketProjectCreateRenderer
- bitbucketSetting={mockAlmSettingsInstance({ alm: AlmKeys.Bitbucket })}
+ bitbucketSetting={mockAlmSettingsInstance({ alm: AlmKeys.BitbucketServer })}
importing={false}
loading={false}
onImportRepository={jest.fn()}
it('should render correctly', () => {
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');
});
) {
const almCounts = {
[AlmKeys.Azure]: 0,
- [AlmKeys.Bitbucket]: 1,
+ [AlmKeys.BitbucketServer]: 1,
[AlmKeys.GitHub]: 0,
[AlmKeys.GitLab]: 0,
...almCountOverrides
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);
return shallow<PersonalAccessTokenFormProps>(
<PersonalAccessTokenForm
almSetting={mockAlmSettingsInstance({
- alm: AlmKeys.Bitbucket,
+ alm: AlmKeys.BitbucketServer,
url: 'http://www.example.com'
})}
onPersonalAccessTokenCreate={jest.fn()}
it('should render correctly', () => {
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<WrongBindingCountAlertProps> = {}) {
- return shallow(<WrongBindingCountAlert alm={AlmKeys.Bitbucket} canAdmin={false} {...props} />);
+ return shallow(
+ <WrongBindingCountAlert alm={AlmKeys.BitbucketServer} canAdmin={false} {...props} />
+ );
}
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';
}
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
};
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' }
]);
});
function shallowRender(overrides: Partial<ProjectCreationMenuItemProps> = {}) {
- return shallow(<ProjectCreationMenuItem alm={AlmKeys.Bitbucket} {...overrides} />);
+ return shallow(<ProjectCreationMenuItem alm={AlmKeys.BitbucketServer} {...overrides} />);
}
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,
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');
{status.type !== AlmSettingsBindingStatusType.Warning && (
<div className="display-flex-row spacer-bottom">
<div className="huge-spacer-right">
- <Tooltip overlay={importFeatureDescription}>
- <span>{importFeatureTitle}</span>
+ <Tooltip overlay={prDecoFeatureDescription}>
+ <span>{prDecoFeatureTitle}</span>
</Tooltip>
{getPRDecorationFeatureStatus(branchesEnabled, status.type)}
</div>
- <div>
- <Tooltip
- overlay={translate(
- 'settings.almintegration.feature.alm_repo_import.description'
- )}>
- <span>{translate('settings.almintegration.feature.alm_repo_import.title')}</span>
- </Tooltip>
- {getImportFeatureStatus(definition, multipleDefinitions, status.type)}
- </div>
+ {IMPORT_COMPATIBLE_ALMS.includes(alm) && (
+ <div>
+ <Tooltip
+ overlay={translate(
+ 'settings.almintegration.feature.alm_repo_import.description'
+ )}>
+ <span>
+ {translate('settings.almintegration.feature.alm_repo_import.title')}
+ </span>
+ </Tooltip>
+ {getImportFeatureStatus(definition, multipleDefinitions, status.type)}
+ </div>
+ )}
</div>
)}
<div className="display-flex-start">
<div className="flex-1">{children}</div>
- {help && (
+ {help ? (
<Alert className="huge-spacer-left flex-1" variant="info">
{help}
</Alert>
+ ) : (
+ <div className="flex-1" />
)}
</div>
</div>
currentAlm: props.location.query.alm || AlmKeys.GitHub,
definitions: {
[AlmKeys.Azure]: [],
- [AlmKeys.Bitbucket]: [],
+ [AlmKeys.BitbucketServer]: [],
+ [AlmKeys.BitbucketCloud]: [],
[AlmKeys.GitHub]: [],
[AlmKeys.GitLab]: []
},
requiresBranchesEnabled: false
},
{
- key: AlmKeys.Bitbucket,
+ key: AlmKeys.BitbucketServer,
label: (
<>
<img
height={16}
src={`${getBaseUrl()}/images/alm/bitbucket.svg`}
/>
- Bitbucket Server
+ Bitbucket
</>
),
requiresBranchesEnabled: false
onUpdateDefinitions={props.onUpdateDefinitions}
/>
)}
- {currentAlm === AlmKeys.Bitbucket && (
+ {currentAlm === AlmKeys.BitbucketServer && (
<BitbucketTab
branchesEnabled={branchesEnabled}
- definitions={definitions.bitbucket}
+ definitions={[...definitions.bitbucket, ...definitions.bitbucketcloud]}
definitionStatus={definitionStatus}
loadingAlmDefinitions={loadingAlmDefinitions}
loadingProjectCount={loadingProjectCount}
}
handleCancel = () => {
- this.setState({
- editedDefinition: undefined,
- success: false
- });
+ this.setState({ editedDefinition: undefined, success: false });
};
handleCreate = () => {
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)
import {
AlmBindingDefinition,
AlmKeys,
- AlmSettingsBindingStatus
+ AlmSettingsBindingStatus,
+ isBitbucketCloudBindingDefinition
} from '../../../../types/alm-settings';
import AlmBindingDefinitionBox from './AlmBindingDefinitionBox';
import AlmBindingDefinitionForm, {
</div>
{definitions.map(def => (
<AlmBindingDefinitionBox
- alm={alm}
+ alm={isBitbucketCloudBindingDefinition(def) ? AlmKeys.BitbucketCloud : alm}
branchesEnabled={branchesEnabled}
definition={def}
key={def.key}
*/
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
+import RadioToggle from 'sonar-ui-common/components/controls/RadioToggle';
import { translate } from 'sonar-ui-common/helpers/l10n';
-import { BitbucketBindingDefinition } from '../../../../types/alm-settings';
+import {
+ AlmKeys,
+ BitbucketBindingDefinition,
+ BitbucketCloudBindingDefinition,
+ isBitbucketBindingDefinition,
+ isBitbucketCloudBindingDefinition
+} from '../../../../types/alm-settings';
import { AlmBindingDefinitionFormField } from './AlmBindingDefinitionFormField';
export interface BitbucketFormProps {
- formData: BitbucketBindingDefinition;
- hideKeyField?: boolean;
- onFieldChange: (fieldId: keyof BitbucketBindingDefinition, value: string) => 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 && (
- <AlmBindingDefinitionFormField
- autoFocus={true}
- help={translate('settings.almintegration.form.name.bitbucket.help')}
- id="name.bitbucket"
- maxLength={100}
- onFieldChange={onFieldChange}
- propKey="key"
- readOnly={readOnly}
- value={formData.key}
- />
+ <div>
+ {isCreating && (
+ <>
+ <strong>{translate('settings.almintegration.form.choose_bitbucket_variant')}</strong>
+ <RadioToggle
+ className="little-spacer-top big-spacer-bottom"
+ name="variant"
+ onCheck={props.onSelectVariant}
+ options={[
+ {
+ label: 'Bitbucket Server',
+ value: AlmKeys.BitbucketServer
+ },
+ { label: 'Bitbucket Cloud', value: AlmKeys.BitbucketCloud }
+ ]}
+ value={variant}
+ />
+ </>
)}
- <AlmBindingDefinitionFormField
- help={
- <FormattedMessage
- defaultMessage={translate('settings.almintegration.form.url.bitbucket.help')}
- id="settings.almintegration.form.url.bitbucket.help"
- values={{ example: 'https://bitbucket-server.your-company.com' }}
+
+ {variant === AlmKeys.BitbucketServer && isBitbucketBindingDefinition(formData) && (
+ <div>
+ <AlmBindingDefinitionFormField
+ autoFocus={true}
+ help={translate('settings.almintegration.form.name.bitbucket.help')}
+ id="name.bitbucket"
+ maxLength={100}
+ onFieldChange={props.onFieldChange}
+ propKey="key"
+ value={formData.key}
+ />
+ <AlmBindingDefinitionFormField
+ help={
+ <FormattedMessage
+ defaultMessage={translate('settings.almintegration.form.url.bitbucket.help')}
+ id="settings.almintegration.form.url.bitbucket.help"
+ values={{ example: 'https://bitbucket-server.your-company.com' }}
+ />
+ }
+ 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}
- />
- <AlmBindingDefinitionFormField
- id="personal_access_token"
- isTextArea={true}
- onFieldChange={onFieldChange}
- overwriteOnly={Boolean(formData.key)}
- propKey="personalAccessToken"
- readOnly={readOnly}
- value={formData.personalAccessToken}
- />
- </>
+ <AlmBindingDefinitionFormField
+ id="personal_access_token"
+ isTextArea={true}
+ onFieldChange={props.onFieldChange}
+ overwriteOnly={Boolean(formData.key)}
+ propKey="personalAccessToken"
+ value={formData.personalAccessToken}
+ />
+ </div>
+ )}
+
+ {variant === AlmKeys.BitbucketCloud && isBitbucketCloudBindingDefinition(formData) && (
+ <div>
+ <AlmBindingDefinitionFormField
+ autoFocus={true}
+ help={translate('settings.almintegration.form.name.bitbucketcloud.help')}
+ id="name.bitbucket"
+ maxLength={100}
+ onFieldChange={props.onFieldChange}
+ propKey="key"
+ value={formData.key}
+ />
+ <AlmBindingDefinitionFormField
+ help={
+ <FormattedMessage
+ defaultMessage={translate(
+ 'settings.almintegration.form.workspace.bitbucketcloud.help'
+ )}
+ id="settings.almintegration.form.workspace.bitbucketcloud.help"
+ values={{
+ example: (
+ <>
+ {'https://bitbucket.org/'}
+ <strong>{'{workspace}'}</strong>
+ {'/{repository}'}
+ </>
+ )
+ }}
+ />
+ }
+ id="workspace.bitbucketcloud"
+ maxLength={2000}
+ onFieldChange={props.onFieldChange}
+ propKey="workspace"
+ value={formData.workspace}
+ />
+ <AlmBindingDefinitionFormField
+ id="client_id.bitbucketcloud"
+ onFieldChange={props.onFieldChange}
+ propKey="clientId"
+ value={formData.clientId}
+ />
+ <AlmBindingDefinitionFormField
+ id="client_secret.bitbucketcloud"
+ onFieldChange={props.onFieldChange}
+ overwriteOnly={Boolean(formData.key)}
+ propKey="clientSecret"
+ value={formData.clientSecret}
+ />
+ </div>
+ )}
+ </div>
);
}
* 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<BitbucketBindingDefinition | BitbucketCloudBindingDefinition>;
definitionStatus: T.Dict<AlmSettingsBindingStatus>;
loadingAlmDefinitions: boolean;
loadingProjectCount: boolean;
onUpdateDefinitions: () => void;
}
-export default function BitbucketTab(props: BitbucketTabProps) {
- const {
- branchesEnabled,
- multipleAlmEnabled,
- definitions,
- definitionStatus,
- loadingAlmDefinitions,
- loadingProjectCount
- } = props;
-
- return (
- <div className="bordered">
- <AlmTab
- alm={AlmKeys.Bitbucket}
+interface State {
+ editedDefinition?: BitbucketBindingDefinition | BitbucketCloudBindingDefinition;
+ isCreating: boolean;
+ submitting: boolean;
+ success: boolean;
+ variant?: AlmKeys.BitbucketServer | AlmKeys.BitbucketCloud;
+}
+
+export const DEFAULT_SERVER_BINDING = { key: '', url: '', personalAccessToken: '' };
+export const DEFAULT_CLOUD_BINDING = { key: '', clientId: '', clientSecret: '', workspace: '' };
+
+export default class BitbucketTab extends React.PureComponent<Props, State> {
+ 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 (
+ <BitbucketTabRenderer
branchesEnabled={branchesEnabled}
- createConfiguration={createBitbucketConfiguration}
- defaultBinding={{ key: '', url: '', personalAccessToken: '' }}
definitions={definitions}
definitionStatus={definitionStatus}
- form={childProps => <BitbucketForm {...childProps} />}
- help={
- <>
- <h3>{translate('onboarding.create_project.pat_help.title')}</h3>
-
- <p className="big-spacer-top">
- {translate('settings.almintegration.bitbucket.help_1')}
- </p>
-
- <ul className="big-spacer-top list-styled">
- <li>{translate('settings.almintegration.bitbucket.help_2')}</li>
- <li>{translate('settings.almintegration.bitbucket.help_3')}</li>
- </ul>
-
- <p className="big-spacer-top big-spacer-bottom">
- <Link target="_blank" to={ALM_DOCUMENTATION_PATHS[AlmKeys.Bitbucket]}>
- {translate('learn_more')}
- </Link>
- </p>
- </>
- }
+ 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}
/>
- </div>
- );
+ );
+ }
}
--- /dev/null
+/*
+ * 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<AlmSettingsBindingStatus>;
+ editedDefinition?: BitbucketBindingDefinition | BitbucketCloudBindingDefinition;
+ definitions: Array<BitbucketBindingDefinition | BitbucketCloudBindingDefinition>;
+ 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 = (
+ <>
+ <h3>{translate('onboarding.create_project.pat_help.title')}</h3>
+
+ <p className="big-spacer-top">{translate('settings.almintegration.bitbucket.help_1')}</p>
+
+ <ul className="big-spacer-top list-styled">
+ <li>{translate('settings.almintegration.bitbucket.help_2')}</li>
+ <li>{translate('settings.almintegration.bitbucket.help_3')}</li>
+ </ul>
+
+ <p className="big-spacer-top big-spacer-bottom">
+ <Link target="_blank" to={ALM_DOCUMENTATION_PATHS[AlmKeys.BitbucketServer]}>
+ {translate('learn_more')}
+ </Link>
+ </p>
+ </>
+ );
+ } else if (variant === AlmKeys.BitbucketCloud) {
+ help = (
+ <FormattedMessage
+ defaultMessage={translate(`settings.almintegration.bitbucketcloud.info`)}
+ id="settings.almintegration.bitbucketcloud.info"
+ values={{
+ link: (
+ <Link target="_blank" to={ALM_DOCUMENTATION_PATHS[AlmKeys.BitbucketCloud]}>
+ {translate('learn_more')}
+ </Link>
+ )
+ }}
+ />
+ );
+ }
+
+ return (
+ <div className="bordered">
+ <AlmTabRenderer
+ branchesEnabled={branchesEnabled}
+ alm={AlmKeys.BitbucketServer} // Always use Bitbucket Server for the translation keys.
+ definitions={definitions}
+ definitionStatus={definitionStatus}
+ editedDefinition={editedDefinition}
+ form={childProps => (
+ <BitbucketForm
+ isCreating={isCreating}
+ onSelectVariant={props.onSelectVariant}
+ variant={variant}
+ {...childProps}
+ />
+ )}
+ 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}
+ />
+ </div>
+ );
+}
value={formData.appId}
/>
<AlmBindingDefinitionFormField
- id="client_id"
+ id="client_id.github"
maxLength={80}
onFieldChange={onFieldChange}
propKey="clientId"
value={formData.clientId}
/>
<AlmBindingDefinitionFormField
- id="client_secret"
+ id="client_secret.github"
maxLength={80}
onFieldChange={onFieldChange}
overwriteOnly={Boolean(formData.key)}
import {
mockAlmSettingsBindingStatus,
mockAzureBindingDefinition,
- mockGithubBindingDefinition
+ mockBitbucketCloudBindingDefinition,
+ mockGithubBindingDefinition,
+ mockGitlabBindingDefinition
} from '../../../../../helpers/mocks/alm-settings';
import { AlmKeys, AlmSettingsBindingStatusType } from '../../../../../types/alm-settings';
import AlmBindingDefinitionBox, { AlmBindingDefinitionBoxProps } from '../AlmBindingDefinitionBox';
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,
deleteConfiguration: jest.fn().mockResolvedValue(undefined),
getAlmDefinitions: jest
.fn()
- .mockResolvedValue({ azure: [], bitbucket: [], github: [], gitlab: [] }),
+ .mockResolvedValue({ azure: [], bitbucket: [], bitbucketcloud: [], github: [], gitlab: [] }),
validateAlmSettings: jest.fn().mockResolvedValue('')
}));
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' }]
});
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');
(validateAlmSettings as jest.Mock)
.mockRejectedValueOnce(undefined)
.mockResolvedValueOnce(failureMessage)
+ .mockResolvedValueOnce('')
.mockResolvedValueOnce('');
await wrapper.instance().handleCheck(definitionKey);
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' }]
};
'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');
});
<AlmIntegrationRenderer
branchesEnabled={true}
currentAlm={AlmKeys.GitHub}
- definitions={{ azure: [], bitbucket: [], github: [], gitlab: [] }}
+ definitions={{ azure: [], bitbucket: [], bitbucketcloud: [], github: [], gitlab: [] }}
definitionStatus={{}}
loadingAlmDefinitions={false}
loadingProjectCount={false}
import * as React from 'react';
import {
mockAzureBindingDefinition,
+ mockBitbucketCloudBindingDefinition,
mockGithubBindingDefinition
} from '../../../../../helpers/mocks/alm-settings';
import {
defaultBinding: mockGithubBindingDefinition(),
definitions: [mockGithubBindingDefinition()]
};
- expect(shallowRender(githubProps)).toMatchSnapshot();
+ expect(shallowRender(githubProps)).toMatchSnapshot('default');
expect(shallowRender({ ...githubProps, definitions: [] })).toMatchSnapshot('empty');
expect(
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<AlmTabRendererProps<AzureBindingDefinition>> = {}) {
*/
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<BitbucketFormProps> = {}) {
return shallow(
<BitbucketForm
formData={{ key: '', personalAccessToken: '', url: '' }}
+ isCreating={false}
onFieldChange={jest.fn()}
+ onSelectVariant={jest.fn()}
+ variant={AlmKeys.BitbucketServer}
{...props}
/>
);
*/
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<BitbucketTabProps> = {}) {
- 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<BitbucketTab['props']> = {}) {
+ return shallow<BitbucketTab>(
<BitbucketTab
branchesEnabled={true}
definitions={[mockBitbucketBindingDefinition()]}
--- /dev/null
+/*
+ * 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import { mockBitbucketBindingDefinition } from '../../../../../helpers/mocks/alm-settings';
+import { AlmKeys, BitbucketBindingDefinition } from '../../../../../types/alm-settings';
+import AlmTabRenderer, { AlmTabRendererProps } from '../AlmTabRenderer';
+import BitbucketTabRenderer, { BitbucketTabRendererProps } from '../BitbucketTabRenderer';
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot('default');
+ expect(shallowRender({ variant: AlmKeys.BitbucketServer })).toMatchSnapshot('bitbucket server');
+ expect(shallowRender({ variant: AlmKeys.BitbucketCloud })).toMatchSnapshot('bitbucket cloud');
+
+ const almTab = shallowRender().find<AlmTabRendererProps<BitbucketBindingDefinition>>(
+ AlmTabRenderer
+ );
+ expect(
+ almTab.props().form({ formData: mockBitbucketBindingDefinition(), onFieldChange: jest.fn() })
+ ).toMatchSnapshot('bitbucket form');
+});
+
+function shallowRender(props: Partial<BitbucketTabRendererProps> = {}) {
+ return shallow<BitbucketTabRendererProps>(
+ <BitbucketTabRenderer
+ branchesEnabled={true}
+ definitions={[]}
+ definitionStatus={{}}
+ isCreating={false}
+ loadingAlmDefinitions={false}
+ loadingProjectCount={false}
+ multipleAlmEnabled={true}
+ onCancel={jest.fn()}
+ onCheck={jest.fn()}
+ onCreate={jest.fn()}
+ onDelete={jest.fn()}
+ onEdit={jest.fn()}
+ onSelectVariant={jest.fn()}
+ onSubmit={jest.fn()}
+ submitting={true}
+ success={false}
+ variant={undefined}
+ {...props}
+ />
+ );
+}
</div>
`;
+exports[`should render correctly: success for Bitbucket Cloud 1`] = `
+<div
+ className="boxed-group-inner bordered spacer-top spacer-bottom it__alm-binding-definition"
+>
+ <div
+ className="actions pull-right"
+ >
+ <Button
+ onClick={[Function]}
+ >
+ <EditIcon
+ className="spacer-right"
+ />
+ edit
+ </Button>
+ <Button
+ className="button-red spacer-left"
+ onClick={[Function]}
+ >
+ <DeleteIcon
+ className="spacer-right"
+ />
+ delete
+ </Button>
+ </div>
+ <div
+ className="big-spacer-bottom"
+ >
+ <h3>
+ key
+ </h3>
+ </div>
+ <div
+ className="display-flex-row spacer-bottom"
+ >
+ <div
+ className="huge-spacer-right"
+ >
+ <Tooltip
+ overlay="settings.almintegration.feature.pr_decoration.description"
+ >
+ <span>
+ settings.almintegration.feature.pr_decoration.title
+ </span>
+ </Tooltip>
+ <AlertSuccessIcon
+ className="spacer-left"
+ />
+ </div>
+ </div>
+ <div
+ className="width-50"
+ />
+ <Button
+ className="big-spacer-top"
+ onClick={[Function]}
+ >
+ settings.almintegration.check_configuration
+ </Button>
+</div>
+`;
+
+exports[`should render correctly: success for GitLab 1`] = `
+<div
+ className="boxed-group-inner bordered spacer-top spacer-bottom it__alm-binding-definition"
+>
+ <div
+ className="actions pull-right"
+ >
+ <Button
+ onClick={[Function]}
+ >
+ <EditIcon
+ className="spacer-right"
+ />
+ edit
+ </Button>
+ <Button
+ className="button-red spacer-left"
+ onClick={[Function]}
+ >
+ <DeleteIcon
+ className="spacer-right"
+ />
+ delete
+ </Button>
+ </div>
+ <div
+ className="big-spacer-bottom"
+ >
+ <h3>
+ foo
+ </h3>
+ </div>
+ <div
+ className="display-flex-row spacer-bottom"
+ >
+ <div
+ className="huge-spacer-right"
+ >
+ <Tooltip
+ overlay="settings.almintegration.feature.mr_decoration.description"
+ >
+ <span>
+ settings.almintegration.feature.mr_decoration.title
+ </span>
+ </Tooltip>
+ <AlertSuccessIcon
+ className="spacer-left"
+ />
+ </div>
+ <div>
+ <Tooltip
+ overlay="settings.almintegration.feature.alm_repo_import.description"
+ >
+ <span>
+ settings.almintegration.feature.alm_repo_import.title
+ </span>
+ </Tooltip>
+ <div
+ className="display-inline-flex-center"
+ >
+ <strong
+ className="spacer-left"
+ >
+ settings.almintegration.feature.alm_repo_import.disabled
+ </strong>
+ <HelpTooltip
+ className="little-spacer-left"
+ overlay="settings.almintegration.feature.alm_repo_import.disabled.no_url"
+ />
+ </div>
+ </div>
+ </div>
+ <div
+ className="width-50"
+ />
+ <Button
+ className="big-spacer-top"
+ onClick={[Function]}
+ >
+ settings.almintegration.check_configuration
+ </Button>
+</div>
+`;
+
exports[`should render correctly: success with alert 1`] = `
<div
className="boxed-group-inner bordered spacer-top spacer-bottom it__alm-binding-definition"
>
<Component />
</div>
+ <div
+ className="flex-1"
+ />
</div>
</div>
<div
>
<Component />
</div>
+ <div
+ className="flex-1"
+ />
</div>
</div>
<div
Object {
"azure": Array [],
"bitbucket": Array [],
+ "bitbucketcloud": Array [],
"github": Array [],
"gitlab": Array [],
}
height={16}
src="/images/alm/bitbucket.svg"
/>
- Bitbucket Server
+ Bitbucket
</React.Fragment>,
"requiresBranchesEnabled": false,
},
height={16}
src="/images/alm/bitbucket.svg"
/>
- Bitbucket Server
+ Bitbucket
</React.Fragment>,
"requiresBranchesEnabled": false,
},
</Fragment>
`;
+exports[`should render correctly: bitbucketcloud 1`] = `
+<Fragment>
+ <header
+ className="page-header"
+ >
+ <h1
+ className="page-title"
+ >
+ settings.almintegration.title
+ </h1>
+ </header>
+ <div
+ className="markdown small spacer-top big-spacer-bottom"
+ >
+ settings.almintegration.description
+ </div>
+ <BoxedTabs
+ onSelect={[MockFunction]}
+ selected="bitbucketcloud"
+ tabs={
+ Array [
+ Object {
+ "key": "github",
+ "label": <React.Fragment>
+ <img
+ alt="github"
+ className="spacer-right"
+ height={16}
+ src="/images/alm/github.svg"
+ />
+ GitHub
+ </React.Fragment>,
+ "requiresBranchesEnabled": false,
+ },
+ Object {
+ "key": "bitbucket",
+ "label": <React.Fragment>
+ <img
+ alt="bitbucket"
+ className="spacer-right"
+ height={16}
+ src="/images/alm/bitbucket.svg"
+ />
+ Bitbucket
+ </React.Fragment>,
+ "requiresBranchesEnabled": false,
+ },
+ Object {
+ "key": "azure",
+ "label": <React.Fragment>
+ <img
+ alt="azure"
+ className="spacer-right"
+ height={16}
+ src="/images/alm/azure.svg"
+ />
+ Azure DevOps
+ </React.Fragment>,
+ "requiresBranchesEnabled": false,
+ },
+ Object {
+ "key": "gitlab",
+ "label": <React.Fragment>
+ <img
+ alt="gitlab"
+ className="spacer-right"
+ height={16}
+ src="/images/alm/gitlab.svg"
+ />
+ GitLab
+ </React.Fragment>,
+ "requiresBranchesEnabled": false,
+ },
+ ]
+ }
+ />
+</Fragment>
+`;
+
exports[`should render correctly: default 1`] = `
<Fragment>
<header
height={16}
src="/images/alm/bitbucket.svg"
/>
- Bitbucket Server
+ Bitbucket
</React.Fragment>,
"requiresBranchesEnabled": false,
},
height={16}
src="/images/alm/bitbucket.svg"
/>
- Bitbucket Server
+ Bitbucket
</React.Fragment>,
"requiresBranchesEnabled": false,
},
height={16}
src="/images/alm/bitbucket.svg"
/>
- Bitbucket Server
+ Bitbucket
</React.Fragment>,
"requiresBranchesEnabled": false,
},
height={16}
src="/images/alm/bitbucket.svg"
/>
- Bitbucket Server
+ Bitbucket
</React.Fragment>,
"requiresBranchesEnabled": false,
},
<AlmTabRenderer
alm="azure"
branchesEnabled={true}
- defaultBinding={
- Object {
- "key": "",
- "personalAccessToken": "",
- "url": undefined,
- }
- }
definitionStatus={Object {}}
definitions={
Array [
</div>
`;
-exports[`should render correctly with validation 1`] = `
+exports[`should render correctly with validation: create a first 1`] = `
<div
className="big-padded"
>
<DeferredSpinner
loading={false}
>
+ <p
+ className="spacer-top"
+ >
+ settings.almintegration.empty.github
+ </p>
<div
- className="spacer-bottom text-right"
+ className="big-spacer-top"
>
<Connect(withAppState(CreationTooltip))
alm="github"
</Button>
</Connect(withAppState(CreationTooltip))>
</div>
- <AlmBindingDefinitionBox
- alm="github"
- branchesEnabled={true}
- definition={
+ <AlmBindingDefinitionForm
+ bindingDefinition={
Object {
"appId": "123456",
"clientId": "client1",
"url": "http://github.enterprise.com",
}
}
- key="key"
- multipleDefinitions={false}
- onCheck={[MockFunction]}
- onDelete={[MockFunction]}
- onEdit={[MockFunction]}
- />
+ help={<div />}
+ isSecondInstance={false}
+ onCancel={[MockFunction]}
+ onSubmit={[MockFunction]}
+ >
+ <Component />
+ </AlmBindingDefinitionForm>
</DeferredSpinner>
</div>
`;
-exports[`should render correctly with validation: create a first 1`] = `
+exports[`should render correctly with validation: create a second 1`] = `
<div
className="big-padded"
>
<DeferredSpinner
loading={false}
>
- <p
- className="spacer-top"
- >
- settings.almintegration.empty.github
- </p>
<div
- className="big-spacer-top"
+ className="spacer-bottom text-right"
>
<Connect(withAppState(CreationTooltip))
alm="github"
</Button>
</Connect(withAppState(CreationTooltip))>
</div>
+ <AlmBindingDefinitionBox
+ alm="github"
+ branchesEnabled={true}
+ definition={
+ Object {
+ "appId": "123456",
+ "clientId": "client1",
+ "clientSecret": "**clientsecret**",
+ "key": "key",
+ "privateKey": "asdf1234",
+ "url": "http://github.enterprise.com",
+ }
+ }
+ key="key"
+ multipleDefinitions={false}
+ onCheck={[MockFunction]}
+ onDelete={[MockFunction]}
+ onEdit={[MockFunction]}
+ />
<AlmBindingDefinitionForm
bindingDefinition={
Object {
}
}
help={<div />}
- isSecondInstance={false}
+ isSecondInstance={true}
onCancel={[MockFunction]}
onSubmit={[MockFunction]}
>
</div>
`;
-exports[`should render correctly with validation: create a second 1`] = `
+exports[`should render correctly with validation: default 1`] = `
<div
className="big-padded"
>
onDelete={[MockFunction]}
onEdit={[MockFunction]}
/>
- <AlmBindingDefinitionForm
- bindingDefinition={
- Object {
- "appId": "123456",
- "clientId": "client1",
- "clientSecret": "**clientsecret**",
- "key": "key",
- "privateKey": "asdf1234",
- "url": "http://github.enterprise.com",
- }
- }
- help={<div />}
- isSecondInstance={true}
- onCancel={[MockFunction]}
- onSubmit={[MockFunction]}
- >
- <Component />
- </AlmBindingDefinitionForm>
</DeferredSpinner>
</div>
`;
</DeferredSpinner>
</div>
`;
+
+exports[`should render correctly with validation: pass the correct key for bitbucket cloud 1`] = `
+<div
+ className="big-padded"
+>
+ <DeferredSpinner
+ loading={false}
+ >
+ <div
+ className="spacer-bottom text-right"
+ >
+ <Connect(withAppState(CreationTooltip))
+ alm="bitbucket"
+ preventCreation={false}
+ >
+ <Button
+ data-test="settings__alm-create"
+ disabled={false}
+ onClick={[MockFunction]}
+ >
+ settings.almintegration.create
+ </Button>
+ </Connect(withAppState(CreationTooltip))>
+ </div>
+ <AlmBindingDefinitionBox
+ alm="bitbucketcloud"
+ branchesEnabled={true}
+ definition={
+ Object {
+ "clientId": "client1",
+ "clientSecret": "**clientsecret**",
+ "key": "key",
+ "workspace": "workspace",
+ }
+ }
+ key="key"
+ multipleDefinitions={false}
+ onCheck={[MockFunction]}
+ onDelete={[MockFunction]}
+ onEdit={[MockFunction]}
+ />
+ </DeferredSpinner>
+</div>
+`;
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`should render correctly 1`] = `
-<Fragment>
- <AlmBindingDefinitionFormField
- autoFocus={true}
- help="settings.almintegration.form.name.bitbucket.help"
- id="name.bitbucket"
- maxLength={100}
- onFieldChange={[MockFunction]}
- propKey="key"
- value=""
- />
- <AlmBindingDefinitionFormField
- help={
- <FormattedMessage
- defaultMessage="settings.almintegration.form.url.bitbucket.help"
- id="settings.almintegration.form.url.bitbucket.help"
- values={
- Object {
- "example": "https://bitbucket-server.your-company.com",
+exports[`should render correctly: bitbucket cloud, edit 1`] = `
+<div>
+ <div>
+ <AlmBindingDefinitionFormField
+ autoFocus={true}
+ help="settings.almintegration.form.name.bitbucketcloud.help"
+ id="name.bitbucket"
+ maxLength={100}
+ onFieldChange={[MockFunction]}
+ propKey="key"
+ value="key"
+ />
+ <AlmBindingDefinitionFormField
+ help={
+ <FormattedMessage
+ defaultMessage="settings.almintegration.form.workspace.bitbucketcloud.help"
+ id="settings.almintegration.form.workspace.bitbucketcloud.help"
+ values={
+ Object {
+ "example": <React.Fragment>
+ https://bitbucket.org/
+ <strong>
+ {workspace}
+ </strong>
+ /{repository}
+ </React.Fragment>,
+ }
}
- }
- />
- }
- id="url.bitbucket"
- maxLength={2000}
- onFieldChange={[MockFunction]}
- propKey="url"
- value=""
- />
- <AlmBindingDefinitionFormField
- id="personal_access_token"
- isTextArea={true}
- onFieldChange={[MockFunction]}
- overwriteOnly={false}
- propKey="personalAccessToken"
- value=""
- />
-</Fragment>
+ />
+ }
+ id="workspace.bitbucketcloud"
+ maxLength={2000}
+ onFieldChange={[MockFunction]}
+ propKey="workspace"
+ value="workspace"
+ />
+ <AlmBindingDefinitionFormField
+ id="client_id.bitbucketcloud"
+ onFieldChange={[MockFunction]}
+ propKey="clientId"
+ value="client1"
+ />
+ <AlmBindingDefinitionFormField
+ id="client_secret.bitbucketcloud"
+ onFieldChange={[MockFunction]}
+ overwriteOnly={true}
+ propKey="clientSecret"
+ value="**clientsecret**"
+ />
+ </div>
+</div>
`;
-exports[`should render correctly 2`] = `
-<Fragment>
- <AlmBindingDefinitionFormField
- autoFocus={true}
- help="settings.almintegration.form.name.bitbucket.help"
- id="name.bitbucket"
- maxLength={100}
- onFieldChange={[MockFunction]}
- propKey="key"
- value="key"
- />
- <AlmBindingDefinitionFormField
- help={
- <FormattedMessage
- defaultMessage="settings.almintegration.form.url.bitbucket.help"
- id="settings.almintegration.form.url.bitbucket.help"
- values={
- Object {
- "example": "https://bitbucket-server.your-company.com",
+exports[`should render correctly: bitbucket cloud, empty 1`] = `
+<div>
+ <div>
+ <AlmBindingDefinitionFormField
+ autoFocus={true}
+ help="settings.almintegration.form.name.bitbucketcloud.help"
+ id="name.bitbucket"
+ maxLength={100}
+ onFieldChange={[MockFunction]}
+ propKey="key"
+ value=""
+ />
+ <AlmBindingDefinitionFormField
+ help={
+ <FormattedMessage
+ defaultMessage="settings.almintegration.form.workspace.bitbucketcloud.help"
+ id="settings.almintegration.form.workspace.bitbucketcloud.help"
+ values={
+ Object {
+ "example": <React.Fragment>
+ https://bitbucket.org/
+ <strong>
+ {workspace}
+ </strong>
+ /{repository}
+ </React.Fragment>,
+ }
+ }
+ />
+ }
+ id="workspace.bitbucketcloud"
+ maxLength={2000}
+ onFieldChange={[MockFunction]}
+ propKey="workspace"
+ value=""
+ />
+ <AlmBindingDefinitionFormField
+ id="client_id.bitbucketcloud"
+ onFieldChange={[MockFunction]}
+ propKey="clientId"
+ value=""
+ />
+ <AlmBindingDefinitionFormField
+ id="client_secret.bitbucketcloud"
+ onFieldChange={[MockFunction]}
+ overwriteOnly={false}
+ propKey="clientSecret"
+ value=""
+ />
+ </div>
+</div>
+`;
+
+exports[`should render correctly: bitbucket server, edit 1`] = `
+<div>
+ <div>
+ <AlmBindingDefinitionFormField
+ autoFocus={true}
+ help="settings.almintegration.form.name.bitbucket.help"
+ id="name.bitbucket"
+ maxLength={100}
+ onFieldChange={[MockFunction]}
+ propKey="key"
+ value="key"
+ />
+ <AlmBindingDefinitionFormField
+ help={
+ <FormattedMessage
+ defaultMessage="settings.almintegration.form.url.bitbucket.help"
+ id="settings.almintegration.form.url.bitbucket.help"
+ values={
+ Object {
+ "example": "https://bitbucket-server.your-company.com",
+ }
}
- }
- />
+ />
+ }
+ id="url.bitbucket"
+ maxLength={2000}
+ onFieldChange={[MockFunction]}
+ propKey="url"
+ value="http://bbs.enterprise.com"
+ />
+ <AlmBindingDefinitionFormField
+ id="personal_access_token"
+ isTextArea={true}
+ onFieldChange={[MockFunction]}
+ overwriteOnly={true}
+ propKey="personalAccessToken"
+ value="asdf1234"
+ />
+ </div>
+</div>
+`;
+
+exports[`should render correctly: bitbucket server, empty 1`] = `
+<div>
+ <div>
+ <AlmBindingDefinitionFormField
+ autoFocus={true}
+ help="settings.almintegration.form.name.bitbucket.help"
+ id="name.bitbucket"
+ maxLength={100}
+ onFieldChange={[MockFunction]}
+ propKey="key"
+ value=""
+ />
+ <AlmBindingDefinitionFormField
+ help={
+ <FormattedMessage
+ defaultMessage="settings.almintegration.form.url.bitbucket.help"
+ id="settings.almintegration.form.url.bitbucket.help"
+ values={
+ Object {
+ "example": "https://bitbucket-server.your-company.com",
+ }
+ }
+ />
+ }
+ id="url.bitbucket"
+ maxLength={2000}
+ onFieldChange={[MockFunction]}
+ propKey="url"
+ value=""
+ />
+ <AlmBindingDefinitionFormField
+ id="personal_access_token"
+ isTextArea={true}
+ onFieldChange={[MockFunction]}
+ overwriteOnly={false}
+ propKey="personalAccessToken"
+ value=""
+ />
+ </div>
+</div>
+`;
+
+exports[`should render correctly: variant select 1`] = `
+<div>
+ <strong>
+ settings.almintegration.form.choose_bitbucket_variant
+ </strong>
+ <RadioToggle
+ className="little-spacer-top big-spacer-bottom"
+ disabled={false}
+ name="variant"
+ onCheck={[MockFunction]}
+ options={
+ Array [
+ Object {
+ "label": "Bitbucket Server",
+ "value": "bitbucket",
+ },
+ Object {
+ "label": "Bitbucket Cloud",
+ "value": "bitbucketcloud",
+ },
+ ]
}
- id="url.bitbucket"
- maxLength={2000}
- onFieldChange={[MockFunction]}
- propKey="url"
- value="http://bbs.enterprise.com"
- />
- <AlmBindingDefinitionFormField
- id="personal_access_token"
- isTextArea={true}
- onFieldChange={[MockFunction]}
- overwriteOnly={true}
- propKey="personalAccessToken"
- value="asdf1234"
+ value="bitbucket"
/>
-</Fragment>
+ <div>
+ <AlmBindingDefinitionFormField
+ autoFocus={true}
+ help="settings.almintegration.form.name.bitbucket.help"
+ id="name.bitbucket"
+ maxLength={100}
+ onFieldChange={[MockFunction]}
+ propKey="key"
+ value=""
+ />
+ <AlmBindingDefinitionFormField
+ help={
+ <FormattedMessage
+ defaultMessage="settings.almintegration.form.url.bitbucket.help"
+ id="settings.almintegration.form.url.bitbucket.help"
+ values={
+ Object {
+ "example": "https://bitbucket-server.your-company.com",
+ }
+ }
+ />
+ }
+ id="url.bitbucket"
+ maxLength={2000}
+ onFieldChange={[MockFunction]}
+ propKey="url"
+ value=""
+ />
+ <AlmBindingDefinitionFormField
+ id="personal_access_token"
+ isTextArea={true}
+ onFieldChange={[MockFunction]}
+ overwriteOnly={false}
+ propKey="personalAccessToken"
+ value=""
+ />
+ </div>
+</div>
`;
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should render correctly 1`] = `
-<div
- className="bordered"
->
- <AlmTab
- alm="bitbucket"
- branchesEnabled={true}
- createConfiguration={[Function]}
- defaultBinding={
+<BitbucketTabRenderer
+ branchesEnabled={true}
+ definitionStatus={Object {}}
+ definitions={
+ Array [
Object {
- "key": "",
- "personalAccessToken": "",
- "url": "",
- }
- }
- definitionStatus={Object {}}
- definitions={
- Array [
- Object {
- "key": "key",
- "personalAccessToken": "asdf1234",
- "url": "http://bbs.enterprise.com",
- },
- ]
- }
- form={[Function]}
- help={
- <React.Fragment>
- <h3>
- onboarding.create_project.pat_help.title
- </h3>
- <p
- className="big-spacer-top"
- >
- settings.almintegration.bitbucket.help_1
- </p>
- <ul
- className="big-spacer-top list-styled"
- >
- <li>
- settings.almintegration.bitbucket.help_2
- </li>
- <li>
- settings.almintegration.bitbucket.help_3
- </li>
- </ul>
- <p
- className="big-spacer-top big-spacer-bottom"
- >
- <Link
- onlyActiveOnIndex={false}
- style={Object {}}
- target="_blank"
- to="/documentation/analysis/bitbucket-integration/"
- >
- learn_more
- </Link>
- </p>
- </React.Fragment>
- }
- loadingAlmDefinitions={false}
- loadingProjectCount={false}
- multipleAlmEnabled={true}
- onCheck={[MockFunction]}
- onDelete={[MockFunction]}
- onUpdateDefinitions={[MockFunction]}
- updateConfiguration={[Function]}
- />
-</div>
+ "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}
+/>
`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly: bitbucket cloud 1`] = `
+<div
+ className="bordered"
+>
+ <AlmTabRenderer
+ alm="bitbucket"
+ branchesEnabled={true}
+ definitionStatus={Object {}}
+ definitions={Array []}
+ form={[Function]}
+ help={
+ <FormattedMessage
+ defaultMessage="settings.almintegration.bitbucketcloud.info"
+ id="settings.almintegration.bitbucketcloud.info"
+ values={
+ Object {
+ "link": <Link
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ target="_blank"
+ to="/documentation/analysis/bitbucket-cloud-integration/"
+ >
+ learn_more
+ </Link>,
+ }
+ }
+ />
+ }
+ loadingAlmDefinitions={false}
+ loadingProjectCount={false}
+ multipleAlmEnabled={true}
+ onCancel={[MockFunction]}
+ onCheck={[MockFunction]}
+ onCreate={[MockFunction]}
+ onDelete={[MockFunction]}
+ onEdit={[MockFunction]}
+ onSubmit={[MockFunction]}
+ submitting={true}
+ success={false}
+ />
+</div>
+`;
+
+exports[`should render correctly: bitbucket form 1`] = `
+<BitbucketForm
+ formData={
+ Object {
+ "key": "key",
+ "personalAccessToken": "asdf1234",
+ "url": "http://bbs.enterprise.com",
+ }
+ }
+ isCreating={false}
+ onFieldChange={[MockFunction]}
+ onSelectVariant={[MockFunction]}
+/>
+`;
+
+exports[`should render correctly: bitbucket server 1`] = `
+<div
+ className="bordered"
+>
+ <AlmTabRenderer
+ alm="bitbucket"
+ branchesEnabled={true}
+ definitionStatus={Object {}}
+ definitions={Array []}
+ form={[Function]}
+ help={
+ <React.Fragment>
+ <h3>
+ onboarding.create_project.pat_help.title
+ </h3>
+ <p
+ className="big-spacer-top"
+ >
+ settings.almintegration.bitbucket.help_1
+ </p>
+ <ul
+ className="big-spacer-top list-styled"
+ >
+ <li>
+ settings.almintegration.bitbucket.help_2
+ </li>
+ <li>
+ settings.almintegration.bitbucket.help_3
+ </li>
+ </ul>
+ <p
+ className="big-spacer-top big-spacer-bottom"
+ >
+ <Link
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ target="_blank"
+ to="/documentation/analysis/bitbucket-integration/"
+ >
+ learn_more
+ </Link>
+ </p>
+ </React.Fragment>
+ }
+ loadingAlmDefinitions={false}
+ loadingProjectCount={false}
+ multipleAlmEnabled={true}
+ onCancel={[MockFunction]}
+ onCheck={[MockFunction]}
+ onCreate={[MockFunction]}
+ onDelete={[MockFunction]}
+ onEdit={[MockFunction]}
+ onSubmit={[MockFunction]}
+ submitting={true}
+ success={false}
+ />
+</div>
+`;
+
+exports[`should render correctly: default 1`] = `
+<div
+ className="bordered"
+>
+ <AlmTabRenderer
+ alm="bitbucket"
+ branchesEnabled={true}
+ definitionStatus={Object {}}
+ definitions={Array []}
+ form={[Function]}
+ loadingAlmDefinitions={false}
+ loadingProjectCount={false}
+ multipleAlmEnabled={true}
+ onCancel={[MockFunction]}
+ onCheck={[MockFunction]}
+ onCreate={[MockFunction]}
+ onDelete={[MockFunction]}
+ onEdit={[MockFunction]}
+ onSubmit={[MockFunction]}
+ submitting={true}
+ success={false}
+ />
+</div>
+`;
value=""
/>
<AlmBindingDefinitionFormField
- id="client_id"
+ id="client_id.github"
maxLength={80}
onFieldChange={[MockFunction]}
propKey="clientId"
value=""
/>
<AlmBindingDefinitionFormField
- id="client_secret"
+ id="client_secret.github"
maxLength={80}
onFieldChange={[MockFunction]}
overwriteOnly={false}
value="123456"
/>
<AlmBindingDefinitionFormField
- id="client_id"
+ id="client_id.github"
maxLength={80}
onFieldChange={[MockFunction]}
propKey="clientId"
value="client1"
/>
<AlmBindingDefinitionFormField
- id="client_secret"
+ id="client_secret.github"
maxLength={80}
onFieldChange={[MockFunction]}
overwriteOnly={true}
*/
import { AlmKeys } from '../../../../types/alm-settings';
-export const ALM_KEY_LIST = [AlmKeys.Azure, AlmKeys.Bitbucket, AlmKeys.GitHub, AlmKeys.GitLab];
+export const ALM_KEY_LIST = [
+ AlmKeys.Azure,
+ AlmKeys.BitbucketServer,
+ AlmKeys.BitbucketCloud,
+ AlmKeys.GitHub,
+ AlmKeys.GitLab
+];
{renderMonoRepoFieldWithDocLink(ALM_DOCUMENTATION_PATHS[AlmKeys.Azure])}
</>
);
- case AlmKeys.Bitbucket:
+ case AlmKeys.BitbucketServer:
return (
<>
{renderField({
[almKey in AlmKeys]: Array<keyof T.Omit<FormData, 'key'>>;
} = {
[AlmKeys.Azure]: ['repository', 'slug'],
- [AlmKeys.Bitbucket]: ['repository', 'slug'],
+ [AlmKeys.BitbucketServer]: ['repository', 'slug'],
+ [AlmKeys.BitbucketCloud]: ['repository'],
[AlmKeys.GitHub]: ['repository'],
[AlmKeys.GitLab]: ['repository']
};
monorepo
});
}
- case AlmKeys.Bitbucket: {
+ case AlmKeys.BitbucketServer: {
if (!repository || !slug) {
return Promise.reject();
}
it.each([
[AlmKeys.Azure, false],
[AlmKeys.Azure, true],
- [AlmKeys.Bitbucket, false],
- [AlmKeys.Bitbucket, true],
+ [AlmKeys.BitbucketServer, false],
+ [AlmKeys.BitbucketServer, true],
[AlmKeys.GitHub, false],
[AlmKeys.GitHub, true],
[AlmKeys.GitLab, false],
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 }
];
[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: {}) => {
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 }
]
url: urls[0]
},
{
- alm: AlmKeys.Bitbucket,
+ alm: AlmKeys.BitbucketServer,
key: 'i3',
url: urls[1]
},
}
const jenkinsAvailable =
- projectBinding && [AlmKeys.Bitbucket, AlmKeys.GitHub].includes(projectBinding.alm);
+ projectBinding && [AlmKeys.BitbucketServer, AlmKeys.GitHub].includes(projectBinding.alm);
return (
<>
});
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);
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);
const { almBinding, branchesEnabled, projectBinding } = props;
switch (projectBinding.alm) {
- case AlmKeys.Bitbucket:
+ case AlmKeys.BitbucketServer:
return (
<WebhookStepBitbucket
almBinding={isBitbucketBindingDefinition(almBinding) ? almBinding : undefined}
function shallowRender(props: Partial<PreRequisitesStepProps> = {}) {
return shallow<PreRequisitesStepProps>(
<PreRequisitesStep
- alm={AlmKeys.Bitbucket}
+ alm={AlmKeys.BitbucketServer}
branchesEnabled={true}
onChangeSkipNextTime={jest.fn()}
onDone={jest.fn()}
mockAzureBindingDefinition(),
mockProjectAlmBindingResponse({ alm: AlmKeys.Azure })
],
- [AlmKeys.Bitbucket, mockBitbucketBindingDefinition(), mockProjectBitbucketBindingResponse()],
+ [
+ AlmKeys.BitbucketServer,
+ mockBitbucketBindingDefinition(),
+ mockProjectBitbucketBindingResponse()
+ ],
[AlmKeys.GitHub, mockGithubBindingDefinition(), mockProjectGithubBindingResponse()],
[
AlmKeys.GitLab,
export const ALM_DOCUMENTATION_PATHS = {
[AlmKeys.Azure]: '/documentation/analysis/azuredevops-integration/',
- [AlmKeys.Bitbucket]: '/documentation/analysis/bitbucket-integration/',
+ [AlmKeys.BitbucketServer]: '/documentation/analysis/bitbucket-integration/',
+ [AlmKeys.BitbucketCloud]: '/documentation/analysis/bitbucket-cloud-integration/',
[AlmKeys.GitHub]: '/documentation/analysis/github-integration/',
[AlmKeys.GitLab]: '/documentation/analysis/gitlab-integration/'
};
+
+export const IMPORT_COMPATIBLE_ALMS = [
+ AlmKeys.Azure,
+ AlmKeys.BitbucketServer,
+ AlmKeys.GitHub,
+ AlmKeys.GitLab
+];
AlmSettingsInstance,
AzureBindingDefinition,
BitbucketBindingDefinition,
+ BitbucketCloudBindingDefinition,
GithubBindingDefinition,
GitlabBindingDefinition,
ProjectAlmBindingResponse,
};
}
+export function mockBitbucketCloudBindingDefinition(
+ overrides: Partial<BitbucketCloudBindingDefinition> = {}
+): BitbucketCloudBindingDefinition {
+ return {
+ key: 'key',
+ clientId: 'client1',
+ clientSecret: '**clientsecret**',
+ workspace: 'workspace',
+ ...overrides
+ };
+}
+
export function mockGithubBindingDefinition(
overrides: Partial<GithubBindingDefinition> = {}
): GithubBindingDefinition {
overrides: Partial<ProjectBitbucketBindingResponse> = {}
): ProjectBitbucketBindingResponse {
return {
- alm: AlmKeys.Bitbucket,
+ alm: AlmKeys.BitbucketServer,
key: 'foo',
repository: 'PROJECT_KEY',
slug: 'repo-slug',
*/
export const enum AlmKeys {
Azure = 'azure',
- Bitbucket = 'bitbucket',
+ BitbucketServer = 'bitbucket',
+ BitbucketCloud = 'bitbucketcloud',
GitHub = 'github',
GitLab = 'gitlab'
}
url: string;
}
+export interface BitbucketCloudBindingDefinition extends AlmBindingDefinition {
+ clientId: string;
+ clientSecret: string;
+ workspace: string;
+}
+
export interface GithubBindingDefinition extends AlmBindingDefinition {
appId: string;
clientId: string;
}
export interface ProjectBitbucketBindingResponse extends ProjectAlmBindingResponse {
- alm: AlmKeys.Bitbucket;
+ alm: AlmKeys.BitbucketServer;
repository: string;
slug: string;
monorepo: boolean;
export interface AlmSettingsBindingDefinitions {
[AlmKeys.Azure]: AzureBindingDefinition[];
- [AlmKeys.Bitbucket]: BitbucketBindingDefinition[];
+ [AlmKeys.BitbucketServer]: BitbucketBindingDefinition[];
+ [AlmKeys.BitbucketCloud]: BitbucketCloudBindingDefinition[];
[AlmKeys.GitHub]: GithubBindingDefinition[];
[AlmKeys.GitLab]: GitlabBindingDefinition[];
}
export function isProjectBitbucketBindingResponse(
binding: ProjectAlmBindingResponse
): binding is ProjectBitbucketBindingResponse {
- return binding.alm === AlmKeys.Bitbucket;
+ return binding.alm === AlmKeys.BitbucketServer;
}
export function isProjectGitHubBindingResponse(
}
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;
}
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
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
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:
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)".