From b39a937e42ab7c224a967e351f1baf647a66dca7 Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Wed, 26 Aug 2020 17:57:26 +0200 Subject: [PATCH] SONAR-13754 Add GitLab CI tutorial --- .../tooltips/tutorials/use-existing-token.md | 5 + .../components/OrganizationEmpty.tsx | 1 - .../tutorials/TutorialSelection.tsx | 5 +- .../tutorials/TutorialSelectionRenderer.tsx | 62 +++- .../__tests__/TutorialSelection-test.tsx | 4 +- .../TutorialSelectionRenderer-test.tsx | 28 +- .../TutorialSelectionRenderer-test.tsx.snap | 91 ++++- .../tutorials/components/EditTokenModal.tsx | 186 ++++++++++ .../components/tutorials/components/Step.css | 23 +- .../__tests__/EditTokenModal-test.tsx | 112 ++++++ .../EditTokenModal-test.tsx.snap | 11 + .../gitlabci/EnvironmentVariablesStep.tsx | 178 +++++++++ .../tutorials/gitlabci/GitLabCITutorial.tsx | 83 +++++ .../tutorials/gitlabci/ProjectKeyStep.tsx | 125 +++++++ .../tutorials/gitlabci/YmlFileStep.tsx | 136 +++++++ .../EnvironmentVariablesStep-test.tsx | 46 +++ .../__tests__/GitLabCITutorial-test.tsx | 45 +++ .../__tests__/ProjectKeyStep-test.tsx | 69 ++++ .../gitlabci/__tests__/YmlFileStep-test.tsx | 41 ++ .../EnvironmentVariablesStep-test.tsx.snap | 173 +++++++++ .../GitLabCITutorial-test.tsx.snap | 94 +++++ .../ProjectKeyStep-test.tsx.snap | 226 ++++++++++++ .../__snapshots__/YmlFileStep-test.tsx.snap | 349 ++++++++++++++++++ .../gitlabci/commands/PipeCommandGradle.tsx | 42 +++ .../gitlabci/commands/PipeCommandMaven.tsx | 43 +++ .../gitlabci/commands/PipeCommandOther.tsx | 45 +++ .../__tests__/PipeCommandGradle-test.tsx | 26 ++ .../__tests__/PipeCommandMaven-test.tsx | 26 ++ .../__tests__/PipeCommandOther-test.tsx | 26 ++ .../PipeCommandGradle-test.tsx.snap | 22 ++ .../PipeCommandMaven-test.tsx.snap | 23 ++ .../PipeCommandOther-test.tsx.snap | 25 ++ .../{styles.css => gitlabci/types.ts} | 8 +- .../src/main/js/components/tutorials/types.ts | 3 +- .../src/main/js/helpers/alm-settings.ts | 9 +- .../src/main/js/helpers/mocks/alm-settings.ts | 15 +- .../src/main/js/types/alm-settings.ts | 6 + .../resources/org/sonar/l10n/core.properties | 36 ++ 38 files changed, 2403 insertions(+), 45 deletions(-) create mode 100644 server/sonar-docs/src/tooltips/tutorials/use-existing-token.md create mode 100644 server/sonar-web/src/main/js/components/tutorials/components/EditTokenModal.tsx create mode 100644 server/sonar-web/src/main/js/components/tutorials/components/__tests__/EditTokenModal-test.tsx create mode 100644 server/sonar-web/src/main/js/components/tutorials/components/__tests__/__snapshots__/EditTokenModal-test.tsx.snap create mode 100644 server/sonar-web/src/main/js/components/tutorials/gitlabci/EnvironmentVariablesStep.tsx create mode 100644 server/sonar-web/src/main/js/components/tutorials/gitlabci/GitLabCITutorial.tsx create mode 100644 server/sonar-web/src/main/js/components/tutorials/gitlabci/ProjectKeyStep.tsx create mode 100644 server/sonar-web/src/main/js/components/tutorials/gitlabci/YmlFileStep.tsx create mode 100644 server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/EnvironmentVariablesStep-test.tsx create mode 100644 server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/GitLabCITutorial-test.tsx create mode 100644 server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/ProjectKeyStep-test.tsx create mode 100644 server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/YmlFileStep-test.tsx create mode 100644 server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/__snapshots__/EnvironmentVariablesStep-test.tsx.snap create mode 100644 server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/__snapshots__/GitLabCITutorial-test.tsx.snap create mode 100644 server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/__snapshots__/ProjectKeyStep-test.tsx.snap create mode 100644 server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/__snapshots__/YmlFileStep-test.tsx.snap create mode 100644 server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/PipeCommandGradle.tsx create mode 100644 server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/PipeCommandMaven.tsx create mode 100644 server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/PipeCommandOther.tsx create mode 100644 server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/__tests__/PipeCommandGradle-test.tsx create mode 100644 server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/__tests__/PipeCommandMaven-test.tsx create mode 100644 server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/__tests__/PipeCommandOther-test.tsx create mode 100644 server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/__tests__/__snapshots__/PipeCommandGradle-test.tsx.snap create mode 100644 server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/__tests__/__snapshots__/PipeCommandMaven-test.tsx.snap create mode 100644 server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/__tests__/__snapshots__/PipeCommandOther-test.tsx.snap rename server/sonar-web/src/main/js/components/tutorials/{styles.css => gitlabci/types.ts} (86%) diff --git a/server/sonar-docs/src/tooltips/tutorials/use-existing-token.md b/server/sonar-docs/src/tooltips/tutorials/use-existing-token.md new file mode 100644 index 00000000000..5c7c31f5f43 --- /dev/null +++ b/server/sonar-docs/src/tooltips/tutorials/use-existing-token.md @@ -0,0 +1,5 @@ +Paste an existing token value into the input field. + +--- + +See also: [User Token](/user-guide/user-token/) diff --git a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationEmpty.tsx b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationEmpty.tsx index ec09e6c5e31..6e639e557bf 100644 --- a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationEmpty.tsx +++ b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationEmpty.tsx @@ -22,7 +22,6 @@ import { Button } from 'sonar-ui-common/components/controls/buttons'; import OnboardingAddMembersIcon from 'sonar-ui-common/components/icons/OnboardingAddMembersIcon'; import { translate } from 'sonar-ui-common/helpers/l10n'; import { Router, withRouter } from '../../../components/hoc/withRouter'; -import '../../../components/tutorials/styles.css'; import './OrganizationEmpty.css'; interface Props { 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 865d08766b9..a077d399d1a 100644 --- a/server/sonar-web/src/main/js/components/tutorials/TutorialSelection.tsx +++ b/server/sonar-web/src/main/js/components/tutorials/TutorialSelection.tsx @@ -22,7 +22,6 @@ import { WithRouterProps } from 'react-router'; import { getAlmDefinitionsNoCatch, getProjectAlmBinding } from '../../api/alm-settings'; import { AlmBindingDefinition, AlmKeys, ProjectAlmBindingResponse } from '../../types/alm-settings'; import { withRouter } from '../hoc/withRouter'; -import './styles.css'; import TutorialSelectionRenderer from './TutorialSelectionRenderer'; import { TutorialModes } from './types'; @@ -59,10 +58,10 @@ export class TutorialSelection extends React.PureComponent { ]); if (this.mounted) { - // We only support Bitbucket & GitHub for now. + // We only support Bitbucket, GitHub & Gitlab for now. if ( projectBinding === undefined || - (projectBinding.alm !== AlmKeys.Bitbucket && projectBinding.alm !== AlmKeys.GitHub) + ![AlmKeys.Bitbucket, AlmKeys.GitHub, AlmKeys.GitLab].includes(projectBinding.alm) ) { this.setState({ loading: false, forceManual: true }); } else { 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 ca68491326e..1fc339d8dcf 100644 --- a/server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx +++ b/server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx @@ -21,7 +21,8 @@ import * as React from 'react'; import { translate } from 'sonar-ui-common/helpers/l10n'; import { getBaseUrl } from 'sonar-ui-common/helpers/urls'; -import { AlmBindingDefinition, ProjectAlmBindingResponse } from '../../types/alm-settings'; +import { AlmBindingDefinition, AlmKeys, ProjectAlmBindingResponse } from '../../types/alm-settings'; +import GitLabCITutorial from './gitlabci/GitLabCITutorial'; import JenkinsTutorial from './jenkins/JenkinsTutorial'; import ManualTutorial from './manual/ManualTutorial'; import { TutorialModes } from './types'; @@ -43,6 +44,9 @@ export default function TutorialSelectionRenderer(props: TutorialSelectionRender return ; } + const jenkinsAvailable = + projectBinding && [AlmKeys.Bitbucket, AlmKeys.GitHub].includes(projectBinding.alm); + return ( <> {selectedTutorial === undefined && ( @@ -53,23 +57,41 @@ export default function TutorialSelectionRenderer(props: TutorialSelectionRender -
- +
+ {projectBinding?.alm === AlmKeys.GitLab && ( + + )} + + {jenkinsAvailable && ( + + )} +
+
+ +`; + +exports[`should render correctly: selection with jenkins available 1`] = ` + +
+
+

+ onboarding.tutorial.choose_method +

+
+
+ + )} +
+ )} + +
+ +
+ + )} + + ); + } +} diff --git a/server/sonar-web/src/main/js/components/tutorials/components/Step.css b/server/sonar-web/src/main/js/components/tutorials/components/Step.css index 5e150f8b666..a89e4fcded8 100644 --- a/server/sonar-web/src/main/js/components/tutorials/components/Step.css +++ b/server/sonar-web/src/main/js/components/tutorials/components/Step.css @@ -80,22 +80,21 @@ .onboarding-step ol.list-styled > li { position: relative; - counter-increment: step-counter; + counter-increment: li; margin-bottom: calc(2 * var(--gridSize)); - padding-left: calc(4 * var(--gridSize)); } .onboarding-step ol.list-styled > li::before { - content: counter(step-counter); - color: white; - background-color: var(--blue); - display: inline-flex; - border-radius: 50%; + display: inline-block; width: 16px; - position: absolute; - left: 0; - font-size: 10px; height: 16px; - justify-content: center; - align-items: center; + margin-right: 8px; + color: #fff; + font-size: 12px; + line-height: 16px; + direction: rtl; + text-align: center; + background-color: #4b9fd5; + border-radius: 50%; + content: counter(li); } diff --git a/server/sonar-web/src/main/js/components/tutorials/components/__tests__/EditTokenModal-test.tsx b/server/sonar-web/src/main/js/components/tutorials/components/__tests__/EditTokenModal-test.tsx new file mode 100644 index 00000000000..0146b988791 --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/components/__tests__/EditTokenModal-test.tsx @@ -0,0 +1,112 @@ +/* + * 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 { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; +import { generateToken, getTokens, revokeToken } from '../../../../api/user-tokens'; +import { mockComponent, mockEvent, mockLoggedInUser } from '../../../../helpers/testMocks'; +import { getUniqueTokenName } from '../../utils'; +import EditTokenModal from '../EditTokenModal'; + +jest.mock('../../../../api/user-tokens', () => ({ + generateToken: jest.fn().mockResolvedValue({ + name: 'baz', + createdAt: '2019-01-21T08:06:00+0100', + login: 'luke', + token: 'token_value' + }), + getTokens: jest.fn().mockResolvedValue([ + { + name: 'foo', + createdAt: '2019-01-15T15:06:33+0100', + lastConnectionDate: '2019-01-18T15:06:33+0100' + }, + { name: 'bar', createdAt: '2019-01-18T15:06:33+0100' } + ]), + revokeToken: jest.fn().mockResolvedValue(Promise.resolve()) +})); + +jest.mock('../../utils', () => ({ + getUniqueTokenName: jest.fn().mockReturnValue('lightsaber-9000') +})); + +beforeEach(() => { + jest.clearAllMocks(); +}); + +it('should render correctly', () => { + expect(shallowRender()).toMatchSnapshot(); +}); + +it('should get tokens and unique name', async () => { + const wrapper = shallowRender(); + const { getTokensAndName } = wrapper.instance(); + + getTokensAndName(); + await waitAndUpdate(wrapper); + + expect(getTokens).toHaveBeenCalled(); + expect(getUniqueTokenName).toHaveBeenCalled(); + expect(wrapper.state('tokenName')).toBe('lightsaber-9000'); +}); + +it('should get a new token', async () => { + const wrapper = shallowRender(); + const { getNewToken } = wrapper.instance(); + + getNewToken(); + await waitAndUpdate(wrapper); + + expect(generateToken).toHaveBeenCalled(); + expect(wrapper.state('token')).toBe('token_value'); +}); + +it('should handle token revocation', async () => { + const wrapper = shallowRender(); + const { getTokensAndName, handleTokenRevoke } = wrapper.instance(); + + getTokensAndName(); + await waitAndUpdate(wrapper); + handleTokenRevoke(); + await waitAndUpdate(wrapper); + + expect(revokeToken).toHaveBeenCalled(); + expect(wrapper.state('token')).toBe(''); + expect(wrapper.state('tokenName')).toBe(''); +}); + +it('should handle change on user input', () => { + const wrapper = shallowRender(); + const instance = wrapper.instance(); + + instance.handleChange(mockEvent({ target: { value: 'my-token' } })); + expect(wrapper.state('tokenName')).toBe('my-token'); +}); + +function shallowRender(props: Partial = {}) { + return shallow( + + ); +} diff --git a/server/sonar-web/src/main/js/components/tutorials/components/__tests__/__snapshots__/EditTokenModal-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/components/__tests__/__snapshots__/EditTokenModal-test.tsx.snap new file mode 100644 index 00000000000..6be1acf2544 --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/components/__tests__/__snapshots__/EditTokenModal-test.tsx.snap @@ -0,0 +1,11 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly 1`] = ` + + + +`; diff --git a/server/sonar-web/src/main/js/components/tutorials/gitlabci/EnvironmentVariablesStep.tsx b/server/sonar-web/src/main/js/components/tutorials/gitlabci/EnvironmentVariablesStep.tsx new file mode 100644 index 00000000000..884899dc23b --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/gitlabci/EnvironmentVariablesStep.tsx @@ -0,0 +1,178 @@ +/* + * 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 Step from '../components/Step'; + +export interface EnvironmentVariablesStepProps { + component: T.Component; + currentUser: T.LoggedInUser; + finished: boolean; + onDone: () => void; + onOpen: () => void; + open: boolean; +} + +const pipelineDescriptionLinkLabel = translate( + 'onboarding.tutorial.with.gitlab_ci.env_variables.description.link' +); + +export default function EnvironmentVariablesStep(props: EnvironmentVariablesStepProps) { + const { component, currentUser, finished, open } = props; + + const [isModalVisible, toggleModal] = React.useState(false); + + const toggleTokenModal = () => toggleModal(!isModalVisible); + const closeTokenModal = () => toggleModal(false); + + const fieldValueTranslation = translate( + 'onboarding.tutorial.with.gitlab_ci.env_variables.enter_field_value' + ); + + const renderForm = () => ( +
+

+ {translate('onboarding.tutorial.with.gitlab_ci.env_variables.section.title')} +

+ + {pipelineDescriptionLinkLabel} + }} + /> + +
    +
  1. + , + field: translate('onboarding.tutorial.with.gitlab_ci.env_variables.step1'), + value: SONAR_TOKEN + }} + /> +
  2. +
  3. + + {translate('onboarding.token.generate_token')} + + ), + field: translate('onboarding.tutorial.with.gitlab_ci.env_variables.step2'), + value: translate( + 'onboarding.tutorial.with.gitlab_ci.env_variables.section.step2.value' + ) + }} + /> +
  4. +
  5. + {translate('onboarding.tutorial.with.gitlab_ci.env_variables.step3')} +
  6. +
  7. + {translate('onboarding.tutorial.with.gitlab_ci.env_variables.section.step4')} +
  8. +
