Explorar el Código

SONAR-14393 Add admin form for Bitbucket Cloud integration

tags/8.7.0.41497
Wouter Admiraal hace 3 años
padre
commit
eaa3c93177
Se han modificado 56 ficheros con 1554 adiciones y 397 borrados
  1. 11
    0
      server/sonar-web/src/main/js/api/alm-settings.ts
  2. 1
    1
      server/sonar-web/src/main/js/apps/create/project/BitbucketProjectCreateRenderer.tsx
  3. 8
    3
      server/sonar-web/src/main/js/apps/create/project/CreateProjectModeSelection.tsx
  4. 2
    2
      server/sonar-web/src/main/js/apps/create/project/CreateProjectPage.tsx
  5. 2
    2
      server/sonar-web/src/main/js/apps/create/project/PersonalAccessTokenForm.tsx
  6. 1
    1
      server/sonar-web/src/main/js/apps/create/project/__tests__/BitbucketProjectCreate-test.tsx
  7. 1
    1
      server/sonar-web/src/main/js/apps/create/project/__tests__/BitbucketProjectCreateRenderer-test.tsx
  8. 6
    3
      server/sonar-web/src/main/js/apps/create/project/__tests__/CreateProjectModeSelection-test.tsx
  9. 1
    1
      server/sonar-web/src/main/js/apps/create/project/__tests__/CreateProjectPage-test.tsx
  10. 1
    1
      server/sonar-web/src/main/js/apps/create/project/__tests__/PersonalAccessTokenForm-test.tsx
  11. 4
    2
      server/sonar-web/src/main/js/apps/create/project/__tests__/WrongBindingCountAlert-test.tsx
  12. 3
    5
      server/sonar-web/src/main/js/apps/projects/components/ProjectCreationMenu.tsx
  13. 2
    2
      server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCreationMenu-test.tsx
  14. 1
    1
      server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCreationMenuItem-test.tsx
  15. 18
    13
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionBox.tsx
  16. 3
    1
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionFormModalRenderer.tsx
  17. 2
    1
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmIntegration.tsx
  18. 4
    4
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmIntegrationRenderer.tsx
  19. 6
    5
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmTab.tsx
  20. 3
    2
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmTabRenderer.tsx
  21. 122
    42
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketForm.tsx
  22. 139
    51
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketTab.tsx
  23. 140
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketTabRenderer.tsx
  24. 2
    2
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/GithubForm.tsx
  25. 23
    1
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionBox-test.tsx
  26. 8
    4
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmIntegration-test.tsx
  27. 3
    2
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmIntegrationRenderer-test.tsx
  28. 9
    1
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmTabRenderer-test.tsx
  29. 25
    3
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/BitbucketForm-test.tsx
  30. 112
    4
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/BitbucketTab-test.tsx
  31. 63
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/BitbucketTabRenderer-test.tsx
  32. 146
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionBox-test.tsx.snap
  33. 6
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionFormModalRenderer-test.tsx.snap
  34. 1
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmIntegration-test.tsx.snap
  35. 85
    6
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmIntegrationRenderer-test.tsx.snap
  36. 0
    7
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmTab-test.tsx.snap
  37. 83
    39
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmTabRenderer-test.tsx.snap
  38. 246
    72
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketForm-test.tsx.snap
  39. 25
    67
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketTab-test.tsx.snap
  40. 143
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketTabRenderer-test.tsx.snap
  41. 4
    4
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GithubForm-test.tsx.snap
  42. 7
    1
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/utils.ts
  43. 1
    1
      server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/AlmSpecificForm.tsx
  44. 3
    2
      server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/PRDecorationBinding.tsx
  45. 2
    2
      server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/AlmSpecificForm-test.tsx
  46. 5
    5
      server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/PRDecorationBinding-test.tsx
  47. 1
    1
      server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/PRDecorationBindingRenderer-test.tsx
  48. 1
    1
      server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx
  49. 3
    3
      server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelection-test.tsx
  50. 1
    1
      server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStep.tsx
  51. 1
    1
      server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/PreRequisitesStep-test.tsx
  52. 5
    1
      server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/WebhookStep-test.tsx
  53. 9
    1
      server/sonar-web/src/main/js/helpers/constants.ts
  54. 14
    1
      server/sonar-web/src/main/js/helpers/mocks/alm-settings.ts
  55. 22
    15
      server/sonar-web/src/main/js/types/alm-settings.ts
  56. 14
    5
      sonar-core/src/main/resources/org/sonar/l10n/core.properties

