Browse Source

SONAR-14364 Enable project import in CE

tags/8.7.0.41497
Jeremy Davis 3 years ago
parent
commit
18a6205853
34 changed files with 565 additions and 363 deletions
  1. 4
    12
      server/sonar-web/src/main/js/apps/create/project/CreateProjectPage.tsx
  2. 1
    6
      server/sonar-web/src/main/js/apps/create/project/__tests__/CreateProjectPage-test.tsx
  3. 0
    22
      server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/CreateProjectPage-test.tsx.snap
  4. 4
    9
      server/sonar-web/src/main/js/apps/projects/components/ProjectCreationMenu.tsx
  5. 1
    8
      server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCreationMenu-test.tsx
  6. 3
    3
      server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageHeader-test.tsx.snap
  7. 58
    10
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionBox.tsx
  8. 0
    8
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmIntegration.tsx
  9. 8
    4
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmIntegrationRenderer.tsx
  10. 3
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmTab.tsx
  11. 6
    25
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmTabRenderer.tsx
  12. 3
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/AzureTab.tsx
  13. 3
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketTab.tsx
  14. 75
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/CreationTooltip.tsx
  15. 35
    38
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/GithubTab.tsx
  16. 29
    32
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/GitlabTab.tsx
  17. 11
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionBox-test.tsx
  18. 1
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmTab-test.tsx
  19. 1
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmTabRenderer-test.tsx
  20. 1
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AzureTab-test.tsx
  21. 1
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/BitbucketTab-test.tsx
  22. 42
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/CreationTooltip-test.tsx
  23. 0
    1
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/GithubTab-test.tsx
  24. 0
    1
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/GitlabTab-test.tsx
  25. 141
    26
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionBox-test.tsx.snap
  26. 26
    12
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmIntegrationRenderer-test.tsx.snap
  27. 1
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmTab-test.tsx.snap
  28. 58
    116
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmTabRenderer-test.tsx.snap
  29. 1
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AzureTab-test.tsx.snap
  30. 1
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketTab-test.tsx.snap
  31. 40
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/CreationTooltip-test.tsx.snap
  32. 1
    15
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GithubTab-test.tsx.snap
  33. 3
    15
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GitlabTab-test.tsx.snap
  34. 3
    0
      sonar-core/src/main/resources/org/sonar/l10n/core.properties

+ 4
- 12
server/sonar-web/src/main/js/apps/create/project/CreateProjectPage.tsx View File

import { CreateProjectModes } from './types'; import { CreateProjectModes } from './types';


interface Props extends Pick<WithRouterProps, 'router' | 'location'> { interface Props extends Pick<WithRouterProps, 'router' | 'location'> {
appState: Pick<T.AppState, 'branchesEnabled' | 'canAdmin'>;
appState: Pick<T.AppState, 'canAdmin'>;
currentUser: T.LoggedInUser; currentUser: T.LoggedInUser;
} }


}; };


componentDidMount() { componentDidMount() {
const {
appState: { branchesEnabled }
} = this.props;
this.mounted = true; this.mounted = true;
if (branchesEnabled) {
this.fetchAlmBindings();
}
this.fetchAlmBindings();
} }


componentWillUnmount() { componentWillUnmount() {
} }


render() { render() {
const {
appState: { branchesEnabled },
location
} = this.props;
const { location } = this.props;
const mode: CreateProjectModes | undefined = location.query?.mode; const mode: CreateProjectModes | undefined = location.query?.mode;


return ( return (
<Helmet title={translate('my_account.create_new.TRK')} titleTemplate="%s" /> <Helmet title={translate('my_account.create_new.TRK')} titleTemplate="%s" />
<A11ySkipTarget anchor="create_project_main" /> <A11ySkipTarget anchor="create_project_main" />
<div className="page page-limited huge-spacer-bottom position-relative" id="create-project"> <div className="page page-limited huge-spacer-bottom position-relative" id="create-project">
{this.renderForm(branchesEnabled ? mode : CreateProjectModes.Manual)}
{this.renderForm(mode)}
</div> </div>
</> </>
); );

+ 1
- 6
server/sonar-web/src/main/js/apps/create/project/__tests__/CreateProjectPage-test.tsx View File

expect(getAlmSettings).toBeCalled(); expect(getAlmSettings).toBeCalled();
}); });


it('should render correctly if no branch support', () => {
expect(shallowRender({ appState: { branchesEnabled: false } })).toMatchSnapshot();
expect(getAlmSettings).not.toBeCalled();
});

