]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-19458 New code definition is made part of Azure project onboarding
authorPhilippe Perrin <philippe.perrin@sonarsource.com>
Fri, 9 Jun 2023 15:40:34 +0000 (17:40 +0200)
committersonartech <sonartech@sonarsource.com>
Wed, 14 Jun 2023 09:51:06 +0000 (09:51 +0000)
server/sonar-web/src/main/js/api/alm-integrations.ts
server/sonar-web/src/main/js/api/mocks/AlmIntegrationsServiceMock.ts
server/sonar-web/src/main/js/apps/create/project/Azure/AzureProjectAccordion.tsx
server/sonar-web/src/main/js/apps/create/project/Azure/AzureProjectCreate.tsx
server/sonar-web/src/main/js/apps/create/project/Azure/AzureProjectCreateRenderer.tsx
server/sonar-web/src/main/js/apps/create/project/Azure/AzureProjectsList.tsx
server/sonar-web/src/main/js/apps/create/project/CreateProjectPage.tsx
server/sonar-web/src/main/js/apps/create/project/__tests__/Azure-it.tsx

index e66a15b098a47a754c818e82ed811392f1148813..451e20fbfb5eebfaf6a42966d4a8e4e613709cb2 100644 (file)
@@ -80,16 +80,23 @@ export function searchAzureRepositories(
   );
 }
 