+ 11
- 0
server/sonar-web/src/main/js/api/alm-settings.ts Ver fichero

@@ -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);
}

+ 1
- 1
server/sonar-web/src/main/js/apps/create/project/BitbucketProjectCreateRenderer.tsx Ver fichero

@@ -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 &&

+ 8
- 3
server/sonar-web/src/main/js/apps/create/project/CreateProjectModeSelection.tsx Ver fichero

@@ -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>

+ 2
- 2
server/sonar-web/src/main/js/apps/create/project/CreateProjectPage.tsx Ver fichero

@@ -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
};

+ 2
- 2
server/sonar-web/src/main/js/apps/create/project/PersonalAccessTokenForm.tsx Ver fichero

@@ -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

+ 1
- 1
server/sonar-web/src/main/js/apps/create/project/__tests__/BitbucketProjectCreate-test.tsx Ver fichero

@@ -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()}

+ 1
- 1
server/sonar-web/src/main/js/apps/create/project/__tests__/BitbucketProjectCreateRenderer-test.tsx Ver fichero

@@ -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()}

+ 6
- 3
server/sonar-web/src/main/js/apps/create/project/__tests__/CreateProjectModeSelection-test.tsx Ver fichero

@@ -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

+ 1
- 1
server/sonar-web/src/main/js/apps/create/project/__tests__/CreateProjectPage-test.tsx Ver fichero

@@ -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);

+ 1
- 1
server/sonar-web/src/main/js/apps/create/project/__tests__/PersonalAccessTokenForm-test.tsx Ver fichero

@@ -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()}

+ 4
- 2
server/sonar-web/src/main/js/apps/create/project/__tests__/WrongBindingCountAlert-test.tsx Ver fichero

@@ -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} />
);
}

+ 3
- 5
server/sonar-web/src/main/js/apps/projects/components/ProjectCreationMenu.tsx Ver fichero

@@ -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
};

+ 2
- 2
server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCreationMenu-test.tsx Ver fichero

@@ -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' }
]);

+ 1
- 1
server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCreationMenuItem-test.tsx Ver fichero

@@ -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} />);
}

+ 18
- 13
server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionBox.tsx Ver fichero

@@ -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>
)}


+ 3
- 1
server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionFormModalRenderer.tsx Ver fichero

@@ -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>

+ 2
- 1
server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmIntegration.tsx Ver fichero

@@ -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]: []
},

+ 4
- 4
server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmIntegrationRenderer.tsx Ver fichero

@@ -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}

+ 6
- 5
server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmTab.tsx Ver fichero

@@ -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)

+ 3
- 2
server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmTabRenderer.tsx Ver fichero

@@ -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}

+ 122
- 42
server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketForm.tsx Ver fichero

@@ -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>
);
}

+ 139
- 51
server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketTab.tsx Ver fichero

@@ -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>
);
);
}
}

+ 140
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketTabRenderer.tsx Ver fichero

@@ -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>
);
}

+ 2
- 2
server/sonar-web/src/main/js/apps/settings/components/almIntegration/GithubForm.tsx Ver fichero

@@ -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)}

+ 23
- 1
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionBox-test.tsx Ver fichero

@@ -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,

+ 8
- 4
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmIntegration-test.tsx Ver fichero

@@ -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' }]
};

+ 3
- 2
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmIntegrationRenderer-test.tsx Ver fichero

@@ -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}

+ 9
- 1
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmTabRenderer-test.tsx Ver fichero

