]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-17528 Update tutorials to use the actual main branch name
authorWouter Admiraal <wouter.admiraal@sonarsource.com>
Thu, 27 Oct 2022 13:42:08 +0000 (15:42 +0200)
committersonartech <sonartech@sonarsource.com>
Fri, 28 Oct 2022 20:03:23 +0000 (20:03 +0000)
64 files changed:
server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts
server/sonar-web/src/main/js/apps/audit-logs/components/__tests__/AuditApp-it.tsx
server/sonar-web/src/main/js/components/tutorials/TutorialSelection.tsx
server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx
server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelection-it.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelection-test.tsx [deleted file]
server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelectionRenderer-test.tsx [deleted file]
server/sonar-web/src/main/js/components/tutorials/__tests__/__snapshots__/TutorialSelection-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/components/tutorials/__tests__/__snapshots__/TutorialSelectionRenderer-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/components/tutorials/github-action/AnalysisCommand.tsx
server/sonar-web/src/main/js/components/tutorials/github-action/GitHubActionTutorial.tsx
server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/AnalysisCommand-test.tsx
server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/GitHubActionTutorial-test.tsx
server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/__snapshots__/AnalysisCommand-test.tsx.snap
server/sonar-web/src/main/js/components/tutorials/github-action/commands/CFamily.tsx
server/sonar-web/src/main/js/components/tutorials/github-action/commands/DotNet.tsx
server/sonar-web/src/main/js/components/tutorials/github-action/commands/Gradle.tsx
server/sonar-web/src/main/js/components/tutorials/github-action/commands/JavaMaven.tsx
server/sonar-web/src/main/js/components/tutorials/github-action/commands/Others.tsx
server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/CFamily-test.tsx
server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/DotNet-test.tsx
server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/Gradle-test.tsx
server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/JavaMaven-test.tsx
server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/Others-test.tsx
server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/__snapshots__/CFamily-test.tsx.snap
server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/__snapshots__/DotNet-test.tsx.snap
server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/__snapshots__/Gradle-test.tsx.snap
server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/__snapshots__/JavaMaven-test.tsx.snap
server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/__snapshots__/Others-test.tsx.snap
server/sonar-web/src/main/js/components/tutorials/github-action/constants.ts [new file with mode: 0644]
server/sonar-web/src/main/js/components/tutorials/github-action/utils.ts [new file with mode: 0644]
server/sonar-web/src/main/js/components/tutorials/gitlabci/GitLabCITutorial.tsx
server/sonar-web/src/main/js/components/tutorials/gitlabci/ProjectKeyStep.tsx
server/sonar-web/src/main/js/components/tutorials/gitlabci/YmlFileStep.tsx
server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/GitLabCITutorial-test.tsx
server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/YmlFileStep-test.tsx
server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/__snapshots__/GitLabCITutorial-test.tsx.snap
server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/__snapshots__/YmlFileStep-test.tsx.snap
server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/PipeCommand.tsx
server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/__tests__/PipeCommand-test.tsx
server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/__tests__/__snapshots__/PipeCommand-test.tsx.snap
server/sonar-web/src/main/js/components/tutorials/other/commands/AnalysisCommand.tsx
server/sonar-web/src/main/js/components/tutorials/other/commands/ClangGCCCommand.tsx
server/sonar-web/src/main/js/components/tutorials/other/commands/DotNet.tsx
server/sonar-web/src/main/js/components/tutorials/other/commands/DotNetCore.tsx
server/sonar-web/src/main/js/components/tutorials/other/commands/DotNetFramework.tsx
server/sonar-web/src/main/js/components/tutorials/other/commands/ExecScanner.tsx
server/sonar-web/src/main/js/components/tutorials/other/commands/JavaGradle.tsx
server/sonar-web/src/main/js/components/tutorials/other/commands/JavaMaven.tsx
server/sonar-web/src/main/js/components/tutorials/other/commands/Other.tsx
server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/CLangGCCCommand-test.tsx
server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/DotNet-test.tsx
server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/DotNetFramework-test.tsx
server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/DotnetCore-test.tsx
server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/ExecScanner-test.tsx
server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/JavaGradle-test.tsx
server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/JavaMaven-test.tsx
server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/Other-test.tsx
server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/__snapshots__/AnalysisCommand-test.tsx.snap
server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/__snapshots__/CLangGCCCommand-test.tsx.snap
server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/__snapshots__/DotNet-test.tsx.snap
server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/__snapshots__/Other-test.tsx.snap
server/sonar-web/src/main/js/components/tutorials/utils.ts
server/sonar-web/src/main/js/helpers/constants.ts

index 4ac206dbf5d953847b147ecac2ea4f83a236fd16..7d22006a5644b1c821583cd6a99a8cab2396824c 100644 (file)
@@ -21,7 +21,7 @@ import { cloneDeep } from 'lodash';
 import { HousekeepingPolicy } from '../../apps/audit-logs/utils';
 import { BranchParameters } from '../../types/branch-like';
 import { SettingsKey, SettingValue } from '../../types/settings';
