aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilippe Perrin <philippe.perrin@sonarsource.com>2023-06-07 17:14:14 +0200
committersonartech <sonartech@sonarsource.com>2023-06-14 09:51:06 +0000
commit546ea739e4a652bb1076aa60b7a9ad4f01c5b0f2 (patch)
treead5c52404a090adac2d4cbec30a6097a13144115
parent815cf53518e591b48b8af46f9840e4cc54c4bb65 (diff)
downloadsonarqube-546ea739e4a652bb1076aa60b7a9ad4f01c5b0f2.tar.gz
sonarqube-546ea739e4a652bb1076aa60b7a9ad4f01c5b0f2.zip
SONAR-19454 New code definition is made part of Gitlab project onboarding
-rw-r--r--server/sonar-web/src/main/js/api/alm-integrations.ts13
-rw-r--r--server/sonar-web/src/main/js/api/mocks/AlmIntegrationsServiceMock.ts2
-rw-r--r--server/sonar-web/src/main/js/apps/create/project/CreateProjectPage.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/create/project/Gitlab/GitlabProjectCreate.tsx39
-rw-r--r--server/sonar-web/src/main/js/apps/create/project/Gitlab/GitlabProjectCreateRenderer.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/create/project/Gitlab/GitlabProjectSelectionForm.tsx166
-rw-r--r--server/sonar-web/src/main/js/apps/create/project/__tests__/GitLab-it.tsx42
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/newcodeperiod/NewCodeDefinitionResolver.java4
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<CreateProjectPageProp
canAdmin={!!canAdmin}
loadingBindings={loading}
location={location}
- onProjectCreate={this.handleProjectCreate}
router={router}
almInstances={gitlabSettings}
+ onProjectSetupDone={this.handleProjectSetupDone}
/>
);
}
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<Props, Stat
}
};
- doImport = async (gitlabProjectId: string) => {
+ 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<Props, Stat
render() {
const { loadingBindings, location, almInstances, canAdmin } = this.props;
const {
- importingGitlabProjectId,
loading,
loadingMore,
projects,
@@ -238,7 +216,6 @@ export default class GitlabProjectCreate extends React.PureComponent<Props, Stat
canAdmin={canAdmin}
almInstances={almInstances}
selectedAlmInstance={selectedAlmInstance}
- importingGitlabProjectId={importingGitlabProjectId}
loading={loading || loadingBindings}
loadingMore={loadingMore}
onImport={this.handleImport}
diff --git a/server/sonar-web/src/main/js/apps/create/project/Gitlab/GitlabProjectCreateRenderer.tsx b/server/sonar-web/src/main/js/apps/create/project/Gitlab/GitlabProjectCreateRenderer.tsx
index 366f5610d70..695ce5dad36 100644
--- a/server/sonar-web/src/main/js/apps/create/project/Gitlab/GitlabProjectCreateRenderer.tsx
+++ b/server/sonar-web/src/main/js/apps/create/project/Gitlab/GitlabProjectCreateRenderer.tsx
@@ -31,7 +31,6 @@ import GitlabProjectSelectionForm from './GitlabProjectSelectionForm';
export interface GitlabProjectCreateRendererProps {
canAdmin?: boolean;
- importingGitlabProjectId?: string;
loading: boolean;
loadingMore: boolean;
onImport: (gitlabProjectId: string) => 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
/>
) : (
<GitlabProjectSelectionForm
- importingGitlabProjectId={importingGitlabProjectId}
loadingMore={loadingMore}
onImport={props.onImport}
onLoadMore={props.onLoadMore}
diff --git a/server/sonar-web/src/main/js/apps/create/project/Gitlab/GitlabProjectSelectionForm.tsx b/server/sonar-web/src/main/js/apps/create/project/Gitlab/GitlabProjectSelectionForm.tsx
index 56f3c8ebb39..87926e314bc 100644
--- a/server/sonar-web/src/main/js/apps/create/project/Gitlab/GitlabProjectSelectionForm.tsx
+++ b/server/sonar-web/src/main/js/apps/create/project/Gitlab/GitlabProjectSelectionForm.tsx
@@ -27,17 +27,14 @@ import { Button } from '../../../../components/controls/buttons';
import CheckIcon from '../../../../components/icons/CheckIcon';
import QualifierIcon from '../../../../components/icons/QualifierIcon';
import { Alert } from '../../../../components/ui/Alert';
-import DeferredSpinner from '../../../../components/ui/DeferredSpinner';
import { translate } from '../../../../helpers/l10n';
import { getProjectUrl, queryToSearch } from '../../../../helpers/urls';
import { GitlabProject } from '../../../../types/alm-integration';
import { ComponentQualifier } from '../../../../types/component';
import { Paging } from '../../../../types/types';
-import InstanceNewCodeDefinitionComplianceWarning from '../components/InstanceNewCodeDefinitionComplianceWarning';
import { CreateProjectModes } from '../types';
export interface GitlabProjectSelectionFormProps {
- importingGitlabProjectId?: string;
loadingMore: boolean;
onImport: (gitlabProjectId: string) => 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 (
- <>
- <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 />
- {projects.length === 0 ? (
- <div className="padded">{translate('no_results')}</div>
- ) : (
- <table className="data zebra zebra-hover">
- <tbody>
- {projects.map((project) => (
- <tr key={project.id}>
+ {projects.length === 0 ? (
+ <div className="padded">{translate('no_results')}</div>
+ ) : (
+ <table className="data zebra zebra-hover">
+ <tbody>
+ {projects.map((project) => (
+ <tr key={project.id}>
+ <td>
+ <Tooltip overlay={project.slug}>
+ <strong className="project-name display-inline-block text-ellipsis">
+ {project.sqProjectKey ? (
+ <Link to={getProjectUrl(project.sqProjectKey)}>
+ <QualifierIcon
+ className="spacer-right"
+ qualifier={ComponentQualifier.Project}
+ />
+ {project.sqProjectName}
+ </Link>
+ ) : (
+ project.name
+ )}
+ </strong>
+ </Tooltip>
+ <br />
+ <Tooltip overlay={project.pathSlug}>
+ <span className="text-muted project-path display-inline-block text-ellipsis">
+ {project.pathName}
+ </span>
+ </Tooltip>
+ </td>
+ <td>
+ <Link
+ className="display-inline-flex-center big-spacer-right"
+ to={project.url}
+ target="_blank"
+ >
+ {translate('onboarding.create_project.gitlab.link')}
+ </Link>
+ </td>
+ {project.sqProjectKey ? (
<td>
- <Tooltip overlay={project.slug}>
- <strong className="project-name display-inline-block text-ellipsis">
- {project.sqProjectKey ? (
- <Link to={getProjectUrl(project.sqProjectKey)}>
- <QualifierIcon
- className="spacer-right"
- qualifier={ComponentQualifier.Project}
- />
- {project.sqProjectName}
- </Link>
- ) : (
- project.name
- )}
- </strong>
- </Tooltip>
- <br />
- <Tooltip overlay={project.pathSlug}>
- <span className="text-muted project-path display-inline-block text-ellipsis">
- {project.pathName}
- </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={project.url}
- target="_blank"
- >
- {translate('onboarding.create_project.gitlab.link')}
- </Link>
+ ) : (
+ <td className="text-right">
+ <Button onClick={() => props.onImport(project.id)}>
+ {translate('onboarding.create_project.set_up')}
+ </Button>
</td>
- {project.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={!!importingGitlabProjectId}
- onClick={() => props.onImport(project.id)}
- >
- {translate('onboarding.create_project.set_up')}
- <DeferredSpinner
- className="spacer-left"
- loading={importingGitlabProjectId === project.id}
- />
- </Button>
- </td>
- )}
- </tr>
- ))}
- </tbody>
- </table>
- )}
- <ListFooter
- count={projects.length}
- loadMore={props.onLoadMore}
- loading={loadingMore}
- pageSize={projectsPaging.pageSize}
- total={projectsPaging.total}
- />
- </div>
- </>
+ )}
+ </tr>
+ ))}
+ </tbody>
+ </table>
+ )}
+ <ListFooter
+ count={projects.length}
+ loadMore={props.onLoadMore}
+ loading={loadingMore}
+ pageSize={projectsPaging.pageSize}
+ total={projectsPaging.total}
+ />
+ </div>
);
}
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<CreateProjectPageProps> = {}) {
renderApp('project/create', <CreateProjectPage {...props} />);
}
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 = "<li>";
private static final String END_ITEM_LIST = "</li>";
- public static final String NEW_CODE_PERIOD_TYPE_DESCRIPTION_PROJECT_CREATION = "Type<br/>" +
+ public static final String NEW_CODE_PERIOD_TYPE_DESCRIPTION_PROJECT_CREATION = "Project New Code Definition Type<br/>" +
"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<br/>" +
+ public static final String NEW_CODE_PERIOD_VALUE_DESCRIPTION_PROJECT_CREATION = "Project New Code Definition Value<br/>" +
"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 +