+ +
+ +

+ {translate('onboarding.tutorial.with.gitlab_ci.env_variables.section2.title')} +

+ + {pipelineDescriptionLinkLabel} + }} + /> + +
    +
  1. + , + field: translate('onboarding.tutorial.with.gitlab_ci.env_variables.step1'), + value: SONAR_HOST_URL + }} + /> +
  2. +
  3. + , + field: translate('onboarding.tutorial.with.gitlab_ci.env_variables.step2'), + value: {getHostUrl()} + }} + /> +
  4. +
  5. + {translate('onboarding.tutorial.with.gitlab_ci.env_variables.step3')} +
  6. +
  7. + {translate('onboarding.tutorial.with.gitlab_ci.env_variables.section2.step4')} +
  8. +
+ + +
+ ); + + return ( + <> + {isModalVisible && ( + + )} + + + + ); +} 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 new file mode 100644 index 00000000000..8d4dee3d6bc --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/gitlabci/GitLabCITutorial.tsx @@ -0,0 +1,83 @@ +/* + * 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 { 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 EnvironmentVariablesStep from './EnvironmentVariablesStep'; +import ProjectKeyStep from './ProjectKeyStep'; +import { BuildTools } from './types'; +import YmlFileStep from './YmlFileStep'; + +export enum Steps { + PROJECT_KEY, + ENV_VARIABLES, + YML +} + +export interface GitLabCITutorialProps { + component: T.Component; + currentUser: T.LoggedInUser; + projectBinding: ProjectAlmBindingResponse; +} + +export default function GitLabCITutorial(props: GitLabCITutorialProps) { + const { component, currentUser, projectBinding } = props; + + const [step, setStep] = React.useState(Steps.PROJECT_KEY); + const [buildTool, setBuildTool] = React.useState(); + + // Failsafe; should never happen. + if (!isProjectGitLabBindingResponse(projectBinding)) { + return ( + {translate('onboarding.tutorial.with.gitlab_ci.unsupported')} + ); + } + + return ( + <> +
+

{translate('onboarding.tutorial.with.gitlab_ci.title')}

+
+ + Steps.PROJECT_KEY} + onDone={() => setStep(Steps.ENV_VARIABLES)} + onOpen={() => setStep(Steps.PROJECT_KEY)} + open={step === Steps.PROJECT_KEY} + setBuildTool={setBuildTool} + /> + + Steps.ENV_VARIABLES} + onDone={() => setStep(Steps.YML)} + onOpen={() => setStep(Steps.ENV_VARIABLES)} + open={step === Steps.ENV_VARIABLES} + /> + + + + ); +} diff --git a/server/sonar-web/src/main/js/components/tutorials/gitlabci/ProjectKeyStep.tsx b/server/sonar-web/src/main/js/components/tutorials/gitlabci/ProjectKeyStep.tsx new file mode 100644 index 00000000000..6583a3dd280 --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/gitlabci/ProjectKeyStep.tsx @@ -0,0 +1,125 @@ +/* + * 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 CodeSnippet from '../../common/CodeSnippet'; +import RenderOptions from '../components/RenderOptions'; +import Step from '../components/Step'; +import { BuildTools } from './types'; + +export interface ProjectKeyStepProps { + buildTool?: BuildTools; + component: T.Component; + finished: boolean; + onDone: () => void; + onOpen: () => void; + open: boolean; + setBuildTool: (tool: BuildTools) => void; +} + +const mavenSnippet = (key: string) => ` + ${key} + true +`; + +const gradleSnippet = (key: string) => `plugins { + id "org.sonarqube" version "3.0" +} + +sonarqube { + properties { + property "sonar.projectKey", "${key}" + property "sonar.qualitygate.wait", true + } +}`; + +const otherSnippet = (key: string) => `sonar.projectKey=${key} +sonar.qualitygate.wait=true +`; + +const snippetForBuildTool = { + [BuildTools.Maven]: mavenSnippet, + [BuildTools.Gradle]: gradleSnippet, + [BuildTools.Other]: otherSnippet +}; + +const filenameForBuildTool = { + [BuildTools.Maven]: 'pom.xml', + [BuildTools.Gradle]: 'build.gradle', + [BuildTools.Other]: 'sonar-project.properties' +}; + +export default function ProjectKeyStep(props: ProjectKeyStepProps) { + const { buildTool, component, finished, open } = props; + + const renderForm = () => ( +
+
    +
  1. + {translate('onboarding.build')} + props.setBuildTool(value as BuildTools)} + optionLabelKey="onboarding.build" + options={Object.values(BuildTools)} + /> +
  2. + {buildTool !== undefined && ( +
  3. + + {filenameForBuildTool[buildTool]} + + + ) + }} + /> + +
  4. + )} +
+ {buildTool !== undefined && } +
+ ); + + return ( + + ); +} diff --git a/server/sonar-web/src/main/js/components/tutorials/gitlabci/YmlFileStep.tsx b/server/sonar-web/src/main/js/components/tutorials/gitlabci/YmlFileStep.tsx new file mode 100644 index 00000000000..7985b7d5b4b --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/gitlabci/YmlFileStep.tsx @@ -0,0 +1,136 @@ +/* + * 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 { translate } from 'sonar-ui-common/helpers/l10n'; +import Step from '../components/Step'; +import PipeCommandGradle from './commands/PipeCommandGradle'; +import PipeCommandMaven from './commands/PipeCommandMaven'; +import PipeCommandOther from './commands/PipeCommandOther'; +import { BuildTools } from './types'; + +export interface YmlFileStepProps { + buildTool?: BuildTools; + open: boolean; +} + +export default function YmlFileStep({ buildTool, open }: YmlFileStepProps) { + const renderForm = () => ( +
+
+
+ {buildTool && ( + <> +
+ + + {translate('onboarding.tutorial.with.gitlab_ci.yml.filename')} + + + + ) + }} + /> +
+ +
+ {buildTool === BuildTools.Maven && } + {buildTool === BuildTools.Gradle && } + {buildTool === BuildTools.Other && } +
+ +

+ {translate('onboarding.tutorial.with.gitlab_ci.yml.baseconfig')} +

+ +

+ {translate('onboarding.tutorial.with.gitlab_ci.yml.existing')} +

+ +
+
+

+ {translate('onboarding.tutorial.with.gitlab_ci.yml.done')} {' '} + +

+

+ + {translate('onboarding.tutorial.with.gitlab_ci.yml.done.then-what')} + {' '} + {translate('onboarding.tutorial.with.gitlab_ci.yml.done.then-what.description')} +

+ +

+ + {translate('onboarding.tutorial.with.gitlab_ci.yml.done.links.QG')} + + ) + }} + /> +

+
+ + )} +
+
+
+ ); + + return ( + + ); +} diff --git a/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/EnvironmentVariablesStep-test.tsx b/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/EnvironmentVariablesStep-test.tsx new file mode 100644 index 00000000000..9ca6c1561da --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/EnvironmentVariablesStep-test.tsx @@ -0,0 +1,46 @@ +/* + * 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, mockLoggedInUser } from '../../../../helpers/testMocks'; +import { renderStepContent } from '../../jenkins/test-utils'; +import EnvironmentVariablesStep, { + EnvironmentVariablesStepProps +} from '../EnvironmentVariablesStep'; + +it('should render correctly', () => { + const wrapper = shallowRender(); + expect(wrapper).toMatchSnapshot('Step wrapper'); + expect(renderStepContent(wrapper)).toMatchSnapshot('initial content'); +}); + +function shallowRender(props: Partial = {}) { + return shallow( + + ); +} diff --git a/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/GitLabCITutorial-test.tsx b/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/GitLabCITutorial-test.tsx new file mode 100644 index 00000000000..613224deabf --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/GitLabCITutorial-test.tsx @@ -0,0 +1,45 @@ +/* + * 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 { + mockProjectGithubBindingResponse, + mockProjectGitLabBindingResponse +} from '../../../../helpers/mocks/alm-settings'; +import { mockComponent, mockLoggedInUser } from '../../../../helpers/testMocks'; +import GitLabCITutorial, { GitLabCITutorialProps } from '../GitLabCITutorial'; + +it('should render correctly', () => { + expect(shallowRender()).toMatchSnapshot(); + expect(shallowRender({ projectBinding: mockProjectGithubBindingResponse() })).toMatchSnapshot( + 'wrong alm' + ); +}); + +function shallowRender(props: Partial = {}) { + return shallow( + + ); +} diff --git a/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/ProjectKeyStep-test.tsx b/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/ProjectKeyStep-test.tsx new file mode 100644 index 00000000000..ea419b7ff87 --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/ProjectKeyStep-test.tsx @@ -0,0 +1,69 @@ +/* + * 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, ShallowWrapper } from 'enzyme'; +import * as React from 'react'; +import { mockComponent } from '../../../../helpers/testMocks'; +import RenderOptions from '../../components/RenderOptions'; +import { renderStepContent } from '../../jenkins/test-utils'; +import ProjectKeyStep, { ProjectKeyStepProps } from '../ProjectKeyStep'; +import { BuildTools } from '../types'; + +it('should render correctly', () => { + const wrapper = shallowRender(); + expect(wrapper).toMatchSnapshot('Step wrapper'); + expect(renderStepContent(wrapper)).toMatchSnapshot('initial content'); +}); + +it.each([[BuildTools.Maven], [BuildTools.Gradle], [BuildTools.Other]])( + 'should render correctly for build tool %s', + buildTool => { + expect(renderStepContent(shallowRender({ buildTool }))).toMatchSnapshot(); + } +); + +it('should correctly callback with selected build tool', () => { + const setBuildTool = jest.fn(); + const wrapper = shallowRender({ setBuildTool }); + selectBuildTool(wrapper, BuildTools.Maven); + + expect(setBuildTool).toBeCalledWith(BuildTools.Maven); +}); + +function selectBuildTool(wrapper: ShallowWrapper, tool: BuildTools) { + const content = new ShallowWrapper(renderStepContent(wrapper) as JSX.Element); + content + .find(RenderOptions) + .props() + .onCheck(tool); +} + +function shallowRender(props: Partial = {}) { + return shallow( + + ); +} diff --git a/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/YmlFileStep-test.tsx b/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/YmlFileStep-test.tsx new file mode 100644 index 00000000000..2e7e0993d63 --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/YmlFileStep-test.tsx @@ -0,0 +1,41 @@ +/* + * 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 { renderStepContent } from '../../jenkins/test-utils'; +import { BuildTools } from '../types'; +import YmlFileStep, { YmlFileStepProps } from '../YmlFileStep'; + +it('should render correctly', () => { + const wrapper = shallowRender(); + expect(wrapper).toMatchSnapshot('Step wrapper'); + expect(renderStepContent(wrapper)).toMatchSnapshot('initial content'); +}); + +it.each([[BuildTools.Maven], [BuildTools.Gradle], [BuildTools.Other]])( + 'should render correctly for build tool %s', + buildTool => { + expect(renderStepContent(shallowRender({ buildTool }))).toMatchSnapshot(); + } +); + +function shallowRender(props: Partial = {}) { + return shallow(); +} diff --git a/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/__snapshots__/EnvironmentVariablesStep-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/__snapshots__/EnvironmentVariablesStep-test.tsx.snap new file mode 100644 index 00000000000..d37c4021463 --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/__snapshots__/EnvironmentVariablesStep-test.tsx.snap @@ -0,0 +1,173 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly: Step wrapper 1`] = ` + + + +`; + +exports[`should render correctly: initial content 1`] = ` +
+

+ onboarding.tutorial.with.gitlab_ci.env_variables.section.title +

+ + onboarding.tutorial.with.gitlab_ci.env_variables.description.link + , + } + } + /> +
    +
  1. + , + "field": "onboarding.tutorial.with.gitlab_ci.env_variables.step1", + "value": + SONAR_TOKEN + , + } + } + /> +
  2. +
  3. + + onboarding.token.generate_token + , + "field": "onboarding.tutorial.with.gitlab_ci.env_variables.step2", + "value": "onboarding.tutorial.with.gitlab_ci.env_variables.section.step2.value", + } + } + /> +
  4. +
  5. + onboarding.tutorial.with.gitlab_ci.env_variables.step3 +
  6. +
  7. + onboarding.tutorial.with.gitlab_ci.env_variables.section.step4 +
  8. +
+
+

+ onboarding.tutorial.with.gitlab_ci.env_variables.section2.title +

+ + onboarding.tutorial.with.gitlab_ci.env_variables.description.link + , + } + } + /> +
    +
  1. + , + "field": "onboarding.tutorial.with.gitlab_ci.env_variables.step1", + "value": + SONAR_HOST_URL + , + } + } + /> +
  2. +
  3. + , + "field": "onboarding.tutorial.with.gitlab_ci.env_variables.step2", + "value": + http://localhost + , + } + } + /> +
  4. +
  5. + onboarding.tutorial.with.gitlab_ci.env_variables.step3 +
  6. +
  7. + onboarding.tutorial.with.gitlab_ci.env_variables.section2.step4 +
  8. +
+ +
+`; diff --git a/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/__snapshots__/GitLabCITutorial-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/__snapshots__/GitLabCITutorial-test.tsx.snap new file mode 100644 index 00000000000..99436397634 --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/__snapshots__/GitLabCITutorial-test.tsx.snap @@ -0,0 +1,94 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly 1`] = ` + +
+

+ onboarding.tutorial.with.gitlab_ci.title +

+
+ + + +
+`; + +exports[`should render correctly: wrong alm 1`] = ` + + onboarding.tutorial.with.gitlab_ci.unsupported + +`; diff --git a/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/__snapshots__/ProjectKeyStep-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/__snapshots__/ProjectKeyStep-test.tsx.snap new file mode 100644 index 00000000000..b1e3b8e57c2 --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/__snapshots__/ProjectKeyStep-test.tsx.snap @@ -0,0 +1,226 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly for build tool gradle 1`] = ` +
+
    +
  1. + onboarding.build + +
  2. +
  3. + + + build.gradle + + + , + } + } + /> + +
  4. +
+ +
+`; + +exports[`should render correctly for build tool maven 1`] = ` +
+
    +
  1. + onboarding.build + +
  2. +
  3. + + + pom.xml + + + , + } + } + /> + +
  4. +
+ +
+`; + +exports[`should render correctly for build tool other 1`] = ` +
+
    +
  1. + onboarding.build + +
  2. +
  3. + + + sonar-project.properties + + + , + } + } + /> + +
  4. +
+ +
+`; + +exports[`should render correctly: Step wrapper 1`] = ` + +`; + +exports[`should render correctly: initial content 1`] = ` +
+
    +
  1. + onboarding.build + +
  2. +
+
+`; diff --git a/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/__snapshots__/YmlFileStep-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/__snapshots__/YmlFileStep-test.tsx.snap new file mode 100644 index 00000000000..95bf2abb6e3 --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/__snapshots__/YmlFileStep-test.tsx.snap @@ -0,0 +1,349 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly for build tool gradle 1`] = ` +
+
+
+ +
+ + + onboarding.tutorial.with.gitlab_ci.yml.filename + + + , + } + } + /> +
+
+ +
+

+ onboarding.tutorial.with.gitlab_ci.yml.baseconfig +

+

+ onboarding.tutorial.with.gitlab_ci.yml.existing +

+
+
+

+ + onboarding.tutorial.with.gitlab_ci.yml.done + + + + +

+

+ + onboarding.tutorial.with.gitlab_ci.yml.done.then-what + + + onboarding.tutorial.with.gitlab_ci.yml.done.then-what.description +

+

+ + onboarding.tutorial.with.gitlab_ci.yml.done.links.QG + , + } + } + /> +

+
+
+
+
+
+`; + +exports[`should render correctly for build tool maven 1`] = ` +
+
+
+ +
+ + + onboarding.tutorial.with.gitlab_ci.yml.filename + + + , + } + } + /> +
+
+ +
+

+ onboarding.tutorial.with.gitlab_ci.yml.baseconfig +

+

+ onboarding.tutorial.with.gitlab_ci.yml.existing +

+
+
+

+ + onboarding.tutorial.with.gitlab_ci.yml.done + + + + +

+

+ + onboarding.tutorial.with.gitlab_ci.yml.done.then-what + + + onboarding.tutorial.with.gitlab_ci.yml.done.then-what.description +

+

+ + onboarding.tutorial.with.gitlab_ci.yml.done.links.QG + , + } + } + /> +

+
+
+
+
+
+`; + +exports[`should render correctly for build tool other 1`] = ` +
+
+
+ +
+ + + onboarding.tutorial.with.gitlab_ci.yml.filename + + + , + } + } + /> +
+
+ +
+

+ onboarding.tutorial.with.gitlab_ci.yml.baseconfig +

+

+ onboarding.tutorial.with.gitlab_ci.yml.existing +

+
+
+

+ + onboarding.tutorial.with.gitlab_ci.yml.done + + + + +

+

+ + onboarding.tutorial.with.gitlab_ci.yml.done.then-what + + + onboarding.tutorial.with.gitlab_ci.yml.done.then-what.description +

+

+ + onboarding.tutorial.with.gitlab_ci.yml.done.links.QG + , + } + } + /> +

+
+
+
+
+
+`; + +exports[`should render correctly: Step wrapper 1`] = ` + +`; + +exports[`should render correctly: initial content 1`] = ` +
+
+
+
+
+`; diff --git a/server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/PipeCommandGradle.tsx b/server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/PipeCommandGradle.tsx new file mode 100644 index 00000000000..089a6f3fccb --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/PipeCommandGradle.tsx @@ -0,0 +1,42 @@ +/* + * 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 CodeSnippet from '../../../common/CodeSnippet'; + +export default function PipeCommandGradle() { + const command = `sonarqube-check: + image: gradle:jre11-slim + variables: + SONAR_USER_HOME: "\${CI_PROJECT_DIR}/.sonar" # Defines the location of the analysis task cache + GIT_DEPTH: "0" # Tells git to fetch all the branches of the project, required by the analysis task + cache: + key: "\${CI_JOB_NAME}" + paths: + - .sonar/cache + script: gradle sonarqube + allow_failure: true + only: + - merge_requests + - master + - develop +`; + + return ; +} diff --git a/server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/PipeCommandMaven.tsx b/server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/PipeCommandMaven.tsx new file mode 100644 index 00000000000..9a665befe80 --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/PipeCommandMaven.tsx @@ -0,0 +1,43 @@ +/* + * 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 CodeSnippet from '../../../common/CodeSnippet'; + +export default function PipeCommandMaven() { + const command = `sonarqube-check: + image: maven:3.6.3-jdk-11 + variables: + SONAR_USER_HOME: "\${CI_PROJECT_DIR}/.sonar" # Defines the location of the analysis task cache + GIT_DEPTH: "0" # Tells git to fetch all the branches of the project, required by the analysis task + cache: + key: "\${CI_JOB_NAME}" + paths: + - .sonar/cache + script: + - mvn verify sonar:sonar + allow_failure: true + only: + - merge_requests + - master + - develop +`; + + return ; +} diff --git a/server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/PipeCommandOther.tsx b/server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/PipeCommandOther.tsx new file mode 100644 index 00000000000..a83cbcdc308 --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/PipeCommandOther.tsx @@ -0,0 +1,45 @@ +/* + * 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 CodeSnippet from '../../../common/CodeSnippet'; + +export default function PipeCommandOther() { + const command = `sonarqube-check: + image: + name: sonarsource/sonar-scanner-cli:latest + entrypoint: [""] + variables: + SONAR_USER_HOME: "\${CI_PROJECT_DIR}/.sonar" # Defines the location of the analysis task cache + GIT_DEPTH: "0" # Tells git to fetch all the branches of the project, required by the analysis task + cache: + key: "\${CI_JOB_NAME}" + paths: + - .sonar/cache + script: + - sonar-scanner + allow_failure: true + only: + - merge_requests + - master + - develop +`; + + return ; +} diff --git a/server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/__tests__/PipeCommandGradle-test.tsx b/server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/__tests__/PipeCommandGradle-test.tsx new file mode 100644 index 00000000000..6ad96b4d25a --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/__tests__/PipeCommandGradle-test.tsx @@ -0,0 +1,26 @@ +/* + * 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 PipeCommandGradle from '../PipeCommandGradle'; + +it('should render correctly', () => { + expect(shallow()).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/__tests__/PipeCommandMaven-test.tsx b/server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/__tests__/PipeCommandMaven-test.tsx new file mode 100644 index 00000000000..0b6056d02c1 --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/__tests__/PipeCommandMaven-test.tsx @@ -0,0 +1,26 @@ +/* + * 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 PipeCommandMaven from '../PipeCommandMaven'; + +it('should render correctly', () => { + expect(shallow()).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/__tests__/PipeCommandOther-test.tsx b/server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/__tests__/PipeCommandOther-test.tsx new file mode 100644 index 00000000000..5b12da83ac4 --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/__tests__/PipeCommandOther-test.tsx @@ -0,0 +1,26 @@ +/* + * 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 PipeCommandOther from '../PipeCommandOther'; + +it('should render correctly', () => { + expect(shallow()).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/__tests__/__snapshots__/PipeCommandGradle-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/__tests__/__snapshots__/PipeCommandGradle-test.tsx.snap new file mode 100644 index 00000000000..61f4c68d1f1 --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/__tests__/__snapshots__/PipeCommandGradle-test.tsx.snap @@ -0,0 +1,22 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly 1`] = ` + +`; diff --git a/server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/__tests__/__snapshots__/PipeCommandMaven-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/__tests__/__snapshots__/PipeCommandMaven-test.tsx.snap new file mode 100644 index 00000000000..0b843680c84 --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/__tests__/__snapshots__/PipeCommandMaven-test.tsx.snap @@ -0,0 +1,23 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly 1`] = ` + +`; diff --git a/server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/__tests__/__snapshots__/PipeCommandOther-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/__tests__/__snapshots__/PipeCommandOther-test.tsx.snap new file mode 100644 index 00000000000..74e84b88d82 --- /dev/null +++ b/server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/__tests__/__snapshots__/PipeCommandOther-test.tsx.snap @@ -0,0 +1,25 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly 1`] = ` + +`; diff --git a/server/sonar-web/src/main/js/components/tutorials/styles.css b/server/sonar-web/src/main/js/components/tutorials/gitlabci/types.ts similarity index 86% rename from server/sonar-web/src/main/js/components/tutorials/styles.css rename to server/sonar-web/src/main/js/components/tutorials/gitlabci/types.ts index 295fb42fd23..d95d7fcc91e 100644 --- a/server/sonar-web/src/main/js/components/tutorials/styles.css +++ b/server/sonar-web/src/main/js/components/tutorials/gitlabci/types.ts @@ -17,7 +17,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -.tutorial-selection { - margin: 0 auto; - max-width: 500px; +export enum BuildTools { + Maven = 'maven', + Gradle = 'gradle', + // MSBuild = 'msbuild', // Not yet supported + Other = 'other' } 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 2ad939070bc..659d13aac12 100644 --- a/server/sonar-web/src/main/js/components/tutorials/types.ts +++ b/server/sonar-web/src/main/js/components/tutorials/types.ts @@ -19,7 +19,8 @@ */ export enum TutorialModes { Manual = 'manual', - Jenkins = 'jenkins' + Jenkins = 'jenkins', + GitLabCI = 'gitlab-ci' } export interface LanguageConfig { diff --git a/server/sonar-web/src/main/js/helpers/alm-settings.ts b/server/sonar-web/src/main/js/helpers/alm-settings.ts index 974968435f3..bd0013775fc 100644 --- a/server/sonar-web/src/main/js/helpers/alm-settings.ts +++ b/server/sonar-web/src/main/js/helpers/alm-settings.ts @@ -24,7 +24,8 @@ import { GithubBindingDefinition, ProjectAlmBindingResponse, ProjectBitbucketBindingResponse, - ProjectGitHubBindingResponse + ProjectGitHubBindingResponse, + ProjectGitLabBindingResponse } from '../types/alm-settings'; export function isProjectBitbucketBindingResponse( @@ -39,6 +40,12 @@ export function isProjectGitHubBindingResponse( 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 { 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 c89b8f0baa2..c5bcc318785 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 @@ -26,7 +26,8 @@ import { GitlabBindingDefinition, ProjectAlmBindingResponse, ProjectBitbucketBindingResponse, - ProjectGitHubBindingResponse + ProjectGitHubBindingResponse, + ProjectGitLabBindingResponse } from '../../types/alm-settings'; export function mockAlmSettingsInstance( @@ -116,3 +117,15 @@ export function mockProjectGithubBindingResponse( ...overrides }; } + +export function mockProjectGitLabBindingResponse( + overrides: Partial = {} +): ProjectGitLabBindingResponse { + return { + alm: AlmKeys.GitLab, + key: 'foo', + repository: 'PROJECT_KEY', + url: 'https://gitlab.com/api/v4', + ...overrides + }; +} 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 18ce632b785..887d227f881 100644 --- a/server/sonar-web/src/main/js/types/alm-settings.ts +++ b/server/sonar-web/src/main/js/types/alm-settings.ts @@ -69,6 +69,12 @@ export interface ProjectGitHubBindingResponse extends ProjectAlmBindingResponse repository: string; } +export interface ProjectGitLabBindingResponse extends ProjectAlmBindingResponse { + alm: AlmKeys.GitLab; + repository: string; + url: string; +} + export interface ProjectAlmBindingParams { almSetting: string; project: string; 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 70115c53fc0..71c985dbd21 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -3239,6 +3239,7 @@ onboarding.token.generate_token=Generate a token onboarding.token.generate_token.placeholder=Enter a name for your token onboarding.token.use_existing_token=Use existing token onboarding.token.use_existing_token.placeholder=Enter your existing token +onboarding.token.use_existing_token.label=Existing token value onboarding.token.invalid_format=The token you have entered has invalid format. onboarding.analysis.header=Run analysis on your project @@ -3322,6 +3323,41 @@ onboarding.tutorial.return_to_list=Choose another option 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.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. +onboarding.tutorial.with.gitlab_ci.project_key.title=Set your project key +onboarding.tutorial.with.gitlab_ci.project_key.maven.step2=Add the following to your {file} file: +onboarding.tutorial.with.gitlab_ci.project_key.gradle.step2=Add the following to your {file} file: +onboarding.tutorial.with.gitlab_ci.project_key.other.step2=Create a {file} file in your repository and paste the following code: + +onboarding.tutorial.with.gitlab_ci.env_variables.title=Add environment variables +onboarding.tutorial.with.gitlab_ci.env_variables.enter_field_value=In the {field} field, enter {value} {extra} +onboarding.tutorial.with.gitlab_ci.env_variables.description.link=Settings > CI/CD > Variables +onboarding.tutorial.with.gitlab_ci.env_variables.section.title=a. Define the SonarQube Token environment variable +onboarding.tutorial.with.gitlab_ci.env_variables.section.description=In GitLab, go to {link} to add the following variable and make sure it is available for your project: +onboarding.tutorial.with.gitlab_ci.env_variables.edit.token.tooltip=Use an existing token or generate a new one. +onboarding.tutorial.with.gitlab_ci.env_variables.step1=Key +onboarding.tutorial.with.gitlab_ci.env_variables.step2=Value +onboarding.tutorial.with.gitlab_ci.env_variables.section.step2.value=an existing token, or a newly generated one: +onboarding.tutorial.with.gitlab_ci.env_variables.step3=Uncheck the "Protect Variable" checkbox +onboarding.tutorial.with.gitlab_ci.env_variables.section.step4=Check the "Mask Variable" checkbox +onboarding.tutorial.with.gitlab_ci.env_variables.section2.title=b. Define the SonarQube URL environment variable +onboarding.tutorial.with.gitlab_ci.env_variables.section2.description=Still in {link} add a new variable and make sure it is available for your project: +onboarding.tutorial.with.gitlab_ci.env_variables.section2.step4=Leave the "Mask variable" checkbox unchecked +onboarding.tutorial.with.gitlab_ci.yml.title=Create or update the configuration file +onboarding.tutorial.with.gitlab_ci.yml.description=Create or update your {filename} file with the following content. +onboarding.tutorial.with.gitlab_ci.yml.filename=.gitlab-ci.yml +onboarding.tutorial.with.gitlab_ci.yml.baseconfig=Note that this is a minimal base configuration to run a SonarQube analysis on your master branch and merge requests. +onboarding.tutorial.with.gitlab_ci.yml.existing=If you already have a pipeline configured and running, you might want to add the example from this step to your existing yml file. +onboarding.tutorial.with.gitlab_ci.yml.done=Is it done? +onboarding.tutorial.with.gitlab_ci.yml.done.description=You should see the page refresh itself in a few moments with your analysis results if the {link}. +onboarding.tutorial.with.gitlab_ci.yml.done.description.link=pipeline runs successfully +onboarding.tutorial.with.gitlab_ci.yml.done.then-what=And then what? +onboarding.tutorial.with.gitlab_ci.yml.done.then-what.description=Each new push triggers an analysis by SonarQube. +onboarding.tutorial.with.gitlab_ci.yml.done.links.title=Check this useful link while you wait: {links} +onboarding.tutorial.with.gitlab_ci.yml.done.links.QG=What is a Quality Gate? onboarding.tutorial.with.jenkins.title=Analyze your project with Jenkins onboarding.tutorial.with.jenkins.unsupported=This tutorial is only available for projects bound to Bitbucket Server or GitHub. -- 2.39.5