it('should render correctly if the manual method is selected', () => { it('should render correctly if the manual method is selected', () => {
expect( expect(
shallowRender({ shallowRender({
function shallowRender(props: Partial<CreateProjectPage['props']> = {}) { function shallowRender(props: Partial<CreateProjectPage['props']> = {}) {
return shallow<CreateProjectPage>( return shallow<CreateProjectPage>(
<CreateProjectPage <CreateProjectPage
appState={{ branchesEnabled: true }}
appState={{}}
currentUser={mockLoggedInUser()} currentUser={mockLoggedInUser()}
location={mockLocation()} location={mockLocation()}
router={mockRouter()} router={mockRouter()}

+ 0
- 22
server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/CreateProjectPage-test.tsx.snap View File

</Fragment> </Fragment>
`; `;


exports[`should render correctly if no branch support 1`] = `
<Fragment>
<Helmet
defer={true}
encodeSpecialCharacters={true}
title="my_account.create_new.TRK"
titleTemplate="%s"
/>
<A11ySkipTarget
anchor="create_project_main"
/>
<div
className="page page-limited huge-spacer-bottom position-relative"
id="create-project"
>
<ManualProjectCreate
onProjectCreate={[Function]}
/>
</div>
</Fragment>
`;

exports[`should render correctly if the Azure method is selected 1`] = ` exports[`should render correctly if the Azure method is selected 1`] = `
<Fragment> <Fragment>
<Helmet <Helmet

+ 4
- 9
server/sonar-web/src/main/js/apps/projects/components/ProjectCreationMenu.tsx View File

import DropdownIcon from 'sonar-ui-common/components/icons/DropdownIcon'; import DropdownIcon from 'sonar-ui-common/components/icons/DropdownIcon';
import { translate } from 'sonar-ui-common/helpers/l10n'; import { translate } from 'sonar-ui-common/helpers/l10n';
import { getAlmSettings } from '../../../api/alm-settings'; import { getAlmSettings } from '../../../api/alm-settings';
import { withAppState } from '../../../components/hoc/withAppState';
import { withCurrentUser } from '../../../components/hoc/withCurrentUser'; import { withCurrentUser } from '../../../components/hoc/withCurrentUser';
import { hasGlobalPermission } from '../../../helpers/users'; import { hasGlobalPermission } from '../../../helpers/users';
import { AlmKeys, AlmSettingsInstance } from '../../../types/alm-settings'; import { AlmKeys, AlmSettingsInstance } from '../../../types/alm-settings';
import ProjectCreationMenuItem from './ProjectCreationMenuItem'; import ProjectCreationMenuItem from './ProjectCreationMenuItem';


interface Props { interface Props {
appState: Pick<T.AppState, 'branchesEnabled'>;
className?: string; className?: string;
currentUser: T.LoggedInUser; currentUser: T.LoggedInUser;
} }
}; };


fetchAlmBindings = async () => { fetchAlmBindings = async () => {
const {
appState: { branchesEnabled },
currentUser
} = this.props;
const { currentUser } = this.props;
const canCreateProject = hasGlobalPermission(currentUser, PROJECT_CREATION_PERMISSION); const canCreateProject = hasGlobalPermission(currentUser, PROJECT_CREATION_PERMISSION);


// getAlmSettings requires branchesEnabled // getAlmSettings requires branchesEnabled
if (!canCreateProject || !branchesEnabled) {
if (!canCreateProject) {
return; return;
} }


const almSettings = await getAlmSettings();
const almSettings: AlmSettingsInstance[] = await getAlmSettings().catch(() => []);


// Import is only available if exactly one binding is configured // Import is only available if exactly one binding is configured
const boundAlms = IMPORT_COMPATIBLE_ALMS.filter(key => { const boundAlms = IMPORT_COMPATIBLE_ALMS.filter(key => {
} }
} }


export default withAppState(withCurrentUser(ProjectCreationMenu));
export default withCurrentUser(ProjectCreationMenu);

+ 1
- 8
server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCreationMenu-test.tsx View File

import * as React from 'react'; import * as React from 'react';
import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
import { getAlmSettings } from '../../../../api/alm-settings'; import { getAlmSettings } from '../../../../api/alm-settings';
import { mockAppState, mockLoggedInUser } from '../../../../helpers/testMocks';
import { mockLoggedInUser } from '../../../../helpers/testMocks';
import { AlmKeys } from '../../../../types/alm-settings'; import { AlmKeys } from '../../../../types/alm-settings';
import { ProjectCreationMenu } from '../ProjectCreationMenu'; import { ProjectCreationMenu } from '../ProjectCreationMenu';


expect(getAlmSettings).not.toBeCalled(); expect(getAlmSettings).not.toBeCalled();
}); });


it('should not fetch alm bindings if branches are not enabled', async () => {
const wrapper = shallowRender({ appState: mockAppState({ branchesEnabled: false }) });
await waitAndUpdate(wrapper);
expect(getAlmSettings).not.toBeCalled();
});

it('should filter alm bindings appropriately', async () => { it('should filter alm bindings appropriately', async () => {
(getAlmSettings as jest.Mock).mockResolvedValueOnce([ (getAlmSettings as jest.Mock).mockResolvedValueOnce([
{ alm: AlmKeys.Azure }, { alm: AlmKeys.Azure },
function shallowRender(overrides: Partial<ProjectCreationMenu['props']> = {}) { function shallowRender(overrides: Partial<ProjectCreationMenu['props']> = {}) {
return shallow<ProjectCreationMenu>( return shallow<ProjectCreationMenu>(
<ProjectCreationMenu <ProjectCreationMenu
appState={mockAppState({ branchesEnabled: true })}
currentUser={mockLoggedInUser({ permissions: { global: ['provisioning'] } })} currentUser={mockLoggedInUser({ permissions: { global: ['provisioning'] } })}
{...overrides} {...overrides}
/> />

+ 3
- 3
server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageHeader-test.tsx.snap View File

<div <div
className="display-flex-center" className="display-flex-center"
> >
<Connect(withAppState(Connect(withCurrentUser(ProjectCreationMenu))))
<Connect(withCurrentUser(ProjectCreationMenu))
className="little-spacer-right" className="little-spacer-right"
/> />
<Connect(withAppState(Connect(withCurrentUser(withRouter(ApplicationCreation))))) <Connect(withAppState(Connect(withCurrentUser(withRouter(ApplicationCreation)))))
<div <div
className="display-flex-center" className="display-flex-center"
> >
<Connect(withAppState(Connect(withCurrentUser(ProjectCreationMenu))))
<Connect(withCurrentUser(ProjectCreationMenu))
className="little-spacer-right" className="little-spacer-right"
/> />
<Connect(withAppState(Connect(withCurrentUser(withRouter(ApplicationCreation))))) <Connect(withAppState(Connect(withCurrentUser(withRouter(ApplicationCreation)))))
<div <div
className="display-flex-center" className="display-flex-center"
> >
<Connect(withAppState(Connect(withCurrentUser(ProjectCreationMenu))))
<Connect(withCurrentUser(ProjectCreationMenu))
className="little-spacer-right" className="little-spacer-right"
/> />
<Connect(withAppState(Connect(withCurrentUser(withRouter(ApplicationCreation))))) <Connect(withAppState(Connect(withCurrentUser(withRouter(ApplicationCreation)))))

+ 58
- 10
server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionBox.tsx View File

* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
import * as React from 'react'; import * as React from 'react';
import { FormattedMessage } from 'react-intl';
import { Button } from 'sonar-ui-common/components/controls/buttons'; import { Button } from 'sonar-ui-common/components/controls/buttons';
import HelpTooltip from 'sonar-ui-common/components/controls/HelpTooltip'; import HelpTooltip from 'sonar-ui-common/components/controls/HelpTooltip';
import Tooltip from 'sonar-ui-common/components/controls/Tooltip'; import Tooltip from 'sonar-ui-common/components/controls/Tooltip';
import EditIcon from 'sonar-ui-common/components/icons/EditIcon'; import EditIcon from 'sonar-ui-common/components/icons/EditIcon';
import { Alert } from 'sonar-ui-common/components/ui/Alert'; import { Alert } from 'sonar-ui-common/components/ui/Alert';
import { translate } from 'sonar-ui-common/helpers/l10n'; import { translate } from 'sonar-ui-common/helpers/l10n';
import { getEdition, getEditionUrl } from '../../../../helpers/editions';
import { import {
AlmBindingDefinition, AlmBindingDefinition,
AlmKeys, AlmKeys,
AlmSettingsBindingStatus, AlmSettingsBindingStatus,
AlmSettingsBindingStatusType AlmSettingsBindingStatusType
} from '../../../../types/alm-settings'; } from '../../../../types/alm-settings';
import { EditionKey } from '../../../../types/editions';


export interface AlmBindingDefinitionBoxProps { export interface AlmBindingDefinitionBoxProps {
alm: AlmKeys; alm: AlmKeys;
branchesEnabled: boolean;
definition: AlmBindingDefinition; definition: AlmBindingDefinition;
multipleDefinitions: boolean; multipleDefinitions: boolean;
onCheck: (definitionKey: string) => void; onCheck: (definitionKey: string) => void;
[AlmSettingsBindingStatusType.Success]: <AlertSuccessIcon className="spacer-left" /> [AlmSettingsBindingStatusType.Success]: <AlertSuccessIcon className="spacer-left" />
}; };


function getPRDecorationFeatureStatus(
branchesEnabled: boolean,
type: AlmSettingsBindingStatusType.Success | AlmSettingsBindingStatusType.Failure
) {
if (branchesEnabled) {
return STATUS_ICON[type];
}

return (
<div className="display-inline-flex-center">
<strong className="spacer-left">
{translate('settings.almintegration.feature.pr_decoration.disabled')}
</strong>
<HelpTooltip
className="little-spacer-left"
overlay={
<FormattedMessage
id="settings.almintegration.feature.pr_decoration.disabled.no_branches"
defaultMessage={translate(
'settings.almintegration.feature.pr_decoration.disabled.no_branches'
)}
values={{
link: (
<a
href={getEditionUrl(getEdition(EditionKey.developer), {
sourceEdition: EditionKey.community
})}
rel="noopener noreferrer"
target="_blank">
{translate(
'settings.almintegration.feature.pr_decoration.disabled.no_branches.link'
)}
</a>
)
}}
/>
}
/>
</div>
);
}

function getImportFeatureStatus( function getImportFeatureStatus(
definition: AlmBindingDefinition, definition: AlmBindingDefinition,
multipleDefinitions: boolean, multipleDefinitions: boolean,
/> />
</div> </div>
); );
} else if (!definition.url) {
}

if (!definition.url) {
return ( return (
<div className="display-inline-flex-center"> <div className="display-inline-flex-center">
<strong className="spacer-left"> <strong className="spacer-left">
/> />
</div> </div>
); );
} else {
return STATUS_ICON[type];
} }

return STATUS_ICON[type];
} }


export default function AlmBindingDefinitionBox(props: AlmBindingDefinitionBoxProps) { export default function AlmBindingDefinitionBox(props: AlmBindingDefinitionBoxProps) {
const { alm, definition, multipleDefinitions, status = DEFAULT_STATUS } = props;
const { alm, branchesEnabled, definition, multipleDefinitions, status = DEFAULT_STATUS } = props;


const importFeatureTitle = const importFeatureTitle =
alm === AlmKeys.GitLab alm === AlmKeys.GitLab
<> <>
{status.type !== AlmSettingsBindingStatusType.Warning && ( {status.type !== AlmSettingsBindingStatusType.Warning && (
<div className="display-flex-row spacer-bottom"> <div className="display-flex-row spacer-bottom">
<Tooltip overlay={importFeatureDescription}>
<div className="huge-spacer-right">
{importFeatureTitle}
{STATUS_ICON[status.type]}
</div>
</Tooltip>
<div className="huge-spacer-right">
<Tooltip overlay={importFeatureDescription}>
<span>{importFeatureTitle}</span>
</Tooltip>
{getPRDecorationFeatureStatus(branchesEnabled, status.type)}
</div>
<div> <div>
<Tooltip <Tooltip
overlay={translate( overlay={translate(

+ 0
- 8
server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmIntegration.tsx View File

}; };


fetchPullRequestDecorationSetting = () => { fetchPullRequestDecorationSetting = () => {
const {
appState: { branchesEnabled }
} = this.props;

if (!branchesEnabled) {
return Promise.resolve();
}

this.setState({ loadingAlmDefinitions: true }); this.setState({ loadingAlmDefinitions: true });
return getAlmDefinitions() return getAlmDefinitions()
.then(definitions => { .then(definitions => {

+ 8
- 4
server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmIntegrationRenderer.tsx View File

/> />
GitHub GitHub
</> </>
)
),
requiresBranchesEnabled: false
}, },
{ {
key: AlmKeys.Bitbucket, key: AlmKeys.Bitbucket,
Bitbucket Server Bitbucket Server
</> </>
), ),
requiresBranchesEnabled: true
requiresBranchesEnabled: false
}, },
{ {
key: AlmKeys.Azure, key: AlmKeys.Azure,
Azure DevOps Server Azure DevOps Server
</> </>
), ),
requiresBranchesEnabled: true
requiresBranchesEnabled: false
}, },
{ {
key: AlmKeys.GitLab, key: AlmKeys.GitLab,
/> />
GitLab GitLab
</> </>
)
),
requiresBranchesEnabled: false
} }
]; ];




{currentAlm === AlmKeys.Azure && ( {currentAlm === AlmKeys.Azure && (
<AzureTab <AzureTab
branchesEnabled={branchesEnabled}
definitions={definitions.azure} definitions={definitions.azure}
definitionStatus={definitionStatus} definitionStatus={definitionStatus}
loadingAlmDefinitions={loadingAlmDefinitions} loadingAlmDefinitions={loadingAlmDefinitions}
)} )}
{currentAlm === AlmKeys.Bitbucket && ( {currentAlm === AlmKeys.Bitbucket && (
<BitbucketTab <BitbucketTab
branchesEnabled={branchesEnabled}
definitions={definitions.bitbucket} definitions={definitions.bitbucket}
definitionStatus={definitionStatus} definitionStatus={definitionStatus}
loadingAlmDefinitions={loadingAlmDefinitions} loadingAlmDefinitions={loadingAlmDefinitions}

+ 3
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmTab.tsx View File



interface Props<B> { interface Props<B> {
alm: AlmKeys; alm: AlmKeys;
branchesEnabled: boolean;
createConfiguration: (data: B) => Promise<void>; createConfiguration: (data: B) => Promise<void>;
defaultBinding: B; defaultBinding: B;
definitions: B[]; definitions: B[];
render() { render() {
const { const {
alm, alm,
branchesEnabled,
defaultBinding, defaultBinding,
definitions, definitions,
definitionStatus, definitionStatus,
return ( return (
<AlmTabRenderer <AlmTabRenderer
alm={alm} alm={alm}
branchesEnabled={branchesEnabled}
defaultBinding={defaultBinding} defaultBinding={defaultBinding}
definitions={definitions} definitions={definitions}
definitionStatus={definitionStatus} definitionStatus={definitionStatus}

+ 6
- 25
server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmTabRenderer.tsx View File

* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
import * as React from 'react'; import * as React from 'react';
import { FormattedMessage } from 'react-intl';
import { Button } from 'sonar-ui-common/components/controls/buttons'; import { Button } from 'sonar-ui-common/components/controls/buttons';
import Tooltip from 'sonar-ui-common/components/controls/Tooltip';
import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner'; import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
import { translate } from 'sonar-ui-common/helpers/l10n'; import { translate } from 'sonar-ui-common/helpers/l10n';
import { getEdition, getEditionUrl } from '../../../../helpers/editions';
import { import {
AlmBindingDefinition, AlmBindingDefinition,
AlmKeys, AlmKeys,
AlmSettingsBindingStatus AlmSettingsBindingStatus
} from '../../../../types/alm-settings'; } from '../../../../types/alm-settings';
import { EditionKey } from '../../../../types/editions';
import AlmBindingDefinitionBox from './AlmBindingDefinitionBox'; import AlmBindingDefinitionBox from './AlmBindingDefinitionBox';
import AlmBindingDefinitionForm, { import AlmBindingDefinitionForm, {
AlmBindingDefinitionFormChildrenProps AlmBindingDefinitionFormChildrenProps
} from './AlmBindingDefinitionForm'; } from './AlmBindingDefinitionForm';
import CreationTooltip from './CreationTooltip';


export interface AlmTabRendererProps<B> { export interface AlmTabRendererProps<B> {
alm: AlmKeys; alm: AlmKeys;
branchesEnabled: boolean;
definitionStatus: T.Dict<AlmSettingsBindingStatus>; definitionStatus: T.Dict<AlmSettingsBindingStatus>;
editedDefinition?: B; editedDefinition?: B;
defaultBinding: B; defaultBinding: B;
) { ) {
const { const {
alm, alm,
branchesEnabled,
definitions, definitions,
definitionStatus, definitionStatus,
editedDefinition, editedDefinition,
} = props; } = props;


const preventCreation = loadingProjectCount || (!multipleAlmEnabled && definitions.length > 0); const preventCreation = loadingProjectCount || (!multipleAlmEnabled && definitions.length > 0);
const creationTooltip = preventCreation ? (
<FormattedMessage
id="settings.almintegration.create.tooltip"
defaultMessage={translate('settings.almintegration.create.tooltip')}
values={{
link: (
<a
href={getEditionUrl(getEdition(EditionKey.enterprise), {
sourceEdition: EditionKey.developer
})}
rel="noopener noreferrer"
target="_blank">
{translate('settings.almintegration.create.tooltip.link')}
</a>
),
alm: translate('alm', alm)
}}
/>
) : null;


return ( return (
<div className="big-padded"> <div className="big-padded">
)} )}


<div className={definitions.length > 0 ? 'spacer-bottom text-right' : 'big-spacer-top'}> <div className={definitions.length > 0 ? 'spacer-bottom text-right' : 'big-spacer-top'}>
<Tooltip overlay={creationTooltip} mouseLeaveDelay={0.25}>
<CreationTooltip alm={alm} preventCreation={preventCreation}>
<Button <Button
data-test="settings__alm-create" data-test="settings__alm-create"
disabled={preventCreation} disabled={preventCreation}
onClick={props.onCreate}> onClick={props.onCreate}>
{translate('settings.almintegration.create')} {translate('settings.almintegration.create')}
</Button> </Button>
</Tooltip>
</CreationTooltip>
</div> </div>
{definitions.map(def => ( {definitions.map(def => (
<AlmBindingDefinitionBox <AlmBindingDefinitionBox
alm={alm} alm={alm}
branchesEnabled={branchesEnabled}
definition={def} definition={def}
key={def.key} key={def.key}
multipleDefinitions={definitions.length > 1} multipleDefinitions={definitions.length > 1}

+ 3
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/AzureTab.tsx View File

import AzureForm from './AzureForm'; import AzureForm from './AzureForm';


export interface AzureTabProps { export interface AzureTabProps {
branchesEnabled: boolean;
definitions: AzureBindingDefinition[]; definitions: AzureBindingDefinition[];
definitionStatus: T.Dict<AlmSettingsBindingStatus>; definitionStatus: T.Dict<AlmSettingsBindingStatus>;
loadingAlmDefinitions: boolean; loadingAlmDefinitions: boolean;


export default function AzureTab(props: AzureTabProps) { export default function AzureTab(props: AzureTabProps) {
const { const {
branchesEnabled,
multipleAlmEnabled, multipleAlmEnabled,
definitions, definitions,
definitionStatus, definitionStatus,
<div className="bordered"> <div className="bordered">
<AlmTab <AlmTab
alm={AlmKeys.Azure} alm={AlmKeys.Azure}
branchesEnabled={branchesEnabled}
createConfiguration={createAzureConfiguration} createConfiguration={createAzureConfiguration}
defaultBinding={{ key: '', personalAccessToken: '', url: '' }} defaultBinding={{ key: '', personalAccessToken: '', url: '' }}
definitions={definitions} definitions={definitions}

+ 3
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketTab.tsx View File

import BitbucketForm from './BitbucketForm'; import BitbucketForm from './BitbucketForm';


export interface BitbucketTabProps { export interface BitbucketTabProps {
branchesEnabled: boolean;
definitions: BitbucketBindingDefinition[]; definitions: BitbucketBindingDefinition[];
definitionStatus: T.Dict<AlmSettingsBindingStatus>; definitionStatus: T.Dict<AlmSettingsBindingStatus>;
loadingAlmDefinitions: boolean; loadingAlmDefinitions: boolean;


export default function BitbucketTab(props: BitbucketTabProps) { export default function BitbucketTab(props: BitbucketTabProps) {
const { const {
branchesEnabled,
multipleAlmEnabled, multipleAlmEnabled,
definitions, definitions,
definitionStatus, definitionStatus,
<div className="bordered"> <div className="bordered">
<AlmTab <AlmTab
alm={AlmKeys.Bitbucket} alm={AlmKeys.Bitbucket}
branchesEnabled={branchesEnabled}
createConfiguration={createBitbucketConfiguration} createConfiguration={createBitbucketConfiguration}
defaultBinding={{ key: '', url: '', personalAccessToken: '' }} defaultBinding={{ key: '', url: '', personalAccessToken: '' }}
definitions={definitions} definitions={definitions}

+ 75
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/CreationTooltip.tsx View File

/*
* 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 Tooltip from 'sonar-ui-common/components/controls/Tooltip';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { withAppState } from '../../../../components/hoc/withAppState';
import { getEdition, getEditionUrl } from '../../../../helpers/editions';
import { AlmKeys } from '../../../../types/alm-settings';
import { EditionKey } from '../../../../types/editions';

export interface CreationTooltipProps {
alm: AlmKeys;
appState: T.AppState;
children: React.ReactElement<{}>;
preventCreation: boolean;
}

export function CreationTooltip(props: CreationTooltipProps) {
const {
alm,
appState: { edition },
children,
preventCreation
} = props;

const sourceEdition = edition ? EditionKey[edition] : undefined;

return (
<Tooltip
overlay={
preventCreation ? (
<FormattedMessage
id="settings.almintegration.create.tooltip"
defaultMessage={translate('settings.almintegration.create.tooltip')}
values={{
link: (
<a
href={getEditionUrl(getEdition(EditionKey.enterprise), {
sourceEdition
})}
rel="noopener noreferrer"
target="_blank">
{translate('settings.almintegration.create.tooltip.link')}
</a>
),
alm: translate('alm', alm)
}}
/>
) : null
}
mouseLeaveDelay={0.25}>
{children}
</Tooltip>
);
}

export default withAppState(CreationTooltip);

+ 35
- 38
server/sonar-web/src/main/js/apps/settings/components/almIntegration/GithubTab.tsx View File



return ( return (
<div className="bordered"> <div className="bordered">
{branchesEnabled && (
<>
<AlmTab
alm={AlmKeys.GitHub}
createConfiguration={createGithubConfiguration}
defaultBinding={{
key: '',
appId: '',
clientId: '',
clientSecret: '',
url: '',
privateKey: ''
<AlmTab
alm={AlmKeys.GitHub}
branchesEnabled={branchesEnabled}
createConfiguration={createGithubConfiguration}
defaultBinding={{
key: '',
appId: '',
clientId: '',
clientSecret: '',
url: '',
privateKey: ''
}}
definitions={definitions}
definitionStatus={definitionStatus}
form={childProps => <GithubForm {...childProps} />}
help={
<FormattedMessage
defaultMessage={translate(`settings.almintegration.github.info`)}
id="settings.almintegration.github.info"
values={{
link: (
<Link target="_blank" to={ALM_DOCUMENTATION_PATHS[AlmKeys.GitHub]}>
{translate('learn_more')}
</Link>
)
}} }}
definitions={definitions}
definitionStatus={definitionStatus}
form={childProps => <GithubForm {...childProps} />}
help={
<FormattedMessage
defaultMessage={translate(`settings.almintegration.github.info`)}
id="settings.almintegration.github.info"
values={{
link: (
<Link target="_blank" to={ALM_DOCUMENTATION_PATHS[AlmKeys.GitHub]}>
{translate('learn_more')}
</Link>
)
}}
/>
}
loadingAlmDefinitions={loadingAlmDefinitions}
loadingProjectCount={loadingProjectCount}
multipleAlmEnabled={multipleAlmEnabled}
onCheck={props.onCheck}
onDelete={props.onDelete}
onUpdateDefinitions={props.onUpdateDefinitions}
updateConfiguration={updateGithubConfiguration}
/> />
}
loadingAlmDefinitions={loadingAlmDefinitions}
loadingProjectCount={loadingProjectCount}
multipleAlmEnabled={multipleAlmEnabled}
onCheck={props.onCheck}
onDelete={props.onDelete}
onUpdateDefinitions={props.onUpdateDefinitions}
updateConfiguration={updateGithubConfiguration}
/>


<div className="huge-spacer-top huge-spacer-bottom bordered-top" />
</>
)}
<div className="huge-spacer-top huge-spacer-bottom bordered-top" />


<div className="big-padded"> <div className="big-padded">
<CategoryDefinitionsList <CategoryDefinitionsList

+ 29
- 32
server/sonar-web/src/main/js/apps/settings/components/almIntegration/GitlabTab.tsx View File



return ( return (
<div className="bordered"> <div className="bordered">
{branchesEnabled && (
<>
<AlmTab
alm={AlmKeys.GitLab}
createConfiguration={createGitlabConfiguration}
defaultBinding={{ key: '', personalAccessToken: '', url: '' }}
definitions={definitions}
definitionStatus={definitionStatus}
form={childProps => <GitlabForm {...childProps} />}
help={
<FormattedMessage
defaultMessage={translate(`settings.almintegration.gitlab.info`)}
id="settings.almintegration.gitlab.info"
values={{
link: (
<Link target="_blank" to={ALM_DOCUMENTATION_PATHS[AlmKeys.GitLab]}>
{translate('learn_more')}
</Link>
)
}}
/>
}
loadingAlmDefinitions={loadingAlmDefinitions}
loadingProjectCount={loadingProjectCount}
multipleAlmEnabled={multipleAlmEnabled}
onCheck={props.onCheck}
onDelete={props.onDelete}
onUpdateDefinitions={props.onUpdateDefinitions}
updateConfiguration={updateGitlabConfiguration}
<AlmTab
alm={AlmKeys.GitLab}
branchesEnabled={branchesEnabled}
createConfiguration={createGitlabConfiguration}
defaultBinding={{ key: '', personalAccessToken: '', url: '' }}
definitions={definitions}
definitionStatus={definitionStatus}
form={childProps => <GitlabForm {...childProps} />}
help={
<FormattedMessage
defaultMessage={translate(`settings.almintegration.gitlab.info`)}
id="settings.almintegration.gitlab.info"
values={{
link: (
<Link target="_blank" to={ALM_DOCUMENTATION_PATHS[AlmKeys.GitLab]}>
{translate('learn_more')}
</Link>
)
}}
/> />
}
loadingAlmDefinitions={loadingAlmDefinitions}
loadingProjectCount={loadingProjectCount}
multipleAlmEnabled={multipleAlmEnabled}
onCheck={props.onCheck}
onDelete={props.onDelete}
onUpdateDefinitions={props.onUpdateDefinitions}
updateConfiguration={updateGitlabConfiguration}
/>


<div className="huge-spacer-top huge-spacer-bottom bordered-top" />
</>
)}
<div className="huge-spacer-top huge-spacer-bottom bordered-top" />


<div className="big-padded"> <div className="big-padded">
<CategoryDefinitionsList <CategoryDefinitionsList

+ 11
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionBox-test.tsx View File

expect( expect(
shallowRender({ alm: AlmKeys.Azure, definition: mockAzureBindingDefinition() }) shallowRender({ alm: AlmKeys.Azure, definition: mockAzureBindingDefinition() })
).toMatchSnapshot('Azure DevOps'); ).toMatchSnapshot('Azure DevOps');

expect(
shallowRender({
branchesEnabled: false,
status: mockAlmSettingsBindingStatus({
alertSuccess: true,
type: AlmSettingsBindingStatusType.Success
})
})
).toMatchSnapshot('success with branches disabled');
}); });


function shallowRender(props: Partial<AlmBindingDefinitionBoxProps> = {}) { function shallowRender(props: Partial<AlmBindingDefinitionBoxProps> = {}) {
return shallow( return shallow(
<AlmBindingDefinitionBox <AlmBindingDefinitionBox
alm={AlmKeys.GitHub} alm={AlmKeys.GitHub}
branchesEnabled={true}
definition={mockGithubBindingDefinition()} definition={mockGithubBindingDefinition()}
multipleDefinitions={false} multipleDefinitions={false}
onCheck={jest.fn()} onCheck={jest.fn()}

+ 1
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmTab-test.tsx View File

return shallow<AlmTab<AzureBindingDefinition>>( return shallow<AlmTab<AzureBindingDefinition>>(
<AlmTab <AlmTab
alm={AlmKeys.Azure} alm={AlmKeys.Azure}
branchesEnabled={true}
createConfiguration={jest.fn()} createConfiguration={jest.fn()}
defaultBinding={DEFAULT_BINDING} defaultBinding={DEFAULT_BINDING}
definitions={[mockAzureBindingDefinition()]} definitions={[mockAzureBindingDefinition()]}

+ 1
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmTabRenderer-test.tsx View File

return shallow( return shallow(
<AlmTabRenderer <AlmTabRenderer
alm={AlmKeys.Azure} alm={AlmKeys.Azure}
branchesEnabled={true}
defaultBinding={{} as any} defaultBinding={{} as any}
definitions={[]} definitions={[]}
definitionStatus={{}} definitionStatus={{}}

+ 1
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AzureTab-test.tsx View File

function shallowRender(props: Partial<AzureTabProps> = {}) { function shallowRender(props: Partial<AzureTabProps> = {}) {
return shallow( return shallow(
<AzureTab <AzureTab
branchesEnabled={true}
definitions={[mockAzureBindingDefinition()]} definitions={[mockAzureBindingDefinition()]}
definitionStatus={{}} definitionStatus={{}}
loadingAlmDefinitions={false} loadingAlmDefinitions={false}

+ 1
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/BitbucketTab-test.tsx View File

function shallowRender(props: Partial<BitbucketTabProps> = {}) { function shallowRender(props: Partial<BitbucketTabProps> = {}) {
return shallow( return shallow(
<BitbucketTab <BitbucketTab
branchesEnabled={true}
definitions={[mockBitbucketBindingDefinition()]} definitions={[mockBitbucketBindingDefinition()]}
definitionStatus={{}} definitionStatus={{}}
loadingAlmDefinitions={false} loadingAlmDefinitions={false}

+ 42
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/CreationTooltip-test.tsx View File

/*
* 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 { mockAppState } from '../../../../../helpers/testMocks';
import { AlmKeys } from '../../../../../types/alm-settings';
import { EditionKey } from '../../../../../types/editions';
import { CreationTooltip, CreationTooltipProps } from '../CreationTooltip';

it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot();
expect(shallowRender({ preventCreation: false })).toMatchSnapshot();
});

function shallowRender(props: Partial<CreationTooltipProps> = {}) {
return shallow(
<CreationTooltip
alm={AlmKeys.Azure}
appState={mockAppState({ edition: EditionKey.community })}
preventCreation={true}
{...props}>
<span>Child</span>
</CreationTooltip>
);
}

+ 0
- 1
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/GithubTab-test.tsx View File



it('should render correctly', () => { it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot('with branch support'); expect(shallowRender()).toMatchSnapshot('with branch support');
expect(shallowRender({ branchesEnabled: false })).toMatchSnapshot('without branch support');
}); });


function shallowRender(props: Partial<GithubTabProps> = {}) { function shallowRender(props: Partial<GithubTabProps> = {}) {

+ 0
- 1
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/GitlabTab-test.tsx View File



it('should render correctly', () => { it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot('with branch support'); expect(shallowRender()).toMatchSnapshot('with branch support');
expect(shallowRender({ branchesEnabled: false })).toMatchSnapshot('without branch support');
expect( expect(
shallowRender({ shallowRender({
definitions: [mockGitlabBindingDefinition({ url: 'https://gitlab.com/api/v4' })] definitions: [mockGitlabBindingDefinition({ url: 'https://gitlab.com/api/v4' })]

+ 141
- 26
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionBox-test.tsx.snap View File

<div <div
className="display-flex-row spacer-bottom" className="display-flex-row spacer-bottom"
> >
<Tooltip
overlay="settings.almintegration.feature.pr_decoration.description"
<div
className="huge-spacer-right"
> >
<div
className="huge-spacer-right"
<Tooltip
overlay="settings.almintegration.feature.pr_decoration.description"
> >
settings.almintegration.feature.pr_decoration.title
<AlertErrorIcon
className="spacer-left"
/>
</div>
</Tooltip>
<span>
settings.almintegration.feature.pr_decoration.title
</span>
</Tooltip>
<AlertErrorIcon
className="spacer-left"
/>
</div>
<div> <div>
<Tooltip <Tooltip
overlay="settings.almintegration.feature.alm_repo_import.description" overlay="settings.almintegration.feature.alm_repo_import.description"
<div <div
className="display-flex-row spacer-bottom" className="display-flex-row spacer-bottom"
> >
<Tooltip
overlay="settings.almintegration.feature.pr_decoration.description"
<div
className="huge-spacer-right"
> >
<div
className="huge-spacer-right"
<Tooltip
overlay="settings.almintegration.feature.pr_decoration.description"
> >
settings.almintegration.feature.pr_decoration.title
<AlertSuccessIcon
className="spacer-left"
/>
</div>
</Tooltip>
<span>
settings.almintegration.feature.pr_decoration.title
</span>
</Tooltip>
<AlertSuccessIcon
className="spacer-left"
/>
</div>
<div> <div>
<Tooltip <Tooltip
overlay="settings.almintegration.feature.alm_repo_import.description" overlay="settings.almintegration.feature.alm_repo_import.description"
<div <div
className="display-flex-row spacer-bottom" className="display-flex-row spacer-bottom"
> >
<Tooltip
overlay="settings.almintegration.feature.pr_decoration.description"
<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>
<Tooltip
overlay="settings.almintegration.feature.alm_repo_import.description"
>
<span>
settings.almintegration.feature.alm_repo_import.title
</span>
</Tooltip>
<AlertSuccessIcon
className="spacer-left"
/>
</div>
</div>
<div
className="width-50"
>
<Alert
variant="success"
>
settings.almintegration.configuration_valid
</Alert>
</div>
<Button
className="big-spacer-top"
onClick={[Function]}
>
settings.almintegration.check_configuration
</Button>
</div>
`;

exports[`should render correctly: success with branches disabled 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>
<span>
http://github.enterprise.com
</span>
</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>
<div <div
className="huge-spacer-right"
className="display-inline-flex-center"
> >
settings.almintegration.feature.pr_decoration.title
<AlertSuccessIcon
<strong
className="spacer-left" className="spacer-left"
>
settings.almintegration.feature.pr_decoration.disabled
</strong>
<HelpTooltip
className="little-spacer-left"
overlay={
<FormattedMessage
defaultMessage="settings.almintegration.feature.pr_decoration.disabled.no_branches"
id="settings.almintegration.feature.pr_decoration.disabled.no_branches"
values={
Object {
"link": <a
href="https://redirect.sonarsource.com/editions/developer.html?sourceEdition=community"
rel="noopener noreferrer"
target="_blank"
>
settings.almintegration.feature.pr_decoration.disabled.no_branches.link
</a>,
}
}
/>
}
/> />
</div> </div>
</Tooltip>
</div>
<div> <div>
<Tooltip <Tooltip
overlay="settings.almintegration.feature.alm_repo_import.description" overlay="settings.almintegration.feature.alm_repo_import.description"

+ 26
- 12
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmIntegrationRenderer-test.tsx.snap View File

/> />
GitHub GitHub
</React.Fragment>, </React.Fragment>,
"requiresBranchesEnabled": false,
}, },
Object { Object {
"key": "bitbucket", "key": "bitbucket",
/> />
Bitbucket Server Bitbucket Server
</React.Fragment>, </React.Fragment>,
"requiresBranchesEnabled": true,
"requiresBranchesEnabled": false,
}, },
Object { Object {
"key": "azure", "key": "azure",
/> />
Azure DevOps Server Azure DevOps Server
</React.Fragment>, </React.Fragment>,
"requiresBranchesEnabled": true,
"requiresBranchesEnabled": false,
}, },
Object { Object {
"key": "gitlab", "key": "gitlab",
/> />
GitLab GitLab
</React.Fragment>, </React.Fragment>,
"requiresBranchesEnabled": false,
}, },
] ]
} }
/> />
<AzureTab <AzureTab
branchesEnabled={true}
definitionStatus={Object {}} definitionStatus={Object {}}
definitions={Array []} definitions={Array []}
loadingAlmDefinitions={false} loadingAlmDefinitions={false}
/> />
GitHub GitHub
</React.Fragment>, </React.Fragment>,
"requiresBranchesEnabled": false,
}, },
Object { Object {
"key": "bitbucket", "key": "bitbucket",
/> />
Bitbucket Server Bitbucket Server
</React.Fragment>, </React.Fragment>,
"requiresBranchesEnabled": true,
"requiresBranchesEnabled": false,
}, },
Object { Object {
"key": "azure", "key": "azure",
/> />
Azure DevOps Server Azure DevOps Server
</React.Fragment>, </React.Fragment>,
"requiresBranchesEnabled": true,
"requiresBranchesEnabled": false,
}, },
Object { Object {
"key": "gitlab", "key": "gitlab",
/> />
GitLab GitLab
</React.Fragment>, </React.Fragment>,
"requiresBranchesEnabled": false,
}, },
] ]
} }
/> />
<BitbucketTab <BitbucketTab
branchesEnabled={true}
definitionStatus={Object {}} definitionStatus={Object {}}
definitions={Array []} definitions={Array []}
loadingAlmDefinitions={false} loadingAlmDefinitions={false}
/> />
GitHub GitHub
</React.Fragment>, </React.Fragment>,
"requiresBranchesEnabled": false,
}, },
Object { Object {
"key": "bitbucket", "key": "bitbucket",
/> />
Bitbucket Server Bitbucket Server
</React.Fragment>, </React.Fragment>,
"requiresBranchesEnabled": true,
"requiresBranchesEnabled": false,
}, },
Object { Object {
"key": "azure", "key": "azure",
/> />
Azure DevOps Server Azure DevOps Server
</React.Fragment>, </React.Fragment>,
"requiresBranchesEnabled": true,
"requiresBranchesEnabled": false,
}, },
Object { Object {
"key": "gitlab", "key": "gitlab",
/> />
GitLab GitLab
</React.Fragment>, </React.Fragment>,
"requiresBranchesEnabled": false,
}, },
] ]
} }
/> />
GitHub GitHub
</React.Fragment>, </React.Fragment>,
"requiresBranchesEnabled": false,
}, },
Object { Object {
"key": "bitbucket", "key": "bitbucket",
/> />
Bitbucket Server Bitbucket Server
</React.Fragment>, </React.Fragment>,
"requiresBranchesEnabled": true,
"requiresBranchesEnabled": false,
}, },
Object { Object {
"key": "azure", "key": "azure",
/> />
Azure DevOps Server Azure DevOps Server
</React.Fragment>, </React.Fragment>,
"requiresBranchesEnabled": true,
"requiresBranchesEnabled": false,
}, },
Object { Object {
"key": "gitlab", "key": "gitlab",
/> />
GitLab GitLab
</React.Fragment>, </React.Fragment>,
"requiresBranchesEnabled": false,
}, },
] ]
} }
/> />
GitHub GitHub
</React.Fragment>, </React.Fragment>,
"requiresBranchesEnabled": false,
}, },
Object { Object {
"key": "bitbucket", "key": "bitbucket",
/> />
Bitbucket Server Bitbucket Server
</React.Fragment>, </React.Fragment>,
"requiresBranchesEnabled": true,
"requiresBranchesEnabled": false,
}, },
Object { Object {
"key": "azure", "key": "azure",
/> />
Azure DevOps Server Azure DevOps Server
</React.Fragment>, </React.Fragment>,
"requiresBranchesEnabled": true,
"requiresBranchesEnabled": false,
}, },
Object { Object {
"key": "gitlab", "key": "gitlab",
/> />
GitLab GitLab
</React.Fragment>, </React.Fragment>,
"requiresBranchesEnabled": false,
}, },
] ]
} }
/> />
GitHub GitHub
</React.Fragment>, </React.Fragment>,
"requiresBranchesEnabled": false,
}, },
Object { Object {
"key": "bitbucket", "key": "bitbucket",
/> />
Bitbucket Server Bitbucket Server
</React.Fragment>, </React.Fragment>,
"requiresBranchesEnabled": true,
"requiresBranchesEnabled": false,
}, },
Object { Object {
"key": "azure", "key": "azure",
/> />
Azure DevOps Server Azure DevOps Server
</React.Fragment>, </React.Fragment>,
"requiresBranchesEnabled": true,
"requiresBranchesEnabled": false,
}, },
Object { Object {
"key": "gitlab", "key": "gitlab",
/> />
GitLab GitLab
</React.Fragment>, </React.Fragment>,
"requiresBranchesEnabled": false,
}, },
] ]
} }

+ 1
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmTab-test.tsx.snap View File

exports[`should render correctly 1`] = ` exports[`should render correctly 1`] = `
<AlmTabRenderer <AlmTabRenderer
alm="azure" alm="azure"
branchesEnabled={true}
defaultBinding={ defaultBinding={
Object { Object {
"key": "", "key": "",

+ 58
- 116
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmTabRenderer-test.tsx.snap View File

<div <div
className="spacer-bottom text-right" className="spacer-bottom text-right"
> >
<Tooltip
mouseLeaveDelay={0.25}
overlay={null}
<Connect(withAppState(CreationTooltip))
alm="azure"
preventCreation={false}
> >
<Button <Button
data-test="settings__alm-create" data-test="settings__alm-create"
> >
settings.almintegration.create settings.almintegration.create
</Button> </Button>
</Tooltip>
</Connect(withAppState(CreationTooltip))>
</div> </div>
<AlmBindingDefinitionBox <AlmBindingDefinitionBox
alm="azure" alm="azure"
branchesEnabled={true}
definition={ definition={
Object { Object {
"key": "key", "key": "key",
<div <div
className="spacer-bottom text-right" className="spacer-bottom text-right"
> >
<Tooltip
mouseLeaveDelay={0.25}
overlay={null}
<Connect(withAppState(CreationTooltip))
alm="azure"
preventCreation={false}
> >
<Button <Button
data-test="settings__alm-create" data-test="settings__alm-create"
> >
settings.almintegration.create settings.almintegration.create
</Button> </Button>
</Tooltip>
</Connect(withAppState(CreationTooltip))>
</div> </div>
<AlmBindingDefinitionBox <AlmBindingDefinitionBox
alm="azure" alm="azure"
branchesEnabled={true}
definition={ definition={
Object { Object {
"key": "key", "key": "key",
<div <div
className="spacer-bottom text-right" className="spacer-bottom text-right"
> >
<Tooltip
mouseLeaveDelay={0.25}
overlay={null}
<Connect(withAppState(CreationTooltip))
alm="azure"
preventCreation={false}
> >
<Button <Button
data-test="settings__alm-create" data-test="settings__alm-create"
> >
settings.almintegration.create settings.almintegration.create
</Button> </Button>
</Tooltip>
</Connect(withAppState(CreationTooltip))>
</div> </div>
<AlmBindingDefinitionBox <AlmBindingDefinitionBox
alm="azure" alm="azure"
branchesEnabled={true}
definition={ definition={
Object { Object {
"key": "key", "key": "key",
<div <div
className="spacer-bottom text-right" className="spacer-bottom text-right"
> >
<Tooltip
mouseLeaveDelay={0.25}
overlay={
<FormattedMessage
defaultMessage="settings.almintegration.create.tooltip"
id="settings.almintegration.create.tooltip"
values={
Object {
"alm": "alm.azure",
"link": <a
href="https://redirect.sonarsource.com/editions/enterprise.html?sourceEdition=developer"
rel="noopener noreferrer"
target="_blank"
>
settings.almintegration.create.tooltip.link
</a>,
}
}
/>
}
<Connect(withAppState(CreationTooltip))
alm="azure"
preventCreation={true}
> >
<Button <Button
data-test="settings__alm-create" data-test="settings__alm-create"
> >
settings.almintegration.create settings.almintegration.create
</Button> </Button>
</Tooltip>
</Connect(withAppState(CreationTooltip))>
</div> </div>
<AlmBindingDefinitionBox <AlmBindingDefinitionBox
alm="azure" alm="azure"
branchesEnabled={true}
definition={ definition={
Object { Object {
"key": "key", "key": "key",
<div <div
className="spacer-bottom text-right" className="spacer-bottom text-right"
> >
<Tooltip
mouseLeaveDelay={0.25}
overlay={null}
<Connect(withAppState(CreationTooltip))
alm="azure"
preventCreation={false}
> >
<Button <Button
data-test="settings__alm-create" data-test="settings__alm-create"
> >
settings.almintegration.create settings.almintegration.create
</Button> </Button>
</Tooltip>
</Connect(withAppState(CreationTooltip))>
</div> </div>
<AlmBindingDefinitionBox <AlmBindingDefinitionBox
alm="azure" alm="azure"
branchesEnabled={true}
definition={ definition={
Object { Object {
"key": "key", "key": "key",
<div <div
className="spacer-bottom text-right" className="spacer-bottom text-right"
> >
<Tooltip
mouseLeaveDelay={0.25}
overlay={
<FormattedMessage
defaultMessage="settings.almintegration.create.tooltip"
id="settings.almintegration.create.tooltip"
values={
Object {
"alm": "alm.azure",
"link": <a
href="https://redirect.sonarsource.com/editions/enterprise.html?sourceEdition=developer"
rel="noopener noreferrer"
target="_blank"
>
settings.almintegration.create.tooltip.link
</a>,
}
}
/>
}
<Connect(withAppState(CreationTooltip))
alm="azure"
preventCreation={true}
> >
<Button <Button
data-test="settings__alm-create" data-test="settings__alm-create"
> >
settings.almintegration.create settings.almintegration.create
</Button> </Button>
</Tooltip>
</Connect(withAppState(CreationTooltip))>
</div> </div>
<AlmBindingDefinitionBox <AlmBindingDefinitionBox
alm="azure" alm="azure"
branchesEnabled={true}
definition={ definition={
Object { Object {
"key": "key", "key": "key",
<div <div
className="spacer-bottom text-right" className="spacer-bottom text-right"
> >
<Tooltip
mouseLeaveDelay={0.25}
overlay={
<FormattedMessage
defaultMessage="settings.almintegration.create.tooltip"
id="settings.almintegration.create.tooltip"
values={
Object {
"alm": "alm.azure",
"link": <a
href="https://redirect.sonarsource.com/editions/enterprise.html?sourceEdition=developer"
rel="noopener noreferrer"
target="_blank"
>
settings.almintegration.create.tooltip.link
</a>,
}
}
/>
}
<Connect(withAppState(CreationTooltip))
alm="azure"
preventCreation={true}
> >
<Button <Button
data-test="settings__alm-create" data-test="settings__alm-create"
> >
settings.almintegration.create settings.almintegration.create
</Button> </Button>
</Tooltip>
</Connect(withAppState(CreationTooltip))>
</div> </div>
<AlmBindingDefinitionBox <AlmBindingDefinitionBox
alm="azure" alm="azure"
branchesEnabled={true}
definition={ definition={
Object { Object {
"key": "key", "key": "key",
<div <div
className="spacer-bottom text-right" className="spacer-bottom text-right"
> >
<Tooltip
mouseLeaveDelay={0.25}
overlay={
<FormattedMessage
defaultMessage="settings.almintegration.create.tooltip"
id="settings.almintegration.create.tooltip"
values={
Object {
"alm": "alm.azure",
"link": <a
href="https://redirect.sonarsource.com/editions/enterprise.html?sourceEdition=developer"
rel="noopener noreferrer"
target="_blank"
>
settings.almintegration.create.tooltip.link
</a>,
}
}
/>
}
<Connect(withAppState(CreationTooltip))
alm="azure"
preventCreation={true}
> >
<Button <Button
data-test="settings__alm-create" data-test="settings__alm-create"
> >
settings.almintegration.create settings.almintegration.create
</Button> </Button>
</Tooltip>
</Connect(withAppState(CreationTooltip))>
</div> </div>
<AlmBindingDefinitionBox <AlmBindingDefinitionBox
alm="azure" alm="azure"
branchesEnabled={true}
definition={ definition={
Object { Object {
"key": "key", "key": "key",
<div <div
className="spacer-bottom text-right" className="spacer-bottom text-right"
> >
<Tooltip
mouseLeaveDelay={0.25}
overlay={null}
<Connect(withAppState(CreationTooltip))
alm="github"
preventCreation={false}
> >
<Button <Button
data-test="settings__alm-create" data-test="settings__alm-create"
> >
settings.almintegration.create settings.almintegration.create
</Button> </Button>
</Tooltip>
</Connect(withAppState(CreationTooltip))>
</div> </div>
<AlmBindingDefinitionBox <AlmBindingDefinitionBox
alm="github" alm="github"
branchesEnabled={true}
definition={ definition={
Object { Object {
"appId": "123456", "appId": "123456",
<div <div
className="big-spacer-top" className="big-spacer-top"
> >
<Tooltip
mouseLeaveDelay={0.25}
overlay={null}
<Connect(withAppState(CreationTooltip))
alm="github"
preventCreation={false}
> >
<Button <Button
data-test="settings__alm-create" data-test="settings__alm-create"
> >
settings.almintegration.create settings.almintegration.create
</Button> </Button>
</Tooltip>
</Connect(withAppState(CreationTooltip))>
</div> </div>
<AlmBindingDefinitionForm <AlmBindingDefinitionForm
bindingDefinition={ bindingDefinition={
<div <div
className="spacer-bottom text-right" className="spacer-bottom text-right"
> >
<Tooltip
mouseLeaveDelay={0.25}
overlay={null}
<Connect(withAppState(CreationTooltip))
alm="github"
preventCreation={false}
> >
<Button <Button
data-test="settings__alm-create" data-test="settings__alm-create"
> >
settings.almintegration.create settings.almintegration.create
</Button> </Button>
</Tooltip>
</Connect(withAppState(CreationTooltip))>
</div> </div>
<AlmBindingDefinitionBox <AlmBindingDefinitionBox
alm="github" alm="github"
branchesEnabled={true}
definition={ definition={
Object { Object {
"appId": "123456", "appId": "123456",
<div <div
className="big-spacer-top" className="big-spacer-top"
> >
<Tooltip
mouseLeaveDelay={0.25}
overlay={null}
<Connect(withAppState(CreationTooltip))
alm="github"
preventCreation={false}
> >
<Button <Button
data-test="settings__alm-create" data-test="settings__alm-create"
> >
settings.almintegration.create settings.almintegration.create
</Button> </Button>
</Tooltip>
</Connect(withAppState(CreationTooltip))>
</div> </div>
</DeferredSpinner> </DeferredSpinner>
</div> </div>

+ 1
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AzureTab-test.tsx.snap View File

> >
<AlmTab <AlmTab
alm="azure" alm="azure"
branchesEnabled={true}
createConfiguration={[Function]} createConfiguration={[Function]}
defaultBinding={ defaultBinding={
Object { Object {

+ 1
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketTab-test.tsx.snap View File

> >
<AlmTab <AlmTab
alm="bitbucket" alm="bitbucket"
branchesEnabled={true}
createConfiguration={[Function]} createConfiguration={[Function]}
defaultBinding={ defaultBinding={
Object { Object {

+ 40
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/CreationTooltip-test.tsx.snap View File

// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should render correctly 1`] = `
<Tooltip
mouseLeaveDelay={0.25}
overlay={
<FormattedMessage
defaultMessage="settings.almintegration.create.tooltip"
id="settings.almintegration.create.tooltip"
values={
Object {
"alm": "alm.azure",
"link": <a
href="https://redirect.sonarsource.com/editions/enterprise.html?sourceEdition=community"
rel="noopener noreferrer"
target="_blank"
>
settings.almintegration.create.tooltip.link
</a>,
}
}
/>
}
>
<span>
Child
</span>
</Tooltip>
`;

exports[`should render correctly 2`] = `
<Tooltip
mouseLeaveDelay={0.25}
overlay={null}
>
<span>
Child
</span>
</Tooltip>
`;

+ 1
- 15
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GithubTab-test.tsx.snap View File

> >
<AlmTab <AlmTab
alm="github" alm="github"
branchesEnabled={true}
createConfiguration={[Function]} createConfiguration={[Function]}
defaultBinding={ defaultBinding={
Object { Object {
</div> </div>
</div> </div>
`; `;

exports[`should render correctly: without branch support 1`] = `
<div
className="bordered"
>
<div
className="big-padded"
>
<Connect(SubCategoryDefinitionsList)
category="almintegration"
subCategory="github"
/>
</div>
</div>
`;

+ 3
- 15
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GitlabTab-test.tsx.snap View File

> >
<AlmTab <AlmTab
alm="gitlab" alm="gitlab"
branchesEnabled={true}
createConfiguration={[Function]} createConfiguration={[Function]}
defaultBinding={ defaultBinding={
Object { Object {
> >
<AlmTab <AlmTab
alm="gitlab" alm="gitlab"
branchesEnabled={true}
createConfiguration={[Function]} createConfiguration={[Function]}
defaultBinding={ defaultBinding={
Object { Object {
> >
<AlmTab <AlmTab
alm="gitlab" alm="gitlab"
branchesEnabled={true}
createConfiguration={[Function]} createConfiguration={[Function]}
defaultBinding={ defaultBinding={
Object { Object {
</div> </div>
</div> </div>
`; `;

exports[`should render correctly: without branch support 1`] = `
<div
className="bordered"
>
<div
className="big-padded"
>
<Connect(SubCategoryDefinitionsList)
category="almintegration"
subCategory="gitlab"
/>
</div>
</div>
`;

+ 3
- 0
sonar-core/src/main/resources/org/sonar/l10n/core.properties View File

settings.almintegration.feature.pr_decoration.description=Add analysis and a Quality Gate to your Pull Requests directly in your ALM provider's interface. settings.almintegration.feature.pr_decoration.description=Add analysis and a Quality Gate to your Pull Requests directly in your ALM provider's interface.
settings.almintegration.feature.mr_decoration.title=Merge Request Decoration settings.almintegration.feature.mr_decoration.title=Merge Request Decoration
settings.almintegration.feature.mr_decoration.description=Add analysis and a Quality Gate to your Merge Requests directly in your ALM provider's interface. settings.almintegration.feature.mr_decoration.description=Add analysis and a Quality Gate to your Merge Requests directly in your ALM provider's interface.
settings.almintegration.feature.pr_decoration.disabled=Disabled
settings.almintegration.feature.pr_decoration.disabled.no_branches=Upgrade to {link} to enable this feature.
settings.almintegration.feature.pr_decoration.disabled.no_branches.link=Developer Edition
settings.almintegration.feature.alm_repo_import.title=Import repositories from your ALM settings.almintegration.feature.alm_repo_import.title=Import repositories from your ALM
settings.almintegration.feature.alm_repo_import.description=Select repositories from your ALM, and import them into SonarQube. settings.almintegration.feature.alm_repo_import.description=Select repositories from your ALM, and import them into SonarQube.
settings.almintegration.feature.alm_repo_import.disabled=Disabled settings.almintegration.feature.alm_repo_import.disabled=Disabled

Loading…
Cancel
Save