From 546ea739e4a652bb1076aa60b7a9ad4f01c5b0f2 Mon Sep 17 00:00:00 2001 From: Philippe Perrin Date: Wed, 7 Jun 2023 17:14:14 +0200 Subject: [PATCH] SONAR-19454 New code definition is made part of Gitlab project onboarding --- .../src/main/js/api/alm-integrations.ts | 13 +- .../api/mocks/AlmIntegrationsServiceMock.ts | 2 + .../apps/create/project/CreateProjectPage.tsx | 2 +- .../project/Gitlab/GitlabProjectCreate.tsx | 39 +--- .../Gitlab/GitlabProjectCreateRenderer.tsx | 3 - .../Gitlab/GitlabProjectSelectionForm.tsx | 166 ++++++++---------- .../create/project/__tests__/GitLab-it.tsx | 42 ++--- .../NewCodeDefinitionResolver.java | 4 +- 8 files changed, 109 insertions(+), 162 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 f33562053c0..bd225e1e2dc 100644 --- a/server/sonar-web/src/main/js/api/alm-integrations.ts +++ b/server/sonar-web/src/main/js/api/alm-integrations.ts @@ -250,13 +250,16 @@ export function getGitlabProjects(data: { .catch(throwGlobalError); } +export function setupGitlabProjectCreation(data: { almSetting: string; gitlabProjectId: string }) { + return (newCodeDefinitionType?: string, newCodeDefinitionValue?: string) => + importGitlabProject({ ...data, newCodeDefinitionType, newCodeDefinitionValue }); +} + export function importGitlabProject(data: { almSetting: string; gitlabProjectId: string; + newCodeDefinitionType?: string; + newCodeDefinitionValue?: string; }): Promise<{ project: ProjectBase }> { - const { almSetting, gitlabProjectId } = data; - return postJSON('/api/alm_integrations/import_gitlab_project', { - almSetting, - gitlabProjectId, - }).catch(throwGlobalError); + return postJSON('/api/alm_integrations/import_gitlab_project', data).catch(throwGlobalError); } 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 59c1c9b3011..e34143b5c02 100644 --- a/server/sonar-web/src/main/js/api/mocks/AlmIntegrationsServiceMock.ts +++ b/server/sonar-web/src/main/js/api/mocks/AlmIntegrationsServiceMock.ts @@ -60,6 +60,7 @@ import { setupAzureProjectCreation, setupBitbucketCloudProjectCreation, setupBitbucketServerProjectCreation, + setupGitlabProjectCreation, } from '../alm-integrations'; export default class AlmIntegrationsServiceMock { @@ -187,6 +188,7 @@ export default class AlmIntegrationsServiceMock { .mockImplementation(this.checkPersonalAccessTokenIsValid); jest.mocked(setAlmPersonalAccessToken).mockImplementation(this.setAlmPersonalAccessToken); jest.mocked(getGitlabProjects).mockImplementation(this.getGitlabProjects); + jest.mocked(setupGitlabProjectCreation).mockReturnValue(() => this.importProject()); jest.mocked(importGitlabProject).mockImplementation(this.importProject); jest.mocked(setupBitbucketCloudProjectCreation).mockReturnValue(() => this.importProject()); jest.mocked(importBitbucketCloudRepository).mockImplementation(this.importProject); 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 fe3e7e1dda0..0a8d1add2b6 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 @@ -255,9 +255,9 @@ export class CreateProjectPage extends React.PureComponent ); } diff --git a/server/sonar-web/src/main/js/apps/create/project/Gitlab/GitlabProjectCreate.tsx b/server/sonar-web/src/main/js/apps/create/project/Gitlab/GitlabProjectCreate.tsx index cfa49099e20..6478fc3709f 100644 --- a/server/sonar-web/src/main/js/apps/create/project/Gitlab/GitlabProjectCreate.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/Gitlab/GitlabProjectCreate.tsx @@ -18,24 +18,24 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import { getGitlabProjects, importGitlabProject } from '../../../../api/alm-integrations'; +import { getGitlabProjects, setupGitlabProjectCreation } from '../../../../api/alm-integrations'; import { Location, Router } from '../../../../components/hoc/withRouter'; import { GitlabProject } from '../../../../types/alm-integration'; import { AlmSettingsInstance } from '../../../../types/alm-settings'; import { Paging } from '../../../../types/types'; +import { CreateProjectApiCallback } from '../types'; import GitlabProjectCreateRenderer from './GitlabProjectCreateRenderer'; interface Props { canAdmin: boolean; loadingBindings: boolean; - onProjectCreate: (projectKey: string) => void; almInstances: AlmSettingsInstance[]; location: Location; router: Router; + onProjectSetupDone: (createProject: CreateProjectApiCallback) => void; } interface State { - importingGitlabProjectId?: string; loading: boolean; loadingMore: boolean; projects?: GitlabProject[]; @@ -134,34 +134,13 @@ export default class GitlabProjectCreate extends React.PureComponent { + handleImport = (gitlabProjectId: string) => { const { selectedAlmInstance } = this.state; - if (!selectedAlmInstance) { - return Promise.resolve(undefined); - } - - try { - return await importGitlabProject({ - almSetting: selectedAlmInstance.key, - gitlabProjectId, - }); - } catch (_) { - return this.handleError(); - } - }; - - handleImport = async (gitlabProjectId: string) => { - this.setState({ importingGitlabProjectId: gitlabProjectId }); - - const result = await this.doImport(gitlabProjectId); - - if (this.mounted) { - this.setState({ importingGitlabProjectId: undefined }); - - if (result) { - this.props.onProjectCreate(result.project.key); - } + if (selectedAlmInstance) { + this.props.onProjectSetupDone( + setupGitlabProjectCreation({ almSetting: selectedAlmInstance.key, gitlabProjectId }) + ); } }; @@ -221,7 +200,6 @@ export default class GitlabProjectCreate extends React.PureComponent void; @@ -52,7 +51,6 @@ export interface GitlabProjectCreateRendererProps { export default function GitlabProjectCreateRenderer(props: GitlabProjectCreateRendererProps) { const { canAdmin, - importingGitlabProjectId, loading, loadingMore, projects, @@ -104,7 +102,6 @@ export default function GitlabProjectCreateRenderer(props: GitlabProjectCreateRe /> ) : ( void; onLoadMore: () => void; @@ -49,14 +46,7 @@ export interface GitlabProjectSelectionFormProps { } export default function GitlabProjectSelectionForm(props: GitlabProjectSelectionFormProps) { - const { - importingGitlabProjectId, - loadingMore, - projects = [], - projectsPaging, - searching, - searchQuery, - } = props; + const { loadingMore, projects = [], projectsPaging, searching, searchQuery } = props; if (projects.length === 0 && searchQuery.length === 0 && !searching) { return ( @@ -82,92 +72,82 @@ export default function GitlabProjectSelectionForm(props: GitlabProjectSelection } return ( - <> - -
- +
+ -
+
- {projects.length === 0 ? ( -
{translate('no_results')}
- ) : ( - - - {projects.map((project) => ( - + {projects.length === 0 ? ( +
{translate('no_results')}
+ ) : ( +
+ + {projects.map((project) => ( + + + + {project.sqProjectKey ? ( - - {project.sqProjectKey ? ( - - ) : ( - - )} - - ))} - -
+ + + {project.sqProjectKey ? ( + + + {project.sqProjectName} + + ) : ( + project.name + )} + + +
+ + + {project.pathName} + + +
+ + {translate('onboarding.create_project.gitlab.link')} + + - - - {project.sqProjectKey ? ( - - - {project.sqProjectName} - - ) : ( - project.name - )} - - -
- - - {project.pathName} - - + + + {translate('onboarding.create_project.repository_imported')} +
- - {translate('onboarding.create_project.gitlab.link')} - + ) : ( + + - - - {translate('onboarding.create_project.repository_imported')} - - - -
- )} - -
- + )} + + ))} + + + )} + +
); } diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/GitLab-it.tsx b/server/sonar-web/src/main/js/apps/create/project/__tests__/GitLab-it.tsx index aa090fb0c25..c3e0080516f 100644 --- a/server/sonar-web/src/main/js/apps/create/project/__tests__/GitLab-it.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/GitLab-it.tsx @@ -26,9 +26,7 @@ import { getGitlabProjects } from '../../../../api/alm-integrations'; import AlmIntegrationsServiceMock from '../../../../api/mocks/AlmIntegrationsServiceMock'; import AlmSettingsServiceMock from '../../../../api/mocks/AlmSettingsServiceMock'; import NewCodePeriodsServiceMock from '../../../../api/mocks/NewCodePeriodsServiceMock'; -import { mockNewCodePeriod } from '../../../../helpers/mocks/new-code-period'; import { renderApp } from '../../../../helpers/testReactTestingUtils'; -import { NewCodePeriodSettingType } from '../../../../types/types'; import CreateProjectPage, { CreateProjectPageProps } from '../CreateProjectPage'; jest.mock('../../../../api/alm-integrations'); @@ -108,16 +106,24 @@ it('should show import project feature when PAT is already set', async () => { '/dashboard?id=key' ); - projectItem = screen.getByRole('row', { - name: 'Gitlab project 2 Company / Best Projects opens_in_new_window onboarding.create_project.gitlab.link onboarding.create_project.set_up', - }); - const importProjectButton = within(projectItem).getByRole('button', { + projectItem = screen.getByRole('row', { name: /Gitlab project 2/ }); + const setupButton = within(projectItem).getByRole('button', { name: 'onboarding.create_project.set_up', }); - await act(async () => { - 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(); }); @@ -182,24 +188,6 @@ it('should show no result message when there are no projects', async () => { expect(screen.getByText('onboarding.create_project.gitlab.no_projects')).toBeInTheDocument(); }); -it('should display a warning if the instance default new code definition is not CaYC compliant', async () => { - const user = userEvent.setup(); - newCodePeriodHandler.setNewCodePeriod( - mockNewCodePeriod({ type: NewCodePeriodSettingType.NUMBER_OF_DAYS, value: '91' }) - ); - renderCreateProject(); - await act(async () => { - await user.click(ui.gitlabCreateProjectButton.get()); - await selectEvent.select(ui.instanceSelector.get(), [/conf-final-2/]); - }); - - expect(screen.getByText('Gitlab project 1')).toBeInTheDocument(); - expect(screen.getByText('Gitlab project 2')).toBeInTheDocument(); - expect( - screen.getByText('onboarding.create_project.new_code_option.warning.title') - ).toBeInTheDocument(); -}); - function renderCreateProject(props: Partial = {}) { renderApp('project/create', ); } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/newcodeperiod/NewCodeDefinitionResolver.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/newcodeperiod/NewCodeDefinitionResolver.java index 968ffc732c1..e5efa29a274 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/newcodeperiod/NewCodeDefinitionResolver.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/newcodeperiod/NewCodeDefinitionResolver.java @@ -43,7 +43,7 @@ public class NewCodeDefinitionResolver { private static final String BEGIN_ITEM_LIST = "
  • "; private static final String END_ITEM_LIST = "
  • "; - public static final String NEW_CODE_PERIOD_TYPE_DESCRIPTION_PROJECT_CREATION = "Type
    " + + public static final String NEW_CODE_PERIOD_TYPE_DESCRIPTION_PROJECT_CREATION = "Project New Code Definition Type
    " + "New code definitions of the following types are allowed:" + BEGIN_LIST + BEGIN_ITEM_LIST + PREVIOUS_VERSION.name() + END_ITEM_LIST + @@ -51,7 +51,7 @@ public class NewCodeDefinitionResolver { BEGIN_ITEM_LIST + REFERENCE_BRANCH.name() + " - will default to the main branch." + END_ITEM_LIST + END_LIST; - public static final String NEW_CODE_PERIOD_VALUE_DESCRIPTION_PROJECT_CREATION = "Value
    " + + public static final String NEW_CODE_PERIOD_VALUE_DESCRIPTION_PROJECT_CREATION = "Project New Code Definition Value
    " + "For each new code definition type, a different value is expected:" + BEGIN_LIST + BEGIN_ITEM_LIST + "no value, when the new code definition type is " + PREVIOUS_VERSION.name() + " and " + REFERENCE_BRANCH.name() + END_ITEM_LIST + -- 2.39.5