diff options
author | Mathieu Suen <mathieu.suen@sonarsource.com> | 2023-10-13 18:06:50 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2023-10-18 20:03:05 +0000 |
commit | 8ff9a3138ec0c7a0056b1dca7e47c71e9dad8494 (patch) | |
tree | 1cfd0786d063237667a6425b2d391ca5374aa01b | |
parent | cb55aa8cb1c94ea1e14115222550f58a98897729 (diff) | |
download | sonarqube-8ff9a3138ec0c7a0056b1dca7e47c71e9dad8494.tar.gz sonarqube-8ff9a3138ec0c7a0056b1dca7e47c71e9dad8494.zip |
SONAR-20708 Add multi project import API call
12 files changed, 257 insertions, 113 deletions
diff --git a/server/sonar-web/src/main/js/apps/create/project/Azure/AzureProjectCreate.tsx b/server/sonar-web/src/main/js/apps/create/project/Azure/AzureProjectCreate.tsx index bb511fa7335..bf418da89e3 100644 --- a/server/sonar-web/src/main/js/apps/create/project/Azure/AzureProjectCreate.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/Azure/AzureProjectCreate.tsx @@ -22,13 +22,13 @@ import { getAzureProjects, getAzureRepositories, searchAzureRepositories, - setupAzureProjectCreation, } from '../../../../api/alm-integrations'; import { Location, Router } from '../../../../components/hoc/withRouter'; import { AzureProject, AzureRepository } from '../../../../types/alm-integration'; import { AlmSettingsInstance } from '../../../../types/alm-settings'; import { Dict } from '../../../../types/types'; -import { CreateProjectApiCallback } from '../types'; +import { ImportProjectParam } from '../CreateProjectPage'; +import { CreateProjectModes } from '../types'; import AzureCreateProjectRenderer from './AzureProjectCreateRenderer'; interface Props { @@ -37,7 +37,7 @@ interface Props { almInstances: AlmSettingsInstance[]; location: Location; router: Router; - onProjectSetupDone: (createProject: CreateProjectApiCallback) => void; + onProjectSetupDone: (importProjects: ImportProjectParam) => void; } interface State { @@ -210,13 +210,16 @@ export default class AzureProjectCreate extends React.PureComponent<Props, State const { selectedAlmInstance } = this.state; if (selectedAlmInstance && selectedRepository) { - this.props.onProjectSetupDone( - setupAzureProjectCreation({ - almSetting: selectedAlmInstance.key, - projectName: selectedRepository.projectName, - repositoryName: selectedRepository.name, - }), - ); + this.props.onProjectSetupDone({ + creationMode: CreateProjectModes.AzureDevOps, + almSetting: selectedAlmInstance.key, + projects: [ + { + projectName: selectedRepository.projectName, + repositoryName: selectedRepository.name, + }, + ], + }); } }; 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 46586352292..870ffe5c33b 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 @@ -18,16 +18,14 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import { - searchForBitbucketCloudRepositories, - setupBitbucketCloudProjectCreation, -} from '../../../../api/alm-integrations'; +import { searchForBitbucketCloudRepositories } 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 { ImportProjectParam } from '../CreateProjectPage'; import { BITBUCKET_CLOUD_PROJECTS_PAGESIZE } from '../constants'; -import { CreateProjectApiCallback } from '../types'; +import { CreateProjectModes } from '../types'; import BitbucketCloudProjectCreateRenderer from './BitbucketCloudProjectCreateRender'; interface Props { @@ -36,7 +34,7 @@ interface Props { loadingBindings: boolean; location: Location; router: Router; - onProjectSetupDone: (createProject: CreateProjectApiCallback) => void; + onProjectSetupDone: (importProjects: ImportProjectParam) => void; } interface State { @@ -193,12 +191,15 @@ export default class BitbucketCloudProjectCreate extends React.PureComponent<Pro const { selectedAlmInstance } = this.state; if (selectedAlmInstance) { - this.props.onProjectSetupDone( - setupBitbucketCloudProjectCreation({ - almSetting: selectedAlmInstance.key, - repositorySlug, - }), - ); + this.props.onProjectSetupDone({ + creationMode: CreateProjectModes.BitbucketCloud, + almSetting: selectedAlmInstance.key, + projects: [ + { + repositorySlug, + }, + ], + }); } }; diff --git a/server/sonar-web/src/main/js/apps/create/project/BitbucketServer/BitbucketProjectCreate.tsx b/server/sonar-web/src/main/js/apps/create/project/BitbucketServer/BitbucketProjectCreate.tsx index 0815912f45b..d6f7d6815bb 100644 --- a/server/sonar-web/src/main/js/apps/create/project/BitbucketServer/BitbucketProjectCreate.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/BitbucketServer/BitbucketProjectCreate.tsx @@ -22,7 +22,6 @@ import { getBitbucketServerProjects, getBitbucketServerRepositories, searchForBitbucketServerRepositories, - setupBitbucketServerProjectCreation, } from '../../../../api/alm-integrations'; import { Location, Router } from '../../../../components/hoc/withRouter'; import { @@ -31,8 +30,9 @@ import { BitbucketRepository, } from '../../../../types/alm-integration'; import { AlmSettingsInstance } from '../../../../types/alm-settings'; +import { ImportProjectParam } from '../CreateProjectPage'; import { DEFAULT_BBS_PAGE_SIZE } from '../constants'; -import { CreateProjectApiCallback } from '../types'; +import { CreateProjectModes } from '../types'; import BitbucketCreateProjectRenderer from './BitbucketProjectCreateRenderer'; interface Props { @@ -41,7 +41,7 @@ interface Props { loadingBindings: boolean; location: Location; router: Router; - onProjectSetupDone: (createProject: CreateProjectApiCallback) => void; + onProjectSetupDone: (importProjects: ImportProjectParam) => void; } interface State { @@ -184,13 +184,16 @@ export default class BitbucketProjectCreate extends React.PureComponent<Props, S const { selectedAlmInstance } = this.state; if (selectedAlmInstance) { - this.props.onProjectSetupDone( - setupBitbucketServerProjectCreation({ - almSetting: selectedAlmInstance.key, - projectKey: selectedRepository.projectKey, - repositorySlug: selectedRepository.slug, - }), - ); + this.props.onProjectSetupDone({ + creationMode: CreateProjectModes.BitbucketServer, + almSetting: selectedAlmInstance.key, + projects: [ + { + projectKey: selectedRepository.projectKey, + repositorySlug: selectedRepository.slug, + }, + ], + }); } }; 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 ead4d439536..e16595621d8 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 @@ -41,7 +41,7 @@ import GitHubProjectCreate from './Github/GitHubProjectCreate'; import GitlabProjectCreate from './Gitlab/GitlabProjectCreate'; import NewCodeDefinitionSelection from './components/NewCodeDefinitionSelection'; import ManualProjectCreate from './manual/ManualProjectCreate'; -import { CreateProjectApiCallback, CreateProjectModes } from './types'; +import { CreateProjectModes } from './types'; export interface CreateProjectPageProps extends WithAvailableFeaturesProps { appState: AppState; @@ -57,7 +57,7 @@ interface State { gitlabSettings: AlmSettingsInstance[]; loading: boolean; creatingAlmDefinition?: AlmKeys; - nbrOfProjects?: number; + importProjects?: ImportProjectParam; } const PROJECT_MODE_FOR_ALM_KEY = { @@ -68,9 +68,56 @@ const PROJECT_MODE_FOR_ALM_KEY = { [AlmKeys.GitLab]: CreateProjectModes.GitLab, }; +export type ImportProjectParam = + | { + creationMode: CreateProjectModes.AzureDevOps; + almSetting: string; + projects: { + projectName: string; + repositoryName: string; + }[]; + } + | { + creationMode: CreateProjectModes.BitbucketCloud; + almSetting: string; + projects: { + repositorySlug: string; + }[]; + } + | { + creationMode: CreateProjectModes.BitbucketServer; + almSetting: string; + projects: { + repositorySlug: string; + projectKey: string; + }[]; + } + | { + creationMode: CreateProjectModes.GitHub; + almSetting: string; + projects: { + organization: string; + repositoryKey: string; + }[]; + } + | { + creationMode: CreateProjectModes.GitLab; + almSetting: string; + projects: { + gitlabProjectId: string; + }[]; + } + | { + creationMode: CreateProjectModes.Manual; + projects: { + project: string; + name: string; + mainBranch: string; + }[]; + }; + export class CreateProjectPage extends React.PureComponent<CreateProjectPageProps, State> { mounted = false; - createProjectFnRef: CreateProjectApiCallback | null = null; state: State = { azureSettings: [], @@ -95,7 +142,7 @@ export class CreateProjectPage extends React.PureComponent<CreateProjectPageProp cleanQueryParameters() { const { location, router } = this.props; - if (location.query?.setncd === 'true' && this.createProjectFnRef === null) { + if (location.query?.setncd === 'true') { // Timeout is required to force the refresh of the URL setTimeout(() => { location.query.setncd = undefined; @@ -138,11 +185,10 @@ export class CreateProjectPage extends React.PureComponent<CreateProjectPageProp this.setState({ creatingAlmDefinition: alm }); }; - handleProjectSetupDone = (createProject: CreateProjectApiCallback, nbrOfProjects?: number) => { + handleProjectSetupDone = (importProjects: ImportProjectParam) => { const { location, router } = this.props; - this.createProjectFnRef = createProject; - this.setState({ nbrOfProjects }); + this.setState({ importProjects }); location.query.setncd = 'true'; router.push(location); @@ -275,8 +321,8 @@ export class CreateProjectPage extends React.PureComponent<CreateProjectPageProp } render() { - const { location, router } = this.props; - const { creatingAlmDefinition, nbrOfProjects } = this.state; + const { location } = this.props; + const { creatingAlmDefinition, importProjects } = this.state; const mode: CreateProjectModes | undefined = location.query?.mode; const isProjectSetupDone = location.query?.setncd === 'true'; const gridLayoutStyle = mode ? 'sw-col-start-2 sw-col-span-10' : 'sw-col-span-12'; @@ -296,13 +342,9 @@ export class CreateProjectPage extends React.PureComponent<CreateProjectPageProp <div className={classNames({ 'sw-hidden': isProjectSetupDone })}> {this.renderProjectCreation(mode)} </div> - <div className={classNames({ 'sw-hidden': !isProjectSetupDone })}> - <NewCodeDefinitionSelection - router={router} - createProjectFnRef={this.createProjectFnRef} - numberOfProjects={nbrOfProjects} - /> - </div> + {importProjects !== undefined && isProjectSetupDone && ( + <NewCodeDefinitionSelection importProjects={importProjects} /> + )} {creatingAlmDefinition && ( <AlmBindingDefinitionForm diff --git a/server/sonar-web/src/main/js/apps/create/project/Github/GitHubProjectCreate.tsx b/server/sonar-web/src/main/js/apps/create/project/Github/GitHubProjectCreate.tsx index 67e742ceae2..6572243a44a 100644 --- a/server/sonar-web/src/main/js/apps/create/project/Github/GitHubProjectCreate.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/Github/GitHubProjectCreate.tsx @@ -24,20 +24,20 @@ import { getGithubClientId, getGithubOrganizations, getGithubRepositories, - setupGithubProjectCreation, } from '../../../../api/alm-integrations'; import { Location, Router } from '../../../../components/hoc/withRouter'; import { getHostUrl } from '../../../../helpers/urls'; import { GithubOrganization, GithubRepository } from '../../../../types/alm-integration'; import { AlmKeys, AlmSettingsInstance } from '../../../../types/alm-settings'; import { Paging } from '../../../../types/types'; -import { CreateProjectApiCallback } from '../types'; +import { ImportProjectParam } from '../CreateProjectPage'; +import { CreateProjectModes } from '../types'; import GitHubProjectCreateRenderer from './GitHubProjectCreateRenderer'; interface Props { canAdmin: boolean; loadingBindings: boolean; - onProjectSetupDone: (createProject: CreateProjectApiCallback, nbrOfProjects: number) => void; + onProjectSetupDone: (importProjects: ImportProjectParam) => void; almInstances: AlmSettingsInstance[]; location: Location; router: Router; @@ -263,14 +263,14 @@ export default class GitHubProjectCreate extends React.Component<Props, State> { const { selectedOrganization, selectedAlmInstance } = this.state; if (selectedAlmInstance && selectedOrganization && repoKeys.length > 0) { - this.props.onProjectSetupDone( - setupGithubProjectCreation({ - almSetting: selectedAlmInstance.key, + this.props.onProjectSetupDone({ + almSetting: selectedAlmInstance.key, + creationMode: CreateProjectModes.GitHub, + projects: repoKeys.map((repositoryKey) => ({ + repositoryKey, organization: selectedOrganization.key, - repositoryKey: repoKeys.join(','), // TBD - }), - repoKeys.length, - ); + })), + }); } }; 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 228f67171b5..e2032788c0f 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,12 +18,13 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import { getGitlabProjects, setupGitlabProjectCreation } from '../../../../api/alm-integrations'; +import { getGitlabProjects } 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 { ImportProjectParam } from '../CreateProjectPage'; +import { CreateProjectModes } from '../types'; import GitlabProjectCreateRenderer from './GitlabProjectCreateRenderer'; interface Props { @@ -32,7 +33,7 @@ interface Props { almInstances: AlmSettingsInstance[]; location: Location; router: Router; - onProjectSetupDone: (createProject: CreateProjectApiCallback) => void; + onProjectSetupDone: (importProjects: ImportProjectParam) => void; } interface State { @@ -139,10 +140,11 @@ export default class GitlabProjectCreate extends React.PureComponent<Props, Stat const { selectedAlmInstance } = this.state; if (selectedAlmInstance) { - this.props.onProjectSetupDone( - // eslint-disable-next-line local-rules/no-api-imports - setupGitlabProjectCreation({ almSetting: selectedAlmInstance.key, gitlabProjectId }), - ); + this.props.onProjectSetupDone({ + creationMode: CreateProjectModes.GitLab, + almSetting: selectedAlmInstance.key, + projects: [{ gitlabProjectId }], + }); } }; diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/Manual-it.tsx b/server/sonar-web/src/main/js/apps/create/project/__tests__/Manual-it.tsx index e54eb0096a7..ff9adf035db 100644 --- a/server/sonar-web/src/main/js/apps/create/project/__tests__/Manual-it.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/Manual-it.tsx @@ -32,9 +32,7 @@ import CreateProjectPage, { CreateProjectPageProps } from '../CreateProjectPage' jest.mock('../../../../api/alm-settings'); jest.mock('../../../../api/newCodeDefinition'); jest.mock('../../../../api/project-management', () => ({ - setupManualProjectCreation: jest - .fn() - .mockReturnValue(() => Promise.resolve({ project: mockProject() })), + createProject: jest.fn().mockReturnValue(Promise.resolve({ project: mockProject() })), })); jest.mock('../../../../api/components', () => ({ ...jest.requireActual('../../../../api/components'), diff --git a/server/sonar-web/src/main/js/apps/create/project/components/NewCodeDefinitionSelection.tsx b/server/sonar-web/src/main/js/apps/create/project/components/NewCodeDefinitionSelection.tsx index c9c56f65fa3..e2d22150707 100644 --- a/server/sonar-web/src/main/js/apps/create/project/components/NewCodeDefinitionSelection.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/components/NewCodeDefinitionSelection.tsx @@ -18,50 +18,81 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import { ButtonPrimary, ButtonSecondary, FlagMessage, Link, Spinner, Title } from 'design-system'; +import { omit } from 'lodash'; import * as React from 'react'; -import { FormattedMessage } from 'react-intl'; +import { useEffect } from 'react'; +import { FormattedMessage, useIntl } from 'react-intl'; import { useNavigate } from 'react-router-dom'; -import { Router } from '../../../../components/hoc/withRouter'; import NewCodeDefinitionSelector from '../../../../components/new-code-definition/NewCodeDefinitionSelector'; import { useDocUrl } from '../../../../helpers/docs'; import { addGlobalSuccessMessage } from '../../../../helpers/globalMessages'; import { translate } from '../../../../helpers/l10n'; -import { getProjectUrl } from '../../../../helpers/urls'; +import { getProjectUrl, queryToSearch } from '../../../../helpers/urls'; +import { + MutationArg, + useImportProjectMutation, + useImportProjectProgress, +} from '../../../../queries/import-projects'; import { NewCodeDefinitiondWithCompliance } from '../../../../types/new-code-definition'; -import { CreateProjectApiCallback } from '../types'; +import { ImportProjectParam } from '../CreateProjectPage'; interface Props { - createProjectFnRef: CreateProjectApiCallback | null; - router: Router; - numberOfProjects?: number; + importProjects: ImportProjectParam; } export default function NewCodeDefinitionSelection(props: Props) { - const { createProjectFnRef, router, numberOfProjects } = props; + const { importProjects } = props; - const [submitting, setSubmitting] = React.useState(false); const [selectedDefinition, selectDefinition] = React.useState<NewCodeDefinitiondWithCompliance>(); - + const { mutate, isLoading, data, reset } = useImportProjectMutation(); + const mutateCount = useImportProjectProgress(); + const intl = useIntl(); const navigate = useNavigate(); - const getDocUrl = useDocUrl(); - const isMultipleProjects = numberOfProjects !== undefined && numberOfProjects !== 1; - const projectCount = isMultipleProjects ? numberOfProjects : 1; + const projectCount = importProjects.projects.length; + const isMultipleProjects = projectCount > 1; - const handleProjectCreation = React.useCallback(async () => { - if (createProjectFnRef && selectedDefinition) { - setSubmitting(true); - const { project } = await createProjectFnRef( - selectedDefinition.type, - selectedDefinition.value, - ); - setSubmitting(false); - router.push(getProjectUrl(project.key)); + useEffect(() => { + if (mutateCount > 0 || !data) { + return; + } + reset(); + addGlobalSuccessMessage( + intl.formatMessage( + { id: 'onboarding.create_project.success' }, + { + count: projectCount, + }, + ), + ); + + if (projectCount === 1) { + navigate(getProjectUrl(data.project.key)); + } else { + navigate({ + pathname: '/projects', + search: queryToSearch({ recent: true }), + }); + } + }, [data, projectCount, mutateCount, reset, intl, navigate]); - addGlobalSuccessMessage(translate('onboarding.create_project.success')); + const handleProjectCreation = () => { + if (selectedDefinition) { + importProjects.projects.forEach((p) => { + const arg = { + // eslint-disable-next-line local-rules/use-metrickey-enum + ...omit(importProjects, 'projects'), + ...p, + } as MutationArg; + mutate({ + newCodeDefinitionType: selectedDefinition.type, + newCodeDefinitionValue: selectedDefinition.value, + ...arg, + }); + }); } - }, [createProjectFnRef, router, selectedDefinition]); + }; return ( <div id="project-ncd-selection" className="sw-body-sm"> @@ -106,7 +137,7 @@ export default function NewCodeDefinitionSelection(props: Props) { </ButtonSecondary> <ButtonPrimary onClick={handleProjectCreation} - disabled={!selectedDefinition?.isCompliant || submitting} + disabled={!selectedDefinition?.isCompliant || isLoading} type="submit" > <FormattedMessage @@ -118,7 +149,7 @@ export default function NewCodeDefinitionSelection(props: Props) { count: projectCount, }} /> - <Spinner className="sw-ml-2" loading={submitting} /> + <Spinner className="sw-ml-2" loading={isLoading} /> </ButtonPrimary> </div> </div> diff --git a/server/sonar-web/src/main/js/apps/create/project/manual/ManualProjectCreate.tsx b/server/sonar-web/src/main/js/apps/create/project/manual/ManualProjectCreate.tsx index 5cf0729d81d..f567f7f2f06 100644 --- a/server/sonar-web/src/main/js/apps/create/project/manual/ManualProjectCreate.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/manual/ManualProjectCreate.tsx @@ -33,19 +33,19 @@ import { debounce, isEmpty } from 'lodash'; import * as React from 'react'; import { FormattedMessage } from 'react-intl'; import { doesComponentExists } from '../../../../api/components'; -import { setupManualProjectCreation } from '../../../../api/project-management'; import { getValue } from '../../../../api/settings'; import { useDocUrl } from '../../../../helpers/docs'; import { translate } from '../../../../helpers/l10n'; import { PROJECT_KEY_INVALID_CHARACTERS, validateProjectKey } from '../../../../helpers/projects'; import { ProjectKeyValidationResult } from '../../../../types/component'; import { GlobalSettingKeys } from '../../../../types/settings'; +import { ImportProjectParam } from '../CreateProjectPage'; import { PROJECT_NAME_MAX_LEN } from '../constants'; -import { CreateProjectApiCallback } from '../types'; +import { CreateProjectModes } from '../types'; interface Props { branchesEnabled: boolean; - onProjectSetupDone: (createProject: CreateProjectApiCallback) => void; + onProjectSetupDone: (importProjects: ImportProjectParam) => void; } interface State { @@ -133,13 +133,16 @@ export default class ManualProjectCreate extends React.PureComponent<Props, Stat event.preventDefault(); const { projectKey, projectName, mainBranchName } = this.state; if (this.canSubmit(this.state)) { - this.props.onProjectSetupDone( - setupManualProjectCreation({ - project: projectKey, - name: (projectName || projectKey).trim(), - mainBranch: mainBranchName, - }), - ); + this.props.onProjectSetupDone({ + creationMode: CreateProjectModes.Manual, + projects: [ + { + project: projectKey, + name: (projectName || projectKey).trim(), + mainBranch: mainBranchName, + }, + ], + }); } }; diff --git a/server/sonar-web/src/main/js/apps/create/project/types.ts b/server/sonar-web/src/main/js/apps/create/project/types.ts index 3933da55379..fdb2f01e800 100644 --- a/server/sonar-web/src/main/js/apps/create/project/types.ts +++ b/server/sonar-web/src/main/js/apps/create/project/types.ts @@ -17,8 +17,6 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { ProjectBase } from '../../../api/components'; -import { NewCodeDefinitionType } from '../../../types/new-code-definition'; export enum CreateProjectModes { Manual = 'manual', @@ -28,8 +26,3 @@ export enum CreateProjectModes { GitHub = 'github', GitLab = 'gitlab', } - -export type CreateProjectApiCallback = ( - newCodeDefinitionType?: NewCodeDefinitionType, - newCodeDefinitionValue?: string, -) => Promise<{ project: ProjectBase }>; diff --git a/server/sonar-web/src/main/js/queries/import-projects.ts b/server/sonar-web/src/main/js/queries/import-projects.ts new file mode 100644 index 00000000000..2510b371c1a --- /dev/null +++ b/server/sonar-web/src/main/js/queries/import-projects.ts @@ -0,0 +1,69 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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 { useIsMutating, useMutation } from '@tanstack/react-query'; +import { + importAzureRepository, + importBitbucketCloudRepository, + importBitbucketServerProject, + importGithubRepository, + importGitlabProject, +} from '../api/alm-integrations'; +import { createProject } from '../api/project-management'; +import { ImportProjectParam } from '../apps/create/project/CreateProjectPage'; +import { CreateProjectModes } from '../apps/create/project/types'; + +export type MutationArg<AlmImport extends ImportProjectParam = ImportProjectParam> = + AlmImport extends { + creationMode: infer A; + almSetting: string; + projects: (infer R)[]; + } + ? { creationMode: A; almSetting: string } & R + : never; + +export function useImportProjectMutation() { + return useMutation({ + mutationFn: ( + data: { + newCodeDefinitionType?: string; + newCodeDefinitionValue?: string; + } & MutationArg, + ) => { + if (data.creationMode === CreateProjectModes.GitHub) { + return importGithubRepository(data); + } else if (data.creationMode === CreateProjectModes.AzureDevOps) { + return importAzureRepository(data); + } else if (data.creationMode === CreateProjectModes.BitbucketCloud) { + return importBitbucketCloudRepository(data); + } else if (data.creationMode === CreateProjectModes.BitbucketServer) { + return importBitbucketServerProject(data); + } else if (data.creationMode === CreateProjectModes.GitLab) { + return importGitlabProject(data); + } + + return createProject(data); + }, + mutationKey: ['import'], + }); +} + +export function useImportProjectProgress() { + return useIsMutating({ mutationKey: ['import'] }); +} diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index fb19ad89c0f..09b12b70209 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -4200,8 +4200,7 @@ onboarding.create_project.new_code_definition.description.link=Defining New Code onboarding.create_project.new_code_definition.create_project=Create project onboarding.create_project.new_code_definition.create_x_projects=Create {count, plural, one {project} other {# projects}} onboarding.create_projects.new_code_definition.change_info=You can change this for each project individually at any time in the project administration. - -onboarding.create_project.success=Congratulations! Your project has been created. +onboarding.create_project.success=Your {count, plural, one {project has} other {# projects have}} been created. onboarding.token.header=Provide a token onboarding.token.text=The token is used to identify you when an analysis is performed. If it has been compromised, you can revoke it at any point in time in your {link}. |