@@ -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>> = {}) {

+ 25
- 3
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/BitbucketForm-test.tsx Ver fichero

@@ -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}
/>
);

+ 112
- 4
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/BitbucketTab-test.tsx Ver fichero

@@ -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()]}

+ 63
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/BitbucketTabRenderer-test.tsx Ver fichero

@@ -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}
/>
);
}

+ 146
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionBox-test.tsx.snap Ver fichero

@@ -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"

+ 6
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionFormModalRenderer-test.tsx.snap Ver fichero

@@ -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

+ 1
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmIntegration-test.tsx.snap Ver fichero

@@ -9,6 +9,7 @@ exports[`should render correctly 1`] = `
Object {
"azure": Array [],
"bitbucket": Array [],
"bitbucketcloud": Array [],
"github": Array [],
"gitlab": Array [],
}

+ 85
- 6
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmIntegrationRenderer-test.tsx.snap Ver fichero

@@ -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,
},

+ 0
- 7
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmTab-test.tsx.snap Ver fichero

@@ -4,13 +4,6 @@ exports[`should render correctly 1`] = `
<AlmTabRenderer
alm="azure"
branchesEnabled={true}
defaultBinding={
Object {
"key": "",
"personalAccessToken": "",
"url": undefined,
}
}
definitionStatus={Object {}}
definitions={
Array [

+ 83
- 39
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmTabRenderer-test.tsx.snap Ver fichero

@@ -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>
`;

+ 246
- 72
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketForm-test.tsx.snap Ver fichero

@@ -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>
`;

+ 25
- 67
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketTab-test.tsx.snap Ver fichero

@@ -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}
/>
`;

+ 143
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketTabRenderer-test.tsx.snap Ver fichero

@@ -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>
`;

+ 4
- 4
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GithubForm-test.tsx.snap Ver fichero

@@ -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}

+ 7
- 1
server/sonar-web/src/main/js/apps/settings/components/almIntegration/utils.ts Ver fichero

@@ -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
];

+ 1
- 1
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/AlmSpecificForm.tsx Ver fichero

@@ -182,7 +182,7 @@ export default function AlmSpecificForm(props: AlmSpecificFormProps) {
{renderMonoRepoFieldWithDocLink(ALM_DOCUMENTATION_PATHS[AlmKeys.Azure])}
</>
);
case AlmKeys.Bitbucket:
case AlmKeys.BitbucketServer:
return (
<>
{renderField({

+ 3
- 2
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/PRDecorationBinding.tsx Ver fichero

@@ -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();
}

+ 2
- 2
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/AlmSpecificForm-test.tsx Ver fichero

@@ -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],

+ 5
- 5
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/PRDecorationBinding-test.tsx Ver fichero

@@ -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 }
]

+ 1
- 1
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/PRDecorationBindingRenderer-test.tsx Ver fichero

@@ -59,7 +59,7 @@ it('should render multiple instances correctly', () => {
url: urls[0]
},
{
alm: AlmKeys.Bitbucket,
alm: AlmKeys.BitbucketServer,
key: 'i3',
url: urls[1]
},

+ 1
- 1
server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx Ver fichero

@@ -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 (
<>

+ 3
- 3
server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelection-test.tsx Ver fichero

@@ -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);

+ 1
- 1
server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStep.tsx Ver fichero

@@ -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}

+ 1
- 1
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/PreRequisitesStep-test.tsx Ver fichero

@@ -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()}

+ 5
- 1
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/WebhookStep-test.tsx Ver fichero

@@ -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,

+ 9
- 1
server/sonar-web/src/main/js/helpers/constants.ts Ver fichero

@@ -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
];

+ 14
- 1
server/sonar-web/src/main/js/helpers/mocks/alm-settings.ts Ver fichero

@@ -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',

+ 22
- 15
server/sonar-web/src/main/js/types/alm-settings.ts Ver fichero

@@ -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;
}

+ 14
- 5
sonar-core/src/main/resources/org/sonar/l10n/core.properties Ver fichero

@@ -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)".

Cargando…
Cancelar
Guardar