]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-17146 Tutorial for Gradle should Consider Kotlin DSL
authorstanislavh <stanislav.honcharov@sonarsource.com>
Wed, 3 May 2023 08:57:05 +0000 (10:57 +0200)
committersonartech <sonartech@sonarsource.com>
Thu, 4 May 2023 20:03:11 +0000 (20:03 +0000)
19 files changed:
server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/PreambuleYaml.tsx
server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/__tests__/BitbucketPipelinesTutorial-it.tsx
server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/__tests__/__snapshots__/BitbucketPipelinesTutorial-it.tsx.snap
server/sonar-web/src/main/js/components/tutorials/components/GradleBuild.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/components/tutorials/components/GradleBuildSelection.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/GithubActionTutorial-it.tsx
server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/__snapshots__/GithubActionTutorial-it.tsx.snap
server/sonar-web/src/main/js/components/tutorials/github-action/commands/Gradle.tsx
server/sonar-web/src/main/js/components/tutorials/gitlabci/YmlFileStep.tsx
server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/GitLabCITutorial-it.tsx
server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/__snapshots__/GitLabCITutorial-it.tsx.snap
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/JenkinsTutorial-it.tsx
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/JenkinsTutorial-it.tsx.snap
server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/Gradle.tsx
server/sonar-web/src/main/js/components/tutorials/other/commands/JavaGradle.tsx
server/sonar-web/src/main/js/components/tutorials/test-utils.ts
server/sonar-web/src/main/js/components/tutorials/types.ts
server/sonar-web/src/main/js/components/tutorials/utils.ts
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index d54087fa9f14025e0d128da02e4d316e6dba8e65..87fec76d2afe81a63b16a8605a51cce8b11ae417 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import { ClipboardIconButton } from '../../../components/controls/clipboard';
-import { translate } from '../../../helpers/l10n';
 import { Component } from '../../../types/types';
-import CodeSnippet from '../../common/CodeSnippet';
 import DefaultProjectKey from '../components/DefaultProjectKey';
+import GradleBuild from '../components/GradleBuild';
 import { BuildTools } from '../types';
