@@ -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); | |||
} |
@@ -101,7 +101,7 @@ export default function BitbucketProjectCreateRenderer(props: BitbucketProjectCr | |||
{loading && <i className="spinner" />} | |||
{!loading && !bitbucketSetting && ( | |||
<WrongBindingCountAlert alm={AlmKeys.Bitbucket} canAdmin={!!canAdmin} /> | |||
<WrongBindingCountAlert alm={AlmKeys.BitbucketServer} canAdmin={!!canAdmin} /> | |||
)} | |||
{!loading && |
@@ -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<T.AppState, 'canAdmin'>; | |||
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 | |||
</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> |
@@ -75,7 +75,7 @@ export class CreateProjectPage extends React.PureComponent<Props, State> { | |||
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<Props, State> { | |||
default: { | |||
const almCounts = { | |||
[AlmKeys.Azure]: azureSettings.length, | |||
[AlmKeys.Bitbucket]: bitbucketSettings.length, | |||
[AlmKeys.BitbucketServer]: bitbucketSettings.length, | |||
[AlmKeys.GitHub]: githubSettings.length, | |||
[AlmKeys.GitLab]: gitlabSettings.length | |||
}; |
@@ -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 | |||
</p> | |||
<ul> | |||
{alm === AlmKeys.Bitbucket && ( | |||
{alm === AlmKeys.BitbucketServer && ( | |||
<> | |||
<li> | |||
<FormattedMessage |
@@ -163,7 +163,7 @@ function shallowRender(props: Partial<BitbucketProjectCreate['props']> = {}) { | |||
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()} |
@@ -48,7 +48,7 @@ it('should render correctly', () => { | |||
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()} |
@@ -30,11 +30,14 @@ import { CreateProjectModes } from '../types'; | |||
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'); | |||
}); | |||
@@ -71,7 +74,7 @@ function shallowRender( | |||
) { | |||
const almCounts = { | |||
[AlmKeys.Azure]: 0, | |||
[AlmKeys.Bitbucket]: 1, | |||
[AlmKeys.BitbucketServer]: 1, | |||
[AlmKeys.GitHub]: 0, | |||
[AlmKeys.GitLab]: 0, | |||
...almCountOverrides |
@@ -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); |
@@ -71,7 +71,7 @@ function shallowRender(props: Partial<PersonalAccessTokenFormProps> = {}) { | |||
return shallow<PersonalAccessTokenFormProps>( | |||
<PersonalAccessTokenForm | |||
almSetting={mockAlmSettingsInstance({ | |||
alm: AlmKeys.Bitbucket, | |||
alm: AlmKeys.BitbucketServer, | |||
url: 'http://www.example.com' | |||
})} | |||
onPersonalAccessTokenCreate={jest.fn()} |
@@ -24,10 +24,12 @@ import WrongBindingCountAlert, { WrongBindingCountAlertProps } from '../WrongBin | |||
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} /> | |||
); | |||
} |
@@ -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 | |||
}; |
@@ -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' } | |||
]); |
@@ -28,5 +28,5 @@ it('should render correctly', () => { | |||
}); | |||
function shallowRender(overrides: Partial<ProjectCreationMenuItemProps> = {}) { | |||
return shallow(<ProjectCreationMenuItem alm={AlmKeys.Bitbucket} {...overrides} />); | |||
return shallow(<ProjectCreationMenuItem alm={AlmKeys.BitbucketServer} {...overrides} />); | |||
} |
@@ -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 && ( | |||
<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> | |||
)} | |||
@@ -58,10 +58,12 @@ export default function AlmBindingDefinitionFormModalRenderer( | |||
<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> |
@@ -62,7 +62,8 @@ export class AlmIntegration extends React.PureComponent<Props, State> { | |||
currentAlm: props.location.query.alm || AlmKeys.GitHub, | |||
definitions: { | |||
[AlmKeys.Azure]: [], | |||
[AlmKeys.Bitbucket]: [], | |||
[AlmKeys.BitbucketServer]: [], | |||
[AlmKeys.BitbucketCloud]: [], | |||
[AlmKeys.GitHub]: [], | |||
[AlmKeys.GitLab]: [] | |||
}, |
@@ -68,7 +68,7 @@ const tabs = [ | |||
requiresBranchesEnabled: false | |||
}, | |||
{ | |||
key: AlmKeys.Bitbucket, | |||
key: AlmKeys.BitbucketServer, | |||
label: ( | |||
<> | |||
<img | |||
@@ -77,7 +77,7 @@ const tabs = [ | |||
height={16} | |||
src={`${getBaseUrl()}/images/alm/bitbucket.svg`} | |||
/> | |||
Bitbucket Server | |||
Bitbucket | |||
</> | |||
), | |||
requiresBranchesEnabled: false | |||
@@ -156,10 +156,10 @@ export default function AlmIntegrationRenderer(props: AlmIntegrationRendererProp | |||
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} |
@@ -67,10 +67,7 @@ export default class AlmTab<B extends AlmBindingDefinition> 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<B extends AlmBindingDefinition> 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) |
@@ -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<B extends AlmBindingDefinition>( | |||
</div> | |||
{definitions.map(def => ( | |||
<AlmBindingDefinitionBox | |||
alm={alm} | |||
alm={isBitbucketCloudBindingDefinition(def) ? AlmKeys.BitbucketCloud : alm} | |||
branchesEnabled={branchesEnabled} | |||
definition={def} | |||
key={def.key} |
@@ -19,58 +19,138 @@ | |||
*/ | |||
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> | |||
); | |||
} |
@@ -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<BitbucketBindingDefinition | BitbucketCloudBindingDefinition>; | |||
definitionStatus: T.Dict<AlmSettingsBindingStatus>; | |||
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 ( | |||
<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> | |||
); | |||
); | |||
} | |||
} |
@@ -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<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> | |||
); | |||
} |
@@ -74,7 +74,7 @@ export default function GithubForm(props: GithubFormProps) { | |||
value={formData.appId} | |||
/> | |||
<AlmBindingDefinitionFormField | |||
id="client_id" | |||
id="client_id.github" | |||
maxLength={80} | |||
onFieldChange={onFieldChange} | |||
propKey="clientId" | |||
@@ -82,7 +82,7 @@ export default function GithubForm(props: GithubFormProps) { | |||
value={formData.clientId} | |||
/> | |||
<AlmBindingDefinitionFormField | |||
id="client_secret" | |||
id="client_secret.github" | |||
maxLength={80} | |||
onFieldChange={onFieldChange} | |||
overwriteOnly={Boolean(formData.key)} |
@@ -22,7 +22,9 @@ import * as React from 'react'; | |||
import { | |||
mockAlmSettingsBindingStatus, | |||
mockAzureBindingDefinition, | |||
mockGithubBindingDefinition | |||
mockBitbucketCloudBindingDefinition, | |||
mockGithubBindingDefinition, | |||
mockGitlabBindingDefinition | |||
} from '../../../../../helpers/mocks/alm-settings'; | |||
import { AlmKeys, AlmSettingsBindingStatusType } from '../../../../../types/alm-settings'; | |||
import AlmBindingDefinitionBox, { AlmBindingDefinitionBoxProps } from '../AlmBindingDefinitionBox'; | |||
@@ -67,6 +69,26 @@ it('should render correctly', () => { | |||
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, |
@@ -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' }] | |||
}; |
@@ -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<AlmIntegrationRendererProps> = {}) { | |||
<AlmIntegrationRenderer | |||
branchesEnabled={true} | |||
currentAlm={AlmKeys.GitHub} | |||
definitions={{ azure: [], bitbucket: [], github: [], gitlab: [] }} | |||
definitions={{ azure: [], bitbucket: [], bitbucketcloud: [], github: [], gitlab: [] }} | |||
definitionStatus={{}} | |||
loadingAlmDefinitions={false} | |||
loadingProjectCount={false} |
@@ -21,6 +21,7 @@ import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { | |||
mockAzureBindingDefinition, | |||
mockBitbucketCloudBindingDefinition, | |||
mockGithubBindingDefinition | |||
} from '../../../../../helpers/mocks/alm-settings'; | |||
import { | |||
@@ -60,7 +61,7 @@ it('should render correctly with validation', () => { | |||
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<AlmTabRendererProps<AzureBindingDefinition>> = {}) { |
@@ -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<BitbucketFormProps> = {}) { | |||
return shallow( | |||
<BitbucketForm | |||
formData={{ key: '', personalAccessToken: '', url: '' }} | |||
isCreating={false} | |||
onFieldChange={jest.fn()} | |||
onSelectVariant={jest.fn()} | |||
variant={AlmKeys.BitbucketServer} | |||
{...props} | |||
/> | |||
); |
@@ -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<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()]} |
@@ -0,0 +1,63 @@ | |||
/* | |||
* 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} | |||
/> | |||
); | |||
} |
@@ -283,6 +283,152 @@ exports[`should render correctly: success 1`] = ` | |||
</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" |
@@ -28,6 +28,9 @@ exports[`should render correctly 1`] = ` | |||
> | |||
<Component /> | |||
</div> | |||
<div | |||
className="flex-1" | |||
/> | |||
</div> | |||
</div> | |||
<div | |||
@@ -86,6 +89,9 @@ exports[`should render correctly: second instance 1`] = ` | |||
> | |||
<Component /> | |||
</div> | |||
<div | |||
className="flex-1" | |||
/> | |||
</div> | |||
</div> | |||
<div |
@@ -9,6 +9,7 @@ exports[`should render correctly 1`] = ` | |||
Object { | |||
"azure": Array [], | |||
"bitbucket": Array [], | |||
"bitbucketcloud": Array [], | |||
"github": Array [], | |||
"gitlab": Array [], | |||
} |
@@ -43,7 +43,7 @@ exports[`should render correctly: azure 1`] = ` | |||
height={16} | |||
src="/images/alm/bitbucket.svg" | |||
/> | |||
Bitbucket Server | |||
Bitbucket | |||
</React.Fragment>, | |||
"requiresBranchesEnabled": false, | |||
}, | |||
@@ -133,7 +133,7 @@ exports[`should render correctly: bitbucket 1`] = ` | |||
height={16} | |||
src="/images/alm/bitbucket.svg" | |||
/> | |||
Bitbucket Server | |||
Bitbucket | |||
</React.Fragment>, | |||
"requiresBranchesEnabled": false, | |||
}, | |||
@@ -180,6 +180,85 @@ exports[`should render correctly: bitbucket 1`] = ` | |||
</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 | |||
@@ -223,7 +302,7 @@ exports[`should render correctly: default 1`] = ` | |||
height={16} | |||
src="/images/alm/bitbucket.svg" | |||
/> | |||
Bitbucket Server | |||
Bitbucket | |||
</React.Fragment>, | |||
"requiresBranchesEnabled": false, | |||
}, | |||
@@ -313,7 +392,7 @@ exports[`should render correctly: delete modal 1`] = ` | |||
height={16} | |||
src="/images/alm/bitbucket.svg" | |||
/> | |||
Bitbucket Server | |||
Bitbucket | |||
</React.Fragment>, | |||
"requiresBranchesEnabled": false, | |||
}, | |||
@@ -408,7 +487,7 @@ exports[`should render correctly: gitlab 1`] = ` | |||
height={16} | |||
src="/images/alm/bitbucket.svg" | |||
/> | |||
Bitbucket Server | |||
Bitbucket | |||
</React.Fragment>, | |||
"requiresBranchesEnabled": false, | |||
}, | |||
@@ -498,7 +577,7 @@ exports[`should render correctly: loading 1`] = ` | |||
height={16} | |||
src="/images/alm/bitbucket.svg" | |||
/> | |||
Bitbucket Server | |||
Bitbucket | |||
</React.Fragment>, | |||
"requiresBranchesEnabled": false, | |||
}, |
@@ -4,13 +4,6 @@ exports[`should render correctly 1`] = ` | |||
<AlmTabRenderer | |||
alm="azure" | |||
branchesEnabled={true} | |||
defaultBinding={ | |||
Object { | |||
"key": "", | |||
"personalAccessToken": "", | |||
"url": undefined, | |||
} | |||
} | |||
definitionStatus={Object {}} | |||
definitions={ | |||
Array [ |
@@ -350,15 +350,20 @@ exports[`should render correctly for single-ALM binding 3`] = ` | |||
</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" | |||
@@ -373,10 +378,8 @@ exports[`should render correctly with validation 1`] = ` | |||
</Button> | |||
</Connect(withAppState(CreationTooltip))> | |||
</div> | |||
<AlmBindingDefinitionBox | |||
alm="github" | |||
branchesEnabled={true} | |||
definition={ | |||
<AlmBindingDefinitionForm | |||
bindingDefinition={ | |||
Object { | |||
"appId": "123456", | |||
"clientId": "client1", | |||
@@ -386,30 +389,26 @@ exports[`should render correctly with validation 1`] = ` | |||
"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" | |||
@@ -424,6 +423,25 @@ exports[`should render correctly with validation: create a first 1`] = ` | |||
</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 { | |||
@@ -436,7 +454,7 @@ exports[`should render correctly with validation: create a first 1`] = ` | |||
} | |||
} | |||
help={<div />} | |||
isSecondInstance={false} | |||
isSecondInstance={true} | |||
onCancel={[MockFunction]} | |||
onSubmit={[MockFunction]} | |||
> | |||
@@ -446,7 +464,7 @@ exports[`should render correctly with validation: create a first 1`] = ` | |||
</div> | |||
`; | |||
exports[`should render correctly with validation: create a second 1`] = ` | |||
exports[`should render correctly with validation: default 1`] = ` | |||
<div | |||
className="big-padded" | |||
> | |||
@@ -488,24 +506,6 @@ exports[`should render correctly with validation: create a second 1`] = ` | |||
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> | |||
`; | |||
@@ -541,3 +541,47 @@ exports[`should render correctly with validation: empty 1`] = ` | |||
</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> | |||
`; |
@@ -1,81 +1,255 @@ | |||
// 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> | |||
`; |
@@ -1,72 +1,30 @@ | |||
// 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} | |||
/> | |||
`; |
@@ -0,0 +1,143 @@ | |||
// 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> | |||
`; |
@@ -41,14 +41,14 @@ exports[`should render correctly 1`] = ` | |||
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} | |||
@@ -107,14 +107,14 @@ exports[`should render correctly 2`] = ` | |||
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} |
@@ -19,4 +19,10 @@ | |||
*/ | |||
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 | |||
]; |
@@ -182,7 +182,7 @@ export default function AlmSpecificForm(props: AlmSpecificFormProps) { | |||
{renderMonoRepoFieldWithDocLink(ALM_DOCUMENTATION_PATHS[AlmKeys.Azure])} | |||
</> | |||
); | |||
case AlmKeys.Bitbucket: | |||
case AlmKeys.BitbucketServer: | |||
return ( | |||
<> | |||
{renderField({ |
@@ -65,7 +65,8 @@ const REQUIRED_FIELDS_BY_ALM: { | |||
[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'] | |||
}; | |||
@@ -180,7 +181,7 @@ export class PRDecorationBinding extends React.PureComponent<Props & StateProps, | |||
monorepo | |||
}); | |||
} | |||
case AlmKeys.Bitbucket: { | |||
case AlmKeys.BitbucketServer: { | |||
if (!repository || !slug) { | |||
return Promise.reject(); | |||
} |
@@ -25,8 +25,8 @@ import AlmSpecificForm, { AlmSpecificFormProps } from '../AlmSpecificForm'; | |||
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], |
@@ -93,7 +93,7 @@ describe('handleSubmit', () => { | |||
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 } | |||
] |
@@ -59,7 +59,7 @@ it('should render multiple instances correctly', () => { | |||
url: urls[0] | |||
}, | |||
{ | |||
alm: AlmKeys.Bitbucket, | |||
alm: AlmKeys.BitbucketServer, | |||
key: 'i3', | |||
url: urls[1] | |||
}, |
@@ -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 ( | |||
<> |
@@ -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); |
@@ -46,7 +46,7 @@ function renderAlmSpecificInstructions(props: WebhookStepProps) { | |||
const { almBinding, branchesEnabled, projectBinding } = props; | |||
switch (projectBinding.alm) { | |||
case AlmKeys.Bitbucket: | |||
case AlmKeys.BitbucketServer: | |||
return ( | |||
<WebhookStepBitbucket | |||
almBinding={isBitbucketBindingDefinition(almBinding) ? almBinding : undefined} |
@@ -36,7 +36,7 @@ it('should render correctly', () => { | |||
function shallowRender(props: Partial<PreRequisitesStepProps> = {}) { | |||
return shallow<PreRequisitesStepProps>( | |||
<PreRequisitesStep | |||
alm={AlmKeys.Bitbucket} | |||
alm={AlmKeys.BitbucketServer} | |||
branchesEnabled={true} | |||
onChangeSkipNextTime={jest.fn()} | |||
onDone={jest.fn()} |
@@ -38,7 +38,11 @@ it.each([ | |||
mockAzureBindingDefinition(), | |||
mockProjectAlmBindingResponse({ alm: AlmKeys.Azure }) | |||
], | |||
[AlmKeys.Bitbucket, mockBitbucketBindingDefinition(), mockProjectBitbucketBindingResponse()], | |||
[ | |||
AlmKeys.BitbucketServer, | |||
mockBitbucketBindingDefinition(), | |||
mockProjectBitbucketBindingResponse() | |||
], | |||
[AlmKeys.GitHub, mockGithubBindingDefinition(), mockProjectGithubBindingResponse()], | |||
[ | |||
AlmKeys.GitLab, |
@@ -65,7 +65,15 @@ export const PROJECT_KEY_MAX_LEN = 400; | |||
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 | |||
]; |
@@ -24,6 +24,7 @@ import { | |||
AlmSettingsInstance, | |||
AzureBindingDefinition, | |||
BitbucketBindingDefinition, | |||
BitbucketCloudBindingDefinition, | |||
GithubBindingDefinition, | |||
GitlabBindingDefinition, | |||
ProjectAlmBindingResponse, | |||
@@ -64,6 +65,18 @@ export function mockBitbucketBindingDefinition( | |||
}; | |||
} | |||
export function mockBitbucketCloudBindingDefinition( | |||
overrides: Partial<BitbucketCloudBindingDefinition> = {} | |||
): BitbucketCloudBindingDefinition { | |||
return { | |||
key: 'key', | |||
clientId: 'client1', | |||
clientSecret: '**clientsecret**', | |||
workspace: 'workspace', | |||
...overrides | |||
}; | |||
} | |||
export function mockGithubBindingDefinition( | |||
overrides: Partial<GithubBindingDefinition> = {} | |||
): GithubBindingDefinition { | |||
@@ -102,7 +115,7 @@ export function mockProjectBitbucketBindingResponse( | |||
overrides: Partial<ProjectBitbucketBindingResponse> = {} | |||
): ProjectBitbucketBindingResponse { | |||
return { | |||
alm: AlmKeys.Bitbucket, | |||
alm: AlmKeys.BitbucketServer, | |||
key: 'foo', | |||
repository: 'PROJECT_KEY', | |||
slug: 'repo-slug', |
@@ -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; | |||
} |
@@ -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)". |