-export function importAzureRepository(
-  almSetting: string,
-  projectName: string,
-  repositoryName: string
-): Promise<{ project: ProjectBase }> {
-  return postJSON('/api/alm_integrations/import_azure_project', {
-    almSetting,
-    projectName,
-    repositoryName,
-  }).catch(throwGlobalError);
+export function setupAzureProjectCreation(data: {
+  almSetting: string;
+  projectName: string;
+  repositoryName: string;
+}) {
+  return (newCodeDefinitionType?: string, newCodeDefinitionValue?: string) =>
+    importAzureRepository({ ...data, newCodeDefinitionType, newCodeDefinitionValue });
+}
+
+export function importAzureRepository(data: {
+  almSetting: string;
+  projectName: string;
+  repositoryName: string;
+  newCodeDefinitionType?: string;
+  newCodeDefinitionValue?: string;
+}): Promise<{ project: ProjectBase }> {
+  return postJSON('/api/alm_integrations/import_azure_project', data).catch(throwGlobalError);
 }
 
 export function getBitbucketServerProjects(
index 48ce63147f51c84755fbaa38048700d8bb9aa943..0a1002c8842047e9bce3763385f8c850f7617eaa 100644 (file)
@@ -57,6 +57,7 @@ import {
   searchForBitbucketCloudRepositories,
   searchForBitbucketServerRepositories,
   setAlmPersonalAccessToken,
+  setupAzureProjectCreation,
 } from '../alm-integrations';
 
 export default class AlmIntegrationsServiceMock {
@@ -192,6 +193,7 @@ export default class AlmIntegrationsServiceMock {
     jest.mocked(getAzureRepositories).mockImplementation(this.getAzureRepositories);
     jest.mocked(getGithubRepositories).mockImplementation(this.getGithubRepositories);
     jest.mocked(searchAzureRepositories).mockImplementation(this.searchAzureRepositories);
+    jest.mocked(setupAzureProjectCreation).mockReturnValue(() => this.importAzureRepository());
     jest.mocked(importAzureRepository).mockImplementation(this.importAzureRepository);
     jest.mocked(importGithubRepository).mockImplementation(this.importGithubRepository);
     jest
index 3556cc7ecbc6dc8ab156fa418b68eaed679c0e8d..8d58b630c2cd38c15a0e7c217586d0852dc49d8b 100644 (file)
@@ -34,7 +34,6 @@ import { AzureProject, AzureRepository } from '../../../../types/alm-integration
 import { CreateProjectModes } from '../types';
 
 export interface AzureProjectAccordionProps {
-  importing: boolean;
   loading: boolean;
   onOpen: (key: string) => void;
   onSelectRepository: (repository: AzureRepository) => void;
@@ -66,7 +65,6 @@ function highlight(text: string, term?: string, underline = false) {
 
 export default function AzureProjectAccordion(props: AzureProjectAccordionProps) {
   const {
-    importing,
     loading,
     startsOpen,
     project,
@@ -148,7 +146,6 @@ export default function AzureProjectAccordion(props: AzureProjectAccordionProps)
                         checked={isSelected(repo)}
                         className="overflow-hidden"
                         alignLabel
-                        disabled={importing}
                         onCheck={() => props.onSelectRepository(repo)}
                         value={repo.name}
                       >
index a65f7c57fe1f3374d1ae8babb3b63d9df2e606e9..ef64815293cdf352c4a99046b0ddb98d4dc23c52 100644 (file)
@@ -22,28 +22,28 @@ import {
   checkPersonalAccessTokenIsValid,
   getAzureProjects,
   getAzureRepositories,
-  importAzureRepository,
   searchAzureRepositories,
   setAlmPersonalAccessToken,
+  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 { tokenExistedBefore } from '../utils';
 import AzureCreateProjectRenderer from './AzureProjectCreateRenderer';
 
 interface Props {
   canAdmin: boolean;
   loadingBindings: boolean;
-  onProjectCreate: (projectKey: string) => void;
   almInstances: AlmSettingsInstance[];
   location: Location;
   router: Router;
+  onProjectSetupDone: (createProject: CreateProjectApiCallback) => void;
 }
 
 interface State {
-  importing: boolean;
   loading: boolean;
   loadingRepositories: Dict<boolean>;
   patIsValid?: boolean;
@@ -65,10 +65,7 @@ export default class AzureProjectCreate extends React.PureComponent<Props, State
   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,
       loadingRepositories: {},
       repositories: {},
@@ -214,28 +211,17 @@ export default class AzureProjectCreate extends React.PureComponent<Props, State
     }
   };
 
-  handleImportRepository = async () => {
+  handleImportRepository = () => {
     const { selectedRepository, selectedAlmInstance } = this.state;
 
-    if (!selectedAlmInstance || !selectedRepository) {
-      return;
-    }
-
-    this.setState({ importing: true });
-
-    const createdProject = await importAzureRepository(
-      selectedAlmInstance.key,
-      selectedRepository.projectName,
-      selectedRepository.name
-    )
-      .then(({ project }) => project)
-      .catch(() => undefined);
-
-    if (this.mounted) {
-      this.setState({ importing: false });
-      if (createdProject) {
-        this.props.onProjectCreate(createdProject.key);
-      }
+    if (selectedAlmInstance && selectedRepository) {
+      this.props.onProjectSetupDone(
+        setupAzureProjectCreation({
+          almSetting: selectedAlmInstance.key,
+          projectName: selectedRepository.projectName,
+          repositoryName: selectedRepository.name,
+        })
+      );
     }
   };
 
@@ -301,7 +287,6 @@ export default class AzureProjectCreate extends React.PureComponent<Props, State
   render() {
     const { canAdmin, loadingBindings, location, almInstances } = this.props;
     const {
-      importing,
       loading,
       loadingRepositories,
       patIsValid,
@@ -320,7 +305,6 @@ export default class AzureProjectCreate extends React.PureComponent<Props, State
     return (
       <AzureCreateProjectRenderer
         canAdmin={canAdmin}
-        importing={importing}
         loading={loading || loadingBindings}
         loadingRepositories={loadingRepositories}
         onImportRepository={this.handleImportRepository}
index cbb051484bc625efd030e283d7f1493d15a17dbb..449961cb081af79ea5a45d6f8407912cd5a8a29a 100644 (file)
@@ -33,14 +33,12 @@ import { Dict } from '../../../../types/types';
 import { ALM_INTEGRATION_CATEGORY } from '../../../settings/constants';
 import AlmSettingsInstanceDropdown from '../components/AlmSettingsInstanceDropdown';
 import CreateProjectPageHeader from '../components/CreateProjectPageHeader';
-import InstanceNewCodeDefinitionComplianceWarning from '../components/InstanceNewCodeDefinitionComplianceWarning';
 import WrongBindingCountAlert from '../components/WrongBindingCountAlert';
 import AzurePersonalAccessTokenForm from './AzurePersonalAccessTokenForm';
 import AzureProjectsList from './AzureProjectsList';
 
 export interface AzureProjectCreateRendererProps {
   canAdmin?: boolean;
-  importing: boolean;
   loading: boolean;
   loadingRepositories: Dict<boolean>;
   onImportRepository: () => void;
@@ -66,7 +64,6 @@ export interface AzureProjectCreateRendererProps {
 export default function AzureProjectCreateRenderer(props: AzureProjectCreateRendererProps) {
   const {
     canAdmin,
-    importing,
     loading,
     loadingRepositories,
     projects,
@@ -94,10 +91,9 @@ export default function AzureProjectCreateRenderer(props: AzureProjectCreateRend
           !showPersonalAccessTokenForm &&
           settingIsValid && (
             <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')}
@@ -165,8 +161,6 @@ export default function AzureProjectCreateRenderer(props: AzureProjectCreateRend
           </div>
         ) : (
           <>
-            <InstanceNewCodeDefinitionComplianceWarning />
-
             <div className="huge-spacer-bottom">
               <SearchBox
                 onChange={props.onSearch}
@@ -175,7 +169,6 @@ export default function AzureProjectCreateRenderer(props: AzureProjectCreateRend
             </div>
             <DeferredSpinner loading={Boolean(searching)}>
               <AzureProjectsList
-                importing={importing}
                 loadingRepositories={loadingRepositories}
                 onOpenProject={props.onOpenProject}
                 onSelectRepository={props.onSelectRepository}
index a393fe25c5cb55f179894d4c9e8e09a00cbeb27b..87f77c4edd35b22b4a47f0e3e43591f86adc63f9 100644 (file)
@@ -31,7 +31,6 @@ import { CreateProjectModes } from '../types';
 import AzureProjectAccordion from './AzureProjectAccordion';
 
 export interface AzureProjectsListProps {
-  importing: boolean;
   loadingRepositories: Dict<boolean>;
   onOpenProject: (key: string) => void;
   onSelectRepository: (repository: AzureRepository) => void;
@@ -46,7 +45,6 @@ const PAGE_SIZE = 10;
 
 export default function AzureProjectsList(props: AzureProjectsListProps) {
   const {
-    importing,
     loadingRepositories,
     projects = [],
     repositories,
@@ -119,7 +117,6 @@ export default function AzureProjectsList(props: AzureProjectsListProps) {
       {displayedProjects.map((p, i) => (
         <AzureProjectAccordion
           key={`${p.name}${keySuffix}`}
-          importing={importing}
           loading={Boolean(loadingRepositories[p.name])}
           onOpen={props.onOpenProject}
           onSelectRepository={props.onSelectRepository}
index 379b9a2b27b89e56116913ca70a9fb5bd1b38c02..7ab2f68ee7c5705e62feed1c6ac644d17853cb99 100644 (file)
@@ -41,10 +41,10 @@ import AlmBindingDefinitionForm from '../../settings/components/almIntegration/A
 import AzureProjectCreate from './Azure/AzureProjectCreate';
 import BitbucketCloudProjectCreate from './BitbucketCloud/BitbucketCloudProjectCreate';
 import BitbucketProjectCreate from './BitbucketServer/BitbucketProjectCreate';
-import CreateProjectPageHeader from './components/CreateProjectPageHeader';
 import CreateProjectModeSelection from './CreateProjectModeSelection';
 import GitHubProjectCreate from './Github/GitHubProjectCreate';
 import GitlabProjectCreate from './Gitlab/GitlabProjectCreate';
+import CreateProjectPageHeader from './components/CreateProjectPageHeader';
 import ManualProjectCreate from './manual/ManualProjectCreate';
 import './style.css';
 import { CreateProjectApiCallback, CreateProjectModes } from './types';
@@ -207,9 +207,9 @@ export class CreateProjectPage extends React.PureComponent<CreateProjectPageProp
             canAdmin={!!canAdmin}
             loadingBindings={loading}
             location={location}
-            onProjectCreate={this.handleProjectCreate}
             router={router}
             almInstances={azureSettings}
+            onProjectSetupDone={this.handleProjectSetupDone}
           />
         );
       }
index 8ddbbacb83327aaf5bf2c9325e69af0ddde8d8c5..db729469f4874b8baa37d0b03c63617e9cb50af9 100644 (file)
@@ -105,6 +105,17 @@ it('should show import project feature when PAT is already set', async () => {
   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();
 });