Browse Source

feat(onboarding): Add platform options to java platforms (#57197)

Add platform options (Gradle / Maven, Framework version) to the
platforms `kotlin`, `java`, `java-jog4j2`, `java-logback`,`java-spring`.

Closes https://github.com/getsentry/sentry/issues/56838
ArthurKnaus 1 year ago
parent
commit
d31016f60a

+ 3 - 1
static/app/components/onboarding/productSelection.tsx

@@ -75,6 +75,9 @@ function getDisabledProducts(organization: Organization): DisabledProducts {
 export const platformProductAvailability = {
   android: [ProductSolution.PERFORMANCE_MONITORING, ProductSolution.PROFILING],
   bun: [ProductSolution.PERFORMANCE_MONITORING],
+  kotlin: [ProductSolution.PERFORMANCE_MONITORING],
+  java: [ProductSolution.PERFORMANCE_MONITORING],
+  'java-spring-boot': [ProductSolution.PERFORMANCE_MONITORING],
   javascript: [ProductSolution.PERFORMANCE_MONITORING, ProductSolution.SESSION_REPLAY],
   'javascript-react': [
     ProductSolution.PERFORMANCE_MONITORING,
@@ -143,7 +146,6 @@ export const platformProductAvailability = {
   'python-tornado': [ProductSolution.PERFORMANCE_MONITORING, ProductSolution.PROFILING],
   'python-starlette': [ProductSolution.PERFORMANCE_MONITORING, ProductSolution.PROFILING],
   'python-wsgi': [ProductSolution.PERFORMANCE_MONITORING, ProductSolution.PROFILING],
-  'java-spring-boot': [ProductSolution.PERFORMANCE_MONITORING],
 } as Record<PlatformKey, ProductSolution[]>;
 
 type ProductProps = {

+ 3 - 1
static/app/gettingStartedDocs/java/java.spec.tsx

@@ -2,7 +2,7 @@ import {render, screen} from 'sentry-test/reactTestingLibrary';
 
 import {StepTitle} from 'sentry/components/onboarding/gettingStartedDoc/step';
 
-import {GettingStartedWithJava, steps} from './java';
+import {GettingStartedWithJava, PackageManager, steps} from './java';
 
 describe('GettingStartedWithJava', function () {
   it('renders doc correctly', function () {
@@ -11,6 +11,8 @@ describe('GettingStartedWithJava', function () {
     // Steps
     for (const step of steps({
       dsn: 'test-dsn',
+      packageManager: PackageManager.GRADLE,
+      hasPerformance: true,
     })) {
       expect(
         screen.getByRole('heading', {name: step.title ?? StepTitle[step.type]})

+ 131 - 67
static/app/gettingStartedDocs/java/java.tsx

@@ -5,16 +5,57 @@ import Link from 'sentry/components/links/link';
 import {Layout, LayoutProps} from 'sentry/components/onboarding/gettingStartedDoc/layout';
 import {ModuleProps} from 'sentry/components/onboarding/gettingStartedDoc/sdkDocumentation';
 import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step';
+import {
+  PlatformOption,
+  useUrlPlatformOptions,
+} from 'sentry/components/onboarding/platformOptionsControl';
+import {ProductSolution} from 'sentry/components/onboarding/productSelection';
 import {t, tct} from 'sentry/locale';
 
+export enum PackageManager {
+  GRADLE = 'gradle',
+  MAVEN = 'maven',
+  SBT = 'sbt',
+}
+
+type PlaformOptionKey = 'packageManager';
+
 interface StepsParams {
   dsn: string;
+  hasPerformance: boolean;
+  packageManager: PackageManager;
   organizationSlug?: string;
   projectSlug?: string;
   sourcePackageRegistries?: ModuleProps['sourcePackageRegistries'];
 }
 
 // Configuration Start
+const packageManagerName: Record<PackageManager, string> = {
+  [PackageManager.GRADLE]: 'Gradle',
+  [PackageManager.MAVEN]: 'Maven',
+  [PackageManager.SBT]: 'SBT',
+};
+
+const platformOptions: Record<PlaformOptionKey, PlatformOption> = {
+  packageManager: {
+    label: t('Package Manager'),
+    items: [
+      {
+        label: packageManagerName[PackageManager.GRADLE],
+        value: PackageManager.GRADLE,
+      },
+      {
+        label: packageManagerName[PackageManager.MAVEN],
+        value: PackageManager.MAVEN,
+      },
+      {
+        label: packageManagerName[PackageManager.SBT],
+        value: PackageManager.SBT,
+      },
+    ],
+  },
+};
+
 const introduction = (
   <p>
     {tct(
@@ -30,12 +71,14 @@ const introduction = (
 export const steps = ({
   dsn,
   sourcePackageRegistries,
+  packageManager,
   projectSlug,
+  hasPerformance,
   organizationSlug,
 }: StepsParams): LayoutProps['steps'] => [
   {
     type: StepType.INSTALL,
-    description: t('Install the SDK via Gradle, Maven, or SBT:'),
+    description: t(`Install the SDK via %s:`, packageManagerName[packageManager]),
     configurations: [
       {
         description: (
@@ -49,30 +92,27 @@ export const steps = ({
           </p>
         ),
         language: 'bash',
-        code: `
-SENTRY_AUTH_TOKEN=___ORG_AUTH_TOKEN___
-            `,
+        code: `SENTRY_AUTH_TOKEN=___ORG_AUTH_TOKEN___`,
       },
-      {
-        description: <h5>{t('Gradle')}</h5>,
-        configurations: [
-          {
-            language: 'groovy',
-            partialLoading: sourcePackageRegistries?.isLoading,
-            description: (
-              <p>
-                {tct(
-                  'The [link:Sentry Gradle Plugin] automatically installs the Sentry SDK as well as available integrations for your dependencies. Add the following to your [code:build.gradle] file:',
-                  {
-                    code: <code />,
-                    link: (
-                      <ExternalLink href="https://github.com/getsentry/sentry-android-gradle-plugin" />
-                    ),
-                  }
-                )}
-              </p>
-            ),
-            code: `
+      ...(packageManager === PackageManager.GRADLE
+        ? [
+            {
+              language: 'groovy',
+              partialLoading: sourcePackageRegistries?.isLoading,
+              description: (
+                <p>
+                  {tct(
+                    'The [link:Sentry Gradle Plugin] automatically installs the Sentry SDK as well as available integrations for your dependencies. Add the following to your [code:build.gradle] file:',
+                    {
+                      code: <code />,
+                      link: (
+                        <ExternalLink href="https://github.com/getsentry/sentry-android-gradle-plugin" />
+                      ),
+                    }
+                  )}
+                </p>
+              ),
+              code: `
 buildscript {
   repositories {
     mavenCentral()
@@ -99,21 +139,24 @@ sentry {
   authToken = System.getenv("SENTRY_AUTH_TOKEN")
 }
         `,
-          },
-        ],
-      },
-      {
-        description: <h5>{t('Maven')}</h5>,
-        configurations: [
-          {
-            language: 'xml',
-            partialLoading: sourcePackageRegistries?.isLoading,
-            description: (
-              <p>
-                {tct('For Maven, add to your [code:pom.xml] file:', {code: <code />})}
-              </p>
-            ),
-            code: `
+            },
+          ]
+        : []),
+      ...(packageManager === PackageManager.MAVEN
+        ? [
+            {
+              description: (
+                <p>
+                  {tct('Add the Sentry SDK to your [code:pom.xml] file:', {
+                    code: <code />,
+                  })}
+                </p>
+              ),
+              configurations: [
+                {
+                  language: 'xml',
+                  partialLoading: sourcePackageRegistries?.isLoading,
+                  code: `
 <dependency>
   <groupId>io.sentry</groupId>
   <artifactId>sentry</artifactId>
@@ -124,14 +167,14 @@ sentry {
   }</version>
 </dependency>
             `,
-          },
-          {
-            language: 'xml',
-            partialLoading: sourcePackageRegistries?.isLoading,
-            description: t(
-              'To upload your source code to Sentry so it can be shown in stack traces, use our Maven plugin.'
-            ),
-            code: `
+                },
+                {
+                  language: 'xml',
+                  partialLoading: sourcePackageRegistries?.isLoading,
+                  description: t(
+                    'To upload your source code to Sentry so it can be shown in stack traces, use our Maven plugin.'
+                  ),
+                  code: `
 <build>
   <plugins>
     <plugin>
@@ -169,24 +212,31 @@ sentry {
 ...
 </build>
             `,
-          },
-        ],
-      },
-      {
-        description: <h5>{t('SBT')}</h5>,
-        configurations: [
-          {
-            description: <p>{tct('For [strong:SBT]:', {strong: <strong />})}</p>,
-            language: 'scala',
-            partialLoading: sourcePackageRegistries?.isLoading,
-            code: `libraryDependencies += "io.sentry" % "sentry" % "${
-              sourcePackageRegistries?.isLoading
-                ? t('\u2026loading')
-                : sourcePackageRegistries?.data?.['sentry.java']?.version ?? '6.27.0'
-            }"`,
-          },
-        ],
-      },
+                },
+              ],
+            },
+          ]
+        : []),
+      ...(packageManager === PackageManager.SBT
+        ? [
+            {
+              description: (
+                <p>
+                  {tct('Add the sentry SDK to your [code:libraryDependencies]:', {
+                    code: <code />,
+                  })}
+                </p>
+              ),
+              language: 'scala',
+              partialLoading: sourcePackageRegistries?.isLoading,
+              code: `libraryDependencies += "io.sentry" % "sentry" % "${
+                sourcePackageRegistries?.isLoading
+                  ? t('\u2026loading')
+                  : sourcePackageRegistries?.data?.['sentry.java']?.version ?? '6.27.0'
+              }"`,
+            },
+          ]
+        : []),
     ],
     additionalInfo: (
       <p>
@@ -213,10 +263,14 @@ sentry {
 import io.sentry.Sentry;
 
 Sentry.init(options -> {
-  options.setDsn("${dsn}");
+  options.setDsn("${dsn}");${
+    hasPerformance
+      ? `
   // Set tracesSampleRate to 1.0 to capture 100% of transactions for performance monitoring.
   // We recommend adjusting this value in production.
-  options.setTracesSampleRate(1.0);
+  options.setTracesSampleRate(1.0);`
+      : ''
+  }
   // When first trying Sentry it's good to see what the SDK is doing:
   options.setDebug(true);
 });
@@ -289,8 +343,15 @@ export function GettingStartedWithJava({
   sourcePackageRegistries,
   projectSlug,
   organization,
+  activeProductSelection = [],
   ...props
 }: ModuleProps) {
+  const optionValues = useUrlPlatformOptions(platformOptions);
+
+  const hasPerformance = activeProductSelection.includes(
+    ProductSolution.PERFORMANCE_MONITORING
+  );
+
   const nextStepDocs = [...nextSteps];
 
   return (
@@ -300,7 +361,10 @@ export function GettingStartedWithJava({
         sourcePackageRegistries,
         projectSlug: projectSlug ?? '___PROJECT_SLUG___',
         organizationSlug: organization?.slug ?? '___ORG_SLUG___',
+        packageManager: optionValues.packageManager as PackageManager,
+        hasPerformance,
       })}
+      platformOptions={platformOptions}
       nextSteps={nextStepDocs}
       introduction={introduction}
       projectSlug={projectSlug}

+ 2 - 1
static/app/gettingStartedDocs/java/log4j2.spec.tsx

@@ -2,7 +2,7 @@ import {render, screen} from 'sentry-test/reactTestingLibrary';
 
 import {StepTitle} from 'sentry/components/onboarding/gettingStartedDoc/step';
 
-import {GettingStartedWithLog4j2, steps} from './log4j2';
+import {GettingStartedWithLog4j2, PackageManager, steps} from './log4j2';
 
 describe('GettingStartedWithLog4j2', function () {
   it('renders doc correctly', function () {
@@ -11,6 +11,7 @@ describe('GettingStartedWithLog4j2', function () {
     // Steps
     for (const step of steps({
       dsn: 'test-dsn',
+      packageManager: PackageManager.GRADLE,
     })) {
       expect(
         screen.getByRole('heading', {name: step.title ?? StepTitle[step.type]})

+ 91 - 56
static/app/gettingStartedDocs/java/log4j2.tsx

@@ -5,16 +5,44 @@ import Link from 'sentry/components/links/link';
 import {Layout, LayoutProps} from 'sentry/components/onboarding/gettingStartedDoc/layout';
 import {ModuleProps} from 'sentry/components/onboarding/gettingStartedDoc/sdkDocumentation';
 import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step';
+import {
+  PlatformOption,
+  useUrlPlatformOptions,
+} from 'sentry/components/onboarding/platformOptionsControl';
 import {t, tct} from 'sentry/locale';
 
+export enum PackageManager {
+  GRADLE = 'gradle',
+  MAVEN = 'maven',
+}
+
+type PlaformOptionKey = 'packageManager';
+
 interface StepsParams {
   dsn: string;
+  packageManager: PackageManager;
   organizationSlug?: string;
   projectSlug?: string;
   sourcePackageRegistries?: ModuleProps['sourcePackageRegistries'];
 }
 
 // Configuration Start
+const platformOptions: Record<PlaformOptionKey, PlatformOption> = {
+  packageManager: {
+    label: t('Package Manager'),
+    items: [
+      {
+        label: t('Gradle'),
+        value: PackageManager.GRADLE,
+      },
+      {
+        label: t('Maven'),
+        value: PackageManager.MAVEN,
+      },
+    ],
+  },
+};
+
 const introduction = (
   <p>
     {tct(
@@ -35,11 +63,13 @@ export const steps = ({
   sourcePackageRegistries,
   projectSlug,
   organizationSlug,
+  packageManager,
 }: StepsParams): LayoutProps['steps'] => [
   {
     type: StepType.INSTALL,
     description: t(
-      "Install Sentry's integration with Log4j 2.x using either Maven or Gradle:"
+      "Install Sentry's integration with Log4j 2.x using %s:",
+      packageManager === PackageManager.GRADLE ? 'Gradle' : 'Maven'
     ),
     configurations: [
       {
@@ -54,29 +84,26 @@ export const steps = ({
           </p>
         ),
         language: 'bash',
-        code: `
-SENTRY_AUTH_TOKEN=___ORG_AUTH_TOKEN___
-            `,
+        code: 'SENTRY_AUTH_TOKEN=___ORG_AUTH_TOKEN___',
       },
-      {
-        description: <h5>{t('Gradle')}</h5>,
-        configurations: [
-          {
-            description: (
-              <p>
-                {tct(
-                  'The [link:Sentry Gradle Plugin] automatically installs the Sentry SDK as well as available integrations for your dependencies. Add the following to your [code:build.gradle] file:',
-                  {
-                    code: <code />,
-                    link: (
-                      <ExternalLink href="https://github.com/getsentry/sentry-android-gradle-plugin" />
-                    ),
-                  }
-                )}
-              </p>
-            ),
-            language: 'groovy',
-            code: `
+      ...(packageManager === PackageManager.GRADLE
+        ? [
+            {
+              description: (
+                <p>
+                  {tct(
+                    'The [link:Sentry Gradle Plugin] automatically installs the Sentry SDK as well as available integrations for your dependencies. Add the following to your [code:build.gradle] file:',
+                    {
+                      code: <code />,
+                      link: (
+                        <ExternalLink href="https://github.com/getsentry/sentry-android-gradle-plugin" />
+                      ),
+                    }
+                  )}
+                </p>
+              ),
+              language: 'groovy',
+              code: `
 buildscript {
   repositories {
     mavenCentral()
@@ -102,17 +129,17 @@ sentry {
   projectName = "${projectSlug}"
   authToken = System.getenv("SENTRY_AUTH_TOKEN")
 }
-            `,
-          },
-        ],
-      },
-      {
-        description: <h5>{t('Maven')}</h5>,
-        configurations: [
-          {
-            language: 'xml',
-            partialLoading: sourcePackageRegistries?.isLoading,
-            code: `
+          `,
+            },
+          ]
+        : []),
+      ...(packageManager === PackageManager.MAVEN
+        ? [
+            {
+              language: 'xml',
+              partialLoading: sourcePackageRegistries?.isLoading,
+              description: t("Add the Sentry SDK to your project's dependencies"),
+              code: `
 <dependency>
   <groupId>io.sentry</groupId>
   <artifactId>sentry-log4j2</artifactId>
@@ -123,14 +150,14 @@ sentry {
   }</version>
 </dependency>
           `,
-          },
-          {
-            language: 'xml',
-            partialLoading: sourcePackageRegistries?.isLoading,
-            description: t(
-              'To upload your source code to Sentry so it can be shown in stack traces, use our Maven plugin.'
-            ),
-            code: `
+            },
+            {
+              language: 'xml',
+              partialLoading: sourcePackageRegistries?.isLoading,
+              description: t(
+                'To upload your source code to Sentry so it can be shown in stack traces, use our Maven plugin.'
+              ),
+              code: `
 <build>
   <plugins>
     <plugin>
@@ -168,9 +195,9 @@ sentry {
   ...
 </build>
         `,
-          },
-        ],
-      },
+            },
+          ]
+        : []),
     ],
   },
   {
@@ -262,9 +289,13 @@ sentry {
     ),
     configurations: [
       {
-        description: <h5>Java</h5>,
         language: 'java',
-        code: `
+        code: [
+          {
+            language: 'java',
+            label: 'Java',
+            value: 'java',
+            code: `
 import java.lang.Exception;
 import io.sentry.Sentry;
 
@@ -272,13 +303,13 @@ try {
   throw new Exception("This is a test.");
 } catch (Exception e) {
   Sentry.captureException(e);
-}
-        `,
-      },
-      {
-        description: <h5>Kotlin</h5>,
-        language: 'java',
-        code: `
+}`,
+          },
+          {
+            language: 'java',
+            label: 'Kotlin',
+            value: 'kotlin',
+            code: `
 import java.lang.Exception
 import io.sentry.Sentry
 
@@ -286,8 +317,9 @@ try {
   throw Exception("This is a test.")
 } catch (e: Exception) {
   Sentry.captureException(e)
-}
-        `,
+}`,
+          },
+        ],
       },
     ],
     additionalInfo: (
@@ -324,6 +356,7 @@ export function GettingStartedWithLog4j2({
   organization,
   ...props
 }: ModuleProps) {
+  const optionValues = useUrlPlatformOptions(platformOptions);
   const nextStepDocs = [...nextSteps];
 
   return (
@@ -333,9 +366,11 @@ export function GettingStartedWithLog4j2({
         sourcePackageRegistries,
         projectSlug: projectSlug ?? '___PROJECT_SLUG___',
         organizationSlug: organization?.slug ?? '___ORG_SLUG___',
+        packageManager: optionValues.packageManager as PackageManager,
       })}
       nextSteps={nextStepDocs}
       introduction={introduction}
+      platformOptions={platformOptions}
       projectSlug={projectSlug}
       {...props}
     />

+ 2 - 1
static/app/gettingStartedDocs/java/logback.spec.tsx

@@ -2,7 +2,7 @@ import {render, screen} from 'sentry-test/reactTestingLibrary';
 
 import {StepTitle} from 'sentry/components/onboarding/gettingStartedDoc/step';
 
-import {GettingStartedWithLogBack, steps} from './logback';
+import {GettingStartedWithLogBack, PackageManager, steps} from './logback';
 
 describe('GettingStartedWithLogBack', function () {
   it('renders doc correctly', function () {
@@ -11,6 +11,7 @@ describe('GettingStartedWithLogBack', function () {
     // Steps
     for (const step of steps({
       dsn: 'test-dsn',
+      packageManager: PackageManager.GRADLE,
     })) {
       expect(
         screen.getByRole('heading', {name: step.title ?? StepTitle[step.type]})

+ 105 - 67
static/app/gettingStartedDocs/java/logback.tsx

@@ -5,16 +5,44 @@ import Link from 'sentry/components/links/link';
 import {Layout, LayoutProps} from 'sentry/components/onboarding/gettingStartedDoc/layout';
 import {ModuleProps} from 'sentry/components/onboarding/gettingStartedDoc/sdkDocumentation';
 import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step';
+import {
+  PlatformOption,
+  useUrlPlatformOptions,
+} from 'sentry/components/onboarding/platformOptionsControl';
 import {t, tct} from 'sentry/locale';
 
+export enum PackageManager {
+  GRADLE = 'gradle',
+  MAVEN = 'maven',
+}
+
+type PlaformOptionKey = 'packageManager';
+
 interface StepsParams {
   dsn: string;
+  packageManager: PackageManager;
   organizationSlug?: string;
   projectSlug?: string;
   sourcePackageRegistries?: ModuleProps['sourcePackageRegistries'];
 }
 
 // Configuration Start
+const platformOptions: Record<PlaformOptionKey, PlatformOption> = {
+  packageManager: {
+    label: t('Package Manager'),
+    items: [
+      {
+        label: t('Gradle'),
+        value: PackageManager.GRADLE,
+      },
+      {
+        label: t('Maven'),
+        value: PackageManager.MAVEN,
+      },
+    ],
+  },
+};
+
 const introduction = (
   <p>
     {tct(
@@ -33,11 +61,13 @@ export const steps = ({
   sourcePackageRegistries,
   projectSlug,
   organizationSlug,
+  packageManager,
 }: StepsParams): LayoutProps['steps'] => [
   {
     type: StepType.INSTALL,
     description: t(
-      "Install Sentry's integration with Logback using either Maven or Gradle:"
+      "Install Sentry's integration with Logback using %s:",
+      packageManager === PackageManager.GRADLE ? 'Gradle' : 'Maven'
     ),
     configurations: [
       {
@@ -52,29 +82,26 @@ export const steps = ({
           </p>
         ),
         language: 'bash',
-        code: `
-SENTRY_AUTH_TOKEN=___ORG_AUTH_TOKEN___
-            `,
+        code: 'SENTRY_AUTH_TOKEN=___ORG_AUTH_TOKEN___',
       },
-      {
-        description: <h5>{t('Gradle')}</h5>,
-        configurations: [
-          {
-            description: (
-              <p>
-                {tct(
-                  'The [link:Sentry Gradle Plugin] automatically installs the Sentry SDK as well as available integrations for your dependencies. Add the following to your [code:build.gradle] file:',
-                  {
-                    code: <code />,
-                    link: (
-                      <ExternalLink href="https://github.com/getsentry/sentry-android-gradle-plugin" />
-                    ),
-                  }
-                )}
-              </p>
-            ),
-            language: 'groovy',
-            code: `
+      ...(packageManager === PackageManager.GRADLE
+        ? [
+            {
+              description: (
+                <p>
+                  {tct(
+                    'The [link:Sentry Gradle Plugin] automatically installs the Sentry SDK as well as available integrations for your dependencies. Add the following to your [code:build.gradle] file:',
+                    {
+                      code: <code />,
+                      link: (
+                        <ExternalLink href="https://github.com/getsentry/sentry-android-gradle-plugin" />
+                      ),
+                    }
+                  )}
+                </p>
+              ),
+              language: 'groovy',
+              code: `
 buildscript {
   repositories {
     mavenCentral()
@@ -100,35 +127,35 @@ sentry {
   projectName = "${projectSlug}"
   authToken = System.getenv("SENTRY_AUTH_TOKEN")
 }
-            `,
-          },
-        ],
-      },
-      {
-        description: <h5>{t('Maven')}</h5>,
-        configurations: [
-          {
-            language: 'xml',
-            partialLoading: sourcePackageRegistries?.isLoading,
-            code: `
+          `,
+            },
+          ]
+        : []),
+      ...(packageManager === PackageManager.MAVEN
+        ? [
+            {
+              language: 'xml',
+              partialLoading: sourcePackageRegistries?.isLoading,
+              description: t("Add the Sentry SDK to your project's dependencies"),
+              code: `
 <dependency>
   <groupId>io.sentry</groupId>
-  <artifactId>sentry-logback</artifactId>
+  <artifactId>sentry-log4j2</artifactId>
   <version>${
     sourcePackageRegistries?.isLoading
       ? t('\u2026loading')
-      : sourcePackageRegistries?.data?.['sentry.java.logback']?.version ?? '6.27.0'
+      : sourcePackageRegistries?.data?.['sentry.java.log4j2']?.version ?? '6.27.0'
   }</version>
 </dependency>
           `,
-          },
-          {
-            language: 'xml',
-            partialLoading: sourcePackageRegistries?.isLoading,
-            description: t(
-              'To upload your source code to Sentry so it can be shown in stack traces, use our Maven plugin.'
-            ),
-            code: `
+            },
+            {
+              language: 'xml',
+              partialLoading: sourcePackageRegistries?.isLoading,
+              description: t(
+                'To upload your source code to Sentry so it can be shown in stack traces, use our Maven plugin.'
+              ),
+              code: `
 <build>
   <plugins>
     <plugin>
@@ -166,19 +193,10 @@ sentry {
   ...
 </build>
         `,
-          },
-        ],
-      },
+            },
+          ]
+        : []),
     ],
-    additionalInfo: (
-      <p>
-        {tct('For other dependency managers see the [link:central Maven repository].', {
-          link: (
-            <ExternalLink href="https://search.maven.org/artifact/io.sentry/sentry-logback" />
-          ),
-        })}
-      </p>
-    ),
   },
   {
     type: StepType.CONFIGURE,
@@ -268,9 +286,13 @@ sentry {
     ),
     configurations: [
       {
-        description: <h5>Java</h5>,
         language: 'java',
-        code: `
+        code: [
+          {
+            language: 'java',
+            label: 'Java',
+            value: 'java',
+            code: `
 import java.lang.Exception;
 import io.sentry.Sentry;
 
@@ -278,13 +300,13 @@ try {
   throw new Exception("This is a test.");
 } catch (Exception e) {
   Sentry.captureException(e);
-}
-        `,
-      },
-      {
-        description: <h5>Kotlin</h5>,
-        language: 'java',
-        code: `
+}`,
+          },
+          {
+            language: 'java',
+            label: 'Kotlin',
+            value: 'kotlin',
+            code: `
 import java.lang.Exception
 import io.sentry.Sentry
 
@@ -292,8 +314,9 @@ try {
   throw Exception("This is a test.")
 } catch (e: Exception) {
   Sentry.captureException(e)
-}
-        `,
+}`,
+          },
+        ],
       },
     ],
     additionalInfo: (
@@ -311,6 +334,18 @@ try {
       </Fragment>
     ),
   },
+  {
+    title: t('Other build tools'),
+    additionalInfo: (
+      <p>
+        {tct('For other dependency managers see the [link:central Maven repository].', {
+          link: (
+            <ExternalLink href="https://search.maven.org/artifact/io.sentry/sentry-logback" />
+          ),
+        })}
+      </p>
+    ),
+  },
 ];
 
 export const nextSteps = [
@@ -330,6 +365,7 @@ export function GettingStartedWithLogBack({
   organization,
   ...props
 }: ModuleProps) {
+  const optionValues = useUrlPlatformOptions(platformOptions);
   const nextStepDocs = [...nextSteps];
 
   return (
@@ -339,9 +375,11 @@ export function GettingStartedWithLogBack({
         sourcePackageRegistries,
         projectSlug: projectSlug ?? '___PROJECT_SLUG___',
         organizationSlug: organization?.slug ?? '___ORG_SLUG___',
+        packageManager: optionValues.packageManager as PackageManager,
       })}
       nextSteps={nextStepDocs}
       introduction={introduction}
+      platformOptions={platformOptions}
       projectSlug={projectSlug}
       {...props}
     />

+ 3 - 1
static/app/gettingStartedDocs/java/spring.spec.tsx

@@ -2,7 +2,7 @@ import {render, screen} from 'sentry-test/reactTestingLibrary';
 
 import {StepTitle} from 'sentry/components/onboarding/gettingStartedDoc/step';
 
-import {GettingStartedWithSpring, steps} from './spring';
+import {GettingStartedWithSpring, PackageManager, SpringVersion, steps} from './spring';
 
 describe('GettingStartedWithSpring', function () {
   it('renders doc correctly', function () {
@@ -11,6 +11,8 @@ describe('GettingStartedWithSpring', function () {
     // Steps
     for (const step of steps({
       dsn: 'test-dsn',
+      packageManager: PackageManager.GRADLE,
+      springVersion: SpringVersion.V6,
     })) {
       expect(
         screen.getByRole('heading', {name: step.title ?? StepTitle[step.type], level: 4})

+ 217 - 202
static/app/gettingStartedDocs/java/spring.tsx

@@ -5,16 +5,63 @@ import Link from 'sentry/components/links/link';
 import {Layout, LayoutProps} from 'sentry/components/onboarding/gettingStartedDoc/layout';
 import {ModuleProps} from 'sentry/components/onboarding/gettingStartedDoc/sdkDocumentation';
 import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step';
+import {
+  PlatformOption,
+  useUrlPlatformOptions,
+} from 'sentry/components/onboarding/platformOptionsControl';
 import {t, tct} from 'sentry/locale';
 
+export enum SpringVersion {
+  V5 = 'v5',
+  V6 = 'v6',
+}
+
+export enum PackageManager {
+  GRADLE = 'gradle',
+  MAVEN = 'maven',
+}
+
+type PlaformOptionKey = 'springVersion' | 'packageManager';
+
 interface StepsParams {
   dsn: string;
+  packageManager: PackageManager;
+  springVersion: SpringVersion;
   organizationSlug?: string;
   projectSlug?: string;
   sourcePackageRegistries?: ModuleProps['sourcePackageRegistries'];
 }
 
 // Configuration Start
+const platformOptions: Record<PlaformOptionKey, PlatformOption> = {
+  springVersion: {
+    label: t('Spring Version'),
+    items: [
+      {
+        label: t('Spring 6'),
+        value: SpringVersion.V6,
+      },
+      {
+        label: t('Spring 5'),
+        value: SpringVersion.V5,
+      },
+    ],
+  },
+  packageManager: {
+    label: t('Package Manager'),
+    items: [
+      {
+        label: t('Gradle'),
+        value: PackageManager.GRADLE,
+      },
+      {
+        label: t('Maven'),
+        value: PackageManager.MAVEN,
+      },
+    ],
+  },
+};
+
 const introduction = (
   <p>
     {tct(
@@ -33,11 +80,14 @@ export const steps = ({
   sourcePackageRegistries,
   projectSlug,
   organizationSlug,
+  packageManager,
+  springVersion,
 }: StepsParams): LayoutProps['steps'] => [
   {
     type: StepType.INSTALL,
     description: t(
-      "Install Sentry's integration with Spring using either Maven or Gradle:"
+      "Install Sentry's integration with Spring using %s:",
+      packageManager === PackageManager.GRADLE ? 'Gradle' : 'Maven'
     ),
     configurations: [
       {
@@ -52,29 +102,26 @@ export const steps = ({
           </p>
         ),
         language: 'bash',
-        code: `
-SENTRY_AUTH_TOKEN=___ORG_AUTH_TOKEN___
-            `,
+        code: 'SENTRY_AUTH_TOKEN=___ORG_AUTH_TOKEN___',
       },
-      {
-        description: <h5>{t('Gradle')}</h5>,
-        configurations: [
-          {
-            description: (
-              <p>
-                {tct(
-                  'The [link:Sentry Gradle Plugin] automatically installs the Sentry SDK as well as available integrations for your dependencies. Add the following to your [code:build.gradle] file:',
-                  {
-                    code: <code />,
-                    link: (
-                      <ExternalLink href="https://github.com/getsentry/sentry-android-gradle-plugin" />
-                    ),
-                  }
-                )}
-              </p>
-            ),
-            language: 'groovy',
-            code: `
+      ...(packageManager === PackageManager.GRADLE
+        ? [
+            {
+              description: (
+                <p>
+                  {tct(
+                    'The [link:Sentry Gradle Plugin] automatically installs the Sentry SDK as well as available integrations for your dependencies. Add the following to your [code:build.gradle] file:',
+                    {
+                      code: <code />,
+                      link: (
+                        <ExternalLink href="https://github.com/getsentry/sentry-android-gradle-plugin" />
+                      ),
+                    }
+                  )}
+                </p>
+              ),
+              language: 'groovy',
+              code: `
 buildscript {
   repositories {
     mavenCentral()
@@ -100,62 +147,86 @@ sentry {
   projectName = "${projectSlug}"
   authToken = System.getenv("SENTRY_AUTH_TOKEN")
 }
-            `,
-          },
-        ],
-      },
-      {
-        description: <h5>{t('Maven')}</h5>,
-        additionalInfo: (
-          <p>
-            {tct(
-              "There are two variants of Sentry available for Spring. If you're using Spring 5, use [sentrySpringLink:sentry-spring]. If you're using Spring 6, use [sentrySpringJakartaLink:sentry-spring-jakarta] instead.",
-              {
-                sentrySpringLink: (
-                  <ExternalLink href="https://github.com/getsentry/sentry-java/tree/master/sentry-spring" />
-                ),
-                sentrySpringJakartaLink: (
-                  <ExternalLink href="https://github.com/getsentry/sentry-java/tree/master/sentry-spring-jakarta" />
-                ),
-              }
-            )}
-          </p>
-        ),
-        configurations: [
-          {
-            language: 'xml',
-            partialLoading: sourcePackageRegistries?.isLoading,
-            description: <strong>{t('Spring 5')}</strong>,
-            code: `
-<dependency>
-  <groupId>io.sentry</groupId>
-  <artifactId>sentry-spring</artifactId>
-  <version>${
-    sourcePackageRegistries?.isLoading
-      ? t('\u2026loading')
-      : sourcePackageRegistries?.data?.['sentry.java.spring']?.version ?? '6.28.0'
-  }</version>
-</dependency>
           `,
-          },
-          {
-            language: 'xml',
-            partialLoading: sourcePackageRegistries?.isLoading,
-            description: <strong>{t('Spring 6')}</strong>,
-            code: `
-<dependency>
-  <groupId>io.sentry</groupId>
-  <artifactId>sentry-spring-jakarta</artifactId>
-  <version>${
-    sourcePackageRegistries?.isLoading
-      ? t('\u2026loading')
-      : sourcePackageRegistries?.data?.['sentry.java.spring.jakarta']?.version ?? '6.28.0'
-  }</version>
-</dependency>
-        `,
-          },
-        ],
-      },
+            },
+          ]
+        : []),
+      ...(packageManager === PackageManager.MAVEN
+        ? [
+            {
+              description: t("Add the Sentry SDK to your project's dependencies."),
+              language: 'xml',
+              partialLoading: sourcePackageRegistries?.isLoading,
+              code:
+                springVersion === SpringVersion.V5
+                  ? `
+  <dependency>
+    <groupId>io.sentry</groupId>
+    <artifactId>sentry-spring</artifactId>
+    <version>${
+      sourcePackageRegistries?.isLoading
+        ? t('\u2026loading')
+        : sourcePackageRegistries?.data?.['sentry.java.spring']?.version ?? '6.28.0'
+    }</version>
+  </dependency>`
+                  : `
+  <dependency>
+    <groupId>io.sentry</groupId>
+    <artifactId>sentry-spring-jakarta</artifactId>
+    <version>${
+      sourcePackageRegistries?.isLoading
+        ? t('\u2026loading')
+        : sourcePackageRegistries?.data?.['sentry.java.spring.jakarta']?.version ??
+          '6.28.0'
+    }</version>
+  </dependency>`,
+            },
+            {
+              language: 'xml',
+              partialLoading: sourcePackageRegistries?.isLoading,
+              description: t(
+                'To upload your source code to Sentry so it can be shown in stack traces, use our Maven plugin.'
+              ),
+              code: `
+<build>
+<plugins>
+<plugin>
+<groupId>io.sentry</groupId>
+<artifactId>sentry-maven-plugin</artifactId>
+<version>${
+                sourcePackageRegistries?.isLoading
+                  ? t('\u2026loading')
+                  : sourcePackageRegistries?.data?.['sentry.java.mavenplugin']?.version ??
+                    '0.0.4'
+              }</version>
+<configuration>
+  <!-- for showing output of sentry-cli -->
+  <debugSentryCli>true</debugSentryCli>
+
+  <org>${organizationSlug}</org>
+
+  <project>${projectSlug}</project>
+
+  <!-- in case you're self hosting, provide the URL here -->
+  <!--<url>http://localhost:8000/</url>-->
+
+  <!-- provide your auth token via SENTRY_AUTH_TOKEN environment variable -->
+  <authToken>\${env.SENTRY_AUTH_TOKEN}</authToken>
+</configuration>
+<executions>
+  <execution>
+    <phase>generate-resources</phase>
+    <goals>
+    <goal>uploadSourceBundle</goal>
+    </goals>
+  </execution>
+</executions>
+</plugin>
+</plugins>
+...`,
+            },
+          ]
+        : []),
     ],
   },
   {
@@ -165,10 +236,15 @@ sentry {
         {t("Configure Sentry as soon as possible in your application's lifecycle:")}
         <p>
           {tct(
-            'The [codeSentrySpring:sentry-spring] and [codeSentrySpringJakarta:sentry-spring-jakarta] libraries provide an [codeEnableSentry:@EnableSentry] annotation that registers all required Spring beans. [codeEnableSentry:@EnableSentry] can be placed on any class annotated with [configurationLink:@Configuration] including the main entry class in Spring Boot applications annotated with [springBootApplicationLink:@SpringBootApplication].',
+            'The [libraryName] library provides an [codeEnableSentry:@EnableSentry] annotation that registers all required Spring beans. [codeEnableSentry:@EnableSentry] can be placed on any class annotated with [configurationLink:@Configuration] including the main entry class in Spring Boot applications annotated with [springBootApplicationLink:@SpringBootApplication].',
             {
-              codeSentrySpring: <code />,
-              codeSentrySpringJakarta: <code />,
+              libraryName: (
+                <code>
+                  {springVersion === SpringVersion.V5
+                    ? 'sentry-spring'
+                    : 'sentry-spring-jakarta'}
+                </code>
+              ),
               codeEnableSentry: <code />,
               configurationLink: (
                 <ExternalLink href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Configuration.html" />
@@ -187,107 +263,37 @@ sentry {
         configurations: [
           {
             language: 'java',
-            description: <strong>{t('Spring 5')}</strong>,
-            code: `
-import io.sentry.spring.EnableSentry;
-
-@EnableSentry(dsn = "${dsn}")
-@Configuration
-class SentryConfiguration {
-}
-          `,
-          },
-          {
-            language: 'java',
-            description: <strong>{t('Spring 6')}</strong>,
-            code: `
-import io.sentry.spring.jakarta.EnableSentry;
+            code: [
+              {
+                language: 'java',
+                label: 'Java',
+                value: 'java',
+                code: `
+import io.sentry.spring${
+                  springVersion === SpringVersion.V6 ? '.jakarta' : ''
+                }.EnableSentry;
 
 @EnableSentry(dsn = "${dsn}")
 @Configuration
 class SentryConfiguration {
-}
-        `,
-          },
-        ],
-      },
-      {
-        description: <h5>{t('Kotlin')}</h5>,
-        configurations: [
-          {
-            language: 'java',
-            description: <strong>{t('Spring 5')}</strong>,
-            code: `
-import io.sentry.spring.EnableSentry
-import org.springframework.core.Ordered
-
-@EnableSentry(
-  dsn = "${dsn}",
-  exceptionResolverOrder = Ordered.LOWEST_PRECEDENCE
-)
-          `,
-          },
-          {
-            language: 'java',
-            description: <strong>{t('Spring 6')}</strong>,
-            code: `
-import io.sentry.spring.jakarta.EnableSentry
+}`,
+              },
+              {
+                language: 'java',
+                label: 'Kotlin',
+                value: 'kotlin',
+                code: `
+import io.sentry.spring${
+                  springVersion === SpringVersion.V6 ? '.jakarta' : ''
+                }.EnableSentry
 import org.springframework.core.Ordered
 
 @EnableSentry(
   dsn = "${dsn}",
   exceptionResolverOrder = Ordered.LOWEST_PRECEDENCE
-)
-        `,
-          },
-        ],
-      },
-      {
-        description: <h5>{t('Source Context')}</h5>,
-        configurations: [
-          {
-            language: 'xml',
-            partialLoading: sourcePackageRegistries?.isLoading,
-            description: t(
-              'To upload your source code to Sentry so it can be shown in stack traces, use our Maven plugin.'
-            ),
-            code: `
-<build>
-  <plugins>
-    <plugin>
-    <groupId>io.sentry</groupId>
-    <artifactId>sentry-maven-plugin</artifactId>
-    <version>${
-      sourcePackageRegistries?.isLoading
-        ? t('\u2026loading')
-        : sourcePackageRegistries?.data?.['sentry.java.mavenplugin']?.version ?? '0.0.4'
-    }</version>
-    <configuration>
-      <!-- for showing output of sentry-cli -->
-      <debugSentryCli>true</debugSentryCli>
-
-      <org>${organizationSlug}</org>
-
-      <project>${projectSlug}</project>
-
-      <!-- in case you're self hosting, provide the URL here -->
-      <!--<url>http://localhost:8000/</url>-->
-
-      <!-- provide your auth token via SENTRY_AUTH_TOKEN environment variable -->
-      <authToken>\${env.SENTRY_AUTH_TOKEN}</authToken>
-    </configuration>
-    <executions>
-      <execution>
-        <phase>generate-resources</phase>
-        <goals>
-        <goal>uploadSourceBundle</goal>
-        </goals>
-      </execution>
-    </executions>
-  </plugin>
-</plugins>
-...
-        `,
+)`,
+              },
+            ],
           },
         ],
       },
@@ -300,9 +306,12 @@ import org.springframework.core.Ordered
     ),
     configurations: [
       {
-        description: <h5>Java</h5>,
-        language: 'java',
-        code: `
+        code: [
+          {
+            language: 'java',
+            label: 'Java',
+            value: 'java',
+            code: `
 import java.lang.Exception;
 import io.sentry.Sentry;
 
@@ -310,13 +319,13 @@ try {
   throw new Exception("This is a test.");
 } catch (Exception e) {
   Sentry.captureException(e);
-}
-        `,
-      },
-      {
-        description: <h5>Kotlin</h5>,
-        language: 'java',
-        code: `
+}`,
+          },
+          {
+            language: 'java',
+            label: 'Kotlin',
+            value: 'kotlin',
+            code: `
 import java.lang.Exception
 import io.sentry.Sentry
 
@@ -324,8 +333,9 @@ try {
   throw Exception("This is a test.")
 } catch (e: Exception) {
   Sentry.captureException(e)
-}
-        `,
+}`,
+          },
+        ],
       },
     ],
     additionalInfo: (
@@ -348,24 +358,24 @@ try {
     additionalInfo: (
       <p>
         {tct(
-          'For other dependency managers see the [mavenRepositorySpring5Link:central Maven repository (Spring 5)] and [mavenRepositorySpring6Link:central Maven repository (Spring 6)].',
+          'For other dependency managers see the [mavenRepositorySpringLink:central Maven repository].',
           {
-            mavenRepositorySpring5Link: (
-              <ExternalLink
-                href={`https://central.sonatype.com/artifact/io.sentry/sentry-spring/${
-                  sourcePackageRegistries?.data?.['sentry.java.spring']?.version ??
-                  '6.28.0'
-                }`}
-              />
-            ),
-            mavenRepositorySpring6Link: (
-              <ExternalLink
-                href={`https://central.sonatype.com/artifact/io.sentry/sentry-spring-jakarta/${
-                  sourcePackageRegistries?.data?.['sentry.java.spring.jakarta']
-                    ?.version ?? '6.28.0'
-                }`}
-              />
-            ),
+            mavenRepositorySpringLink:
+              springVersion === SpringVersion.V5 ? (
+                <ExternalLink
+                  href={`https://central.sonatype.com/artifact/io.sentry/sentry-spring/${
+                    sourcePackageRegistries?.data?.['sentry.java.spring']?.version ??
+                    '6.28.0'
+                  }`}
+                />
+              ) : (
+                <ExternalLink
+                  href={`https://central.sonatype.com/artifact/io.sentry/sentry-spring-jakarta/${
+                    sourcePackageRegistries?.data?.['sentry.java.spring.jakarta']
+                      ?.version ?? '6.28.0'
+                  }`}
+                />
+              ),
           }
         )}
       </p>
@@ -398,6 +408,8 @@ export function GettingStartedWithSpring({
   organization,
   ...props
 }: ModuleProps) {
+  const optionValues = useUrlPlatformOptions(platformOptions);
+
   const nextStepDocs = [...nextSteps];
 
   return (
@@ -407,9 +419,12 @@ export function GettingStartedWithSpring({
         sourcePackageRegistries,
         projectSlug: projectSlug ?? '___PROJECT_SLUG___',
         organizationSlug: organization?.slug ?? '___ORG_SLUG___',
+        springVersion: optionValues.springVersion as SpringVersion,
+        packageManager: optionValues.packageManager as PackageManager,
       })}
       nextSteps={nextStepDocs}
       introduction={introduction}
+      platformOptions={platformOptions}
       projectSlug={projectSlug}
       {...props}
     />

+ 6 - 2
static/app/gettingStartedDocs/kotlin/kotlin.spec.tsx

@@ -2,14 +2,18 @@ import {render, screen} from 'sentry-test/reactTestingLibrary';
 
 import {StepTitle} from 'sentry/components/onboarding/gettingStartedDoc/step';
 
-import {GettingStartedWithKotlin, steps} from './kotlin';
+import {GettingStartedWithKotlin, PackageManager, steps} from './kotlin';
 
 describe('GettingStartedWithKotlin', function () {
   it('renders doc correctly', function () {
     render(<GettingStartedWithKotlin dsn="test-dsn" projectSlug="test-project" />);
 
     // Steps
-    for (const step of steps()) {
+    for (const step of steps({
+      dsn: 'test-dsn',
+      hasPerformance: true,
+      packageManager: PackageManager.GRADLE,
+    })) {
       expect(
         screen.getByRole('heading', {name: step.title ?? StepTitle[step.type]})
       ).toBeInTheDocument();

Some files were not shown because too many files changed in this diff