Browse Source

SONAR-19456 New code definition is made part of Bitbucket Server project onboarding

tags/10.1.0.73491
Philippe Perrin 11 months ago
parent
commit
fb56254f6a

+ 19
- 10
server/sonar-web/src/main/js/api/alm-integrations.ts View File

@@ -118,16 +118,25 @@ export function getBitbucketServerRepositories(
});
}

export function importBitbucketServerProject(
almSetting: string,
projectKey: string,
repositorySlug: string
): Promise<{ project: ProjectBase }> {
return postJSON('/api/alm_integrations/import_bitbucketserver_project', {
almSetting,
projectKey,
repositorySlug,
}).catch(throwGlobalError);
export function setupBitbucketServerProjectCreation(data: {
almSetting: string;
projectKey: string;
repositorySlug: string;
}) {
return (newCodeDefinitionType?: string, newCodeDefinitionValue?: string) =>
importBitbucketServerProject({ ...data, newCodeDefinitionType, newCodeDefinitionValue });
}

export function importBitbucketServerProject(data: {
almSetting: string;
projectKey: string;
repositorySlug: string;
newCodeDefinitionType?: string;
newCodeDefinitionValue?: string;
}): Promise<{ project: ProjectBase }> {
return postJSON('/api/alm_integrations/import_bitbucketserver_project', data).catch(
throwGlobalError
);
}

export function searchForBitbucketServerRepositories(

+ 4
- 0
server/sonar-web/src/main/js/api/mocks/AlmIntegrationsServiceMock.ts View File

@@ -58,6 +58,7 @@ import {
searchForBitbucketServerRepositories,
setAlmPersonalAccessToken,
setupAzureProjectCreation,
setupBitbucketServerProjectCreation,
} from '../alm-integrations';

export default class AlmIntegrationsServiceMock {
@@ -204,6 +205,9 @@ export default class AlmIntegrationsServiceMock {
.mocked(getBitbucketServerRepositories)
.mockImplementation(this.getBitbucketServerRepositories);
jest.mocked(importBitbucketServerProject).mockImplementation(this.importBitbucketServerProject);
jest
.mocked(setupBitbucketServerProjectCreation)
.mockReturnValue(() => this.importBitbucketServerProject());
jest
.mocked(searchForBitbucketServerRepositories)
.mockImplementation(this.searchForBitbucketServerRepositories);

+ 0
- 7
server/sonar-web/src/main/js/apps/create/project/BitbucketServer/BitbucketImportRepositoryForm.tsx View File

@@ -29,13 +29,11 @@ import {
BitbucketProjectRepositories,
BitbucketRepository,
} from '../../../../types/alm-integration';
import InstanceNewCodeDefinitionComplianceWarning from '../components/InstanceNewCodeDefinitionComplianceWarning';
import { CreateProjectModes } from '../types';
import BitbucketRepositories from './BitbucketRepositories';
import BitbucketSearchResults from './BitbucketSearchResults';

export interface BitbucketImportRepositoryFormProps {
disableRepositories: boolean;
onSearch: (query: string) => void;
onSelectRepository: (repo: BitbucketRepository) => void;
projects?: BitbucketProject[];
@@ -47,7 +45,6 @@ export interface BitbucketImportRepositoryFormProps {

export default function BitbucketImportRepositoryForm(props: BitbucketImportRepositoryFormProps) {
const {
disableRepositories,
projects = [],
projectRepositories = {},
searchResults,
@@ -80,8 +77,6 @@ export default function BitbucketImportRepositoryForm(props: BitbucketImportRepo

return (
<div className="create-project-import-bbs">
<InstanceNewCodeDefinitionComplianceWarning />

<SearchBox
onChange={props.onSearch}
placeholder={translate('onboarding.create_project.search_repositories_by_name')}
@@ -89,7 +84,6 @@ export default function BitbucketImportRepositoryForm(props: BitbucketImportRepo

{searching || searchResults ? (
<BitbucketSearchResults
disableRepositories={disableRepositories}
onSelectRepository={props.onSelectRepository}
projects={projects}
searchResults={searchResults}
@@ -98,7 +92,6 @@ export default function BitbucketImportRepositoryForm(props: BitbucketImportRepo
/>
) : (
<BitbucketRepositories
disableRepositories={disableRepositories}
onSelectRepository={props.onSelectRepository}
projectRepositories={projectRepositories}
projects={projects}

+ 2
- 15
server/sonar-web/src/main/js/apps/create/project/BitbucketServer/BitbucketProjectAccordion.tsx View File

@@ -32,7 +32,6 @@ import { BitbucketProject, BitbucketRepository } from '../../../../types/alm-int
import { CreateProjectModes } from '../types';

export interface BitbucketProjectAccordionProps {
disableRepositories: boolean;
onClick?: () => void;
onSelectRepository: (repo: BitbucketRepository) => void;
open: boolean;
@@ -43,14 +42,7 @@ export interface BitbucketProjectAccordionProps {
}

export default function BitbucketProjectAccordion(props: BitbucketProjectAccordionProps) {
const {
disableRepositories,
open,
project,
repositories,
selectedRepository,
showingAllRepositories,
} = props;
const { open, project, repositories, selectedRepository, showingAllRepositories } = props;

const repositoryCount = repositories.length;

@@ -119,12 +111,7 @@ export default function BitbucketProjectAccordion(props: BitbucketProjectAccordi
) : (
<Radio
checked={selectedRepository?.id === repo.id}
className={classNames(
'display-flex-start spacer-right spacer-bottom create-project-import-bbs-repo overflow-hidden',
{
disabled: disableRepositories,
}
)}
className="display-flex-start spacer-right spacer-bottom create-project-import-bbs-repo overflow-hidden"
key={repo.id}
onCheck={() => props.onSelectRepository(repo)}
value={String(repo.id)}

+ 11
- 28
server/sonar-web/src/main/js/apps/create/project/BitbucketServer/BitbucketProjectCreate.tsx View File

@@ -21,8 +21,8 @@ import * as React from 'react';
import {
getBitbucketServerProjects,
getBitbucketServerRepositories,
importBitbucketServerProject,
searchForBitbucketServerRepositories,
setupBitbucketServerProjectCreation,
} from '../../../../api/alm-integrations';
import { Location, Router } from '../../../../components/hoc/withRouter';
import {
@@ -32,20 +32,20 @@ import {
} from '../../../../types/alm-integration';
import { AlmSettingsInstance } from '../../../../types/alm-settings';
import { DEFAULT_BBS_PAGE_SIZE } from '../constants';
import { CreateProjectApiCallback } from '../types';
import BitbucketCreateProjectRenderer from './BitbucketProjectCreateRenderer';

interface Props {
canAdmin: boolean;
almInstances: AlmSettingsInstance[];
loadingBindings: boolean;
onProjectCreate: (projectKey: string) => void;
location: Location;
router: Router;
onProjectSetupDone: (createProject: CreateProjectApiCallback) => void;
}

interface State {
selectedAlmInstance?: AlmSettingsInstance;
importing: boolean;
loading: boolean;
projects?: BitbucketProject[];
projectRepositories?: BitbucketProjectRepositories;
@@ -61,10 +61,7 @@ export default class BitbucketProjectCreate extends React.PureComponent<Props, S
constructor(props: Props) {
super(props);
this.state = {
// For now, we only handle a single instance. So we always use the first
// one from the list.
selectedAlmInstance: props.almInstances[0],
importing: false,
loading: false,
searching: false,
showPersonalAccessTokenForm: true,
@@ -187,27 +184,15 @@ export default class BitbucketProjectCreate extends React.PureComponent<Props, S
handleImportRepository = () => {
const { selectedAlmInstance, selectedRepository } = this.state;

if (!selectedAlmInstance || !selectedRepository) {
return;
if (selectedAlmInstance && selectedRepository) {
this.props.onProjectSetupDone(
setupBitbucketServerProjectCreation({
almSetting: selectedAlmInstance.key,
projectKey: selectedRepository.projectKey,
repositorySlug: selectedRepository.slug,
})
);
}

this.setState({ importing: true });
importBitbucketServerProject(
selectedAlmInstance.key,
selectedRepository.projectKey,
selectedRepository.slug
)
.then(({ project: { key } }) => {
if (this.mounted) {
this.setState({ importing: false });
this.props.onProjectCreate(key);
}
})
.catch(() => {
if (this.mounted) {
this.setState({ importing: false });
}
});
};

handleSearch = (query: string) => {
@@ -253,7 +238,6 @@ export default class BitbucketProjectCreate extends React.PureComponent<Props, S
const { canAdmin, loadingBindings, location, almInstances } = this.props;
const {
selectedAlmInstance,
importing,
loading,
projectRepositories,
projects,
@@ -268,7 +252,6 @@ export default class BitbucketProjectCreate extends React.PureComponent<Props, S
selectedAlmInstance={selectedAlmInstance}
almInstances={almInstances}
canAdmin={canAdmin}
importing={importing}
loading={loading || loadingBindings}
onImportRepository={this.handleImportRepository}
onPersonalAccessTokenCreated={this.handlePersonalAccessTokenCreated}

+ 1
- 6
server/sonar-web/src/main/js/apps/create/project/BitbucketServer/BitbucketProjectCreateRenderer.tsx View File

@@ -19,7 +19,6 @@
*/
import * as React from 'react';
import { Button } from '../../../../components/controls/buttons';
import DeferredSpinner from '../../../../components/ui/DeferredSpinner';
import { translate } from '../../../../helpers/l10n';
import { getBaseUrl } from '../../../../helpers/system';
import {
@@ -38,7 +37,6 @@ export interface BitbucketProjectCreateRendererProps {
selectedAlmInstance?: AlmSettingsInstance;
almInstances: AlmSettingsInstance[];
canAdmin?: boolean;
importing: boolean;
loading: boolean;
onImportRepository: () => void;
onSearch: (query: string) => void;
@@ -59,7 +57,6 @@ export default function BitbucketProjectCreateRenderer(props: BitbucketProjectCr
almInstances,
selectedAlmInstance,
canAdmin,
importing,
loading,
projects,
projectRepositories,
@@ -76,10 +73,9 @@ export default function BitbucketProjectCreateRenderer(props: BitbucketProjectCr
additionalActions={
!showPersonalAccessTokenForm && (
<div className="display-flex-center pull-right">
<DeferredSpinner className="spacer-right" loading={importing} />
<Button
className="button-large button-primary"
disabled={!selectedRepository || importing}
disabled={!selectedRepository}
onClick={props.onImportRepository}
>
{translate('onboarding.create_project.import_selected_repo')}
@@ -123,7 +119,6 @@ export default function BitbucketProjectCreateRenderer(props: BitbucketProjectCr
/>
) : (
<BitbucketImportRepositoryForm
disableRepositories={importing}
onSearch={props.onSearch}
onSelectRepository={props.onSelectRepository}
projectRepositories={projectRepositories}

+ 1
- 3
server/sonar-web/src/main/js/apps/create/project/BitbucketServer/BitbucketRepositories.tsx View File

@@ -29,7 +29,6 @@ import {
import BitbucketProjectAccordion from './BitbucketProjectAccordion';

export interface BitbucketRepositoriesProps {
disableRepositories: boolean;
onSelectRepository: (repo: BitbucketRepository) => void;
projects: BitbucketProject[];
projectRepositories: BitbucketProjectRepositories;
@@ -37,7 +36,7 @@ export interface BitbucketRepositoriesProps {
}

export default function BitbucketRepositories(props: BitbucketRepositoriesProps) {
const { disableRepositories, projects, projectRepositories, selectedRepository } = props;
const { projects, projectRepositories, selectedRepository } = props;

const [openProjectKeys, setOpenProjectKeys] = React.useState(
projects.length > 0 ? [projects[0].key] : []
@@ -68,7 +67,6 @@ export default function BitbucketRepositories(props: BitbucketRepositoriesProps)

return (
<BitbucketProjectAccordion
disableRepositories={disableRepositories}
key={project.key}
onClick={() => handleClick(isOpen, project.key)}
onSelectRepository={props.onSelectRepository}

+ 1
- 10
server/sonar-web/src/main/js/apps/create/project/BitbucketServer/BitbucketSearchResults.tsx View File

@@ -25,7 +25,6 @@ import { BitbucketProject, BitbucketRepository } from '../../../../types/alm-int
import BitbucketProjectAccordion from './BitbucketProjectAccordion';

export interface BitbucketSearchResultsProps {
disableRepositories: boolean;
onSelectRepository: (repo: BitbucketRepository) => void;
projects: BitbucketProject[];
searching: boolean;
@@ -34,13 +33,7 @@ export interface BitbucketSearchResultsProps {
}

export default function BitbucketSearchResults(props: BitbucketSearchResultsProps) {
const {
disableRepositories,
projects,
searching,
searchResults = [],
selectedRepository,
} = props;
const { projects, searching, searchResults = [], selectedRepository } = props;

if (searchResults.length === 0 && !searching) {
return (
@@ -63,7 +56,6 @@ export default function BitbucketSearchResults(props: BitbucketSearchResultsProp
<DeferredSpinner loading={searching}>
{filteredSearchResults.length > 0 && (
<BitbucketProjectAccordion
disableRepositories={disableRepositories}
onSelectRepository={props.onSelectRepository}
open
repositories={filteredSearchResults}
@@ -77,7 +69,6 @@ export default function BitbucketSearchResults(props: BitbucketSearchResultsProp

return (
<BitbucketProjectAccordion
disableRepositories={disableRepositories}
key={project.key}
onSelectRepository={props.onSelectRepository}
open

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

@@ -220,8 +220,8 @@ export class CreateProjectPage extends React.PureComponent<CreateProjectPageProp
almInstances={bitbucketSettings}
loadingBindings={loading}
location={location}
onProjectCreate={this.handleProjectCreate}
router={router}
onProjectSetupDone={this.handleProjectSetupDone}
/>
);
}

+ 12
- 0
server/sonar-web/src/main/js/apps/create/project/__tests__/Bitbucket-it.tsx View File

@@ -125,6 +125,18 @@ it('should show import project feature when PAT is already set', async () => {
await user.click(radioButton);
expect(importButton).toBeEnabled();
await user.click(importButton);

expect(
screen.getByRole('heading', { name: 'onboarding.create_project.new_code_definition.title' })
).toBeInTheDocument();

await user.click(screen.getByRole('radio', { name: 'new_code_definition.global_setting' }));
await user.click(
screen.getByRole('button', {
name: 'onboarding.create_project.new_code_definition.create_project',
})
);

expect(await screen.findByText('/dashboard?id=key')).toBeInTheDocument();
});


Loading…
Cancel
Save