-import { getValue } from '../settings';
+import { getAllValues, getValue, getValues } from '../settings';
 
 export default class SettingsServiceMock {
   settingValues: SettingValue[];
@@ -34,28 +34,43 @@ export default class SettingsServiceMock {
 
   constructor() {
     this.settingValues = cloneDeep(this.defaultValues);
-    (getValue as jest.Mock).mockImplementation(this.handleGetValues);
+    (getValue as jest.Mock).mockImplementation(this.handleGetValue);
+    (getValues as jest.Mock).mockImplementation(this.handleGetValues);
+    (getAllValues as jest.Mock).mockImplementation(this.handleGetAllValues);
   }
 
-  handleGetValues = (data: { key: string; component?: string } & BranchParameters) => {
+  handleGetValue = (data: { key: string; component?: string } & BranchParameters) => {
     const setting = this.settingValues.find(s => s.key === data.key);
-
     return this.reply(setting);
   };
 
-  emptySettings() {
+  handleGetValues = (data: { keys: string[]; component?: string } & BranchParameters) => {
+    const settings = this.settingValues.filter(s => data.keys.includes(s.key));
+    return this.reply(settings);
+  };
+
+  handleGetAllValues = () => {
+    return this.reply(this.settingValues);
+  };
+
+  emptySettings = () => {
     this.settingValues = [];
-  }
+    return this;
+  };
 
-  setYearlyHousekeepingPolicy() {
-    const auditSetting = this.settingValues.find(s => s.key === SettingsKey.AuditHouseKeeping);
-    if (auditSetting) {
-      auditSetting.value = HousekeepingPolicy.Yearly;
+  set = (key: SettingsKey, value: string) => {
+    const setting = this.settingValues.find(s => s.key === key);
+    if (setting) {
+      setting.value = value;
+    } else {
+      this.settingValues.push({ key, value });
     }
-  }
+    return this;
+  };
 
-  resetSettingvalues = () => {
+  reset = () => {
     this.settingValues = cloneDeep(this.defaultValues);
+    return this;
   };
 
   reply<T>(response: T): Promise<T> {
index 813ede23e2ddd6b6e8a42fab0c51688baa4d31b4..1130413e4d6ca3907531ad90ad702085a8402aea 100644 (file)
@@ -27,7 +27,9 @@ import { now } from '../../../../helpers/dates';
 import { getShortMonthName } from '../../../../helpers/l10n';
 import { renderAppWithAdminContext } from '../../../../helpers/testReactTestingUtils';
 import { AdminPageExtension } from '../../../../types/extension';
+import { SettingsKey } from '../../../../types/settings';
 import routes from '../../routes';
+import { HousekeepingPolicy } from '../../utils';
 
 jest.mock('../../../../api/settings');
 
@@ -73,11 +75,11 @@ beforeAll(() => {
   handler = new SettingsServiceMock();
 });
 
-afterEach(() => handler.resetSettingvalues());
+afterEach(() => handler.reset());
 
 it('should handle download button click', async () => {
   const user = userEvent.setup();
-  handler.setYearlyHousekeepingPolicy();
+  handler.set(SettingsKey.AuditHouseKeeping, HousekeepingPolicy.Yearly);
   renderAuditLogs();
   const downloadButton = await ui.downloadButton.find();
   expect(downloadButton).toBeInTheDocument();
@@ -152,7 +154,7 @@ it('should show right option when keeping log for month', async () => {
 });
 
 it('should show right option when keeping log for year', async () => {
-  handler.setYearlyHousekeepingPolicy();
+  handler.set(SettingsKey.AuditHouseKeeping, HousekeepingPolicy.Yearly);
   renderAuditLogs();
   expect(await ui.pageTitle.find()).toBeInTheDocument();
   expect(ui.todayRadio.get()).toBeInTheDocument();
index 9888924b8e9e1b3f6c6a4c3f3256f69fdc2aec7e..661ef43a318543bb7d4695655a4f1e657b649917 100644 (file)
@@ -21,9 +21,12 @@ import * as React from 'react';
 import { getAlmSettingsNoCatch } from '../../api/alm-settings';
 import { getScannableProjects } from '../../api/components';
 import { getValue } from '../../api/settings';
+import { ComponentContext } from '../../app/components/componentContext/ComponentContext';
+import { isMainBranch } from '../../helpers/branch-like';
 import { getHostUrl } from '../../helpers/urls';
 import { hasGlobalPermission } from '../../helpers/users';
 import { AlmSettingsInstance, ProjectAlmBindingResponse } from '../../types/alm-settings';
+import { MainBranch } from '../../types/branch-like';
 import { Permissions } from '../../types/permissions';
 import { SettingsKey } from '../../types/settings';
 import { Component } from '../../types/types';
@@ -48,6 +51,8 @@ interface State {
   loading: boolean;
 }
 
+const DEFAULT_MAIN_BRANCH_NAME = 'main';
+
 export class TutorialSelection extends React.PureComponent<Props, State> {
   mounted = false;
   state: State = {
@@ -134,18 +139,26 @@ export class TutorialSelection extends React.PureComponent<Props, State> {
     const selectedTutorial: TutorialModes | undefined = location.query?.selectedTutorial;
 
     return (
-      <TutorialSelectionRenderer
-        almBinding={almBinding}
-        baseUrl={baseUrl}
-        component={component}
-        currentUser={currentUser}
-        currentUserCanScanProject={currentUserCanScanProject}
-        loading={loading}
-        onSelectTutorial={this.handleSelectTutorial}
-        projectBinding={projectBinding}
-        selectedTutorial={selectedTutorial}
-        willRefreshAutomatically={willRefreshAutomatically}
-      />
+      <ComponentContext.Consumer>
+        {({ branchLikes }) => (
+          <TutorialSelectionRenderer
+            almBinding={almBinding}
+            baseUrl={baseUrl}
+            component={component}
+            currentUser={currentUser}
+            currentUserCanScanProject={currentUserCanScanProject}
+            loading={loading}
+            mainBranchName={
+              (branchLikes.find(b => isMainBranch(b)) as MainBranch | undefined)?.name ||
+              DEFAULT_MAIN_BRANCH_NAME
+            }
+            onSelectTutorial={this.handleSelectTutorial}
+            projectBinding={projectBinding}
+            selectedTutorial={selectedTutorial}
+            willRefreshAutomatically={willRefreshAutomatically}
+          />
+        )}
+      </ComponentContext.Consumer>
     );
   }
 }
index f08f088b8013bc0b395b8bc1f7947523470e53f3..fdaaeacad270ecba682a5379623ede079a966516 100644 (file)
@@ -40,6 +40,7 @@ export interface TutorialSelectionRendererProps {
   currentUser: LoggedInUser;
   currentUserCanScanProject: boolean;
   loading: boolean;
+  mainBranchName: string;
   onSelectTutorial: (mode: TutorialModes) => void;
   projectBinding?: ProjectAlmBindingResponse;
   selectedTutorial?: TutorialModes;
@@ -77,13 +78,14 @@ export default function TutorialSelectionRenderer(props: TutorialSelectionRender
     currentUser,
     currentUserCanScanProject,
     loading,
+    mainBranchName,
     projectBinding,
     selectedTutorial,
     willRefreshAutomatically
   } = props;
 
   if (loading) {
-    return <i className="spinner" />;
+    return <i aria-label={translate('loading')} className="spinner" />;
   }
 
   if (!currentUserCanScanProject) {
@@ -99,7 +101,7 @@ export default function TutorialSelectionRenderer(props: TutorialSelectionRender
   if (projectBinding !== undefined) {
     showGitHubActions = projectBinding.alm === AlmKeys.GitHub;
     showGitLabCICD = projectBinding.alm === AlmKeys.GitLab;
-    showBitbucketPipelines = projectBinding?.alm === AlmKeys.BitbucketCloud;
+    showBitbucketPipelines = projectBinding.alm === AlmKeys.BitbucketCloud;
     showAzurePipelines = [AlmKeys.Azure, AlmKeys.GitHub].includes(projectBinding.alm);
     showJenkins = [
       AlmKeys.BitbucketCloud,
@@ -233,6 +235,7 @@ export default function TutorialSelectionRenderer(props: TutorialSelectionRender
           baseUrl={baseUrl}
           component={component}
           currentUser={currentUser}
+          mainBranchName={mainBranchName}
           projectBinding={projectBinding}
           willRefreshAutomatically={willRefreshAutomatically}
         />
@@ -253,13 +256,14 @@ export default function TutorialSelectionRenderer(props: TutorialSelectionRender
           baseUrl={baseUrl}
           component={component}
           currentUser={currentUser}
+          mainBranchName={mainBranchName}
           willRefreshAutomatically={willRefreshAutomatically}
         />
       )}
 
       {selectedTutorial === TutorialModes.AzurePipelines && (
         <AzurePipelinesTutorial
-          alm={almBinding?.alm}
+          alm={projectBinding?.alm}
           baseUrl={baseUrl}
           component={component}
           currentUser={currentUser}
diff --git a/server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelection-it.tsx b/server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelection-it.tsx
new file mode 100644 (file)
index 0000000..b2c6859
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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 { screen, waitFor } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { UserEvent } from '@testing-library/user-event/dist/types/setup';
+import * as React from 'react';
+import { byLabelText, byRole, byText } from 'testing-library-selector';
+import { getAlmSettingsNoCatch } from '../../../api/alm-settings';
+import { getScannableProjects } from '../../../api/components';
+import SettingsServiceMock from '../../../api/mocks/SettingsServiceMock';
+import UserTokensMock from '../../../api/mocks/UserTokensMock';
+import {
+  mockGithubBindingDefinition,
+  mockProjectAlmBindingResponse
+} from '../../../helpers/mocks/alm-settings';
+import { mockComponent } from '../../../helpers/mocks/component';
+import { mockLoggedInUser } from '../../../helpers/testMocks';
+import { renderApp } from '../../../helpers/testReactTestingUtils';
+import { AlmKeys } from '../../../types/alm-settings';
+import { Feature } from '../../../types/features';
+import { Permissions } from '../../../types/permissions';
+import { SettingsKey } from '../../../types/settings';
+import { withRouter } from '../../hoc/withRouter';
+import { TutorialSelection } from '../TutorialSelection';
+import { TutorialModes } from '../types';
+
+jest.mock('../../../api/settings');
+jest.mock('../../../api/user-tokens');
+
+jest.mock('../../../helpers/urls', () => ({
+  ...jest.requireActual('../../../helpers/urls'),
+  getHostUrl: jest.fn().mockReturnValue('http://host.url')
+}));
+
+jest.mock('../../../api/alm-settings', () => ({
+  getAlmSettingsNoCatch: jest.fn().mockRejectedValue(null)
+}));
+
+jest.mock('../../../api/components', () => ({
+  getScannableProjects: jest.fn().mockResolvedValue({ projects: [] })
+}));
+
+let settingsMock: SettingsServiceMock;
+let tokenMock: UserTokensMock;
+
+beforeAll(() => {
+  settingsMock = new SettingsServiceMock();
+  tokenMock = new UserTokensMock();
+});
+
+afterEach(() => {
+  tokenMock.reset();
+  settingsMock.reset();
+});
+
+beforeEach(jest.clearAllMocks);
+
+const ui = {
+  loading: byLabelText('loading'),
+  noScanRights: byText('onboarding.tutorial.no_scan_rights'),
+  chooseTutorialBtn: (mode: TutorialModes) =>
+    byRole('button', { name: `onboarding.tutorial.choose_method.${mode}` })
+};
+
+it.each([
+  [TutorialModes.Jenkins, 'onboarding.tutorial.with.jenkins.title'],
+  [TutorialModes.AzurePipelines, 'onboarding.tutorial.with.azure_pipelines.title'],
+  [
+    TutorialModes.BitbucketPipelines,
+    'onboarding.tutorial.with.bitbucket_pipelines.create_secret.title'
+  ],
+  [TutorialModes.GitHubActions, 'onboarding.tutorial.with.github_action.create_secret.title'],
+  [TutorialModes.GitLabCI, 'onboarding.tutorial.with.gitlab_ci.title'],
+  [TutorialModes.Local, 'onboarding.project_analysis.header'],
+  [TutorialModes.OtherCI, 'onboarding.project_analysis.header']
+])('should behave correctly for %s', async (mode, title) => {
+  const user = userEvent.setup();
+  renderTutorialSelection();
+  await waitOnDataLoaded();
+
+  expect(screen.getByText('onboarding.tutorial.choose_method')).toBeInTheDocument();
+
+  await user.click(ui.chooseTutorialBtn(mode).get());
+  expect(screen.getByText(title)).toBeInTheDocument();
+});
+
+it.each([
+  [
+    AlmKeys.GitHub,
+    [TutorialModes.GitHubActions, TutorialModes.Jenkins, TutorialModes.AzurePipelines]
+  ],
+  [AlmKeys.GitLab, [TutorialModes.GitLabCI, TutorialModes.Jenkins]],
+  [AlmKeys.Azure, [TutorialModes.AzurePipelines]],
+  [AlmKeys.BitbucketServer, [TutorialModes.Jenkins]],
+  [AlmKeys.BitbucketCloud, [TutorialModes.BitbucketPipelines, TutorialModes.Jenkins]]
+])('should show correct buttons if project is bound to %s', async (alm, modes) => {
+  renderTutorialSelection({ projectBinding: mockProjectAlmBindingResponse({ alm }) });
+  await waitOnDataLoaded();
+
+  modes.forEach(mode => expect(ui.chooseTutorialBtn(mode).get()).toBeInTheDocument());
+});
+
+it('should correctly fetch the corresponding ALM setting', async () => {
+  (getAlmSettingsNoCatch as jest.Mock).mockResolvedValueOnce([
+    mockGithubBindingDefinition({ key: 'binding', url: 'https://enterprise.github.com' })
+  ]);
+  const user = userEvent.setup();
+  renderTutorialSelection({
+    projectBinding: mockProjectAlmBindingResponse({ alm: AlmKeys.GitHub, key: 'binding' })
+  });
+  await waitOnDataLoaded();
+
+  await startJenkinsTutorial(user);
+  expect(screen.getByText('https://enterprise.github.com', { exact: false })).toBeInTheDocument();
+});
+
+it('should correctly fetch the instance URL', async () => {
+  settingsMock.set(SettingsKey.ServerBaseUrl, 'http://sq.example.com');
+  const user = userEvent.setup();
+  renderTutorialSelection();
+  await waitOnDataLoaded();
+
+  await startLocalTutorial(user);
+  expect(
+    screen.getByText('-Dsonar.host.url=http://sq.example.com', { exact: false })
+  ).toBeInTheDocument();
+});
+
+it('should fallback on the host URL', async () => {
+  const user = userEvent.setup();
+  renderTutorialSelection();
+  await waitOnDataLoaded();
+
+  await startLocalTutorial(user);
+  expect(
+    screen.getByText('-Dsonar.host.url=http://host.url', { exact: false })
+  ).toBeInTheDocument();
+});
+
+it('should not display a warning if the user has no global scan permission, but can scan the project', async () => {
+  (getScannableProjects as jest.Mock).mockResolvedValueOnce({ projects: [{ key: 'foo' }] });
+  renderTutorialSelection({ currentUser: mockLoggedInUser() });
+  await waitOnDataLoaded();
+
+  expect(ui.noScanRights.query()).not.toBeInTheDocument();
+});
+
+it('should correctly display a warning if the user has no scan permissions', async () => {
+  renderTutorialSelection({ currentUser: mockLoggedInUser() });
+  await waitOnDataLoaded();
+
+  expect(ui.noScanRights.query()).toBeInTheDocument();
+});
+
+async function waitOnDataLoaded() {
+  await waitFor(() => {
+    expect(ui.loading.query()).not.toBeInTheDocument();
+  });
+}
+
+async function startLocalTutorial(user: UserEvent) {
+  await user.click(ui.chooseTutorialBtn(TutorialModes.Local).get());
+  await user.click(screen.getByRole('button', { name: 'onboarding.token.generate' }));
+  await user.click(screen.getByRole('button', { name: 'continue' }));
+  await user.click(screen.getByRole('button', { name: 'onboarding.build.maven' }));
+}
+
+async function startJenkinsTutorial(user: UserEvent) {
+  await user.click(ui.chooseTutorialBtn(TutorialModes.Jenkins).get());
+  await user.click(
+    screen.getByRole('button', { name: 'onboarding.tutorial.with.jenkins.prereqs.done' })
+  );
+}
+
+function renderTutorialSelection(props: Partial<TutorialSelection['props']> = {}) {
+  const Wrapper = withRouter(({ router, location, ...subProps }: TutorialSelection['props']) => {
+    return <TutorialSelection location={location} router={router} {...subProps} />;
+  });
+
+  return renderApp(
+    '/',
+    <Wrapper
+      component={mockComponent({ key: 'foo' })}
+      currentUser={mockLoggedInUser({ permissions: { global: [Permissions.Scan] } })}
+      {...props}
+    />,
+    { featureList: [Feature.BranchSupport] }
+  );
+}
diff --git a/server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelection-test.tsx b/server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelection-test.tsx
deleted file mode 100644 (file)
index 80b92e0..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { getAlmSettingsNoCatch } from '../../../api/alm-settings';
-import { getScannableProjects } from '../../../api/components';
-import { getValue } from '../../../api/settings';
-import {
-  mockAlmSettingsInstance,
-  mockProjectBitbucketBindingResponse
-} from '../../../helpers/mocks/alm-settings';
-import { mockComponent } from '../../../helpers/mocks/component';
-import { mockLocation, mockLoggedInUser, mockRouter } from '../../../helpers/testMocks';
-import { waitAndUpdate } from '../../../helpers/testUtils';
-import { getHostUrl } from '../../../helpers/urls';
-import { Permissions } from '../../../types/permissions';
-import { SettingsKey } from '../../../types/settings';
-import { TutorialSelection } from '../TutorialSelection';
-import { TutorialModes } from '../types';
-
-jest.mock('../../../helpers/urls', () => ({
-  getHostUrl: jest.fn().mockReturnValue('http://host.url')
-}));
-
-jest.mock('../../../api/alm-settings', () => ({
-  getAlmSettingsNoCatch: jest.fn().mockRejectedValue(null)
-}));
-
-jest.mock('../../../api/settings', () => ({
-  getValue: jest.fn().mockResolvedValue({})
-}));
-
-jest.mock('../../../api/components', () => ({
-  getScannableProjects: jest.fn().mockResolvedValue({ projects: [] })
-}));
-
-beforeEach(jest.clearAllMocks);
-
-it('should render correctly', () => {
-  expect(shallowRender()).toMatchSnapshot();
-});
-
-it('should correctly find the global ALM binding definition', async () => {
-  const key = 'foo';
-  const almBinding = mockAlmSettingsInstance({ key });
-  (getAlmSettingsNoCatch as jest.Mock).mockResolvedValueOnce([
-    almBinding,
-    mockAlmSettingsInstance({ key: 'bar' })
-  ]);
-  const wrapper = shallowRender({ projectBinding: mockProjectBitbucketBindingResponse({ key }) });
-  await waitAndUpdate(wrapper);
-  expect(wrapper.state().almBinding).toBe(almBinding);
-});
-
-it('should handle selection', () => {
-  const push = jest.fn();
-  const wrapper = shallowRender({ router: mockRouter({ push }) });
-  const instance = wrapper.instance();
-
-  instance.handleSelectTutorial(TutorialModes.Local);
-  expect(push).toHaveBeenLastCalledWith(
-    expect.objectContaining({
-      query: { selectedTutorial: TutorialModes.Local }
-    })
-  );
-
-  instance.handleSelectTutorial(TutorialModes.Jenkins);
-  expect(push).toHaveBeenLastCalledWith(
-    expect.objectContaining({
-      query: { selectedTutorial: TutorialModes.Jenkins }
-    })
-  );
-});
-
-it('should fetch the correct baseUrl', async () => {
-  (getValue as jest.Mock)
-    .mockResolvedValueOnce({ key: SettingsKey.ServerBaseUrl, value: '' })
-    .mockResolvedValueOnce({ key: SettingsKey.ServerBaseUrl, value: 'http://sq.example.com' })
-    .mockRejectedValueOnce(null);
-
-  let wrapper = shallowRender();
-
-  expect(getValue).toHaveBeenCalled();
-  expect(getHostUrl).toHaveBeenCalled();
-
-  // No baseURL, fallback to the URL in the browser.
-  await waitAndUpdate(wrapper);
-  expect(wrapper.state().baseUrl).toBe('http://host.url');
-
-  // A baseURL was set.
-  wrapper = shallowRender();
-  await waitAndUpdate(wrapper);
-  expect(wrapper.state().baseUrl).toBe('http://sq.example.com');
-
-  // Access denied, fallback to the URL in the browser.
-  wrapper = shallowRender();
-  await waitAndUpdate(wrapper);
-  expect(wrapper.state().baseUrl).toBe('http://host.url');
-});
-
-it("should correctly determine the user's permission", async () => {
-  const component = mockComponent({ key: 'bar', name: 'Bar' });
-  (getScannableProjects as jest.Mock)
-    .mockResolvedValueOnce({
-      projects: [
-        { key: 'foo', name: 'Foo' },
-        { key: component.key, name: component.name }
-      ]
-    })
-    .mockResolvedValueOnce({ projects: [{ key: 'foo', name: 'Foo' }] });
-
-  // Global scan permission.
-  let wrapper = shallowRender({
-    component,
-    currentUser: mockLoggedInUser({ permissions: { global: [Permissions.Scan] } })
-  });
-  await waitAndUpdate(wrapper);
-  expect(wrapper.state().currentUserCanScanProject).toBe(true);
-  expect(getScannableProjects).not.toHaveBeenCalled();
-
-  // Project scan permission.
-  wrapper = shallowRender({ component });
-  await waitAndUpdate(wrapper);
-  expect(getScannableProjects).toHaveBeenCalled();
-  expect(wrapper.state().currentUserCanScanProject).toBe(true);
-
-  // No scan permission.
-  wrapper = shallowRender({ component });
-  await waitAndUpdate(wrapper);
-  expect(getScannableProjects).toHaveBeenCalledTimes(2);
-  expect(wrapper.state().currentUserCanScanProject).toBe(false);
-});
-
-function shallowRender(props: Partial<TutorialSelection['props']> = {}) {
-  return shallow<TutorialSelection>(
-    <TutorialSelection
-      component={mockComponent()}
-      currentUser={mockLoggedInUser()}
-      location={mockLocation()}
-      router={mockRouter()}
-      {...props}
-    />
-  );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelectionRenderer-test.tsx b/server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelectionRenderer-test.tsx
deleted file mode 100644 (file)
index b9200fb..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import {
-  mockAlmSettingsInstance,
-  mockProjectAzureBindingResponse,
-  mockProjectBitbucketBindingResponse,
-  mockProjectBitbucketCloudBindingResponse,
-  mockProjectGithubBindingResponse,
-  mockProjectGitLabBindingResponse
-} from '../../../helpers/mocks/alm-settings';
-import { mockComponent } from '../../../helpers/mocks/component';
-import { mockLoggedInUser } from '../../../helpers/testMocks';
-import { click } from '../../../helpers/testUtils';
-import TutorialSelectionRenderer, {
-  TutorialSelectionRendererProps
-} from '../TutorialSelectionRenderer';
-import { TutorialModes } from '../types';
-
-it.each([
-  ['bitbucket server', mockProjectBitbucketBindingResponse()],
-  ['github', mockProjectGithubBindingResponse()],
-  ['gitlab', mockProjectGitLabBindingResponse()],
-  ['azure', mockProjectAzureBindingResponse()]
-])('should render correctly for %s', (_, projectBinding) => {
-  expect(shallowRender({ projectBinding })).toMatchSnapshot();
-});
-
-it('should render correctly', () => {
-  expect(shallowRender()).toMatchSnapshot('selection');
-  expect(shallowRender({ loading: true })).toMatchSnapshot('loading');
-  expect(shallowRender({ selectedTutorial: TutorialModes.Local })).toMatchSnapshot(
-    'manual tutorial'
-  );
-  expect(
-    shallowRender({
-      selectedTutorial: TutorialModes.Jenkins,
-      projectBinding: mockProjectBitbucketBindingResponse()
-    })
-  ).toMatchSnapshot('jenkins tutorial');
-  expect(
-    shallowRender({
-      selectedTutorial: TutorialModes.GitHubActions,
-      projectBinding: mockProjectGithubBindingResponse()
-    })
-  ).toMatchSnapshot('github actions tutorial');
-  expect(
-    shallowRender({
-      selectedTutorial: TutorialModes.GitLabCI,
-      projectBinding: mockProjectGitLabBindingResponse()
-    })
-  ).toMatchSnapshot('gitlab tutorial');
-  expect(
-    shallowRender({
-      selectedTutorial: TutorialModes.AzurePipelines,
-      projectBinding: mockProjectAzureBindingResponse()
-    })
-  ).toMatchSnapshot('azure pipelines tutorial');
-  expect(shallowRender({ currentUserCanScanProject: false })).toMatchSnapshot(
-    'user has no scan permission'
-  );
-});
-
-it('should allow mode selection for Bitbucket', () => {
-  const onSelectTutorial = jest.fn();
-  const wrapper = shallowRender({
-    onSelectTutorial,
-    projectBinding: mockProjectBitbucketBindingResponse()
-  });
-
-  click(wrapper.find('button.tutorial-mode-jenkins'));
-  expect(onSelectTutorial).toHaveBeenLastCalledWith(TutorialModes.Jenkins);
-
-  click(wrapper.find('button.tutorial-mode-local'));
-  expect(onSelectTutorial).toHaveBeenLastCalledWith(TutorialModes.Local);
-});
-
-it('should allow mode selection for Github', () => {
-  const onSelectTutorial = jest.fn();
-  const wrapper = shallowRender({
-    onSelectTutorial,
-    projectBinding: mockProjectGithubBindingResponse()
-  });
-
-  click(wrapper.find('button.tutorial-mode-jenkins'));
-  expect(onSelectTutorial).toHaveBeenLastCalledWith(TutorialModes.Jenkins);
-
-  click(wrapper.find('button.tutorial-mode-local'));
-  expect(onSelectTutorial).toHaveBeenLastCalledWith(TutorialModes.Local);
-
-  click(wrapper.find('button.tutorial-mode-github-actions'));
-  expect(onSelectTutorial).toHaveBeenLastCalledWith(TutorialModes.GitHubActions);
-
-  click(wrapper.find('button.tutorial-mode-azure-pipelines'));
-  expect(onSelectTutorial).toHaveBeenLastCalledWith(TutorialModes.AzurePipelines);
-});
-
-it('should allow mode selection for GitLab', () => {
-  const onSelectTutorial = jest.fn();
-  const wrapper = shallowRender({
-    onSelectTutorial,
-    projectBinding: mockProjectGitLabBindingResponse()
-  });
-
-  click(wrapper.find('button.tutorial-mode-jenkins'));
-  expect(onSelectTutorial).toHaveBeenLastCalledWith(TutorialModes.Jenkins);
-
-  click(wrapper.find('button.tutorial-mode-gitlab-ci'));
-  expect(onSelectTutorial).toHaveBeenLastCalledWith(TutorialModes.GitLabCI);
-
-  click(wrapper.find('button.tutorial-mode-local'));
-  expect(onSelectTutorial).toHaveBeenLastCalledWith(TutorialModes.Local);
-});
-
-it('should allow mode selection for Bitbucket pipepline', () => {
-  const onSelectTutorial = jest.fn();
-  const wrapper = shallowRender({
-    onSelectTutorial,
-    projectBinding: mockProjectBitbucketCloudBindingResponse()
-  });
-
-  click(wrapper.find('button.tutorial-mode-jenkins'));
-  expect(onSelectTutorial).toHaveBeenLastCalledWith(TutorialModes.Jenkins);
-
-  click(wrapper.find('button.tutorial-mode-bitbucket-pipelines'));
-  expect(onSelectTutorial).toHaveBeenLastCalledWith(TutorialModes.BitbucketPipelines);
-
-  click(wrapper.find('button.tutorial-mode-local'));
-  expect(onSelectTutorial).toHaveBeenLastCalledWith(TutorialModes.Local);
-});
-
-it('should allow mode selection for Azure DevOps', () => {
-  const onSelectTutorial = jest.fn();
-  const wrapper = shallowRender({
-    onSelectTutorial,
-    projectBinding: mockProjectAzureBindingResponse()
-  });
-
-  click(wrapper.find('button.tutorial-mode-azure-pipelines'));
-  expect(onSelectTutorial).toHaveBeenLastCalledWith(TutorialModes.AzurePipelines);
-
-  click(wrapper.find('button.tutorial-mode-local'));
-  expect(onSelectTutorial).toHaveBeenLastCalledWith(TutorialModes.Local);
-});
-
-function shallowRender(props: Partial<TutorialSelectionRendererProps> = {}) {
-  return shallow<TutorialSelectionRendererProps>(
-    <TutorialSelectionRenderer
-      almBinding={mockAlmSettingsInstance()}
-      baseUrl="http://localhost:9000"
-      component={mockComponent()}
-      currentUser={mockLoggedInUser()}
-      currentUserCanScanProject={true}
-      loading={false}
-      onSelectTutorial={jest.fn()}
-      {...props}
-    />
-  );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/__tests__/__snapshots__/TutorialSelection-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/__tests__/__snapshots__/TutorialSelection-test.tsx.snap
deleted file mode 100644 (file)
index 6d0a8ba..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<TutorialSelectionRenderer
-  baseUrl="http://host.url"
-  component={
-    Object {
-      "breadcrumbs": Array [],
-      "key": "my-project",
-      "name": "MyProject",
-      "qualifier": "TRK",
-      "qualityGate": Object {
-        "isDefault": true,
-        "key": "30",
-        "name": "Sonar way",
-      },
-      "qualityProfiles": Array [
-        Object {
-          "deleted": false,
-          "key": "my-qp",
-          "language": "ts",
-          "name": "Sonar way",
-        },
-      ],
-      "tags": Array [],
-    }
-  }
-  currentUser={
-    Object {
-      "dismissedNotices": Object {
-        "educationPrinciples": false,
-      },
-      "groups": Array [],
-      "isLoggedIn": true,
-      "login": "luke",
-      "name": "Skywalker",
-      "scmAccounts": Array [],
-    }
-  }
-  currentUserCanScanProject={false}
-  loading={true}
-  onSelectTutorial={[Function]}
-/>
-`;
diff --git a/server/sonar-web/src/main/js/components/tutorials/__tests__/__snapshots__/TutorialSelectionRenderer-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/__tests__/__snapshots__/TutorialSelectionRenderer-test.tsx.snap
deleted file mode 100644 (file)
index 93fcf70..0000000
+++ /dev/null
@@ -1,738 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly for azure 1`] = `
-<Fragment>
-  <h2
-    className="spacer-top huge-spacer-bottom"
-  >
-    onboarding.tutorial.choose_method
-  </h2>
-  <div
-    className="tutorial-selection"
-  >
-    <p
-      className="big-spacer-bottom"
-    >
-      onboarding.tutorial.choose_method.devops_platform.description
-    </p>
-    <div
-      className="display-flex-start display-flex-wrap"
-    >
-      <button
-        className="button button-huge display-flex-column big-spacer-right big-spacer-bottom tutorial-mode-azure-pipelines"
-        onClick={[Function]}
-        type="button"
-      >
-        <img
-          alt=""
-          height={60}
-          src="/images/tutorials/azure-pipelines.svg"
-        />
-        <div
-          className="medium big-spacer-top"
-        >
-          onboarding.tutorial.choose_method.azure-pipelines
-        </div>
-      </button>
-      <button
-        className="button button-huge display-flex-column big-spacer-right big-spacer-bottom tutorial-mode-other-ci"
-        onClick={[Function]}
-        type="button"
-      >
-        <EllipsisIcon
-          size={60}
-        />
-        <div
-          className="medium big-spacer-top"
-        >
-          onboarding.tutorial.choose_method.other-ci
-        </div>
-      </button>
-    </div>
-    <p
-      className="big-spacer-bottom spacer-top"
-    >
-      onboarding.tutorial.choose_method.local.description
-    </p>
-    <div>
-      <button
-        className="button button-huge display-flex-column big-spacer-right big-spacer-bottom tutorial-mode-local"
-        onClick={[Function]}
-        type="button"
-      >
-        <img
-          alt=""
-          height={60}
-          src="/images/tutorials/manual.svg"
-        />
-        <div
-          className="medium big-spacer-top"
-        >
-          onboarding.tutorial.choose_method.local
-        </div>
-      </button>
-    </div>
-  </div>
-</Fragment>
-`;
-
-exports[`should render correctly for bitbucket server 1`] = `
-<Fragment>
-  <h2
-    className="spacer-top huge-spacer-bottom"
-  >
-    onboarding.tutorial.choose_method
-  </h2>
-  <div
-    className="tutorial-selection"
-  >
-    <p
-      className="big-spacer-bottom"
-    >
-      onboarding.tutorial.choose_method.devops_platform.description
-    </p>
-    <div
-      className="display-flex-start display-flex-wrap"
-    >
-      <button
-        className="button button-huge display-flex-column big-spacer-right big-spacer-bottom tutorial-mode-jenkins"
-        onClick={[Function]}
-        type="button"
-      >
-        <img
-          alt=""
-          height={60}
-          src="/images/tutorials/jenkins.svg"
-        />
-        <div
-          className="medium big-spacer-top"
-        >
-          onboarding.tutorial.choose_method.jenkins
-        </div>
-      </button>
-      <button
-        className="button button-huge display-flex-column big-spacer-right big-spacer-bottom tutorial-mode-other-ci"
-        onClick={[Function]}
-        type="button"
-      >
-        <EllipsisIcon
-          size={60}
-        />
-        <div
-          className="medium big-spacer-top"
-        >
-          onboarding.tutorial.choose_method.other-ci
-        </div>
-      </button>
-    </div>
-    <p
-      className="big-spacer-bottom spacer-top"
-    >
-      onboarding.tutorial.choose_method.local.description
-    </p>
-    <div>
-      <button
-        className="button button-huge display-flex-column big-spacer-right big-spacer-bottom tutorial-mode-local"
-        onClick={[Function]}
-        type="button"
-      >
-        <img
-          alt=""
-          height={60}
-          src="/images/tutorials/manual.svg"
-        />
-        <div
-          className="medium big-spacer-top"
-        >
-          onboarding.tutorial.choose_method.local
-        </div>
-      </button>
-    </div>
-  </div>
-</Fragment>
-`;
-
-exports[`should render correctly for github 1`] = `
-<Fragment>
-  <h2
-    className="spacer-top huge-spacer-bottom"
-  >
-    onboarding.tutorial.choose_method
-  </h2>
-  <div
-    className="tutorial-selection"
-  >
-    <p
-      className="big-spacer-bottom"
-    >
-      onboarding.tutorial.choose_method.devops_platform.description
-    </p>
-    <div
-      className="display-flex-start display-flex-wrap"
-    >
-      <button
-        className="button button-huge display-flex-column big-spacer-right big-spacer-bottom tutorial-mode-jenkins"
-        onClick={[Function]}
-        type="button"
-      >
-        <img
-          alt=""
-          height={60}
-          src="/images/tutorials/jenkins.svg"
-        />
-        <div
-          className="medium big-spacer-top"
-        >
-          onboarding.tutorial.choose_method.jenkins
-        </div>
-      </button>
-      <button
-        className="button button-huge display-flex-column big-spacer-right big-spacer-bottom tutorial-mode-github-actions"
-        onClick={[Function]}
-        type="button"
-      >
-        <img
-          alt=""
-          className="spacer-bottom spacer-top"
-          height={46}
-          src="/images/tutorials/github-actions.svg"
-        />
-        <div
-          className="medium big-spacer-top"
-        >
-          onboarding.tutorial.choose_method.github-actions
-        </div>
-      </button>
-      <button
-        className="button button-huge display-flex-column big-spacer-right big-spacer-bottom tutorial-mode-azure-pipelines"
-        onClick={[Function]}
-        type="button"
-      >
-        <img
-          alt=""
-          height={60}
-          src="/images/tutorials/azure-pipelines.svg"
-        />
-        <div
-          className="medium big-spacer-top"
-        >
-          onboarding.tutorial.choose_method.azure-pipelines
-        </div>
-      </button>
-      <button
-        className="button button-huge display-flex-column big-spacer-right big-spacer-bottom tutorial-mode-other-ci"
-        onClick={[Function]}
-        type="button"
-      >
-        <EllipsisIcon
-          size={60}
-        />
-        <div
-          className="medium big-spacer-top"
-        >
-          onboarding.tutorial.choose_method.other-ci
-        </div>
-      </button>
-    </div>
-    <p
-      className="big-spacer-bottom spacer-top"
-    >
-      onboarding.tutorial.choose_method.local.description
-    </p>
-    <div>
-      <button
-        className="button button-huge display-flex-column big-spacer-right big-spacer-bottom tutorial-mode-local"
-        onClick={[Function]}
-        type="button"
-      >
-        <img
-          alt=""
-          height={60}
-          src="/images/tutorials/manual.svg"
-        />
-        <div
-          className="medium big-spacer-top"
-        >
-          onboarding.tutorial.choose_method.local
-        </div>
-      </button>
-    </div>
-  </div>
-</Fragment>
-`;
-
-exports[`should render correctly for gitlab 1`] = `
-<Fragment>
-  <h2
-    className="spacer-top huge-spacer-bottom"
-  >
-    onboarding.tutorial.choose_method
-  </h2>
-  <div
-    className="tutorial-selection"
-  >
-    <p
-      className="big-spacer-bottom"
-    >
-      onboarding.tutorial.choose_method.devops_platform.description
-    </p>
-    <div
-      className="display-flex-start display-flex-wrap"
-    >
-      <button
-        className="button button-huge display-flex-column big-spacer-right big-spacer-bottom tutorial-mode-jenkins"
-        onClick={[Function]}
-        type="button"
-      >
-        <img
-          alt=""
-          height={60}
-          src="/images/tutorials/jenkins.svg"
-        />
-        <div
-          className="medium big-spacer-top"
-        >
-          onboarding.tutorial.choose_method.jenkins
-        </div>
-      </button>
-      <button
-        className="button button-huge display-flex-column big-spacer-right big-spacer-bottom tutorial-mode-gitlab-ci"
-        onClick={[Function]}
-        type="button"
-      >
-        <img
-          alt=""
-          height={60}
-          src="/images/alm/gitlab.svg"
-        />
-        <div
-          className="medium big-spacer-top"
-        >
-          onboarding.tutorial.choose_method.gitlab-ci
-        </div>
-      </button>
-      <button
-        className="button button-huge display-flex-column big-spacer-right big-spacer-bottom tutorial-mode-other-ci"
-        onClick={[Function]}
-        type="button"
-      >
-        <EllipsisIcon
-          size={60}
-        />
-        <div
-          className="medium big-spacer-top"
-        >
-          onboarding.tutorial.choose_method.other-ci
-        </div>
-      </button>
-    </div>
-    <p
-      className="big-spacer-bottom spacer-top"
-    >
-      onboarding.tutorial.choose_method.local.description
-    </p>
-    <div>
-      <button
-        className="button button-huge display-flex-column big-spacer-right big-spacer-bottom tutorial-mode-local"
-        onClick={[Function]}
-        type="button"
-      >
-        <img
-          alt=""
-          height={60}
-          src="/images/tutorials/manual.svg"
-        />
-        <div
-          className="medium big-spacer-top"
-        >
-          onboarding.tutorial.choose_method.local
-        </div>
-      </button>
-    </div>
-  </div>
-</Fragment>
-`;
-
-exports[`should render correctly: azure pipelines tutorial 1`] = `
-<Fragment>
-  <AzurePipelinesTutorial
-    alm="github"
-    baseUrl="http://localhost:9000"
-    component={
-      Object {
-        "breadcrumbs": Array [],
-        "key": "my-project",
-        "name": "MyProject",
-        "qualifier": "TRK",
-        "qualityGate": Object {
-          "isDefault": true,
-          "key": "30",
-          "name": "Sonar way",
-        },
-        "qualityProfiles": Array [
-          Object {
-            "deleted": false,
-            "key": "my-qp",
-            "language": "ts",
-            "name": "Sonar way",
-          },
-        ],
-        "tags": Array [],
-      }
-    }
-    currentUser={
-      Object {
-        "dismissedNotices": Object {
-          "educationPrinciples": false,
-        },
-        "groups": Array [],
-        "isLoggedIn": true,
-        "login": "luke",
-        "name": "Skywalker",
-        "scmAccounts": Array [],
-      }
-    }
-  />
-</Fragment>
-`;
-
-exports[`should render correctly: github actions tutorial 1`] = `
-<Fragment>
-  <GitHubActionTutorial
-    almBinding={
-      Object {
-        "alm": "github",
-        "key": "key",
-      }
-    }
-    baseUrl="http://localhost:9000"
-    component={
-      Object {
-        "breadcrumbs": Array [],
-        "key": "my-project",
-        "name": "MyProject",
-        "qualifier": "TRK",
-        "qualityGate": Object {
-          "isDefault": true,
-          "key": "30",
-          "name": "Sonar way",
-        },
-        "qualityProfiles": Array [
-          Object {
-            "deleted": false,
-            "key": "my-qp",
-            "language": "ts",
-            "name": "Sonar way",
-          },
-        ],
-        "tags": Array [],
-      }
-    }
-    currentUser={
-      Object {
-        "dismissedNotices": Object {
-          "educationPrinciples": false,
-        },
-        "groups": Array [],
-        "isLoggedIn": true,
-        "login": "luke",
-        "name": "Skywalker",
-        "scmAccounts": Array [],
-      }
-    }
-    projectBinding={
-      Object {
-        "alm": "github",
-        "key": "foo",
-        "monorepo": true,
-        "repository": "PROJECT_KEY",
-      }
-    }
-  />
-</Fragment>
-`;
-
-exports[`should render correctly: gitlab tutorial 1`] = `
-<Fragment>
-  <GitLabCITutorial
-    baseUrl="http://localhost:9000"
-    component={
-      Object {
-        "breadcrumbs": Array [],
-        "key": "my-project",
-        "name": "MyProject",
-        "qualifier": "TRK",
-        "qualityGate": Object {
-          "isDefault": true,
-          "key": "30",
-          "name": "Sonar way",
-        },
-        "qualityProfiles": Array [
-          Object {
-            "deleted": false,
-            "key": "my-qp",
-            "language": "ts",
-            "name": "Sonar way",
-          },
-        ],
-        "tags": Array [],
-      }
-    }
-    currentUser={
-      Object {
-        "dismissedNotices": Object {
-          "educationPrinciples": false,
-        },
-        "groups": Array [],
-        "isLoggedIn": true,
-        "login": "luke",
-        "name": "Skywalker",
-        "scmAccounts": Array [],
-      }
-    }
-  />
-</Fragment>
-`;
-
-exports[`should render correctly: jenkins tutorial 1`] = `
-<Fragment>
-  <withAvailableFeaturesContext(JenkinsTutorial)
-    almBinding={
-      Object {
-        "alm": "github",
-        "key": "key",
-      }
-    }
-    baseUrl="http://localhost:9000"
-    component={
-      Object {
-        "breadcrumbs": Array [],
-        "key": "my-project",
-        "name": "MyProject",
-        "qualifier": "TRK",
-        "qualityGate": Object {
-          "isDefault": true,
-          "key": "30",
-          "name": "Sonar way",
-        },
-        "qualityProfiles": Array [
-          Object {
-            "deleted": false,
-            "key": "my-qp",
-            "language": "ts",
-            "name": "Sonar way",
-          },
-        ],
-        "tags": Array [],
-      }
-    }
-    projectBinding={
-      Object {
-        "alm": "bitbucket",
-        "key": "foo",
-        "monorepo": true,
-        "repository": "PROJECT_KEY",
-        "slug": "repo-slug",
-      }
-    }
-  />
-</Fragment>
-`;
-
-exports[`should render correctly: loading 1`] = `
-<i
-  className="spinner"
-/>
-`;
-
-exports[`should render correctly: manual tutorial 1`] = `
-<Fragment>
-  <OtherTutorial
-    baseUrl="http://localhost:9000"
-    component={
-      Object {
-        "breadcrumbs": Array [],
-        "key": "my-project",
-        "name": "MyProject",
-        "qualifier": "TRK",
-        "qualityGate": Object {
-          "isDefault": true,
-          "key": "30",
-          "name": "Sonar way",
-        },
-        "qualityProfiles": Array [
-          Object {
-            "deleted": false,
-            "key": "my-qp",
-            "language": "ts",
-            "name": "Sonar way",
-          },
-        ],
-        "tags": Array [],
-      }
-    }
-    currentUser={
-      Object {
-        "dismissedNotices": Object {
-          "educationPrinciples": false,
-        },
-        "groups": Array [],
-        "isLoggedIn": true,
-        "login": "luke",
-        "name": "Skywalker",
-        "scmAccounts": Array [],
-      }
-    }
-    isLocal={true}
-  />
-</Fragment>
-`;
-
-exports[`should render correctly: selection 1`] = `
-<Fragment>
-  <h2
-    className="spacer-top huge-spacer-bottom"
-  >
-    onboarding.tutorial.choose_method
-  </h2>
-  <div
-    className="tutorial-selection"
-  >
-    <p
-      className="big-spacer-bottom"
-    >
-      onboarding.tutorial.choose_method.devops_platform.description
-    </p>
-    <div
-      className="display-flex-start display-flex-wrap"
-    >
-      <button
-        className="button button-huge display-flex-column big-spacer-right big-spacer-bottom tutorial-mode-jenkins"
-        onClick={[Function]}
-        type="button"
-      >
-        <img
-          alt=""
-          height={60}
-          src="/images/tutorials/jenkins.svg"
-        />
-        <div
-          className="medium big-spacer-top"
-        >
-          onboarding.tutorial.choose_method.jenkins
-        </div>
-      </button>
-      <button
-        className="button button-huge display-flex-column big-spacer-right big-spacer-bottom tutorial-mode-github-actions"
-        onClick={[Function]}
-        type="button"
-      >
-        <img
-          alt=""
-          className="spacer-bottom spacer-top"
-          height={46}
-          src="/images/tutorials/github-actions.svg"
-        />
-        <div
-          className="medium big-spacer-top"
-        >
-          onboarding.tutorial.choose_method.github-actions
-        </div>
-      </button>
-      <button
-        className="button button-huge display-flex-column big-spacer-right big-spacer-bottom tutorial-mode-bitbucket-pipelines"
-        onClick={[Function]}
-        type="button"
-      >
-        <img
-          alt=""
-          height={60}
-          src="/images/alm/bitbucket.svg"
-        />
-        <div
-          className="medium big-spacer-top"
-        >
-          onboarding.tutorial.choose_method.bitbucket-pipelines
-        </div>
-      </button>
-      <button
-        className="button button-huge display-flex-column big-spacer-right big-spacer-bottom tutorial-mode-gitlab-ci"
-        onClick={[Function]}
-        type="button"
-      >
-        <img
-          alt=""
-          height={60}
-          src="/images/alm/gitlab.svg"
-        />
-        <div
-          className="medium big-spacer-top"
-        >
-          onboarding.tutorial.choose_method.gitlab-ci
-        </div>
-      </button>
-      <button
-        className="button button-huge display-flex-column big-spacer-right big-spacer-bottom tutorial-mode-azure-pipelines"
-        onClick={[Function]}
-        type="button"
-      >
-        <img
-          alt=""
-          height={60}
-          src="/images/tutorials/azure-pipelines.svg"
-        />
-        <div
-          className="medium big-spacer-top"
-        >
-          onboarding.tutorial.choose_method.azure-pipelines
-        </div>
-      </button>
-      <button
-        className="button button-huge display-flex-column big-spacer-right big-spacer-bottom tutorial-mode-other-ci"
-        onClick={[Function]}
-        type="button"
-      >
-        <EllipsisIcon
-          size={60}
-        />
-        <div
-          className="medium big-spacer-top"
-        >
-          onboarding.tutorial.choose_method.other-ci
-        </div>
-      </button>
-    </div>
-    <p
-      className="big-spacer-bottom spacer-top"
-    >
-      onboarding.tutorial.choose_method.local.description
-    </p>
-    <div>
-      <button
-        className="button button-huge display-flex-column big-spacer-right big-spacer-bottom tutorial-mode-local"
-        onClick={[Function]}
-        type="button"
-      >
-        <img
-          alt=""
-          height={60}
-          src="/images/tutorials/manual.svg"
-        />
-        <div
-          className="medium big-spacer-top"
-        >
-          onboarding.tutorial.choose_method.local
-        </div>
-      </button>
-    </div>
-  </div>
-</Fragment>
-`;
-
-exports[`should render correctly: user has no scan permission 1`] = `
-<Alert
-  variant="warning"
->
-  onboarding.tutorial.no_scan_rights
-</Alert>
-`;
index 256d7592b4689aa0c8e4fc817b6922268e8408e3..823ad58c8b98d41e6cb91b8e0ea534d421b734b6 100644 (file)
@@ -32,12 +32,13 @@ import Others from './commands/Others';
 
 export interface AnalysisCommandProps extends WithAvailableFeaturesProps {
   buildTool: BuildTools;
+  mainBranchName: string;
   component: Component;
   onDone: () => void;
 }
 
 export function AnalysisCommand(props: AnalysisCommandProps) {
-  const { buildTool, component } = props;
+  const { buildTool, component, mainBranchName } = props;
   const branchSupportEnabled = props.hasFeature(Feature.BranchSupport);
 
   if (!buildTool) {
@@ -49,6 +50,7 @@ export function AnalysisCommand(props: AnalysisCommandProps) {
       return (
         <JavaMaven
           branchesEnabled={branchSupportEnabled}
+          mainBranchName={mainBranchName}
           component={component}
           onDone={props.onDone}
         />
@@ -57,6 +59,7 @@ export function AnalysisCommand(props: AnalysisCommandProps) {
       return (
         <Gradle
           branchesEnabled={branchSupportEnabled}
+          mainBranchName={mainBranchName}
           component={component}
           onDone={props.onDone}
         />
@@ -65,6 +68,7 @@ export function AnalysisCommand(props: AnalysisCommandProps) {
       return (
         <DotNet
           branchesEnabled={branchSupportEnabled}
+          mainBranchName={mainBranchName}
           component={component}
           onDone={props.onDone}
         />
@@ -73,6 +77,7 @@ export function AnalysisCommand(props: AnalysisCommandProps) {
       return (
         <CFamily
           branchesEnabled={branchSupportEnabled}
+          mainBranchName={mainBranchName}
           component={component}
           onDone={props.onDone}
         />
@@ -81,12 +86,12 @@ export function AnalysisCommand(props: AnalysisCommandProps) {
       return (
         <Others
           branchesEnabled={branchSupportEnabled}
+          mainBranchName={mainBranchName}
           component={component}
           onDone={props.onDone}
         />
       );
   }
-  return null;
 }
 
 export default withAvailableFeatures(AnalysisCommand);
index efa89c8d623ee5b695264bf30f17efc7b2dca25d..64a8ffd6e6c32a8873c75da9f562b86b1a2642d1 100644 (file)
@@ -43,6 +43,7 @@ export interface GitHubActionTutorialProps {
   baseUrl: string;
   component: Component;
   currentUser: LoggedInUser;
+  mainBranchName: string;
   projectBinding?: ProjectAlmBindingResponse;
   willRefreshAutomatically?: boolean;
 }
@@ -54,6 +55,7 @@ export default function GitHubActionTutorial(props: GitHubActionTutorialProps) {
     currentUser,
     component,
     projectBinding,
+    mainBranchName,
     willRefreshAutomatically
   } = props;
 
@@ -86,6 +88,7 @@ export default function GitHubActionTutorial(props: GitHubActionTutorialProps) {
             {buildTool => (
               <AnalysisCommand
                 buildTool={buildTool}
+                mainBranchName={mainBranchName}
                 component={component}
                 onDone={() => setStep(Steps.ALL_SET)}
               />
index eeb4667d1f8197dde5cebda72da655e0d8afc7f9..47f444fdd9cef92ecbaa91439f8e42579de1a1f0 100644 (file)
@@ -38,6 +38,7 @@ function shallowRender(props: Partial<AnalysisCommandProps> = {}) {
   return shallow<AnalysisCommandProps>(
     <AnalysisCommand
       hasFeature={jest.fn().mockReturnValue(false)}
+      mainBranchName="main"
       component={mockComponent()}
       buildTool={BuildTools.DotNet}
       onDone={jest.fn()}
index 25a51c4036a4b01b1699b895f1b769cff049a244..e0bde53be19669baec077ee45040122a9e5c96cb 100644 (file)
@@ -77,6 +77,7 @@ function shallowRender(props: Partial<GitHubActionTutorialProps> = {}) {
       baseUrl="test"
       currentUser={mockLoggedInUser()}
       component={mockComponent()}
+      mainBranchName="master"
       projectBinding={mockProjectGithubBindingResponse()}
       willRefreshAutomatically={true}
       {...props}
index 5543105efd6ed178dab68ad7baa842bb5d3fed9a..01a9adb6013b3cef2ca2f1b96711b4408e8c3bdd 100644 (file)
@@ -25,6 +25,7 @@ exports[`should render correctly for "cfamily" 1`] = `
       "tags": Array [],
     }
   }
+  mainBranchName="main"
   onDone={[MockFunction]}
 />
 `;
@@ -54,6 +55,7 @@ exports[`should render correctly for "dotnet" 1`] = `
       "tags": Array [],
     }
   }
+  mainBranchName="main"
   onDone={[MockFunction]}
 />
 `;
@@ -83,6 +85,7 @@ exports[`should render correctly for "gradle" 1`] = `
       "tags": Array [],
     }
   }
+  mainBranchName="main"
   onDone={[MockFunction]}
 />
 `;
@@ -112,6 +115,7 @@ exports[`should render correctly for "maven" 1`] = `
       "tags": Array [],
     }
   }
+  mainBranchName="main"
   onDone={[MockFunction]}
 />
 `;
@@ -141,6 +145,7 @@ exports[`should render correctly for "other" 1`] = `
       "tags": Array [],
     }
   }
+  mainBranchName="main"
   onDone={[MockFunction]}
 />
 `;
index c6e3e5bd27fe60ae9b16f00b439a7b6ce9760566..bccaf877ee48dc162883759141c891b835d7040a 100644 (file)
@@ -27,20 +27,17 @@ import FinishButton from '../../components/FinishButton';
 import GithubCFamilyExampleRepositories from '../../components/GithubCFamilyExampleRepositories';
 import RenderOptions from '../../components/RenderOptions';
 import { OSs, TutorialModes } from '../../types';
+import { generateGitHubActionsYaml } from '../utils';
 
 export interface CFamilyProps {
   branchesEnabled?: boolean;
+  mainBranchName: string;
   component: Component;
   onDone: () => void;
 }
 
 const STEPS = {
-  [OSs.Linux]: `steps:
-      - name: Checkout code
-        uses: actions/checkout@v2
-        with:
-          fetch-depth: 0
-
+  [OSs.Linux]: `
       - name: Download and install the build wrapper, build the project
         run: |
           mkdir $HOME/.sonar
@@ -64,12 +61,7 @@ const STEPS = {
         env:
           SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
           SONAR_HOST_URL: \${{ secrets.SONAR_HOST_URL }}`,
-  [OSs.MacOS]: `steps:
-      - name: Checkout code
-        uses: actions/checkout@v2
-        with:
-          fetch-depth: 0
-
+  [OSs.MacOS]: `
       - name: Download and install the build wrapper
         run: |
           mkdir $HOME/.sonar
@@ -91,12 +83,7 @@ const STEPS = {
         env:
           SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
           SONAR_HOST_URL: \${{ secrets.SONAR_HOST_URL }}`,
-  [OSs.Windows]: `steps:
-      - name: Checkout code
-        uses: actions/checkout@v2
-        with:
-          fetch-depth: 0
-
+  [OSs.Windows]: `
       - name: Download and install the build wrapper
         shell: powershell
         run: |
@@ -129,21 +116,8 @@ const STEPS = {
           SONAR_HOST_URL: \${{ secrets.SONAR_HOST_URL }}`
 };
 
-const cfamilyYamlTemplate = (branchesEnabled: boolean, os: OSs) => `name: Build
-on:
-  push:
-    branches:
-      - master # or the name of your main branch
-${branchesEnabled ? '  pull_request:\n    types: [opened, synchronize, reopened]' : ''}
-
-jobs:
-  build:
-    runs-on: <image ready for your build toolchain>
-    ${STEPS[os]}
-`;
-
 export default function CFamily(props: CFamilyProps) {
-  const { component, branchesEnabled } = props;
+  const { component, branchesEnabled, mainBranchName } = props;
   const [os, setOs] = React.useState<undefined | OSs>();
 
   return (
@@ -170,7 +144,12 @@ export default function CFamily(props: CFamilyProps) {
         <>
           <CreateYmlFile
             yamlFileName=".github/workflows/build.yml"
-            yamlTemplate={cfamilyYamlTemplate(!!branchesEnabled, os)}
+            yamlTemplate={generateGitHubActionsYaml(
+              mainBranchName,
+              !!branchesEnabled,
+              '<image ready for your build toolchain>',
+              STEPS[os]
+            )}
           />
           <CompilationInfo className="abs-width-800" />
           <FinishButton onClick={props.onDone} />
index 810d1236eb181099162b76a1ec8cd3db4569532d..3a09a7e28e885ee4529f683d2df80c37e650af0a 100644 (file)
@@ -21,31 +21,22 @@ import * as React from 'react';
 import { Component } from '../../../../types/types';
 import CreateYmlFile from '../../components/CreateYmlFile';
 import FinishButton from '../../components/FinishButton';
+import { GITHUB_ACTIONS_RUNS_ON_WINDOWS } from '../constants';
+import { generateGitHubActionsYaml } from '../utils';
 
 export interface DotNetProps {
   branchesEnabled?: boolean;
+  mainBranchName: string;
   component: Component;
   onDone: () => void;
 }
 
-const dotnetYamlTemplate = (projectKey: string, branchesEnabled: boolean) => `name: Build
-on:
-  push:
-    branches:
-      - master # or the name of your main branch
-${branchesEnabled ? '  pull_request:\n    types: [opened, synchronize, reopened]' : ''}
-jobs:
-  build:
-    name: Build
-    runs-on: windows-latest
-    steps:
+function dotnetYamlSteps(projectKey: string) {
+  return `
       - name: Set up JDK 11
         uses: actions/setup-java@v1
         with:
           java-version: 1.11
-      - uses: actions/checkout@v2
-        with:
-          fetch-depth: 0  # Shallow clones should be disabled for a better relevancy of analysis
       - name: Cache SonarQube packages
         uses: actions/cache@v1
         with:
@@ -73,14 +64,20 @@ jobs:
           .\\.sonar\\scanner\\dotnet-sonarscanner begin /k:"${projectKey}" /d:sonar.login="\${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="\${{ secrets.SONAR_HOST_URL }}"
           dotnet build
           .\\.sonar\\scanner\\dotnet-sonarscanner end /d:sonar.login="\${{ secrets.SONAR_TOKEN }}"`;
+}
 
 export default function DotNet(props: DotNetProps) {
-  const { component, branchesEnabled } = props;
+  const { component, branchesEnabled, mainBranchName } = props;
   return (
     <>
       <CreateYmlFile
         yamlFileName=".github/workflows/build.yml"
-        yamlTemplate={dotnetYamlTemplate(component.key, !!branchesEnabled)}
+        yamlTemplate={generateGitHubActionsYaml(
+          mainBranchName,
+          !!branchesEnabled,
+          GITHUB_ACTIONS_RUNS_ON_WINDOWS,
+          dotnetYamlSteps(component.key)
+        )}
       />
       <FinishButton onClick={props.onDone} />
     </>
index 4d76a483c3d7f91304a7a59c8f709feeb5aebe91..e2b8d44eb67371e83306a24faa940dd8a254be99 100644 (file)
@@ -26,26 +26,17 @@ import CodeSnippet from '../../../common/CodeSnippet';
 import CreateYmlFile from '../../components/CreateYmlFile';
 import FinishButton from '../../components/FinishButton';
 import { buildGradleSnippet } from '../../utils';
+import { GITHUB_ACTIONS_RUNS_ON_LINUX } from '../constants';
+import { generateGitHubActionsYaml } from '../utils';
 
 export interface GradleProps {
   branchesEnabled?: boolean;
+  mainBranchName: string;
   component: Component;
   onDone: () => void;
 }
-const gradleYamlTemplate = (branchesEnabled: boolean) => `name: Build
-on:
-  push:
-    branches:
-      - master # or the name of your main branch
-${branchesEnabled ? '  pull_request:\n    types: [opened, synchronize, reopened]' : ''}
-jobs:
-  build:
-    name: Build
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v2
-        with:
-          fetch-depth: 0  # Shallow clones should be disabled for a better relevancy of analysis
+
+const GRADLE_YAML_STEPS = `
       - name: Set up JDK 11
         uses: actions/setup-java@v1
         with:
@@ -70,7 +61,7 @@ jobs:
         run: ./gradlew build sonarqube --info`;
 
 export default function Gradle(props: GradleProps) {
-  const { component, branchesEnabled } = props;
+  const { component, branchesEnabled, mainBranchName } = props;
 
   return (
     <>
@@ -92,7 +83,12 @@ export default function Gradle(props: GradleProps) {
       </li>
       <CreateYmlFile
         yamlFileName=".github/workflows/build.yml"
-        yamlTemplate={gradleYamlTemplate(!!branchesEnabled)}
+        yamlTemplate={generateGitHubActionsYaml(
+          mainBranchName,
+          !!branchesEnabled,
+          GITHUB_ACTIONS_RUNS_ON_LINUX,
+          GRADLE_YAML_STEPS
+        )}
       />
       <FinishButton onClick={props.onDone} />
     </>
index a3c69da85fa8e654d83639c9191c7b74342d50fe..706f66d27df61e314a565222b5bfa74aa9093a1a 100644 (file)
@@ -21,27 +21,18 @@ import * as React from 'react';
 import { Component } from '../../../../types/types';
 import CreateYmlFile from '../../components/CreateYmlFile';
 import FinishButton from '../../components/FinishButton';
+import { GITHUB_ACTIONS_RUNS_ON_LINUX } from '../constants';
+import { generateGitHubActionsYaml } from '../utils';
 
 export interface JavaMavenProps {
   branchesEnabled?: boolean;
+  mainBranchName: string;
   component: Component;
   onDone: () => void;
 }
 
-const mavenYamlTemplte = (branchesEnabled: boolean, projectKey: string) => `name: Build
-on:
-  push:
-    branches:
-      - master # or the name of your main branch
-${branchesEnabled ? '  pull_request:\n    types: [opened, synchronize, reopened]' : ''}
-jobs:
-  build:
-    name: Build
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v2
-        with:
-          fetch-depth: 0  # Shallow clones should be disabled for a better relevancy of analysis
+function mavenYamlSteps(projectKey: string) {
+  return `
       - name: Set up JDK 11
         uses: actions/setup-java@v1
         with:
@@ -64,14 +55,20 @@ jobs:
           SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
           SONAR_HOST_URL: \${{ secrets.SONAR_HOST_URL }}
         run: mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=${projectKey}`;
+}
 
 export default function JavaMaven(props: JavaMavenProps) {
-  const { component, branchesEnabled } = props;
+  const { component, branchesEnabled, mainBranchName } = props;
   return (
     <>
       <CreateYmlFile
         yamlFileName=".github/workflows/build.yml"
-        yamlTemplate={mavenYamlTemplte(!!branchesEnabled, component.key)}
+        yamlTemplate={generateGitHubActionsYaml(
+          mainBranchName,
+          !!branchesEnabled,
+          GITHUB_ACTIONS_RUNS_ON_LINUX,
+          mavenYamlSteps(component.key)
+        )}
       />
       <FinishButton onClick={props.onDone} />
     </>
index 3d0d382588607f3c6c2cd451275235e319ef9b9c..b100b775993e3e1f0b5170606ca046c686288c50 100644 (file)
@@ -22,35 +22,18 @@ import { Component } from '../../../../types/types';
 import CreateYmlFile from '../../components/CreateYmlFile';
 import DefaultProjectKey from '../../components/DefaultProjectKey';
 import FinishButton from '../../components/FinishButton';
+import { GITHUB_ACTIONS_RUNS_ON_LINUX } from '../constants';
+import { generateGitHubActionsYaml } from '../utils';
 
 export interface OthersProps {
   branchesEnabled?: boolean;
+  mainBranchName: string;
   component: Component;
   onDone: () => void;
 }
 
-const yamlTemplate = (branchesEnabled: boolean) => {
-  let output = `name: Build
-on:
-  push:
-    branches:
-      - master # or the name of your main branch`;
-
-  if (branchesEnabled) {
-    output += `
-  pull_request:
-    types: [opened, synchronize, reopened]`;
-  }
-
-  output += `
-jobs:
-  build:
-    name: Build
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v2
-        with:
-          fetch-depth: 0
+function otherYamlSteps(branchesEnabled: boolean) {
+  let output = `
       - uses: sonarsource/sonarqube-scan-action@master
         env:
           SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
@@ -71,16 +54,21 @@ jobs:
       #     SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}`;
 
   return output;
-};
+}
 
 export default function Others(props: OthersProps) {
-  const { component, branchesEnabled } = props;
+  const { component, branchesEnabled, mainBranchName } = props;
   return (
     <>
       <DefaultProjectKey component={component} />
       <CreateYmlFile
         yamlFileName=".github/workflows/build.yml"
-        yamlTemplate={yamlTemplate(!!branchesEnabled)}
+        yamlTemplate={generateGitHubActionsYaml(
+          mainBranchName,
+          !!branchesEnabled,
+          GITHUB_ACTIONS_RUNS_ON_LINUX,
+          otherYamlSteps(!!branchesEnabled)
+        )}
       />
       <FinishButton onClick={props.onDone} />
     </>
index 2bbbdf8fd09de653ccdfd50a0c30fcd7fa3ce023..dc4ea5ec120adb16a34c0ccd3494282189df81e5 100644 (file)
@@ -43,6 +43,12 @@ it.each([
 
 function shallowRender(props: Partial<CFamilyProps> = {}) {
   return shallow<CFamilyProps>(
-    <CFamily branchesEnabled={true} component={mockComponent()} {...props} onDone={jest.fn()} />
+    <CFamily
+      branchesEnabled={true}
+      component={mockComponent()}
+      mainBranchName="main"
+      onDone={jest.fn()}
+      {...props}
+    />
   );
 }
index 853724357833f942674ddb19c03725ed8aac9743..1dc3811dc324069f60d5efd14fb3b49d3c05e2b4 100644 (file)
@@ -29,6 +29,12 @@ it('should render correctly', () => {
 
 function shallowRender(props: Partial<DotNetProps> = {}) {
   return shallow<DotNetProps>(
-    <DotNet branchesEnabled={true} component={mockComponent()} {...props} onDone={jest.fn()} />
+    <DotNet
+      branchesEnabled={true}
+      component={mockComponent()}
+      mainBranchName="main"
+      {...props}
+      onDone={jest.fn()}
+    />
   );
 }
index 0c9448ce285cd5cb4a210046efa47505ce5f4dec..a52cbb5d2f6bd3ee7bb1a488da4619b3456ec6db 100644 (file)
@@ -29,6 +29,12 @@ it('should render correctly', () => {
 
 function shallowRender(props: Partial<GradleProps> = {}) {
   return shallow<GradleProps>(
-    <Gradle branchesEnabled={true} component={mockComponent()} {...props} onDone={jest.fn()} />
+    <Gradle
+      branchesEnabled={true}
+      component={mockComponent()}
+      mainBranchName="main"
+      onDone={jest.fn()}
+      {...props}
+    />
   );
 }
index 3eee022fe7632e6a1d6df054fc816da3826186a2..a042cedc600595b64ca1c8c01dfb636e5ab13cc1 100644 (file)
@@ -29,6 +29,12 @@ it('should render correctly', () => {
 
 function shallowRender(props: Partial<JavaMavenProps> = {}) {
   return shallow<JavaMavenProps>(
-    <JavaMaven branchesEnabled={true} component={mockComponent()} {...props} onDone={jest.fn()} />
+    <JavaMaven
+      branchesEnabled={true}
+      component={mockComponent()}
+      mainBranchName="main"
+      onDone={jest.fn()}
+      {...props}
+    />
   );
 }
index 1b4212ead6bf7a7e608764a9e701168f95936c44..48b464822dbc1103fa2cb591a6f30737b3a1bc68 100644 (file)
@@ -29,6 +29,12 @@ it('should render correctly', () => {
 
 function shallowRender(props: Partial<OthersProps> = {}) {
   return shallow<OthersProps>(
-    <Others branchesEnabled={true} component={mockComponent()} {...props} onDone={jest.fn()} />
+    <Others
+      branchesEnabled={true}
+      component={mockComponent()}
+      mainBranchName="main"
+      onDone={jest.fn()}
+      {...props}
+    />
   );
 }
index 0bb3b8961db293d9464133554ce3b89f0afe39c0..15eeaf5e46e604a3501529507a5dc553ea974f69 100644 (file)
@@ -102,21 +102,21 @@ exports[`should render correctly for linux: branches disabled 1`] = `
   <CreateYmlFile
     yamlFileName=".github/workflows/build.yml"
     yamlTemplate="name: Build
+
 on:
   push:
     branches:
-      - master # or the name of your main branch
+      - main
 
 
 jobs:
   build:
+    name: Build
     runs-on: <image ready for your build toolchain>
     steps:
-      - name: Checkout code
-        uses: actions/checkout@v2
+      - uses: actions/checkout@v2
         with:
-          fetch-depth: 0
-
+          fetch-depth: 0  # Shallow clones should be disabled for a better relevancy of analysis
       - name: Download and install the build wrapper, build the project
         run: |
           mkdir $HOME/.sonar
@@ -139,8 +139,7 @@ jobs:
           sonar-scanner --define sonar.cfamily.build-wrapper-output=bw-output  
         env:
           SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
-          SONAR_HOST_URL: \${{ secrets.SONAR_HOST_URL }}
-"
+          SONAR_HOST_URL: \${{ secrets.SONAR_HOST_URL }}"
   />
   <CompilationInfo
     className="abs-width-800"
@@ -205,22 +204,22 @@ exports[`should render correctly for mac: branches enabled 1`] = `
   <CreateYmlFile
     yamlFileName=".github/workflows/build.yml"
     yamlTemplate="name: Build
+
 on:
   push:
     branches:
-      - master # or the name of your main branch
+      - main
   pull_request:
     types: [opened, synchronize, reopened]
 
 jobs:
   build:
+    name: Build
     runs-on: <image ready for your build toolchain>
     steps:
-      - name: Checkout code
-        uses: actions/checkout@v2
+      - uses: actions/checkout@v2
         with:
-          fetch-depth: 0
-
+          fetch-depth: 0  # Shallow clones should be disabled for a better relevancy of analysis
       - name: Download and install the build wrapper
         run: |
           mkdir $HOME/.sonar
@@ -241,8 +240,7 @@ jobs:
           $HOME/.sonar/sonar-scanner-4.6.2.2472-macosx/bin/sonar-scanner -Dsonar.cfamily.build-wrapper-output=bw-output
         env:
           SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
-          SONAR_HOST_URL: \${{ secrets.SONAR_HOST_URL }}
-"
+          SONAR_HOST_URL: \${{ secrets.SONAR_HOST_URL }}"
   />
   <CompilationInfo
     className="abs-width-800"
@@ -307,22 +305,22 @@ exports[`should render correctly for win: branches enabled 1`] = `
   <CreateYmlFile
     yamlFileName=".github/workflows/build.yml"
     yamlTemplate="name: Build
+
 on:
   push:
     branches:
-      - master # or the name of your main branch
+      - main
   pull_request:
     types: [opened, synchronize, reopened]
 
 jobs:
   build:
+    name: Build
     runs-on: <image ready for your build toolchain>
     steps:
-      - name: Checkout code
-        uses: actions/checkout@v2
+      - uses: actions/checkout@v2
         with:
-          fetch-depth: 0
-
+          fetch-depth: 0  # Shallow clones should be disabled for a better relevancy of analysis
       - name: Download and install the build wrapper
         shell: powershell
         run: |
@@ -352,8 +350,7 @@ jobs:
           sonar-scanner.bat \\"-Dsonar.cfamily.build-wrapper-output=bw-output\\"
         env:
           SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
-          SONAR_HOST_URL: \${{ secrets.SONAR_HOST_URL }}
-"
+          SONAR_HOST_URL: \${{ secrets.SONAR_HOST_URL }}"
   />
   <CompilationInfo
     className="abs-width-800"
index 3e0e44b10decb1e87ab6b0bf68ac01a9dd5b6f81..485c8da4d8075953e09fc170169a5a1d33290192 100644 (file)
@@ -5,24 +5,26 @@ exports[`should render correctly 1`] = `
   <CreateYmlFile
     yamlFileName=".github/workflows/build.yml"
     yamlTemplate="name: Build
+
 on:
   push:
     branches:
-      - master # or the name of your main branch
+      - main
   pull_request:
     types: [opened, synchronize, reopened]
+
 jobs:
   build:
     name: Build
     runs-on: windows-latest
     steps:
+      - uses: actions/checkout@v2
+        with:
+          fetch-depth: 0  # Shallow clones should be disabled for a better relevancy of analysis
       - name: Set up JDK 11
         uses: actions/setup-java@v1
         with:
           java-version: 1.11
-      - uses: actions/checkout@v2
-        with:
-          fetch-depth: 0  # Shallow clones should be disabled for a better relevancy of analysis
       - name: Cache SonarQube packages
         uses: actions/cache@v1
         with:
@@ -62,23 +64,25 @@ exports[`should render correctly: without branch enabled 1`] = `
   <CreateYmlFile
     yamlFileName=".github/workflows/build.yml"
     yamlTemplate="name: Build
+
 on:
   push:
     branches:
-      - master # or the name of your main branch
+      - main
+
 
 jobs:
   build:
     name: Build
     runs-on: windows-latest
     steps:
+      - uses: actions/checkout@v2
+        with:
+          fetch-depth: 0  # Shallow clones should be disabled for a better relevancy of analysis
       - name: Set up JDK 11
         uses: actions/setup-java@v1
         with:
           java-version: 1.11
-      - uses: actions/checkout@v2
-        with:
-          fetch-depth: 0  # Shallow clones should be disabled for a better relevancy of analysis
       - name: Cache SonarQube packages
         uses: actions/cache@v1
         with:
index 04dcf26e29cd4074169496af8b38db5ad644aecf..9cf9e7c596786a3713a0ed04f238f1717c8e33bd 100644 (file)
@@ -43,12 +43,14 @@ sonarqube {
   <CreateYmlFile
     yamlFileName=".github/workflows/build.yml"
     yamlTemplate="name: Build
+
 on:
   push:
     branches:
-      - master # or the name of your main branch
+      - main
   pull_request:
     types: [opened, synchronize, reopened]
+
 jobs:
   build:
     name: Build
@@ -129,10 +131,12 @@ sonarqube {
   <CreateYmlFile
     yamlFileName=".github/workflows/build.yml"
     yamlTemplate="name: Build
+
 on:
   push:
     branches:
-      - master # or the name of your main branch
+      - main
+
 
 jobs:
   build:
index 766cf60eb73e07f7b24c9c0ad4f31865e785666f..c26604e439ebad031954b01ea0c7491b14efe991 100644 (file)
@@ -5,12 +5,14 @@ exports[`should render correctly 1`] = `
   <CreateYmlFile
     yamlFileName=".github/workflows/build.yml"
     yamlTemplate="name: Build
+
 on:
   push:
     branches:
-      - master # or the name of your main branch
+      - main
   pull_request:
     types: [opened, synchronize, reopened]
+
 jobs:
   build:
     name: Build
@@ -53,10 +55,12 @@ exports[`should render correctly: without branch enabled 1`] = `
   <CreateYmlFile
     yamlFileName=".github/workflows/build.yml"
     yamlTemplate="name: Build
+
 on:
   push:
     branches:
-      - master # or the name of your main branch
+      - main
+
 
 jobs:
   build:
index 6ecc6c79c53b4f226efd00354f8377bcc0cbb536..5c063040760a810520957fee2e1cde2fc6d63a01 100644 (file)
@@ -29,12 +29,14 @@ exports[`should render correctly 1`] = `
   <CreateYmlFile
     yamlFileName=".github/workflows/build.yml"
     yamlTemplate="name: Build
+
 on:
   push:
     branches:
-      - master # or the name of your main branch
+      - main
   pull_request:
     types: [opened, synchronize, reopened]
+
 jobs:
   build:
     name: Build
@@ -42,7 +44,7 @@ jobs:
     steps:
       - uses: actions/checkout@v2
         with:
-          fetch-depth: 0
+          fetch-depth: 0  # Shallow clones should be disabled for a better relevancy of analysis
       - uses: sonarsource/sonarqube-scan-action@master
         env:
           SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
@@ -91,10 +93,13 @@ exports[`should render correctly: without branch enabled 1`] = `
   <CreateYmlFile
     yamlFileName=".github/workflows/build.yml"
     yamlTemplate="name: Build
+
 on:
   push:
     branches:
-      - master # or the name of your main branch
+      - main
+
+
 jobs:
   build:
     name: Build
@@ -102,7 +107,7 @@ jobs:
     steps:
       - uses: actions/checkout@v2
         with:
-          fetch-depth: 0
+          fetch-depth: 0  # Shallow clones should be disabled for a better relevancy of analysis
       - uses: sonarsource/sonarqube-scan-action@master
         env:
           SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/constants.ts b/server/sonar-web/src/main/js/components/tutorials/github-action/constants.ts
new file mode 100644 (file)
index 0000000..2f96d51
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.
+ */
+export const GITHUB_ACTIONS_RUNS_ON_LINUX = 'ubuntu-latest';
+export const GITHUB_ACTIONS_RUNS_ON_WINDOWS = 'windows-latest';
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/utils.ts b/server/sonar-web/src/main/js/components/tutorials/github-action/utils.ts
new file mode 100644 (file)
index 0000000..a024083
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.
+ */
+export function generateGitHubActionsYaml(
+  mainBranchName: string,
+  branchesEnabled: boolean,
+  runsOn: string,
+  steps: string
+) {
+  return `name: Build
+
+on:
+  push:
+    branches:
+      - ${mainBranchName}
+${branchesEnabled ? '  pull_request:\n    types: [opened, synchronize, reopened]' : ''}
+
+jobs:
+  build:
+    name: Build
+    runs-on: ${runsOn}
+    steps:
+      - uses: actions/checkout@v2
+        with:
+          fetch-depth: 0  # Shallow clones should be disabled for a better relevancy of analysis${steps}`;
+}
index d1c7291d9b386ec7f93c0bcc2ef744599efb5189..2c114176b9a437b8693ecfe080a5bbf8bef6c914 100644 (file)
@@ -39,11 +39,12 @@ export interface GitLabCITutorialProps {
   baseUrl: string;
   component: Component;
   currentUser: LoggedInUser;
+  mainBranchName: string;
   willRefreshAutomatically?: boolean;
 }
 
 export default function GitLabCITutorial(props: GitLabCITutorialProps) {
-  const { baseUrl, component, currentUser, willRefreshAutomatically } = props;
+  const { baseUrl, component, currentUser, willRefreshAutomatically, mainBranchName } = props;
 
   const [step, setStep] = React.useState(Steps.PROJECT_KEY);
   const [buildTool, setBuildTool] = React.useState<BuildTools>();
@@ -77,6 +78,7 @@ export default function GitLabCITutorial(props: GitLabCITutorialProps) {
       <YmlFileStep
         buildTool={buildTool}
         finished={step > Steps.YML}
+        mainBranchName={mainBranchName}
         onDone={() => setStep(Steps.ALL_SET)}
         onOpen={() => setStep(Steps.YML)}
         open={step === Steps.YML}
index df7bcb7b2de63a6b36f6f7fe6bff8d95e6a80c3c..3c3c4970eba37c9aafa2a185b9b86edb873be0e6 100644 (file)
@@ -21,6 +21,7 @@ import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
 import { Button } from '../../../components/controls/buttons';
 import { ClipboardIconButton } from '../../../components/controls/clipboard';
+import { GRADLE_SCANNER_VERSION } from '../../../helpers/constants';
 import { translate } from '../../../helpers/l10n';
 import { Component } from '../../../types/types';
 import CodeSnippet from '../../common/CodeSnippet';
@@ -45,7 +46,7 @@ const mavenSnippet = () => `<properties>
 </properties>`;
 
 const gradleSnippet = (key: string) => `plugins {
-  id "org.sonarqube" version "3.4.0.2513"
+  id "org.sonarqube" version "${GRADLE_SCANNER_VERSION}"
 }
 
 sonarqube {
index af9f96dc8c40fcf771e8752479225c9791e00d6e..9d38b84438541dd8c05b783a4b92f8dd0a396e71 100644 (file)
@@ -38,10 +38,11 @@ export interface YmlFileStepProps extends WithAvailableFeaturesProps {
   onOpen: () => void;
   open: boolean;
   projectKey: string;
+  mainBranchName: string;
 }
 
 export function YmlFileStep(props: YmlFileStepProps) {
-  const { buildTool, open, finished, projectKey } = props;
+  const { buildTool, open, finished, projectKey, mainBranchName } = props;
   const branchSupportEnabled = props.hasFeature(Feature.BranchSupport);
 
   const renderForm = () => (
@@ -79,6 +80,7 @@ export function YmlFileStep(props: YmlFileStepProps) {
                 <PipeCommand
                   buildTool={buildTool}
                   branchesEnabled={branchSupportEnabled}
+                  mainBranchName={mainBranchName}
                   projectKey={projectKey}
                 />
               </div>
index a5b34b50822b82330ae28f621eee0da035d88adc..49baf4738989a8851dbeab7404f208868da32179 100644 (file)
@@ -33,6 +33,7 @@ function shallowRender(props: Partial<GitLabCITutorialProps> = {}) {
       baseUrl="http://localhost:9000"
       component={mockComponent()}
       currentUser={mockLoggedInUser()}
+      mainBranchName="main"
       willRefreshAutomatically={true}
       {...props}
     />
index 9c6b0614afa8a7405df57fdf58d27190da65bc61..ac93bffa6cf93988988daaf54036e108a38c17bc 100644 (file)
@@ -49,6 +49,7 @@ function shallowRender(props: Partial<YmlFileStepProps> = {}) {
       open={true}
       projectKey="test"
       finished={true}
+      mainBranchName="main"
       onDone={jest.fn()}
       onOpen={jest.fn()}
       {...props}
index d3fc71fa39947fd86b088721c170fab3c6108917..5d6322ac43e3fd1979f0640fc9cf841c505f487a 100644 (file)
@@ -83,6 +83,7 @@ exports[`should render correctly 1`] = `
   />
   <withAvailableFeaturesContext(YmlFileStep)
     finished={false}
+    mainBranchName="main"
     onDone={[Function]}
     onOpen={[Function]}
     open={false}
index 7ac6df811c5bb3a679a0e20aa6d9bb5da28cc6e6..24bb911d84af6efe9b71252224df3c3134cd2caf 100644 (file)
@@ -44,6 +44,7 @@ exports[`should render correctly for build tool cfamily: with branch support 1`]
           <PipeCommand
             branchesEnabled={true}
             buildTool="cfamily"
+            mainBranchName="main"
             projectKey="test"
           />
         </div>
@@ -108,6 +109,7 @@ exports[`should render correctly for build tool cfamily: without branch support
           <PipeCommand
             branchesEnabled={false}
             buildTool="cfamily"
+            mainBranchName="main"
             projectKey="test"
           />
         </div>
@@ -168,6 +170,7 @@ exports[`should render correctly for build tool dotnet: with branch support 1`]
           <PipeCommand
             branchesEnabled={true}
             buildTool="dotnet"
+            mainBranchName="main"
             projectKey="test"
           />
         </div>
@@ -228,6 +231,7 @@ exports[`should render correctly for build tool dotnet: without branch support 1
           <PipeCommand
             branchesEnabled={false}
             buildTool="dotnet"
+            mainBranchName="main"
             projectKey="test"
           />
         </div>
@@ -288,6 +292,7 @@ exports[`should render correctly for build tool gradle: with branch support 1`]
           <PipeCommand
             branchesEnabled={true}
             buildTool="gradle"
+            mainBranchName="main"
             projectKey="test"
           />
         </div>
@@ -348,6 +353,7 @@ exports[`should render correctly for build tool gradle: without branch support 1
           <PipeCommand
             branchesEnabled={false}
             buildTool="gradle"
+            mainBranchName="main"
             projectKey="test"
           />
         </div>
@@ -408,6 +414,7 @@ exports[`should render correctly for build tool maven: with branch support 1`] =
           <PipeCommand
             branchesEnabled={true}
             buildTool="maven"
+            mainBranchName="main"
             projectKey="test"
           />
         </div>
@@ -468,6 +475,7 @@ exports[`should render correctly for build tool maven: without branch support 1`
           <PipeCommand
             branchesEnabled={false}
             buildTool="maven"
+            mainBranchName="main"
             projectKey="test"
           />
         </div>
@@ -528,6 +536,7 @@ exports[`should render correctly for build tool other: with branch support 1`] =
           <PipeCommand
             branchesEnabled={true}
             buildTool="other"
+            mainBranchName="main"
             projectKey="test"
           />
         </div>
@@ -588,6 +597,7 @@ exports[`should render correctly for build tool other: without branch support 1`
           <PipeCommand
             branchesEnabled={false}
             buildTool="other"
+            mainBranchName="main"
             projectKey="test"
           />
         </div>
index 9b78795ed09a8c0d1ba0552ba8d8207ce687eae7..4202cb2cd519411c1ce3de12f4e21cde4efc1949 100644 (file)
@@ -25,6 +25,7 @@ import { BuildTools } from '../../types';
 export interface PipeCommandProps {
   branchesEnabled?: boolean;
   buildTool: BuildTools;
+  mainBranchName: string;
   projectKey: string;
 }
 
@@ -55,7 +56,8 @@ const BUILD_TOOL_SPECIFIC = {
   }
 };
 
-export default function PipeCommand({ projectKey, branchesEnabled, buildTool }: PipeCommandProps) {
+export default function PipeCommand(props: PipeCommandProps) {
+  const { projectKey, branchesEnabled, buildTool, mainBranchName } = props;
   let command: string;
   if (buildTool === BuildTools.CFamily) {
     command = `image: <image ready for your build toolchain>
@@ -91,9 +93,9 @@ sonarqube-check:
   } else {
     const onlyBlock = branchesEnabled
       ? `- merge_requests
-    - master # or the name of your main branch
+    - ${mainBranchName}
     - develop`
-      : '- master # or the name of your main branch';
+      : `- ${mainBranchName}`;
 
     const { image, script } = BUILD_TOOL_SPECIFIC[buildTool];
 
index 1542dd14cf276668eaa8b234ce78b532579cccb3..0304f125f472ef9b8ff72c016e1ffb2337bf6694 100644 (file)
@@ -30,9 +30,23 @@ it.each([
   [BuildTools.Other]
 ])('should render correctly for %s', buildTool => {
   expect(
-    shallow(<PipeCommand buildTool={buildTool} branchesEnabled={true} projectKey="test" />)
+    shallow(
+      <PipeCommand
+        buildTool={buildTool}
+        branchesEnabled={true}
+        mainBranchName="main"
+        projectKey="test"
+      />
+    )
   ).toMatchSnapshot('branches enabled');
   expect(
-    shallow(<PipeCommand buildTool={buildTool} branchesEnabled={true} projectKey="test" />)
+    shallow(
+      <PipeCommand
+        buildTool={buildTool}
+        branchesEnabled={true}
+        mainBranchName="main"
+        projectKey="test"
+      />
+    )
   ).toMatchSnapshot('branches not enabled');
 });
index 94a01df480b6d1466ecd5d81e490404eba36a722..9b66a6ec41e3b7c1dabac71b3b807acd96cdb02f 100644 (file)
@@ -99,7 +99,7 @@ exports[`should render correctly for dotnet: branches enabled 1`] = `
   allow_failure: true
   only:
     - merge_requests
-    - master # or the name of your main branch
+    - main
     - develop
 "
   />
@@ -129,7 +129,7 @@ exports[`should render correctly for dotnet: branches not enabled 1`] = `
   allow_failure: true
   only:
     - merge_requests
-    - master # or the name of your main branch
+    - main
     - develop
 "
   />
@@ -152,7 +152,7 @@ exports[`should render correctly for gradle: branches enabled 1`] = `
   allow_failure: true
   only:
     - merge_requests
-    - master # or the name of your main branch
+    - main
     - develop
 "
   />
@@ -175,7 +175,7 @@ exports[`should render correctly for gradle: branches not enabled 1`] = `
   allow_failure: true
   only:
     - merge_requests
-    - master # or the name of your main branch
+    - main
     - develop
 "
   />
@@ -199,7 +199,7 @@ exports[`should render correctly for maven: branches enabled 1`] = `
   allow_failure: true
   only:
     - merge_requests
-    - master # or the name of your main branch
+    - main
     - develop
 "
   />
@@ -223,7 +223,7 @@ exports[`should render correctly for maven: branches not enabled 1`] = `
   allow_failure: true
   only:
     - merge_requests
-    - master # or the name of your main branch
+    - main
     - develop
 "
   />
@@ -249,7 +249,7 @@ exports[`should render correctly for other: branches enabled 1`] = `
   allow_failure: true
   only:
     - merge_requests
-    - master # or the name of your main branch
+    - main
     - develop
 "
   />
@@ -275,7 +275,7 @@ exports[`should render correctly for other: branches not enabled 1`] = `
   allow_failure: true
   only:
     - merge_requests
-    - master # or the name of your main branch
+    - main
     - develop
 "
   />
index 3b47235be27bab76499fbd7e644c8a73597cfc90..1f94552c9e333dcf34b2a37f91fb04b69473b706 100644 (file)
@@ -18,7 +18,6 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
-import { getHostUrl } from '../../../../helpers/urls';
 import { Component } from '../../../../types/types';
 import { BuildTools, ManualTutorialConfig } from '../../types';
 import ClangGCCCustom from './ClangGCCCommand';
@@ -42,24 +41,21 @@ export default function AnalysisCommand(props: AnalysisCommandProps) {
     return null;
   }
 
-  const host = getHostUrl();
-
   switch (languageConfig.buildTool) {
     case BuildTools.Maven:
-      return <JavaMaven host={host} component={component} token={token} />;
+      return <JavaMaven baseUrl={baseUrl} component={component} token={token} />;
 
     case BuildTools.Gradle:
-      return <JavaGradle host={host} component={component} token={token} />;
+      return <JavaGradle baseUrl={baseUrl} component={component} token={token} />;
 
     case BuildTools.DotNet:
-      return <DotNet host={host} component={component} token={token} />;
+      return <DotNet baseUrl={baseUrl} component={component} token={token} />;
 
     case BuildTools.CFamily:
       return languageConfig.os !== undefined ? (
         <ClangGCCCustom
           os={languageConfig.os}
           baseUrl={baseUrl}
-          host={host}
           component={component}
           isLocal={isLocal}
           token={token}
@@ -69,7 +65,7 @@ export default function AnalysisCommand(props: AnalysisCommandProps) {
     case BuildTools.Other:
       return languageConfig.os !== undefined ? (
         <Other
-          host={host}
+          baseUrl={baseUrl}
           os={languageConfig.os}
           component={component}
           isLocal={isLocal}
index db6ad94b881fc6dec5e7e34168eab1330dc53f04..510689eb97d17aede672a2cc5c09e36218ccb32b 100644 (file)
@@ -30,13 +30,12 @@ export interface ClangGCCCustomProps {
   component: Component;
   baseUrl: string;
   isLocal: boolean;
-  host: string;
   os: OSs;
   token: string;
 }
 
 export default function ClangGCCCustom(props: ClangGCCCustomProps) {
-  const { os, baseUrl, host, component, isLocal, token } = props;
+  const { os, baseUrl, component, isLocal, token } = props;
 
   return (
     <div>
@@ -45,7 +44,7 @@ export default function ClangGCCCustom(props: ClangGCCCustomProps) {
       <ExecBuildWrapper os={os} />
       <CompilationInfo />
       <ExecScanner
-        host={host}
+        baseUrl={baseUrl}
         isLocal={isLocal}
         component={component}
         os={os}
index e512f38cab2e067a4855e464199764bef43d3819..b8daff7cbefbfa810eb49ec89fe6ebab5dca6f15 100644 (file)
@@ -26,7 +26,7 @@ import DotNetFramework from './DotNetFramework';
 
 export interface DotNetProps {
   component: Component;
-  host: string;
+  baseUrl: string;
   token: string;
 }
 
index c89fb8d9fd5debc2c95cbeb8debc8d8925b1bd58..81b4441a97b67c9b6f7c217b559c1d12c28f5a7c 100644 (file)
@@ -25,10 +25,10 @@ import { DotNetProps } from './DotNet';
 import DotNetExecute from './DotNetExecute';
 
 export default function DotNetCore(props: DotNetProps) {
-  const { host, component, token } = props;
+  const { baseUrl, component, token } = props;
 
   const commands = [
-    `dotnet sonarscanner begin /k:"${component.key}" /d:sonar.host.url="${host}"  /d:sonar.login="${token}"`,
+    `dotnet sonarscanner begin /k:"${component.key}" /d:sonar.host.url="${baseUrl}"  /d:sonar.login="${token}"`,
     'dotnet build',
     `dotnet sonarscanner end /d:sonar.login="${token}"`
   ];
index b8846a24cb890d38f1678c01add1a9435b8d78ac..52a9482414127d926ae230f27bd2f26a5a6048ba 100644 (file)
@@ -25,10 +25,10 @@ import { DotNetProps } from './DotNet';
 import DotNetExecute from './DotNetExecute';
 
 export default function DotNetFramework(props: DotNetProps) {
-  const { host, component, token } = props;
+  const { baseUrl, component, token } = props;
 
   const commands = [
-    `SonarScanner.MSBuild.exe begin /k:"${component.key}" /d:sonar.host.url="${host}" /d:sonar.login="${token}"`,
+    `SonarScanner.MSBuild.exe begin /k:"${component.key}" /d:sonar.host.url="${baseUrl}" /d:sonar.login="${token}"`,
     'MsBuild.exe /t:Rebuild',
     `SonarScanner.MSBuild.exe end /d:sonar.login="${token}"`
   ];
index 067af232fd2677651b2d1cf5e3a7cba6f5512136..646fbd9d1ac82c10d44cf654561f0cbd85038a36 100644 (file)
@@ -30,7 +30,7 @@ import DoneNextSteps from '../DoneNextSteps';
 
 export interface ExecScannerProps {
   component: Component;
-  host: string;
+  baseUrl: string;
   isLocal: boolean;
   os: OSs;
   token: string;
@@ -38,7 +38,7 @@ export interface ExecScannerProps {
 }
 
 export default function ExecScanner(props: ExecScannerProps) {
-  const { host, os, isLocal, component, token, cfamily } = props;
+  const { baseUrl, os, isLocal, component, token, cfamily } = props;
 
   const q = quote(os);
   const command = [
@@ -46,7 +46,7 @@ export default function ExecScanner(props: ExecScannerProps) {
     '-D' + q(`sonar.projectKey=${component.key}`),
     '-D' + q('sonar.sources=.'),
     cfamily ? '-D' + q('sonar.cfamily.build-wrapper-output=bw-output') : undefined,
-    '-D' + q(`sonar.host.url=${host}`),
+    '-D' + q(`sonar.host.url=${baseUrl}`),
     isLocal ? '-D' + q(`sonar.login=${token}`) : undefined
   ];
 
index 85a191cf74aa0c25e8fa393767e1b7f7b5eebae7..567ee2ccf28b5e3f9635ca48b1d69a5b941a3169 100644 (file)
@@ -19,6 +19,7 @@
  */
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
+import { GRADLE_SCANNER_VERSION } from '../../../../helpers/constants';
 import { translate } from '../../../../helpers/l10n';
 import { Component } from '../../../../types/types';
 import CodeSnippet from '../../../common/CodeSnippet';
@@ -28,18 +29,20 @@ import DoneNextSteps from '../DoneNextSteps';
 
 export interface JavaGradleProps {
   component: Component;
-  host: string;
+  baseUrl: string;
   token: string;
 }
 
 export default function JavaGradle(props: JavaGradleProps) {
-  const { host, component, token } = props;
-  const config = 'plugins {\n  id "org.sonarqube" version "3.4.0.2513"\n}';
+  const { baseUrl, component, token } = props;
+  const config = `plugins {
+  id "org.sonarqube" version "${GRADLE_SCANNER_VERSION}"
+}`;
 
   const command = [
     './gradlew sonarqube',
     `-Dsonar.projectKey=${component.key}`,
-    `-Dsonar.host.url=${host}`,
+    `-Dsonar.host.url=${baseUrl}`,
     `-Dsonar.login=${token}`
   ];
 
index 473f99d17ac0ec2652f760f9d9d3b456c59eb820..90e5464eddfa655f05c8f0309d8c0631a9c214d5 100644 (file)
@@ -28,16 +28,16 @@ import DoneNextSteps from '../DoneNextSteps';
 
 export interface JavaMavenProps {
   component: Component;
-  host: string;
+  baseUrl: string;
   token: string;
 }
 
 export default function JavaMaven(props: JavaMavenProps) {
-  const { host, component, token } = props;
+  const { baseUrl, component, token } = props;
   const command = [
     'mvn clean verify sonar:sonar',
     `-Dsonar.projectKey=${component.key}`,
-    `-Dsonar.host.url=${host}`,
+    `-Dsonar.host.url=${baseUrl}`,
     `-Dsonar.login=${token}`
   ];
 
index 2656e640bbfbd6e61a792f9817f0db85a21cf9aa..e1b1358c9944eba2ed90faf08e2d27d60d1c3bb0 100644 (file)
@@ -26,18 +26,24 @@ import ExecScanner from './ExecScanner';
 export interface OtherProps {
   component: Component;
   isLocal: boolean;
-  host: string;
+  baseUrl: string;
   os: OSs;
   token: string;
 }
 
 export default function Other(props: OtherProps) {
-  const { host, os, component, isLocal, token } = props;
+  const { baseUrl, os, component, isLocal, token } = props;
 
   return (
     <div>
       <DownloadScanner isLocal={isLocal} os={os} token={token} />
-      <ExecScanner host={host} isLocal={isLocal} os={os} component={component} token={token} />
+      <ExecScanner
+        baseUrl={baseUrl}
+        isLocal={isLocal}
+        os={os}
+        component={component}
+        token={token}
+      />
     </div>
   );
 }
index b1ecce6b02d010070dda14891fb598e054b95d96..8bbc94e82703a6cdebfd57eb66a18a5be30812a9 100644 (file)
@@ -30,7 +30,6 @@ it('should render correctly', () => {
         os={OSs.Linux}
         baseUrl="http://example.com"
         isLocal={true}
-        host="host"
         component={mockComponent({ key: 'projectKey' })}
         token="token"
       />
index 1b40ad0419e4be30d0773453c4cadbd113342586..2a7411fdb72c5b55e19a58084e8fbf13c6a306c2 100644 (file)
@@ -24,6 +24,8 @@ import DotNet from '../DotNet';
 
 it('should render correctly', () => {
   expect(
-    shallow(<DotNet host="host" component={mockComponent({ key: 'projectKey' })} token="token" />)
+    shallow(
+      <DotNet baseUrl="host" component={mockComponent({ key: 'projectKey' })} token="token" />
+    )
   ).toMatchSnapshot();
 });
index 12932520c37f23b252bf3557fc22b65826531846..c1dc010779f9aea171217a9b87fe9767a69c51b8 100644 (file)
@@ -25,7 +25,11 @@ import DotNetFramework from '../DotNetFramework';
 it('should render correctly', () => {
   expect(
     shallow(
-      <DotNetFramework host="host" component={mockComponent({ key: 'projectKey' })} token="token" />
+      <DotNetFramework
+        baseUrl="host"
+        component={mockComponent({ key: 'projectKey' })}
+        token="token"
+      />
     )
   ).toMatchSnapshot();
 });
index f40ad7f077fe015cfb332bfc4c6a81abbd2f8f3b..a8998cf65d8447c6bc5469943a74d1d0d10cde07 100644 (file)
@@ -25,7 +25,7 @@ import DotNetCore from '../DotNetCore';
 it('should render correctly', () => {
   expect(
     shallow(
-      <DotNetCore host="host" component={mockComponent({ key: 'projectKey' })} token="token" />
+      <DotNetCore baseUrl="host" component={mockComponent({ key: 'projectKey' })} token="token" />
     )
   ).toMatchSnapshot();
 });
index dbea16d6b08a41ccfa93e658b17ffd2d5c499fd5..1fbe02bb25f8e1fa5f024b08ac8d4f8bc7cb51d8 100644 (file)
@@ -38,7 +38,7 @@ it('should render correctly for remote execution', () => {
 function shallowRender(props: Partial<ExecScannerProps> = {}) {
   return shallow<ExecScannerProps>(
     <ExecScanner
-      host="host"
+      baseUrl="host"
       isLocal={true}
       os={OSs.Linux}
       component={mockComponent({ key: 'projectKey' })}
index 02ced39618eb62609d68b2b582d07b31494b4ff0..b556c1f53acb7f45a33b90a4fde373cec3b53305 100644 (file)
@@ -25,7 +25,7 @@ import JavaGradle from '../JavaGradle';
 it('renders correctly', () => {
   expect(
     shallow(
-      <JavaGradle host="host" component={mockComponent({ key: 'projectKey' })} token="token" />
+      <JavaGradle baseUrl="host" component={mockComponent({ key: 'projectKey' })} token="token" />
     )
   ).toMatchSnapshot();
 });
index 808712fe5eb061d3f45b78b7fd5533121f973881..4eed77c8bea6e306fa656dc29b73c8743ccac097 100644 (file)
@@ -25,7 +25,7 @@ import JavaMaven from '../JavaMaven';
 it('renders correctly', () => {
   expect(
     shallow(
-      <JavaMaven host="host" component={mockComponent({ key: 'projectKey' })} token="token" />
+      <JavaMaven baseUrl="host" component={mockComponent({ key: 'projectKey' })} token="token" />
     )
   ).toMatchSnapshot();
 });
index 0beb634c1f987ca986ca3a75346004b9e3e62e59..14a43eaf93cdc6d6492ed1e71f0bccd8eed088e6 100644 (file)
@@ -30,7 +30,7 @@ it('renders correctly', () => {
 function shallowRender(props: Partial<OtherProps> = {}) {
   return shallow<OtherProps>(
     <Other
-      host="host"
+      baseUrl="host"
       isLocal={true}
       os={OSs.Linux}
       component={mockComponent({ key: 'projectKey' })}
index e09a721a9141cc6a97d6d8cb93bf0b38ca7d0885..c7c84eec78da920c44ebbe68f27d52825121ac6a 100644 (file)
@@ -2,6 +2,7 @@
 
 exports[`renders correctly: .NET 1`] = `
 <DotNet
+  baseUrl="http://example.com"
   component={
     Object {
       "breadcrumbs": Array [],
@@ -24,7 +25,6 @@ exports[`renders correctly: .NET 1`] = `
       "tags": Array [],
     }
   }
-  host="HOST"
   token="myToken"
 />
 `;
@@ -54,7 +54,6 @@ exports[`renders correctly: CFamily 1`] = `
       "tags": Array [],
     }
   }
-  host="HOST"
   isLocal={true}
   os="linux"
   token="myToken"
@@ -65,6 +64,7 @@ exports[`renders correctly: Empty CFamily 1`] = `""`;
 
 exports[`renders correctly: gradle 1`] = `
 <JavaGradle
+  baseUrl="http://example.com"
   component={
     Object {
       "breadcrumbs": Array [],
@@ -87,13 +87,13 @@ exports[`renders correctly: gradle 1`] = `
       "tags": Array [],
     }
   }
-  host="HOST"
   token="myToken"
 />
 `;
 
 exports[`renders correctly: maven 1`] = `
 <JavaMaven
+  baseUrl="http://example.com"
   component={
     Object {
       "breadcrumbs": Array [],
@@ -116,13 +116,13 @@ exports[`renders correctly: maven 1`] = `
       "tags": Array [],
     }
   }
-  host="HOST"
   token="myToken"
 />
 `;
 
 exports[`renders correctly: other 1`] = `
 <Other
+  baseUrl="http://example.com"
   component={
     Object {
       "breadcrumbs": Array [],
@@ -145,7 +145,6 @@ exports[`renders correctly: other 1`] = `
       "tags": Array [],
     }
   }
-  host="HOST"
   isLocal={true}
   os="win"
   token="myToken"
index 02c9c2f09f7293a54ef9c7b193264f87c0d5470e..c565c997a5a6bab2c8018f1db3be33a2ccb92377 100644 (file)
@@ -17,6 +17,7 @@ exports[`should render correctly 1`] = `
   />
   <CompilationInfo />
   <ExecScanner
+    baseUrl="http://example.com"
     cfamily={true}
     component={
       Object {
@@ -40,7 +41,6 @@ exports[`should render correctly 1`] = `
         "tags": Array [],
       }
     }
-    host="host"
     isLocal={true}
     os="linux"
     token="token"
index 02c7e57d294960fcead604eb2c446db0e10cf18b..96e497c59129a101571d606c97ec98db79b9ba79 100644 (file)
@@ -16,6 +16,7 @@ exports[`should render correctly 1`] = `
     titleLabelKey="onboarding.build.dotnet.variant"
   />
   <DotNetCore
+    baseUrl="host"
     component={
       Object {
         "breadcrumbs": Array [],
@@ -38,7 +39,6 @@ exports[`should render correctly 1`] = `
         "tags": Array [],
       }
     }
-    host="host"
     token="token"
   />
 </Fragment>
index ffbf9f32605b1cada3340583f368d6db9168c4f4..a64504b17ef2bc182e64303e1087a9a31ed652ad 100644 (file)
@@ -8,6 +8,7 @@ exports[`renders correctly 1`] = `
     token="token"
   />
   <ExecScanner
+    baseUrl="host"
     component={
       Object {
         "breadcrumbs": Array [],
@@ -30,7 +31,6 @@ exports[`renders correctly 1`] = `
         "tags": Array [],
       }
     }
-    host="host"
     isLocal={true}
     os="linux"
     token="token"
index 7bdc50d230ac11b2086284a38e7ab59539a2bbce..19f13e7a09ca45d69a01a03703d95f70dccb548f 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+import { GRADLE_SCANNER_VERSION } from '../../helpers/constants';
 import { convertGithubApiUrlToLink, stripTrailingSlash } from '../../helpers/urls';
 import { AlmSettingsInstance, ProjectAlmBindingResponse } from '../../types/alm-settings';
 import { UserToken } from '../../types/token';
@@ -27,7 +28,7 @@ export function quote(os: string): (s: string) => string {
 
 export function buildGradleSnippet(key: string) {
   return `plugins {
-  id "org.sonarqube" version "3.4.0.2513"
+  id "org.sonarqube" version "${GRADLE_SCANNER_VERSION}"
 }
 
 sonarqube {
index 0f73991916f2b8e63484d5b659c3eddaa80368fc..eb251b676cefb830db131ad03a1ac366908ca5b1 100644 (file)
@@ -76,3 +76,5 @@ export const IMPORT_COMPATIBLE_ALMS = [
 export const IMPORT_COMPATIBLE_ALM_COUNT = IMPORT_COMPATIBLE_ALMS.filter(
   a => a !== AlmKeys.BitbucketCloud
 ).length;
+
+export const GRADLE_SCANNER_VERSION = '3.4.0.2513';