-import { buildGradleSnippet } from '../utils';
 
 export interface PreambuleYamlProps {
   buildTool: BuildTools;
@@ -36,24 +32,7 @@ export function PreambuleYaml(props: PreambuleYamlProps) {
   const { buildTool, component } = props;
   switch (buildTool) {
     case BuildTools.Gradle:
-      return (
-        <li className="abs-width-600">
-          <FormattedMessage
-            defaultMessage={translate('onboarding.tutorial.with.yaml.gradle')}
-            id="onboarding.tutorial.with.yaml.gradle"
-            values={{
-              gradle: (
-                <>
-                  <code className="rule">build.gradle</code>
-                  <ClipboardIconButton copyValue="build.gradle" />
-                </>
-              ),
-              sq: <code className="rule">org.sonarqube</code>,
-            }}
-          />
-          <CodeSnippet snippet={buildGradleSnippet(component.key, component.name)} />
-        </li>
-      );
+      return <GradleBuild component={component} />;
     case BuildTools.CFamily:
     case BuildTools.Other:
       return <DefaultProjectKey component={component} />;
index 7d85f9e2ca5e97c2936cf8e695e53bedb637b47c..0a1285123a27bc8c90e67758ca54c9afaf5ea164 100644 (file)
@@ -37,7 +37,7 @@ import {
   getTutorialActionButtons,
   getTutorialBuildButtons,
 } from '../../test-utils';
-import { TutorialModes } from '../../types';
+import { GradleBuildDSL, TutorialModes } from '../../types';
 import BitbucketPipelinesTutorial, {
   BitbucketPipelinesTutorialProps,
 } from '../BitbucketPipelinesTutorial';
@@ -79,8 +79,10 @@ it('should follow and complete all steps', async () => {
 
   // Gradle
   await user.click(ui.gradleBuildButton.get());
-  expect(getCopyToClipboardValue(1)).toMatchSnapshot('Gradle: build.gradle');
-  expect(getCopyToClipboardValue(3)).toMatchSnapshot('Gradle: bitbucket-pipelines.yml');
+  expect(getCopyToClipboardValue(2)).toMatchSnapshot('Groovy: build.gradle');
+  await user.click(ui.gradleDSLButton(GradleBuildDSL.Kotlin).get());
+  expect(getCopyToClipboardValue(2)).toMatchSnapshot('Kotlin: build.gradle.kts');
+  expect(getCopyToClipboardValue(4)).toMatchSnapshot('Gradle: bitbucket-pipelines.yml');
 
   // .NET
   await user.click(ui.dotnetBuildButton.get());
index 4491112afda53983250518258af710ead84d8a35..918f9f18ec98e9974372e8c1fb0e4f08473fe6f1 100644 (file)
@@ -95,7 +95,7 @@ pipelines:
       - step: *build-step"
 `;
 
-exports[`should follow and complete all steps: Gradle: build.gradle 1`] = `
+exports[`should follow and complete all steps: Groovy: build.gradle 1`] = `
 "plugins {
   id "org.sonarqube" version "4.0.0.2929"
 }
@@ -108,6 +108,19 @@ sonar {
 }"
 `;
 
+exports[`should follow and complete all steps: Kotlin: build.gradle.kts 1`] = `
+"plugins {
+  id("org.sonarqube") version "4.0.0.2929"
+}
+    
+sonar {
+  properties {
+    property("sonar.projectKey", "my-project")
+    property("sonar.projectName", "MyProject")
+  }
+}"
+`;
+
 exports[`should follow and complete all steps: Maven: bitbucket-pipelines.yml 1`] = `
 "image: maven:3-openjdk-11
 
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/GradleBuild.tsx b/server/sonar-web/src/main/js/components/tutorials/components/GradleBuild.tsx
new file mode 100644 (file)
index 0000000..895aadb
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import { FormattedMessage } from 'react-intl';
+import { translate } from '../../../helpers/l10n';
+import { Component } from '../../../types/types';
+import CodeSnippet from '../../common/CodeSnippet';
+import { ClipboardIconButton } from '../../controls/clipboard';
+import { GradleBuildDSL } from '../types';
+import { buildGradleSnippet } from '../utils';
+import GradleBuildSelection from './GradleBuildSelection';
+
+interface Props {
+  component: Component;
+}
+
+export default function GradleBuild({ component }: Props) {
+  return (
+    <li className="abs-width-600">
+      <FormattedMessage
+        defaultMessage={translate('onboarding.tutorial.with.yaml.gradle')}
+        id="onboarding.tutorial.with.yaml.gradle"
+        values={{
+          groovy: (
+            <>
+              <code className="rule">{GradleBuildDSL.Groovy}</code>
+              <ClipboardIconButton copyValue={GradleBuildDSL.Groovy} />
+            </>
+          ),
+          kotlin: (
+            <>
+              <code className="rule">{GradleBuildDSL.Kotlin}</code>
+              <ClipboardIconButton copyValue={GradleBuildDSL.Kotlin} />
+            </>
+          ),
+          sq: <code className="rule">org.sonarqube</code>,
+        }}
+      />
+      <GradleBuildSelection className="big-spacer-top big-spacer-bottom">
+        {(build) => (
+          <CodeSnippet snippet={buildGradleSnippet(component.key, component.name, build)} />
+        )}
+      </GradleBuildSelection>
+    </li>
+  );
+}
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/GradleBuildSelection.tsx b/server/sonar-web/src/main/js/components/tutorials/components/GradleBuildSelection.tsx
new file mode 100644 (file)
index 0000000..4ed7e76
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import ButtonToggle from '../../controls/ButtonToggle';
+import { GradleBuildDSL } from '../types';
+
+interface Props {
+  className?: string;
+  children: (build: GradleBuildDSL) => React.ReactNode;
+}
+
+export default function GradleBuildSelection({ children, className }: Props) {
+  const [build, setBuild] = React.useState<GradleBuildDSL>(GradleBuildDSL.Groovy);
+
+  const buildOptions = Object.values(GradleBuildDSL).map((v: GradleBuildDSL) => ({
+    label: v,
+    value: v,
+  }));
+
+  return (
+    <>
+      <div className={className}>
+        <ButtonToggle
+          options={buildOptions}
+          value={build}
+          onCheck={(value: GradleBuildDSL) => setBuild(value)}
+        />
+      </div>
+      {children(build)}
+    </>
+  );
+}
index 22bd34521090ff8ac8cc1dbab60866a534d0ae6a..06ab3f48ec55b6c075b9a962913dcbef15a0bf8a 100644 (file)
@@ -37,7 +37,7 @@ import {
   getTutorialActionButtons,
   getTutorialBuildButtons,
 } from '../../test-utils';
-import { TutorialModes } from '../../types';
+import { GradleBuildDSL, TutorialModes } from '../../types';
 import GitHubActionTutorial, { GitHubActionTutorialProps } from '../GitHubActionTutorial';
 
 jest.mock('../../../../api/user-tokens');
@@ -77,8 +77,10 @@ it('should follow and complete all steps', async () => {
 
   // Gradle
   await user.click(ui.gradleBuildButton.get());
-  expect(getCopyToClipboardValue(1)).toMatchSnapshot('Gradle: build.gradle');
-  expect(getCopyToClipboardValue(3)).toMatchSnapshot('Gradle: .github/workflows/build.yml');
+  expect(getCopyToClipboardValue(2)).toMatchSnapshot('Groovy: build.gradle');
+  await user.click(ui.gradleDSLButton(GradleBuildDSL.Kotlin).get());
+  expect(getCopyToClipboardValue(2)).toMatchSnapshot('Kotlin: build.gradle.kts');
+  expect(getCopyToClipboardValue(4)).toMatchSnapshot('Gradle: .github/workflows/build.yml');
 
   // .NET
   await user.click(ui.dotnetBuildButton.get());
index 178e17d227342d2ee930f5ede29e6fab074a7380..8d9f38230177e538963b86f766d1aeb7f9286ddd 100644 (file)
@@ -229,7 +229,7 @@ jobs:
         run: ./gradlew build sonar --info"
 `;
 
-exports[`should follow and complete all steps: Gradle: build.gradle 1`] = `
+exports[`should follow and complete all steps: Groovy: build.gradle 1`] = `
 "plugins {
   id "org.sonarqube" version "4.0.0.2929"
 }
@@ -242,6 +242,19 @@ sonar {
 }"
 `;
 
+exports[`should follow and complete all steps: Kotlin: build.gradle.kts 1`] = `
+"plugins {
+  id("org.sonarqube") version "4.0.0.2929"
+}
+    
+sonar {
+  properties {
+    property("sonar.projectKey", "my-project")
+    property("sonar.projectName", "MyProject")
+  }
+}"
+`;
+
 exports[`should follow and complete all steps: Maven: .github/workflows/build.yml 1`] = `
 "name: Build
 
index 7d1a8247e219bf125c1233222e9b670b946e2c9e..c0e84c06cd8d87b99d10a90b85b579a947903ed3 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import { ClipboardIconButton } from '../../../../components/controls/clipboard';
-import { translate } from '../../../../helpers/l10n';
 import { Component } from '../../../../types/types';
-import CodeSnippet from '../../../common/CodeSnippet';
 import CreateYmlFile from '../../components/CreateYmlFile';
 import FinishButton from '../../components/FinishButton';
-import { buildGradleSnippet } from '../../utils';
+import GradleBuild from '../../components/GradleBuild';
 import { GITHUB_ACTIONS_RUNS_ON_LINUX } from '../constants';
 import { generateGitHubActionsYaml } from '../utils';
 
@@ -65,22 +61,7 @@ export default function Gradle(props: GradleProps) {
 
   return (
     <>
-      <li className="abs-width-600">
-        <FormattedMessage
-          defaultMessage={translate('onboarding.tutorial.with.yaml.gradle')}
-          id="onboarding.tutorial.with.yaml.gradle"
-          values={{
-            gradle: (
-              <>
-                <code className="rule">build.gradle</code>
-                <ClipboardIconButton copyValue="build.gradle" />
-              </>
-            ),
-            sq: <code className="rule">org.sonarqube</code>,
-          }}
-        />
-        <CodeSnippet snippet={buildGradleSnippet(component.key, component.name)} />
-      </li>
+      <GradleBuild component={component} />
       <CreateYmlFile
         yamlFileName=".github/workflows/build.yml"
         yamlTemplate={generateGitHubActionsYaml(
index ea255c15c0fcdb8dde12ea3ca626b855bf56c475..1b727795d95db4898f8b4ecc83651940ddeedaf2 100644 (file)
@@ -31,9 +31,10 @@ import CodeSnippet from '../../common/CodeSnippet';
 import { withCLanguageFeature } from '../../hoc/withCLanguageFeature';
 import FinishButton from '../components/FinishButton';
 import GithubCFamilyExampleRepositories from '../components/GithubCFamilyExampleRepositories';
+import GradleBuildSelection from '../components/GradleBuildSelection';
 import RenderOptions from '../components/RenderOptions';
 import Step from '../components/Step';
-import { BuildTools, TutorialModes } from '../types';
+import { BuildTools, GradleBuildDSL, TutorialModes } from '../types';
 import PipeCommand from './commands/PipeCommand';
 
 export interface YmlFileStepProps extends WithAvailableFeaturesProps {
@@ -50,7 +51,9 @@ const mavenSnippet = () => `<properties>
   <sonar.qualitygate.wait>true</sonar.qualitygate.wait>
 </properties>`;
 
-const gradleSnippet = (key: string, name: string) => `plugins {
+const gradleSnippet = (key: string, name: string, build: GradleBuildDSL) => {
+  const map = {
+    [GradleBuildDSL.Groovy]: `plugins {
   id "org.sonarqube" version "${GRADLE_SCANNER_VERSION}"
 }
 
@@ -60,7 +63,21 @@ sonar {
     property "sonar.projectName", "${name}"
     property "sonar.qualitygate.wait", true 
   }
-}`;
+}`,
+    [GradleBuildDSL.Kotlin]: `plugins {
+  id ("org.sonarqube") version "${GRADLE_SCANNER_VERSION}"
+}
+
+sonar {
+  properties {
+    property("sonar.projectKey", "${key}")
+    property("sonar.projectName", "${name}")
+    property("sonar.qualitygate.wait", true)
+  }
+}`,
+  };
+  return map[build];
+};
 
 const otherSnippet = (key: string) => `sonar.projectKey=${key}
 sonar.qualitygate.wait=true
@@ -75,7 +92,7 @@ const snippetForBuildTool = {
 
 const filenameForBuildTool = {
   [BuildTools.Maven]: 'pom.xml',
-  [BuildTools.Gradle]: 'build.gradle',
+  [BuildTools.Gradle]: GradleBuildDSL.Groovy,
   [BuildTools.CFamily]: 'sonar-project.properties',
   [BuildTools.Other]: 'sonar-project.properties',
 };
@@ -118,19 +135,44 @@ export function YmlFileStep(props: YmlFileStepProps) {
                 `onboarding.tutorial.with.gitlab_ci.project_key.${buildTool}.step2`
               )}
               id={`onboarding.tutorial.with.gitlab_ci.project_key.${buildTool}.step2`}
-              values={{
-                file: (
-                  <>
-                    <code className="rule">{filenameForBuildTool[buildTool]}</code>
-                    <ClipboardIconButton
-                      className="little-spacer-left"
-                      copyValue={filenameForBuildTool[buildTool]}
-                    />
-                  </>
-                ),
-              }}
+              values={Object.assign(
+                {
+                  file: (
+                    <>
+                      <code className="rule">{filenameForBuildTool[buildTool]}</code>
+                      <ClipboardIconButton
+                        className="little-spacer-left"
+                        copyValue={filenameForBuildTool[buildTool]}
+                      />
+                    </>
+                  ),
+                },
+                buildTool === BuildTools.Gradle
+                  ? {
+                      file2: (
+                        <>
+                          <code className="rule">{GradleBuildDSL.Kotlin}</code>
+                          <ClipboardIconButton
+                            className="little-spacer-left"
+                            copyValue={GradleBuildDSL.Kotlin}
+                          />
+                        </>
+                      ),
+                    }
+                  : {}
+              )}
             />
-            <CodeSnippet snippet={snippetForBuildTool[buildTool](component.key, component.name)} />
+            {buildTool === BuildTools.Gradle ? (
+              <GradleBuildSelection className="spacer-top big-spacer-bottom">
+                {(build) => (
+                  <CodeSnippet
+                    snippet={snippetForBuildTool[buildTool](component.key, component.name, build)}
+                  />
+                )}
+              </GradleBuildSelection>
+            ) : (
+              <CodeSnippet snippet={snippetForBuildTool[buildTool](component.key)} />
+            )}
           </li>
         )}
         {buildTool && (
index d251382f17c1fc51e50bfc42f2a2b2e85bc62612..7d76c65e381620aa4e890641b8e5e0bffbb82bc8 100644 (file)
@@ -31,7 +31,7 @@ import {
   getTutorialActionButtons,
   getTutorialBuildButtons,
 } from '../../test-utils';
-import { TutorialModes } from '../../types';
+import { GradleBuildDSL, TutorialModes } from '../../types';
 import GitLabCITutorial, { GitLabCITutorialProps } from '../GitLabCITutorial';
 
 jest.mock('../../../../api/user-tokens');
@@ -72,8 +72,10 @@ it('should follow and complete all steps', async () => {
 
   // Gradle
   await user.click(ui.gradleBuildButton.get());
-  expect(getCopyToClipboardValue(1)).toMatchSnapshot('Gradle: build.gradle');
-  expect(getCopyToClipboardValue(3)).toMatchSnapshot('Gradle: gitlab-ci.yml');
+  expect(getCopyToClipboardValue(2)).toMatchSnapshot('Groovy: build.gradle');
+  await user.click(ui.gradleDSLButton(GradleBuildDSL.Kotlin).get());
+  expect(getCopyToClipboardValue(2)).toMatchSnapshot('Kotlin: build.gradle.kts');
+  expect(getCopyToClipboardValue(4)).toMatchSnapshot('Gradle: gitlab-ci.yml');
 
   // .NET
   await user.click(ui.dotnetBuildButton.get());
index cc7c5e33d3ddddb7726eabdbe4f7f72f4120a16c..d87708cae7bd1f50b45c6f274e7094ea018cb52b 100644 (file)
@@ -63,20 +63,6 @@ sonar.qualitygate.wait=true
 "
 `;
 
-exports[`should follow and complete all steps: Gradle: build.gradle 1`] = `
-"plugins {
-  id "org.sonarqube" version "4.0.0.2929"
-}
-
-sonar {
-  properties {
-    property "sonar.projectKey", "my-project"
-    property "sonar.projectName", "MyProject"
-    property "sonar.qualitygate.wait", true 
-  }
-}"
-`;
-
 exports[`should follow and complete all steps: Gradle: gitlab-ci.yml 1`] = `
 "sonarqube-check:
   image: gradle:jre11-slim
@@ -94,6 +80,34 @@ exports[`should follow and complete all steps: Gradle: gitlab-ci.yml 1`] = `
 "
 `;
 
+exports[`should follow and complete all steps: Groovy: build.gradle 1`] = `
+"plugins {
+  id "org.sonarqube" version "4.0.0.2929"
+}
+
+sonar {
+  properties {
+    property "sonar.projectKey", "my-project"
+    property "sonar.projectName", "MyProject"
+    property "sonar.qualitygate.wait", true 
+  }
+}"
+`;
+
+exports[`should follow and complete all steps: Kotlin: build.gradle.kts 1`] = `
+"plugins {
+  id ("org.sonarqube") version "4.0.0.2929"
+}
+
+sonar {
+  properties {
+    property("sonar.projectKey", "my-project")
+    property("sonar.projectName", "MyProject")
+    property("sonar.qualitygate.wait", true)
+  }
+}"
+`;
+
 exports[`should follow and complete all steps: Maven: gitlab-ci.yml 1`] = `
 "sonarqube-check:
   image: maven:3.6.3-jdk-11
index 045672dea7a8540f12db03f7239c58d504860e6c..60c73e541921acdcd61690006371415879d660dd 100644 (file)
@@ -32,6 +32,7 @@ import {
   getTutorialActionButtons,
   getTutorialBuildButtons,
 } from '../../test-utils';
+import { GradleBuildDSL } from '../../types';
 import JenkinsTutorial, { JenkinsTutorialProps } from '../JenkinsTutorial';
 
 jest.mock('../../../../api/user-tokens');
@@ -117,9 +118,12 @@ it.each([AlmKeys.BitbucketCloud, AlmKeys.BitbucketServer, AlmKeys.GitHub, AlmKey
     await user.click(ui.mavenBuildButton.get());
     expect(getCopyToClipboardValue()).toMatchSnapshot(`maven jenkinsfile`);
 
-    // Gradle
+    // Gradle (Groovy)
     await user.click(ui.gradleBuildButton.get());
-    expect(getCopyToClipboardValue()).toMatchSnapshot(`build.gradle file`);
+    expect(getCopyToClipboardValue()).toMatchSnapshot(`Groovy: build.gradle file`);
+    // Gradle(Kotlin)
+    await user.click(ui.gradleDSLButton(GradleBuildDSL.Kotlin).get());
+    expect(getCopyToClipboardValue()).toMatchSnapshot(`Kotlin: build.gradle.kts file`);
     expect(getCopyToClipboardValue(1)).toMatchSnapshot(`gradle jenkinsfile`);
 
     // .NET
index 12650e20ff1538084d49a0f008e706778ada0301..5f8c93bd70782e824d14df89e8d0fce4bd86920c 100644 (file)
@@ -1,6 +1,6 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`bitbucket: can select devops platform and complete all the steps with copying code snippets: build.gradle file 1`] = `
+exports[`bitbucket: can select devops platform and complete all the steps with copying code snippets: Groovy: build.gradle file 1`] = `
 "plugins {
   id "org.sonarqube" version "4.0.0.2929"
 }
@@ -13,6 +13,19 @@ sonar {
 }"
 `;
 
+exports[`bitbucket: can select devops platform and complete all the steps with copying code snippets: Kotlin: build.gradle.kts file 1`] = `
+"plugins {
+  id("org.sonarqube") version "4.0.0.2929"
+}
+    
+sonar {
+  properties {
+    property("sonar.projectKey", "my-project")
+    property("sonar.projectName", "MyProject")
+  }
+}"
+`;
+
 exports[`bitbucket: can select devops platform and complete all the steps with copying code snippets: cfamily linux jenkinsfile 1`] = `
 "node {
   stage('SCM') {
@@ -194,7 +207,7 @@ exports[`bitbucket: can select devops platform and complete all the steps with c
 "
 `;
 
-exports[`bitbucketcloud: can select devops platform and complete all the steps with copying code snippets: build.gradle file 1`] = `
+exports[`bitbucketcloud: can select devops platform and complete all the steps with copying code snippets: Groovy: build.gradle file 1`] = `
 "plugins {
   id "org.sonarqube" version "4.0.0.2929"
 }
@@ -207,6 +220,19 @@ sonar {
 }"
 `;
 
+exports[`bitbucketcloud: can select devops platform and complete all the steps with copying code snippets: Kotlin: build.gradle.kts file 1`] = `
+"plugins {
+  id("org.sonarqube") version "4.0.0.2929"
+}
+    
+sonar {
+  properties {
+    property("sonar.projectKey", "my-project")
+    property("sonar.projectName", "MyProject")
+  }
+}"
+`;
+
 exports[`bitbucketcloud: can select devops platform and complete all the steps with copying code snippets: cfamily linux jenkinsfile 1`] = `
 "node {
   stage('SCM') {
@@ -388,7 +414,7 @@ exports[`bitbucketcloud: can select devops platform and complete all the steps w
 "
 `;
 
-exports[`github: can select devops platform and complete all the steps with copying code snippets: build.gradle file 1`] = `
+exports[`github: can select devops platform and complete all the steps with copying code snippets: Groovy: build.gradle file 1`] = `
 "plugins {
   id "org.sonarqube" version "4.0.0.2929"
 }
@@ -401,6 +427,19 @@ sonar {
 }"
 `;
 
+exports[`github: can select devops platform and complete all the steps with copying code snippets: Kotlin: build.gradle.kts file 1`] = `
+"plugins {
+  id("org.sonarqube") version "4.0.0.2929"
+}
+    
+sonar {
+  properties {
+    property("sonar.projectKey", "my-project")
+    property("sonar.projectName", "MyProject")
+  }
+}"
+`;
+
 exports[`github: can select devops platform and complete all the steps with copying code snippets: cfamily linux jenkinsfile 1`] = `
 "node {
   stage('SCM') {
@@ -582,7 +621,7 @@ exports[`github: can select devops platform and complete all the steps with copy
 "
 `;
 
-exports[`gitlab: can select devops platform and complete all the steps with copying code snippets: build.gradle file 1`] = `
+exports[`gitlab: can select devops platform and complete all the steps with copying code snippets: Groovy: build.gradle file 1`] = `
 "plugins {
   id "org.sonarqube" version "4.0.0.2929"
 }
@@ -595,6 +634,19 @@ sonar {
 }"
 `;
 
+exports[`gitlab: can select devops platform and complete all the steps with copying code snippets: Kotlin: build.gradle.kts file 1`] = `
+"plugins {
+  id("org.sonarqube") version "4.0.0.2929"
+}
+    
+sonar {
+  properties {
+    property("sonar.projectKey", "my-project")
+    property("sonar.projectName", "MyProject")
+  }
+}"
+`;
+
 exports[`gitlab: can select devops platform and complete all the steps with copying code snippets: cfamily linux jenkinsfile 1`] = `
 "node {
   stage('SCM') {
index 478ae99d2dddd11ebcc56e34c17cf595bfe0089f..51c24f8c8ef9cddcef3b7408318b597f6f08e401 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
+import { FormattedMessage } from 'react-intl';
+import { translate } from '../../../../helpers/l10n';
 import CodeSnippet from '../../../common/CodeSnippet';
 import FinishButton from '../../components/FinishButton';
-import SentenceWithFilename from '../../components/SentenceWithFilename';
+import GradleBuildSelection from '../../components/GradleBuildSelection';
+import { GradleBuildDSL } from '../../types';
 import { buildGradleSnippet } from '../../utils';
 import { LanguageProps } from '../JenkinsfileStep';
 import CreateJenkinsfileBulletPoint from './CreateJenkinsfileBulletPoint';
@@ -38,14 +41,28 @@ const JENKINSFILE_SNIPPET = `node {
 
 export default function Gradle(props: LanguageProps) {
   const { component } = props;
+
   return (
     <>
       <li className="abs-width-600">
-        <SentenceWithFilename
-          filename="build.gradle"
-          translationKey="onboarding.tutorial.with.jenkins.jenkinsfile.gradle.step2"
-        />
-        <CodeSnippet snippet={buildGradleSnippet(component.key, component.name)} />
+        <span className="markdown">
+          <FormattedMessage
+            defaultMessage={translate(
+              'onboarding.tutorial.with.jenkins.jenkinsfile.gradle.step2',
+              'sentence'
+            )}
+            id="onboarding.tutorial.with.jenkins.jenkinsfile.gradle.step2.sentence"
+            values={{
+              groovy: <code>{GradleBuildDSL.Groovy}</code>,
+              kotlin: <code>{GradleBuildDSL.Kotlin}</code>,
+            }}
+          />
+        </span>
+        <GradleBuildSelection className="big-spacer-top big-spacer-bottom">
+          {(build) => (
+            <CodeSnippet snippet={buildGradleSnippet(component.key, component.name, build)} />
+          )}
+        </GradleBuildSelection>
       </li>
       <CreateJenkinsfileBulletPoint snippet={JENKINSFILE_SNIPPET} />
       <FinishButton onClick={props.onDone} />
index 929bb0e0904416e606aef8155059b121262461aa..d4d21baa62b7a42fd7cb59cc9619db3f3f684f2b 100644 (file)
@@ -25,6 +25,8 @@ import { Component } from '../../../../types/types';
 import CodeSnippet from '../../../common/CodeSnippet';
 import DocLink from '../../../common/DocLink';
 import InstanceMessage from '../../../common/InstanceMessage';
+import GradleBuildSelection from '../../components/GradleBuildSelection';
+import { GradleBuildDSL } from '../../types';
 import DoneNextSteps from '../DoneNextSteps';
 
 export interface JavaGradleProps {
@@ -33,11 +35,17 @@ export interface JavaGradleProps {
   token: string;
 }
 
+const config = {
+  [GradleBuildDSL.Groovy]: `plugins {
+  id "org.sonarqube" version "${GRADLE_SCANNER_VERSION}"
+}`,
+  [GradleBuildDSL.Kotlin]: `plugins {
+  id("org.sonarqube") version "${GRADLE_SCANNER_VERSION}"
+}`,
+};
+
 export default function JavaGradle(props: JavaGradleProps) {
   const { baseUrl, component, token } = props;
-  const config = `plugins {
-  id "org.sonarqube" version "${GRADLE_SCANNER_VERSION}"
-}`;
 
   const command = [
     './gradlew sonar',
@@ -58,13 +66,16 @@ export default function JavaGradle(props: JavaGradleProps) {
               id="onboarding.analysis.java.gradle.text.1"
               values={{
                 plugin_code: <code>org.sonarqube</code>,
-                filename: <code>build.gradle</code>,
+                groovy: <code>{GradleBuildDSL.Groovy}</code>,
+                kotlin: <code>{GradleBuildDSL.Kotlin}</code>,
               }}
             />
           </p>
         )}
       </InstanceMessage>
-      <CodeSnippet snippet={config} />
+      <GradleBuildSelection className="big-spacer-top big-spacer-bottom">
+        {(build) => <CodeSnippet snippet={config[build]} />}
+      </GradleBuildSelection>
       <p className="big-spacer-bottom markdown">
         <em className="small text-muted">
           <FormattedMessage
index f57a2722b0ded44ec0d7e528451a048a4d43008b..4fa5d81d13d9955d442f37d29e8663eed8b0e137 100644 (file)
@@ -19,7 +19,7 @@
  */
 import { screen } from '@testing-library/react';
 import { byRole, byText } from 'testing-library-selector';
-import { BuildTools, OSs, TutorialModes } from './types';
+import { BuildTools, GradleBuildDSL, OSs, TutorialModes } from './types';
 
 const CI_TRANSLATE_MAP: Partial<Record<TutorialModes, string>> = {
   [TutorialModes.BitbucketPipelines]: 'bitbucket_pipelines',
@@ -70,6 +70,7 @@ export function getTutorialBuildButtons() {
     describeBuildTitle: byRole('heading', { name: 'onboarding.build' }),
     mavenBuildButton: byRole('button', { name: `onboarding.build.${BuildTools.Maven}` }),
     gradleBuildButton: byRole('button', { name: `onboarding.build.${BuildTools.Gradle}` }),
+    gradleDSLButton: (name: GradleBuildDSL) => byRole('button', { name }),
     dotnetBuildButton: byRole('button', { name: `onboarding.build.${BuildTools.DotNet}` }),
     cFamilyBuildButton: byRole('button', { name: `onboarding.build.${BuildTools.CFamily}` }),
     otherBuildButton: byRole('button', { name: `onboarding.build.${BuildTools.Other}` }),
index 77fe8964a2d8ae86e51178173aac7b9ba487cb70..7364208f171e99ca8f4d81f227f5e06f729ec4c3 100644 (file)
@@ -35,6 +35,11 @@ export enum BuildTools {
   Other = 'other',
 }
 
+export enum GradleBuildDSL {
+  Groovy = 'build.gradle',
+  Kotlin = 'build.gradle.kts',
+}
+
 export enum OSs {
   Linux = 'linux',
   Windows = 'win',
index 7d271864828b948ecb687addfa5e152b57a32239..e35657317d06a00014c94f2f7bbbac5a0f844d7a 100644 (file)
@@ -21,13 +21,15 @@ import { GRADLE_SCANNER_VERSION } from '../../helpers/constants';
 import { convertGithubApiUrlToLink, stripTrailingSlash } from '../../helpers/urls';
 import { AlmSettingsInstance, ProjectAlmBindingResponse } from '../../types/alm-settings';
 import { UserToken } from '../../types/token';
+import { GradleBuildDSL } from './types';
 
 export function quote(os: string): (s: string) => string {
   return os === 'win' ? (s: string) => `"${s}"` : (s: string) => s;
 }
 
-export function buildGradleSnippet(key: string, name: string) {
-  return `plugins {
+export function buildGradleSnippet(key: string, name: string, build: GradleBuildDSL) {
+  const map = {
+    [GradleBuildDSL.Groovy]: `plugins {
   id "org.sonarqube" version "${GRADLE_SCANNER_VERSION}"
 }
 
@@ -36,7 +38,19 @@ sonar {
     property "sonar.projectKey", "${key}"
     property "sonar.projectName", "${name}"
   }
-}`;
+}`,
+    [GradleBuildDSL.Kotlin]: `plugins {
+  id("org.sonarqube") version "${GRADLE_SCANNER_VERSION}"
+}
+    
+sonar {
+  properties {
+    property("sonar.projectKey", "${key}")
+    property("sonar.projectName", "${name}")
+  }
+}`,
+  };
+  return map[build];
 }
 
 export function getUniqueTokenName(tokens: UserToken[], initialTokenName: string) {
index 30a37db786b22cf69a870dfa82aec63521542af4..c37a64d1e7b3b40c0ae1aad47f67ac8724ddc8d3 100644 (file)
@@ -3834,7 +3834,7 @@ onboarding.analysis.java.maven.docs_link=official documentation of the Scanner f
 onboarding.analysis.java.maven.text.custom=Run the following command in your project's folder.
 
 onboarding.analysis.java.gradle.header=Execute the Scanner for Gradle
-onboarding.analysis.java.gradle.text.1=Running an analysis with Gradle is straighforward. You just need to declare the {plugin_code} plugin in your {filename} file:
+onboarding.analysis.java.gradle.text.1=Running an analysis with Gradle is straighforward. You just need to declare the {plugin_code} plugin in your {groovy} or {kotlin} file:
 onboarding.analysis.java.gradle.text.2=and run the following command:
 onboarding.analysis.java.gradle.latest_version=You can find the latest version of the Gradle plugin {link}.
 onboarding.analysis.java.gradle.docs_link=official documentation of the Scanner for Gradle
@@ -3898,7 +3898,7 @@ onboarding.tutorial.choose_method.azure-pipelines=With Azure Pipelines
 onboarding.tutorial.choose_method.bitbucket-pipelines=With Bitbucket Pipelines
 
 
-onboarding.tutorial.with.yaml.gradle=Update your {gradle} file with the {sq} plugin and it's configuration:
+onboarding.tutorial.with.yaml.gradle=Update your {groovy} or {kotlin} file with the {sq} plugin and its configuration:
 
 
 
@@ -3928,7 +3928,7 @@ onboarding.tutorial.with.github_action.yaml.create_yml=Create or update your {fi
 onboarding.tutorial.with.gitlab_ci.title=Analyze your project with GitLab CI
 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.gradle.step2=Add the following to your {file} or {file2} 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.project_key.dotnet.step2=Create a {file} file in your repository and paste the following code:
 onboarding.tutorial.with.gitlab_ci.project_key.cfamily.step2=Create a {file} file in your repository and paste the following code:
@@ -4151,7 +4151,7 @@ onboarding.tutorial.with.jenkins.jenkinsfile.maven.step3.help1.sentence.path=Man
 onboarding.tutorial.with.jenkins.jenkinsfile.maven.step3.help2.sentence=The name is located under the {path} section, in the {name} field.
 onboarding.tutorial.with.jenkins.jenkinsfile.maven.step3.help2.sentence.path=Maven > Maven installations
 onboarding.tutorial.with.jenkins.jenkinsfile.maven.step3.help2.sentence.name=Name
-onboarding.tutorial.with.jenkins.jenkinsfile.gradle.step2.sentence=Add the following to your {file} file:
+onboarding.tutorial.with.jenkins.jenkinsfile.gradle.step2.sentence=Add the following to your {groovy} or {kotlin} file:
 onboarding.tutorial.with.jenkins.jenkinsfile.dotnet.build_agent=Choose your build agent.
 
 onboarding.tutorial.with.jenkins.dotnet.msbuild.prereqs.title.sentence=Prerequisite: Add a {default_msbuild} tool.