From: Philippe Perrin Date: Wed, 18 Nov 2020 12:23:52 +0000 (+0100) Subject: SONAR-14079 Add Azure Pipelines tutorial for Azure DevOps Server X-Git-Tag: 8.6.0.39681~35 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=9dea56b68988cf5c77a51a9fb6a3b076c546cb93;p=sonarqube.git SONAR-14079 Add Azure Pipelines tutorial for Azure DevOps Server --- diff --git a/server/sonar-web/src/main/js/components/tutorials/TutorialSelection.tsx b/server/sonar-web/src/main/js/components/tutorials/TutorialSelection.tsx index a077d399d1a..24095a0d008 100644 --- a/server/sonar-web/src/main/js/components/tutorials/TutorialSelection.tsx +++ b/server/sonar-web/src/main/js/components/tutorials/TutorialSelection.tsx @@ -20,7 +20,7 @@ import * as React from 'react'; import { WithRouterProps } from 'react-router'; import { getAlmDefinitionsNoCatch, getProjectAlmBinding } from '../../api/alm-settings'; -import { AlmBindingDefinition, AlmKeys, ProjectAlmBindingResponse } from '../../types/alm-settings'; +import { AlmBindingDefinition, ProjectAlmBindingResponse } from '../../types/alm-settings'; import { withRouter } from '../hoc/withRouter'; import TutorialSelectionRenderer from './TutorialSelectionRenderer'; import { TutorialModes } from './types'; @@ -58,11 +58,7 @@ export class TutorialSelection extends React.PureComponent { ]); if (this.mounted) { - // We only support Bitbucket, GitHub & Gitlab for now. - if ( - projectBinding === undefined || - ![AlmKeys.Bitbucket, AlmKeys.GitHub, AlmKeys.GitLab].includes(projectBinding.alm) - ) { + if (projectBinding === undefined) { this.setState({ loading: false, forceManual: true }); } else { let almBinding; diff --git a/server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx b/server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx index 1fc339d8dcf..1cf814c2646 100644 --- a/server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx +++ b/server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx @@ -22,6 +22,7 @@ import * as React from 'react'; import { translate } from 'sonar-ui-common/helpers/l10n'; import { getBaseUrl } from 'sonar-ui-common/helpers/urls'; import { AlmBindingDefinition, AlmKeys, ProjectAlmBindingResponse } from '../../types/alm-settings'; +import AzurePipelinesTutorial from './azure-pipelines/AzurePipelinesTutorial'; import GitLabCITutorial from './gitlabci/GitLabCITutorial'; import JenkinsTutorial from './jenkins/JenkinsTutorial'; import ManualTutorial from './manual/ManualTutorial'; @@ -74,6 +75,22 @@ export default function TutorialSelectionRenderer(props: TutorialSelectionRender )} + {projectBinding?.alm === AlmKeys.Azure && ( + + )} + {jenkinsAvailable && ( + )} + + )} + /> + ))} + + ); +} diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/BranchAnalysisStepContent.tsx b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/BranchAnalysisStepContent.tsx new file mode 100644 index 00000000000..f091e226786 --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/BranchAnalysisStepContent.tsx @@ -0,0 +1,208 @@ +/* + * SonarQube + * Copyright (C) 2009-2020 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 * as React from 'react'; +import { FormattedMessage } from 'react-intl'; +import { Link } from 'react-router'; +import { ClipboardIconButton } from 'sonar-ui-common/components/controls/clipboard'; +import { Alert } from 'sonar-ui-common/components/ui/Alert'; +import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n'; +import CodeSnippet from '../../common/CodeSnippet'; +import RenderOptions from '../components/RenderOptions'; +import SentenceWithHighlights from '../components/SentenceWithHighlights'; + +export interface BranchesAnalysisStepProps { + component: T.Component; + onStepValidationChange: (isValid: boolean) => void; +} + +export enum BuildTechnology { + DotNet = 'dotnet', + Maven = 'maven', + Gradle = 'gradle', + Other = 'other' +} + +export default function BranchAnalysisStepContent(props: BranchesAnalysisStepProps) { + const { component, onStepValidationChange } = props; + + const [buildTechnology, setBuildTechnology] = React.useState(); + + React.useEffect(() => { + if (buildTechnology) { + onStepValidationChange(true); + } + }, [buildTechnology, onStepValidationChange]); + + const MAVEN_GRADLE_PROPS_SNIPPET = `# Additional properties that will be passed to the scanner, +# Put one key=value per line, example: +# sonar.exclusions=**/*.bin +sonar.projectKey=${component.key}`; + + return ( + <> + {translate('onboarding.build')} + setBuildTechnology(value as BuildTechnology)} + optionLabelKey="onboarding.build" + options={Object.values(BuildTechnology)} + /> +
    + {buildTechnology && ( + <> +
  1. + +
  2. +
      +
    • + +
    • +
    • + + {translate( + 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare.run_analysis.section' + )} + + ), + run_analysis_value: ( + + {translate( + 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare.run_analysis.values', + buildTechnology + )} + + ) + }} + /> +
    • + {buildTechnology === BuildTechnology.Other && ( +
    • + +
    • + )} + {[BuildTechnology.DotNet, BuildTechnology.Other].includes(buildTechnology) && ( +
    • + {component.key}, + button: + }} + /> +
    • + )} + {[BuildTechnology.Maven, BuildTechnology.Gradle].includes(buildTechnology) && ( +
    • + + : + +
    • + )} +
    + {[BuildTechnology.DotNet, BuildTechnology.Other].includes(buildTechnology) && ( +
  3. + +
  4. + )} + {[BuildTechnology.Maven, BuildTechnology.Gradle].includes(buildTechnology) && ( + <> +
  5. + {translateWithParameters( + 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.java', + translate('onboarding.build', buildTechnology) + )} +
  6. +
      +
    • + +
    • +
    + + )} + +
  7. + + + {translate( + 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.publish_qg.info.sentence1' + )} + +
  8. +
  9. + +
  10. +
    + + {translate( + 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.branch_protection.link' + )} + + ) + }} + /> + + )} +
+ + ); +} diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/ExtensionInstallationStepContent.tsx b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/ExtensionInstallationStepContent.tsx new file mode 100644 index 00000000000..4e00f962e9c --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/ExtensionInstallationStepContent.tsx @@ -0,0 +1,55 @@ +/* + * SonarQube + * Copyright (C) 2009-2020 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 * as React from 'react'; +import { FormattedMessage } from 'react-intl'; +import { translate } from 'sonar-ui-common/helpers/l10n'; + +export default function ExtensionInstallationStepContent() { + return ( + + + {translate( + 'onboarding.tutorial.with.azure_pipelines.ExtensionInstallation.sentence.link' + )} + + ), + button: ( + + {translate( + 'onboarding.tutorial.with.azure_pipelines.ExtensionInstallation.sentence.button' + )} + + ) + }} + /> + + ); +} diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/SaveAndRunStepContent.tsx b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/SaveAndRunStepContent.tsx new file mode 100644 index 00000000000..ed70ae4ccc8 --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/SaveAndRunStepContent.tsx @@ -0,0 +1,66 @@ +/* + * SonarQube + * Copyright (C) 2009-2020 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 * as React from 'react'; +import { translate } from 'sonar-ui-common/helpers/l10n'; +import { getBaseUrl } from '../../../helpers/system'; + +export default function SaveAndRunStepContent() { + return ( + <> +
+
+ +
+
+

+ + {translate('onboarding.tutorial.with.azure_pipelines.SaveAndRun.commit')} + +

+

{translate('onboarding.tutorial.with.azure_pipelines.SaveAndRun.commit.why')}

+
+
+
+
+ +
+
+

+ + {translate('onboarding.tutorial.with.azure_pipelines.SaveAndRun.refresh')} + +

+

{translate('onboarding.tutorial.with.azure_pipelines.SaveAndRun.refresh.why')}

+
+
+ + ); +} diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/ServiceEndpointStepContent.tsx b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/ServiceEndpointStepContent.tsx new file mode 100644 index 00000000000..69a907af0c4 --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/ServiceEndpointStepContent.tsx @@ -0,0 +1,92 @@ +/* + * SonarQube + * Copyright (C) 2009-2020 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 * as React from 'react'; +import { FormattedMessage } from 'react-intl'; +import { Button } from 'sonar-ui-common/components/controls/buttons'; +import { ClipboardIconButton } from 'sonar-ui-common/components/controls/clipboard'; +import { translate } from 'sonar-ui-common/helpers/l10n'; +import { getHostUrl } from 'sonar-ui-common/helpers/urls'; +import EditTokenModal from '../components/EditTokenModal'; +import SentenceWithHighlights from '../components/SentenceWithHighlights'; + +export interface ServiceEndpointStepProps { + component: T.Component; + currentUser: T.LoggedInUser; +} + +export default function ServiceEndpointStepContent(props: ServiceEndpointStepProps) { + const { component, currentUser } = props; + + const [isModalVisible, toggleModal] = React.useState(false); + + return ( + <> +
    +
  1. + +
  2. +
  3. + +
  4. +
  5. + {translate('onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.step3.sentence')} +
  6. +
  7. + {getHostUrl()}, + button: + }} + /> +
  8. +
  9. + + {translate('onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.step5.sentence')}: + + +
  10. +
  11. + {translate('onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.step6.sentence')} +
  12. +
+ + {isModalVisible && ( + toggleModal(false)} + /> + )} + + ); +} diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/AzurePipelinesTutorial-test.tsx b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/AzurePipelinesTutorial-test.tsx new file mode 100644 index 00000000000..d7ad84a21c2 --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/AzurePipelinesTutorial-test.tsx @@ -0,0 +1,111 @@ +/* + * SonarQube + * Copyright (C) 2009-2020 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 { Button } from 'sonar-ui-common/components/controls/buttons'; +import { click } from 'sonar-ui-common/helpers/testUtils'; +import { + mockProjectAzureBindingResponse, + mockProjectGithubBindingResponse +} from '../../../../helpers/mocks/alm-settings'; +import { mockComponent, mockLoggedInUser } from '../../../../helpers/testMocks'; +import Step from '../../components/Step'; +import AzurePipelinesTutorial, { AzurePipelinesTutorialProps } from '../AzurePipelinesTutorial'; + +it('should render correctly', () => { + const wrapper = shallowRender(); + expect(wrapper).toMatchSnapshot(); + expect( + wrapper + .find(Step) + .first() + .dive() + ).toMatchSnapshot('first-step-wrapper'); + expect( + wrapper + .find(Step) + .last() + .dive() + ).toMatchSnapshot('last-step-wrapper'); + expect(shallowRender({ projectBinding: mockProjectGithubBindingResponse() })).toMatchSnapshot( + 'wrong alm' + ); +}); + +it('should display the next step when one is finished', () => { + const wrapper = shallowRender(); + expect( + wrapper + .find(Step) + .filterWhere(elt => elt.props().open === true) + .props().stepNumber + ).toBe(1); + + click( + wrapper + .find(Step) + .first() + .dive() + .find(Button) + ); + + expect( + wrapper + .find(Step) + .filterWhere(elt => elt.props().open === true) + .props().stepNumber + ).toBe(2); +}); + +it('should open a step when user click on it', () => { + const wrapper = shallowRender(); + expect( + wrapper + .find(Step) + .filterWhere(elt => elt.props().open === true) + .props().stepNumber + ).toBe(1); + + ( + wrapper + .find(Step) + .filterWhere(elt => elt.props().stepNumber === 3) + .props().onOpen ?? (() => {}) + )(); + + expect( + wrapper + .find(Step) + .filterWhere(elt => elt.props().open === true) + .props().stepNumber + ).toBe(3); +}); + +function shallowRender(props: Partial = {}) { + return shallow( + + ); +} diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/BranchAnalysisStepContent-test.tsx b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/BranchAnalysisStepContent-test.tsx new file mode 100644 index 00000000000..f6f45aed90b --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/BranchAnalysisStepContent-test.tsx @@ -0,0 +1,58 @@ +/* + * SonarQube + * Copyright (C) 2009-2020 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 { mockComponent } from '../../../../helpers/testMocks'; +import RenderOptions from '../../components/RenderOptions'; +import BranchAnalysisStepContent, { + BranchesAnalysisStepProps, + BuildTechnology +} from '../BranchAnalysisStepContent'; + +it('should render correctly', () => { + const wrapper = shallowRender(); + expect(wrapper).toMatchSnapshot(); +}); + +it.each([ + BuildTechnology.DotNet, + BuildTechnology.Gradle, + BuildTechnology.Maven, + BuildTechnology.Other +])('should render correctly', (buildTech: BuildTechnology) => { + const wrapper = shallowRender(); + wrapper + .find(RenderOptions) + .props() + .onCheck(buildTech); + + expect(wrapper).toMatchSnapshot(buildTech); +}); + +function shallowRender(props: Partial = {}) { + return shallow( + + ); +} diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/ExtensionInstallationStepContent-test.tsx b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/ExtensionInstallationStepContent-test.tsx new file mode 100644 index 00000000000..da361004576 --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/ExtensionInstallationStepContent-test.tsx @@ -0,0 +1,32 @@ +/* + * SonarQube + * Copyright (C) 2009-2020 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 ExtensionInstallationStepContent from '../ExtensionInstallationStepContent'; + +it('should render correctly', () => { + const wrapper = shallowRender(); + expect(wrapper).toMatchSnapshot(); +}); + +function shallowRender() { + return shallow(); +} diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/SaveAndRunStepContent-test.tsx b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/SaveAndRunStepContent-test.tsx new file mode 100644 index 00000000000..0e0af022fe5 --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/SaveAndRunStepContent-test.tsx @@ -0,0 +1,32 @@ +/* + * SonarQube + * Copyright (C) 2009-2020 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 SaveAndRunStepContent from '../SaveAndRunStepContent'; + +it('should render correctly', () => { + const wrapper = shallowRender(); + expect(wrapper).toMatchSnapshot(); +}); + +function shallowRender() { + return shallow(); +} diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/ServiceEndpointStepContent-test.tsx b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/ServiceEndpointStepContent-test.tsx new file mode 100644 index 00000000000..683e9321561 --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/ServiceEndpointStepContent-test.tsx @@ -0,0 +1,52 @@ +/* + * SonarQube + * Copyright (C) 2009-2020 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 { Button } from 'sonar-ui-common/components/controls/buttons'; +import { click } from 'sonar-ui-common/helpers/testUtils'; +import { mockComponent, mockLoggedInUser } from '../../../../helpers/testMocks'; +import EditTokenModal from '../../components/EditTokenModal'; +import ServiceEndpointStepContent from '../ServiceEndpointStepContent'; + +it('should render correctly', () => { + const wrapper = shallowRender(); + expect(wrapper).toMatchSnapshot(); +}); + +it('should render open/close the token modal when asked to', () => { + const wrapper = shallowRender(); + expect(wrapper.exists(EditTokenModal)).toBe(false); + + click(wrapper.find(Button)); + expect(wrapper.exists(EditTokenModal)).toBe(true); + + wrapper + .find(EditTokenModal) + .props() + .onClose(); + expect(wrapper.exists(EditTokenModal)).toBe(false); +}); + +function shallowRender() { + return shallow( + + ); +} diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/__snapshots__/AzurePipelinesTutorial-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/__snapshots__/AzurePipelinesTutorial-test.tsx.snap new file mode 100644 index 00000000000..84e32877db7 --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/__snapshots__/AzurePipelinesTutorial-test.tsx.snap @@ -0,0 +1,128 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly 1`] = ` + +
+

+ onboarding.tutorial.with.azure_pipelines.title +

+
+ + + + +
+`; + +exports[`should render correctly: first-step-wrapper 1`] = ` +
+
+ 1 +
+
+

+ onboarding.tutorial.with.azure_pipelines.ExtensionInstallation.title +

+
+
+
+
+ +
+ +
+
+
+`; + +exports[`should render correctly: last-step-wrapper 1`] = ` +
+
+ 4 +
+
+

+ onboarding.tutorial.with.azure_pipelines.SaveAndRun.title +

+
+
+
+
+
+ +
+
+
+
+`; + +exports[`should render correctly: wrong alm 1`] = ` + + onboarding.tutorial.with.azure_pipelines.unsupported + +`; diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/__snapshots__/BranchAnalysisStepContent-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/__snapshots__/BranchAnalysisStepContent-test.tsx.snap new file mode 100644 index 00000000000..07602310f0f --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/__snapshots__/BranchAnalysisStepContent-test.tsx.snap @@ -0,0 +1,613 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly 1`] = ` + + + onboarding.build + + +
    + +`; + +exports[`should render correctly: dotnet 1`] = ` + + + onboarding.build + + +
      +
    1. + +
    2. +
        +
      • + +
      • +
      • + + onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare.run_analysis.values.dotnet + , + "section": + onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare.run_analysis.section + , + } + } + /> +
      • +
      • + , + "key": + my-project + , + } + } + /> +
      • +
      +
    3. + +
    4. +
    5. + + + onboarding.tutorial.with.azure_pipelines.BranchAnalysis.publish_qg.info.sentence1 + +
    6. +
    7. + +
    8. +
      + + onboarding.tutorial.with.azure_pipelines.BranchAnalysis.branch_protection.link + , + } + } + /> +
    +
    +`; + +exports[`should render correctly: gradle 1`] = ` + + + onboarding.build + + +
      +
    1. + +
    2. +
        +
      • + +
      • +
      • + + onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare.run_analysis.values.gradle + , + "section": + onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare.run_analysis.section + , + } + } + /> +
      • +
      • + + : + +
      • +
      +
    3. + onboarding.tutorial.with.azure_pipelines.BranchAnalysis.java.onboarding.build.gradle +
    4. +
        +
      • + +
      • +
      +
    5. + + + onboarding.tutorial.with.azure_pipelines.BranchAnalysis.publish_qg.info.sentence1 + +
    6. +
    7. + +
    8. +
      + + onboarding.tutorial.with.azure_pipelines.BranchAnalysis.branch_protection.link + , + } + } + /> +
    +
    +`; + +exports[`should render correctly: maven 1`] = ` + + + onboarding.build + + +
      +
    1. + +
    2. +
        +
      • + +
      • +
      • + + onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare.run_analysis.values.maven + , + "section": + onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare.run_analysis.section + , + } + } + /> +
      • +
      • + + : + +
      • +
      +
    3. + onboarding.tutorial.with.azure_pipelines.BranchAnalysis.java.onboarding.build.maven +
    4. +
        +
      • + +
      • +
      +
    5. + + + onboarding.tutorial.with.azure_pipelines.BranchAnalysis.publish_qg.info.sentence1 + +
    6. +
    7. + +
    8. +
      + + onboarding.tutorial.with.azure_pipelines.BranchAnalysis.branch_protection.link + , + } + } + /> +
    +
    +`; + +exports[`should render correctly: other 1`] = ` + + + onboarding.build + + +
      +
    1. + +
    2. +
        +
      • + +
      • +
      • + + onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare.run_analysis.values.other + , + "section": + onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare.run_analysis.section + , + } + } + /> +
      • +
      • + +
      • +
      • + , + "key": + my-project + , + } + } + /> +
      • +
      +
    3. + +
    4. +
    5. + + + onboarding.tutorial.with.azure_pipelines.BranchAnalysis.publish_qg.info.sentence1 + +
    6. +
    7. + +
    8. +
      + + onboarding.tutorial.with.azure_pipelines.BranchAnalysis.branch_protection.link + , + } + } + /> +
    +
    +`; diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/__snapshots__/ExtensionInstallationStepContent-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/__snapshots__/ExtensionInstallationStepContent-test.tsx.snap new file mode 100644 index 00000000000..9a8c93a3e5f --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/__snapshots__/ExtensionInstallationStepContent-test.tsx.snap @@ -0,0 +1,24 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly 1`] = ` + + + onboarding.tutorial.with.azure_pipelines.ExtensionInstallation.sentence.button + , + "link": + onboarding.tutorial.with.azure_pipelines.ExtensionInstallation.sentence.link + , + } + } + /> + +`; diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/__snapshots__/SaveAndRunStepContent-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/__snapshots__/SaveAndRunStepContent-test.tsx.snap new file mode 100644 index 00000000000..9f4dd3417bd --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/__snapshots__/SaveAndRunStepContent-test.tsx.snap @@ -0,0 +1,54 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly 1`] = ` + +
    +
    + +
    +
    +

    + + onboarding.tutorial.with.azure_pipelines.SaveAndRun.commit + +

    +

    + onboarding.tutorial.with.azure_pipelines.SaveAndRun.commit.why +

    +
    +
    +
    +
    + +
    +
    +

    + + onboarding.tutorial.with.azure_pipelines.SaveAndRun.refresh + +

    +

    + onboarding.tutorial.with.azure_pipelines.SaveAndRun.refresh.why +

    +
    +
    +
    +`; diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/__snapshots__/ServiceEndpointStepContent-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/__snapshots__/ServiceEndpointStepContent-test.tsx.snap new file mode 100644 index 00000000000..1596e44fa1c --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/__snapshots__/ServiceEndpointStepContent-test.tsx.snap @@ -0,0 +1,66 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly 1`] = ` + +
      +
    1. + +
    2. +
    3. + +
    4. +
    5. + onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.step3.sentence +
    6. +
    7. + , + "url": + http://localhost + , + } + } + /> +
    8. +
    9. + + onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.step5.sentence + : + + +
    10. +
    11. + onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.step6.sentence +
    12. +
    +
    +`; diff --git a/server/sonar-web/src/main/js/components/tutorials/gitlabci/GitLabCITutorial.tsx b/server/sonar-web/src/main/js/components/tutorials/gitlabci/GitLabCITutorial.tsx index 8d4dee3d6bc..d66ac7b3771 100644 --- a/server/sonar-web/src/main/js/components/tutorials/gitlabci/GitLabCITutorial.tsx +++ b/server/sonar-web/src/main/js/components/tutorials/gitlabci/GitLabCITutorial.tsx @@ -20,8 +20,10 @@ import * as React from 'react'; import { Alert } from 'sonar-ui-common/components/ui/Alert'; import { translate } from 'sonar-ui-common/helpers/l10n'; -import { isProjectGitLabBindingResponse } from '../../../helpers/alm-settings'; -import { ProjectAlmBindingResponse } from '../../../types/alm-settings'; +import { + isProjectGitLabBindingResponse, + ProjectAlmBindingResponse +} from '../../../types/alm-settings'; import EnvironmentVariablesStep from './EnvironmentVariablesStep'; import ProjectKeyStep from './ProjectKeyStep'; import { BuildTools } from './types'; diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/JenkinsTutorial.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/JenkinsTutorial.tsx index a516260891f..cdc00fbf235 100644 --- a/server/sonar-web/src/main/js/components/tutorials/jenkins/JenkinsTutorial.tsx +++ b/server/sonar-web/src/main/js/components/tutorials/jenkins/JenkinsTutorial.tsx @@ -21,13 +21,14 @@ import * as React from 'react'; import { connect } from 'react-redux'; import { Alert } from 'sonar-ui-common/components/ui/Alert'; import { translate } from 'sonar-ui-common/helpers/l10n'; -import { - isProjectBitbucketBindingResponse, - isProjectGitHubBindingResponse -} from '../../../helpers/alm-settings'; import { getCurrentUserSetting, Store } from '../../../store/rootReducer'; import { setCurrentUserSetting } from '../../../store/users'; -import { AlmBindingDefinition, ProjectAlmBindingResponse } from '../../../types/alm-settings'; +import { + AlmBindingDefinition, + isProjectBitbucketBindingResponse, + isProjectGitHubBindingResponse, + ProjectAlmBindingResponse +} from '../../../types/alm-settings'; import JenkinsfileStep from './JenkinsfileStep'; import MultiBranchPipelineStep from './MultiBranchPipelineStep'; import PreRequisitesStep from './PreRequisitesStep'; diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/MultiBranchPipelineStep.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/MultiBranchPipelineStep.tsx index d0feb3133bc..26279e2c0c7 100644 --- a/server/sonar-web/src/main/js/components/tutorials/jenkins/MultiBranchPipelineStep.tsx +++ b/server/sonar-web/src/main/js/components/tutorials/jenkins/MultiBranchPipelineStep.tsx @@ -21,12 +21,10 @@ import * as React from 'react'; import { Button } from 'sonar-ui-common/components/controls/buttons'; import { translate } from 'sonar-ui-common/helpers/l10n'; import { + AlmBindingDefinition, isGithubBindingDefinition, isProjectBitbucketBindingResponse, - isProjectGitHubBindingResponse -} from '../../../helpers/alm-settings'; -import { - AlmBindingDefinition, + isProjectGitHubBindingResponse, ProjectBitbucketBindingResponse, ProjectGitHubBindingResponse } from '../../../types/alm-settings'; diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStep.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStep.tsx index 60dfc618314..4243c27cc2e 100644 --- a/server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStep.tsx +++ b/server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStep.tsx @@ -21,13 +21,11 @@ import * as React from 'react'; import { FormattedMessage } from 'react-intl'; import { Button, ButtonLink } from 'sonar-ui-common/components/controls/buttons'; import { translate } from 'sonar-ui-common/helpers/l10n'; -import { - isBitbucketBindingDefinition, - isGithubBindingDefinition -} from '../../../helpers/alm-settings'; import { AlmBindingDefinition, AlmKeys, + isBitbucketBindingDefinition, + isGithubBindingDefinition, ProjectAlmBindingResponse } from '../../../types/alm-settings'; import Step from '../components/Step'; diff --git a/server/sonar-web/src/main/js/components/tutorials/types.ts b/server/sonar-web/src/main/js/components/tutorials/types.ts index 80e22751eda..46edfc4f552 100644 --- a/server/sonar-web/src/main/js/components/tutorials/types.ts +++ b/server/sonar-web/src/main/js/components/tutorials/types.ts @@ -20,7 +20,8 @@ export enum TutorialModes { Manual = 'manual', Jenkins = 'jenkins', - GitLabCI = 'gitlab-ci' + GitLabCI = 'gitlab-ci', + AzurePipelines = 'azure-pipelines' } export enum BuildTools { diff --git a/server/sonar-web/src/main/js/helpers/__tests__/alm-settings-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/alm-settings-test.ts deleted file mode 100644 index 2f8c1c4a189..00000000000 --- a/server/sonar-web/src/main/js/helpers/__tests__/alm-settings-test.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2020 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 { AlmKeys } from '../../types/alm-settings'; -import { - isBitbucketBindingDefinition, - isGithubBindingDefinition, - isProjectBitbucketBindingResponse, - isProjectGitHubBindingResponse -} from '../alm-settings'; -import { - mockBitbucketBindingDefinition, - mockGithubBindingDefinition, - mockProjectAlmBindingResponse, - mockProjectBitbucketBindingResponse, - mockProjectGithubBindingResponse -} from '../mocks/alm-settings'; - -/* eslint-disable sonarjs/no-duplicate-string */ - -describe('isProjectBitbucketBindingResponse', () => { - it('works as expected', () => { - expect(isProjectBitbucketBindingResponse(mockProjectAlmBindingResponse())).toBe(false); - expect(isProjectBitbucketBindingResponse(mockProjectBitbucketBindingResponse())).toBe(true); - }); -}); - -describe('isBitbucketBindingDefinition', () => { - it('works as expected', () => { - expect(isBitbucketBindingDefinition(undefined)).toBe(false); - expect(isBitbucketBindingDefinition(mockGithubBindingDefinition())).toBe(false); - expect(isBitbucketBindingDefinition(mockBitbucketBindingDefinition())).toBe(true); - }); -}); - -describe('isProjectGithubBindingResponse', () => { - it('works as expected', () => { - expect( - isProjectGitHubBindingResponse(mockProjectAlmBindingResponse({ alm: AlmKeys.Azure })) - ).toBe(false); - expect(isProjectGitHubBindingResponse(mockProjectGithubBindingResponse())).toBe(true); - }); -}); - -describe('isGithubBindingDefinition', () => { - it('works as expected', () => { - expect(isGithubBindingDefinition(undefined)).toBe(false); - expect(isGithubBindingDefinition(mockBitbucketBindingDefinition())).toBe(false); - expect(isGithubBindingDefinition(mockGithubBindingDefinition())).toBe(true); - }); -}); diff --git a/server/sonar-web/src/main/js/helpers/alm-settings.ts b/server/sonar-web/src/main/js/helpers/alm-settings.ts deleted file mode 100644 index bd0013775fc..00000000000 --- a/server/sonar-web/src/main/js/helpers/alm-settings.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2020 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 { - AlmBindingDefinition, - AlmKeys, - BitbucketBindingDefinition, - GithubBindingDefinition, - ProjectAlmBindingResponse, - ProjectBitbucketBindingResponse, - ProjectGitHubBindingResponse, - ProjectGitLabBindingResponse -} from '../types/alm-settings'; - -export function isProjectBitbucketBindingResponse( - binding: ProjectAlmBindingResponse -): binding is ProjectBitbucketBindingResponse { - return binding.alm === AlmKeys.Bitbucket; -} - -export function isProjectGitHubBindingResponse( - binding: ProjectAlmBindingResponse -): binding is ProjectGitHubBindingResponse { - return binding.alm === AlmKeys.GitHub; -} - -export function isProjectGitLabBindingResponse( - binding: ProjectAlmBindingResponse -): binding is ProjectGitLabBindingResponse { - return binding.alm === AlmKeys.GitLab; -} - -export function isBitbucketBindingDefinition( - binding?: AlmBindingDefinition & { url?: string; personalAccessToken?: string } -): binding is BitbucketBindingDefinition { - return ( - binding !== undefined && binding.url !== undefined && binding.personalAccessToken !== undefined - ); -} - -export function isGithubBindingDefinition( - binding?: AlmBindingDefinition & { appId?: string; privateKey?: string; url?: string } -): binding is GithubBindingDefinition { - return ( - binding !== undefined && - binding.appId !== undefined && - binding.privateKey !== undefined && - binding.url !== undefined - ); -} diff --git a/server/sonar-web/src/main/js/helpers/mocks/alm-settings.ts b/server/sonar-web/src/main/js/helpers/mocks/alm-settings.ts index b4a67f72610..b8de0c0aa21 100644 --- a/server/sonar-web/src/main/js/helpers/mocks/alm-settings.ts +++ b/server/sonar-web/src/main/js/helpers/mocks/alm-settings.ts @@ -27,6 +27,7 @@ import { GithubBindingDefinition, GitlabBindingDefinition, ProjectAlmBindingResponse, + ProjectAzureBindingResponse, ProjectBitbucketBindingResponse, ProjectGitHubBindingResponse, ProjectGitLabBindingResponse @@ -132,6 +133,19 @@ export function mockProjectGitLabBindingResponse( }; } +export function mockProjectAzureBindingResponse( + overrides: Partial = {} +): ProjectAzureBindingResponse { + return { + alm: AlmKeys.Azure, + key: 'foo', + slug: 'PROJECT_NAME', + repository: 'REPOSITORY_NAME', + url: 'https://ado.my_company.com/mycollection', + ...overrides + }; +} + export function mockAlmSettingsBindingStatus( overrides: Partial ): AlmSettingsBindingStatus { diff --git a/server/sonar-web/src/main/js/types/alm-settings.ts b/server/sonar-web/src/main/js/types/alm-settings.ts index c27018afb25..c70a371b878 100644 --- a/server/sonar-web/src/main/js/types/alm-settings.ts +++ b/server/sonar-web/src/main/js/types/alm-settings.ts @@ -60,6 +60,13 @@ export interface ProjectAlmBindingResponse { summaryCommentEnabled?: boolean; } +export interface ProjectAzureBindingResponse extends ProjectAlmBindingResponse { + alm: AlmKeys.Azure; + repository: string; + slug: string; + url: string; +} + export interface ProjectBitbucketBindingResponse extends ProjectAlmBindingResponse { alm: AlmKeys.Bitbucket; repository: string; @@ -126,3 +133,46 @@ export enum AlmSettingsBindingStatusType { Failure, Warning } + +export function isProjectBitbucketBindingResponse( + binding: ProjectAlmBindingResponse +): binding is ProjectBitbucketBindingResponse { + return binding.alm === AlmKeys.Bitbucket; +} + +export function isProjectGitHubBindingResponse( + binding: ProjectAlmBindingResponse +): binding is ProjectGitHubBindingResponse { + return binding.alm === AlmKeys.GitHub; +} + +export function isProjectGitLabBindingResponse( + binding: ProjectAlmBindingResponse +): binding is ProjectGitLabBindingResponse { + return binding.alm === AlmKeys.GitLab; +} + +export function isProjectAzureBindingResponse( + binding: ProjectAlmBindingResponse +): binding is ProjectAzureBindingResponse { + return binding.alm === AlmKeys.Azure; +} + +export function isBitbucketBindingDefinition( + binding?: AlmBindingDefinition & { url?: string; personalAccessToken?: string } +): binding is BitbucketBindingDefinition { + return ( + binding !== undefined && binding.url !== undefined && binding.personalAccessToken !== undefined + ); +} + +export function isGithubBindingDefinition( + binding?: AlmBindingDefinition & { appId?: string; privateKey?: string; url?: string } +): binding is GithubBindingDefinition { + return ( + binding !== undefined && + binding.appId !== undefined && + binding.privateKey !== undefined && + binding.url !== undefined + ); +} diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index 38cefcb7b22..68cb4d8e9b4 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -3447,6 +3447,7 @@ onboarding.tutorial.choose_method=How do you want to analyze your repository? onboarding.tutorial.choose_method.manual=Manually onboarding.tutorial.choose_method.jenkins=With Jenkins onboarding.tutorial.choose_method.gitlab_ci=With GitLab CI +onboarding.tutorial.choose_method.azure_pipelines=With Azure Pipelines onboarding.tutorial.with.gitlab_ci.title=Analyze your project with GitLab CI onboarding.tutorial.with.gitlab_ci.unsupported=This tutorial is only available for projects bound to GitLab. @@ -3598,6 +3599,63 @@ onboarding.tutorial.with.jenkins.commit.why=Each new push you make on your branc onboarding.tutorial.with.jenkins.refresh=This page will then refresh with your analysis results. onboarding.tutorial.with.jenkins.refresh.why=If the page doesn't refresh after a while, please double-check the analysis configuration. +onboarding.tutorial.with.azure_pipelines.title=Analyze your project with Azure DevOps Pipelines +onboarding.tutorial.with.azure_pipelines.unsupported=This tutorial is only available for projects bound to Azure DevOps Server. +onboarding.tutorial.with.azure_pipelines.ExtensionInstallation.title=Install SonarQube extension for Azure DevOps Server +onboarding.tutorial.with.azure_pipelines.ExtensionInstallation.sentence=From your Azure DevOps Server instance, navigate to the Visual Studio Marketplace and install the {link} by clicking the {button} button. +onboarding.tutorial.with.azure_pipelines.ExtensionInstallation.sentence.link=SonarQube extension +onboarding.tutorial.with.azure_pipelines.ExtensionInstallation.sentence.button=Get it free +onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.title=Add a new SonarQube Service Endpoint +onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.step1.sentence=In Azure DevOps Server, go to {menu} +onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.step1.sentence.menu=Project settings > Service connections +onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.step2.sentence=Add a new service connection of type {type} +onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.step2.sentence.type=SonarQube +onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.step3.sentence=Enter a memorable connection name +onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.step4.sentence=Enter your SonarQube server url: {url} {button} +onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.step5.sentence=Enter an existing token, or a newly generated one +onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.step6.sentence=Create the service connection +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.title=Configure Branch analysis +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare.sentence=In Azure DevOps Server, create or edit a {pipeline} and add a new {task} task {before} your build task +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare.sentence.pipeline=Build Pipeline +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare.sentence.task=Prepare Analysis Configuration +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare.sentence.before=before +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare.endpoint.sentence=Select the {endpoint} you created in Step 2 +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare.endpoint.sentence.endpoint=SonarQube server endpoint +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare.run_analysis=Under {section}, select {run_analysis_value} +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare.run_analysis.section=Choose the way to run the analysis +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare.run_analysis.values.dotnet=Integrate with MSBuild +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare.run_analysis.values.maven=Integrate with Maven or Gradle +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare.run_analysis.values.gradle=Integrate with Maven or Gradle +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare.run_analysis.values.other=Use standalone scanner +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.manual.sentence=Select the {mode} mode +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.manual.sentence.mode=Manually provide configuration +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.run.sentence=Add a new {task} task {after} your build task +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.run.sentence.task=Run Code Analysis +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.run.sentence.after=after +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.run.key.sentence=In the project key field, enter {key} {button} +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.advanced_properties.sentence=Expand the {section} and replace the {properties} with the following snippet +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.advanced_properties.sentence.section=Advanced section +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.advanced_properties.sentence.properties=Additional Properties +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.java=Edit or add a new {0} task +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.java.settings.sentence=Under {section}, check {option} +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.java.settings.sentence.section=Code Analysis +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.java.settings.sentence.option=Run SonarQube or SonarCloud Analysis +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.publish_qg.sentence=Add a new {task} task to publish SonarQube's Quality Gate results on your build pipeline summary +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.publish_qg.info.sentence1=This task may increase your build time as your pipeline will have to wait for SonarQube to process the analysis report. It is highly recommended but optional. +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.publish_qg.sentence.task=Publish Quality Gate Result +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.continous_integration.sentence=Under the {tab} tab of your pipeline, check {continuous_integration} and select all the branches for which you want the SonarQube analysis to run automatically +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.continous_integration.sentence.tab=Triggers +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.continous_integration.sentence.continuous_integration=Enable continuous integration +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.branch_protection=To make sure your Pull Requests are analyzed automatically and aren't merged when they're failing their quality gate, check out the {link}. +onboarding.tutorial.with.azure_pipelines.BranchAnalysis.branch_protection.link=documentation +onboarding.tutorial.with.azure_pipelines.SaveAndRun.title=Save and run your pipeline +onboarding.tutorial.with.azure_pipelines.SaveAndRun.commit=Save your pipeline and push your code to start the analysis +onboarding.tutorial.with.azure_pipelines.SaveAndRun.commit.why=Each new push you make on your branches will trigger a new analysis in SonarQube +onboarding.tutorial.with.azure_pipelines.SaveAndRun.refresh=This page will then refresh with your analysis results +onboarding.tutorial.with.azure_pipelines.SaveAndRun.refresh.why=If this page doesn't refresh after a while, please double-check your pipeline configuration +onboarding.tutorial.with.azure_pipelines.SaveAndRun.then={what} Checkout our {link} to make sure SonarQube analyze and decorate all of your Pull Requests +onboarding.tutorial.with.azure_pipelines.SaveAndRun.then.what=Then what? +onboarding.tutorial.with.azure_pipelines.SaveAndRun.then.link=Azure integration documentation #------------------------------------------------------------------------------ # # BRANCHES