diff options
author | Philippe Perrin <philippe.perrin@sonarsource.com> | 2023-06-09 17:21:05 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2023-06-14 09:51:06 +0000 |
commit | 815cf53518e591b48b8af46f9840e4cc54c4bb65 (patch) | |
tree | 9e209127f4f0d1c2eeecdfb5826cd279101822dd /server | |
parent | fb56254f6aedba9c8c63dee5ef73cca636f1ccab (diff) | |
download | sonarqube-815cf53518e591b48b8af46f9840e4cc54c4bb65.tar.gz sonarqube-815cf53518e591b48b8af46f9840e4cc54c4bb65.zip |
SONAR-19457 New code definition is made part of Bitbucket Cloud project onboarding
Diffstat (limited to 'server')
7 files changed, 135 insertions, 150 deletions
diff --git a/server/sonar-web/src/main/js/api/alm-integrations.ts b/server/sonar-web/src/main/js/api/alm-integrations.ts index 7e81ff101ba..f33562053c0 100644 --- a/server/sonar-web/src/main/js/api/alm-integrations.ts +++ b/server/sonar-web/src/main/js/api/alm-integrations.ts @@ -173,14 +173,21 @@ export function getGithubClientId(almSetting: string): Promise<{ clientId?: stri return getJSON('/api/alm_integrations/get_github_client_id', { almSetting }); } -export function importBitbucketCloudRepository( - almSetting: string, - repositorySlug: string -): Promise<{ project: ProjectBase }> { - return postJSON('/api/alm_integrations/import_bitbucketcloud_repo', { - almSetting, - repositorySlug, - }).catch(throwGlobalError); +export function setupBitbucketCloudProjectCreation(data: { + almSetting: string; + repositorySlug: string; +}) { + return (newCodeDefinitionType?: string, newCodeDefinitionValue?: string) => + importBitbucketCloudRepository({ ...data, newCodeDefinitionType, newCodeDefinitionValue }); +} + +export function importBitbucketCloudRepository(data: { + almSetting: string; + repositorySlug: string; + newCodeDefinitionType?: string; + newCodeDefinitionValue?: string; +}): Promise<{ project: ProjectBase }> { + return postJSON('/api/alm_integrations/import_bitbucketcloud_repo', data).catch(throwGlobalError); } export function importGithubRepository( diff --git a/server/sonar-web/src/main/js/api/mocks/AlmIntegrationsServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/AlmIntegrationsServiceMock.ts index 05a6d32f6b8..59c1c9b3011 100644 --- a/server/sonar-web/src/main/js/api/mocks/AlmIntegrationsServiceMock.ts +++ b/server/sonar-web/src/main/js/api/mocks/AlmIntegrationsServiceMock.ts @@ -58,6 +58,7 @@ import { searchForBitbucketServerRepositories, setAlmPersonalAccessToken, setupAzureProjectCreation, + setupBitbucketCloudProjectCreation, setupBitbucketServerProjectCreation, } from '../alm-integrations'; @@ -187,6 +188,7 @@ export default class AlmIntegrationsServiceMock { jest.mocked(setAlmPersonalAccessToken).mockImplementation(this.setAlmPersonalAccessToken); jest.mocked(getGitlabProjects).mockImplementation(this.getGitlabProjects); jest.mocked(importGitlabProject).mockImplementation(this.importProject); + jest.mocked(setupBitbucketCloudProjectCreation).mockReturnValue(() => this.importProject()); jest.mocked(importBitbucketCloudRepository).mockImplementation(this.importProject); jest.mocked(getGithubClientId).mockImplementation(this.getGithubClientId); jest.mocked(getGithubOrganizations).mockImplementation(this.getGithubOrganizations); diff --git a/server/sonar-web/src/main/js/apps/create/project/BitbucketCloud/BitbucketCloudProjectCreate.tsx b/server/sonar-web/src/main/js/apps/create/project/BitbucketCloud/BitbucketCloudProjectCreate.tsx index 41adf4c9baa..0a4a2baf20c 100644 --- a/server/sonar-web/src/main/js/apps/create/project/BitbucketCloud/BitbucketCloudProjectCreate.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/BitbucketCloud/BitbucketCloudProjectCreate.tsx @@ -19,26 +19,26 @@ */ import * as React from 'react'; import { - importBitbucketCloudRepository, searchForBitbucketCloudRepositories, + setupBitbucketCloudProjectCreation, } from '../../../../api/alm-integrations'; import { Location, Router } from '../../../../components/hoc/withRouter'; import { BitbucketCloudRepository } from '../../../../types/alm-integration'; import { AlmSettingsInstance } from '../../../../types/alm-settings'; import { Paging } from '../../../../types/types'; +import { CreateProjectApiCallback } from '../types'; import BitbucketCloudProjectCreateRenderer from './BitbucketCloudProjectCreateRender'; interface Props { canAdmin: boolean; almInstances: AlmSettingsInstance[]; loadingBindings: boolean; - onProjectCreate: (projectKey: string) => void; location: Location; router: Router; + onProjectSetupDone: (createProject: CreateProjectApiCallback) => void; } interface State { - importingSlug?: string; isLastPage?: boolean; loading: boolean; loadingMore: boolean; @@ -189,26 +189,16 @@ export default class BitbucketCloudProjectCreate extends React.PureComponent<Pro ); }; - handleImport = async (repositorySlug: string) => { + handleImport = (repositorySlug: string) => { const { selectedAlmInstance } = this.state; - if (!selectedAlmInstance) { - return; - } - - this.setState({ importingSlug: repositorySlug }); - - const result = await importBitbucketCloudRepository( - selectedAlmInstance.key, - repositorySlug - ).catch(() => undefined); - - if (this.mounted) { - this.setState({ importingSlug: undefined }); - - if (result) { - this.props.onProjectCreate(result.project.key); - } + if (selectedAlmInstance) { + this.props.onProjectSetupDone( + setupBitbucketCloudProjectCreation({ + almSetting: selectedAlmInstance.key, + repositorySlug, + }) + ); } }; @@ -226,7 +216,6 @@ export default class BitbucketCloudProjectCreate extends React.PureComponent<Pro render() { const { canAdmin, loadingBindings, location, almInstances } = this.props; const { - importingSlug, isLastPage = true, selectedAlmInstance, loading, @@ -239,7 +228,6 @@ export default class BitbucketCloudProjectCreate extends React.PureComponent<Pro } = this.state; return ( <BitbucketCloudProjectCreateRenderer - importingSlug={importingSlug} isLastPage={isLastPage} selectedAlmInstance={selectedAlmInstance} almInstances={almInstances} diff --git a/server/sonar-web/src/main/js/apps/create/project/BitbucketCloud/BitbucketCloudProjectCreateRender.tsx b/server/sonar-web/src/main/js/apps/create/project/BitbucketCloud/BitbucketCloudProjectCreateRender.tsx index 28356e43449..770e8cac2ec 100644 --- a/server/sonar-web/src/main/js/apps/create/project/BitbucketCloud/BitbucketCloudProjectCreateRender.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/BitbucketCloud/BitbucketCloudProjectCreateRender.tsx @@ -29,7 +29,6 @@ import WrongBindingCountAlert from '../components/WrongBindingCountAlert'; import BitbucketCloudSearchForm from './BitbucketCloudSearchForm'; export interface BitbucketCloudProjectCreateRendererProps { - importingSlug?: string; isLastPage: boolean; canAdmin?: boolean; loading: boolean; @@ -53,7 +52,6 @@ export default function BitbucketCloudProjectCreateRenderer( ) { const { almInstances, - importingSlug, isLastPage, selectedAlmInstance, canAdmin, @@ -105,7 +103,6 @@ export default function BitbucketCloudProjectCreateRenderer( /> ) : ( <BitbucketCloudSearchForm - importingSlug={importingSlug} isLastPage={isLastPage} loadingMore={loadingMore} searchQuery={searchQuery} diff --git a/server/sonar-web/src/main/js/apps/create/project/BitbucketCloud/BitbucketCloudSearchForm.tsx b/server/sonar-web/src/main/js/apps/create/project/BitbucketCloud/BitbucketCloudSearchForm.tsx index d52b70a176a..8b90691f348 100644 --- a/server/sonar-web/src/main/js/apps/create/project/BitbucketCloud/BitbucketCloudSearchForm.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/BitbucketCloud/BitbucketCloudSearchForm.tsx @@ -33,11 +33,9 @@ import { getProjectUrl, queryToSearch } from '../../../../helpers/urls'; import { BitbucketCloudRepository } from '../../../../types/alm-integration'; import { ComponentQualifier } from '../../../../types/component'; import { MetricType } from '../../../../types/metrics'; -import InstanceNewCodeDefinitionComplianceWarning from '../components/InstanceNewCodeDefinitionComplianceWarning'; import { CreateProjectModes } from '../types'; export interface BitbucketCloudSearchFormProps { - importingSlug?: string; isLastPage: boolean; loadingMore: boolean; onImport: (repositorySlug: string) => void; @@ -53,14 +51,7 @@ function getRepositoryUrl(workspace: string, slug: string) { } export default function BitbucketCloudSearchForm(props: BitbucketCloudSearchFormProps) { - const { - importingSlug, - isLastPage, - loadingMore, - repositories = [], - searching, - searchQuery, - } = props; + const { isLastPage, loadingMore, repositories = [], searching, searchQuery } = props; if (repositories.length === 0 && searchQuery.length === 0 && !searching) { return ( @@ -86,109 +77,101 @@ export default function BitbucketCloudSearchForm(props: BitbucketCloudSearchForm } return ( - <> - <InstanceNewCodeDefinitionComplianceWarning /> - <div className="boxed-group big-padded create-project-import"> - <SearchBox - className="spacer" - loading={searching} - minLength={3} - onChange={props.onSearch} - placeholder={translate('onboarding.create_project.search_prompt')} - /> + <div className="boxed-group big-padded create-project-import"> + <SearchBox + className="spacer" + loading={searching} + minLength={3} + onChange={props.onSearch} + placeholder={translate('onboarding.create_project.search_prompt')} + /> - <hr /> + <hr /> - {repositories.length === 0 ? ( - <div className="padded">{translate('no_results')}</div> - ) : ( - <table className="data zebra zebra-hover"> - <tbody> - {repositories.map((repository) => ( - <tr key={repository.uuid}> + {repositories.length === 0 ? ( + <div className="padded">{translate('no_results')}</div> + ) : ( + <table className="data zebra zebra-hover"> + <tbody> + {repositories.map((repository) => ( + <tr key={repository.uuid}> + <td> + <Tooltip overlay={repository.slug}> + <strong className="project-name display-inline-block text-ellipsis"> + {repository.sqProjectKey ? ( + <Link to={getProjectUrl(repository.sqProjectKey)}> + <QualifierIcon + className="spacer-right" + qualifier={ComponentQualifier.Project} + /> + {repository.name} + </Link> + ) : ( + repository.name + )} + </strong> + </Tooltip> + <br /> + <Tooltip overlay={repository.projectKey}> + <span className="text-muted project-path display-inline-block text-ellipsis"> + {repository.projectKey} + </span> + </Tooltip> + </td> + <td> + <Link + className="display-inline-flex-center big-spacer-right" + to={getRepositoryUrl(repository.workspace, repository.slug)} + target="_blank" + > + {translate('onboarding.create_project.bitbucketcloud.link')} + </Link> + </td> + {repository.sqProjectKey ? ( <td> - <Tooltip overlay={repository.slug}> - <strong className="project-name display-inline-block text-ellipsis"> - {repository.sqProjectKey ? ( - <Link to={getProjectUrl(repository.sqProjectKey)}> - <QualifierIcon - className="spacer-right" - qualifier={ComponentQualifier.Project} - /> - {repository.name} - </Link> - ) : ( - repository.name - )} - </strong> - </Tooltip> - <br /> - <Tooltip overlay={repository.projectKey}> - <span className="text-muted project-path display-inline-block text-ellipsis"> - {repository.projectKey} - </span> - </Tooltip> + <span className="display-flex-center display-flex-justify-end already-set-up"> + <CheckIcon className="little-spacer-right" size={12} /> + {translate('onboarding.create_project.repository_imported')} + </span> </td> - <td> - <Link - className="display-inline-flex-center big-spacer-right" - to={getRepositoryUrl(repository.workspace, repository.slug)} - target="_blank" + ) : ( + <td className="text-right"> + <Button + onClick={() => { + props.onImport(repository.slug); + }} > - {translate('onboarding.create_project.bitbucketcloud.link')} - </Link> + {translate('onboarding.create_project.set_up')} + </Button> </td> - {repository.sqProjectKey ? ( - <td> - <span className="display-flex-center display-flex-justify-end already-set-up"> - <CheckIcon className="little-spacer-right" size={12} /> - {translate('onboarding.create_project.repository_imported')} - </span> - </td> - ) : ( - <td className="text-right"> - <Button - disabled={Boolean(importingSlug)} - onClick={() => { - props.onImport(repository.slug); - }} - > - {translate('onboarding.create_project.set_up')} - <DeferredSpinner - className="spacer-left" - loading={importingSlug === repository.slug} - /> - </Button> - </td> - )} - </tr> - ))} - </tbody> - </table> - )} - <footer className="spacer-top note text-center"> - {isLastPage && - translateWithParameters( - 'x_of_y_shown', - formatMeasure(repositories.length, MetricType.Integer, null), - formatMeasure(repositories.length, MetricType.Integer, null) - )} - {!isLastPage && ( - <Button - className="spacer-left" - disabled={loadingMore} - data-test="show-more" - onClick={props.onLoadMore} - > - {translate('show_more')} - </Button> + )} + </tr> + ))} + </tbody> + </table> + )} + <footer className="spacer-top note text-center"> + {isLastPage && + translateWithParameters( + 'x_of_y_shown', + formatMeasure(repositories.length, MetricType.Integer, null), + formatMeasure(repositories.length, MetricType.Integer, null) )} - <DeferredSpinner - className="text-bottom spacer-left position-absolute" - loading={loadingMore} - /> - </footer> - </div> - </> + {!isLastPage && ( + <Button + className="spacer-left" + disabled={loadingMore} + data-test="show-more" + onClick={props.onLoadMore} + > + {translate('show_more')} + </Button> + )} + <DeferredSpinner + className="text-bottom spacer-left position-absolute" + loading={loadingMore} + /> + </footer> + </div> ); } diff --git a/server/sonar-web/src/main/js/apps/create/project/CreateProjectPage.tsx b/server/sonar-web/src/main/js/apps/create/project/CreateProjectPage.tsx index 2f0734b6481..fe3e7e1dda0 100644 --- a/server/sonar-web/src/main/js/apps/create/project/CreateProjectPage.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/CreateProjectPage.tsx @@ -231,7 +231,7 @@ export class CreateProjectPage extends React.PureComponent<CreateProjectPageProp canAdmin={!!canAdmin} loadingBindings={loading} location={location} - onProjectCreate={this.handleProjectCreate} + onProjectSetupDone={this.handleProjectSetupDone} router={router} almInstances={bitbucketCloudSettings} /> diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/BitbucketCloud-it.tsx b/server/sonar-web/src/main/js/apps/create/project/__tests__/BitbucketCloud-it.tsx index ee4792f5d19..376024a2e44 100644 --- a/server/sonar-web/src/main/js/apps/create/project/__tests__/BitbucketCloud-it.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/BitbucketCloud-it.tsx @@ -124,9 +124,7 @@ it('should show import project feature when PAT is already set', async () => { expect(screen.getByText('BitbucketCloud Repo 1')).toBeInTheDocument(); expect(screen.getByText('BitbucketCloud Repo 2')).toBeInTheDocument(); - projectItem = screen.getByRole('row', { - name: 'qualifier.TRK BitbucketCloud Repo 1 project opens_in_new_window onboarding.create_project.bitbucketcloud.link onboarding.create_project.repository_imported', - }); + projectItem = screen.getByRole('row', { name: /BitbucketCloud Repo 1/ }); expect( within(projectItem).getByText('onboarding.create_project.repository_imported') ).toBeInTheDocument(); @@ -139,14 +137,24 @@ it('should show import project feature when PAT is already set', async () => { '/dashboard?id=key' ); - projectItem = screen.getByRole('row', { - name: 'BitbucketCloud Repo 2 project opens_in_new_window onboarding.create_project.bitbucketcloud.link onboarding.create_project.set_up', - }); - const importProjectButton = within(projectItem).getByRole('button', { + projectItem = screen.getByRole('row', { name: /BitbucketCloud Repo 2/ }); + const setupButton = within(projectItem).getByRole('button', { name: 'onboarding.create_project.set_up', }); - await user.click(importProjectButton); + await user.click(setupButton); + + 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(); }); |