Browse Source

ref(onboarding): Convert go platforms to new structure – part 1 (#59523)

Convert platforms `go`, `go-gin`, `go-fasthttp`, `go-echo`

- relates to https://github.com/getsentry/sentry/issues/56549
ArthurKnaus 1 year ago
parent
commit
e107d076c8

+ 10 - 13
static/app/gettingStartedDocs/go/echo.spec.tsx

@@ -1,18 +1,15 @@
-import {render, screen} from 'sentry-test/reactTestingLibrary';
+import {renderWithOnboardingLayout} from 'sentry-test/onboarding/renderWithOnboardingLayout';
+import {screen} from 'sentry-test/reactTestingLibrary';
 
-import {StepTitle} from 'sentry/components/onboarding/gettingStartedDoc/step';
+import docs from './echo';
 
-import {GettingStartedWithEcho, steps} from './echo';
+describe('echo onboarding docs', function () {
+  it('renders docs correctly', function () {
+    renderWithOnboardingLayout(docs);
 
-describe('GettingStartedWithEcho', function () {
-  it('renders doc correctly', function () {
-    render(<GettingStartedWithEcho dsn="test-dsn" projectSlug="test-project" />);
-
-    // Steps
-    for (const step of steps()) {
-      expect(
-        screen.getByRole('heading', {name: step.title ?? StepTitle[step.type]})
-      ).toBeInTheDocument();
-    }
+    // Renders main headings
+    expect(screen.getByRole('heading', {name: 'Install'})).toBeInTheDocument();
+    expect(screen.getByRole('heading', {name: 'Configure SDK'})).toBeInTheDocument();
+    expect(screen.getByRole('heading', {name: 'Usage'})).toBeInTheDocument();
   });
 });

+ 119 - 113
static/app/gettingStartedDocs/go/echo.tsx

@@ -3,40 +3,17 @@ import styled from '@emotion/styled';
 
 import {Alert} from 'sentry/components/alert';
 import ExternalLink from 'sentry/components/links/externalLink';
-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 type {
+  Docs,
+  DocsParams,
+  OnboardingConfig,
+} from 'sentry/components/onboarding/gettingStartedDoc/types';
 import {t, tct} from 'sentry/locale';
 
-// Configuration Start
-export const steps = ({
-  dsn,
-}: Partial<Pick<ModuleProps, 'dsn'>> = {}): LayoutProps['steps'] => [
-  {
-    type: StepType.INSTALL,
-    description: (
-      <p>
-        {tct('Install our Go Echo SDK using [code:go get]:', {
-          code: <code />,
-        })}
-      </p>
-    ),
-    configurations: [
-      {
-        language: 'bash',
-        code: 'go get github.com/getsentry/sentry-go/echo',
-      },
-    ],
-  },
-  {
-    type: StepType.CONFIGURE,
-    description: t(
-      "Import and initialize the Sentry SDK early in your application's setup:"
-    ),
-    configurations: [
-      {
-        language: 'go',
-        code: `
+type Params = DocsParams;
+
+const getConfigureSnippet = (params: Params) => `
 import (
   "fmt"
   "net/http"
@@ -49,7 +26,7 @@ import (
 
 // To initialize Sentry's handler, you need to initialize Sentry itself beforehand
 if err := sentry.Init(sentry.ClientOptions{
-  Dsn: "${dsn}",
+  Dsn: "${params.dsn}",
   // Set TracesSampleRate to 1.0 to capture 100%
   // of transactions for performance monitoring.
   // We recommend adjusting this value in production,
@@ -73,24 +50,9 @@ app.GET("/", func(ctx echo.Context) error {
 })
 
 // And run it
-app.Logger.Fatal(app.Start(":3000"))
-        `,
-      },
-      {
-        description: (
-          <Fragment>
-            <strong>{t('Options')}</strong>
-            <p>
-              {tct(
-                '[sentryEchoCode:sentryecho] accepts a struct of [optionsCode:Options] that allows you to configure how the handler will behave.',
-                {sentryEchoCode: <code />, optionsCode: <code />}
-              )}
-            </p>
-            {t('Currently it respects 3 options:')}
-          </Fragment>
-        ),
-        language: 'go',
-        code: `
+app.Logger.Fatal(app.Start(":3000"))`;
+
+const getOptionsSnippet = () => `
 // Repanic configures whether Sentry should repanic after recovery, in most cases it should be set to true,
 // as echo includes its own Recover middleware that handles http responses.
 Repanic bool
@@ -99,42 +61,9 @@ Repanic bool
 // it's safe to either skip this option or set it to "false".
 WaitForDelivery bool
 // Timeout for the event delivery requests.
-Timeout time.Duration
-        `,
-      },
-    ],
-  },
-  {
-    title: t('Usage'),
-    description: (
-      <Fragment>
-        <p>
-          {tct(
-            "[sentryEchoCode:sentryecho] attaches an instance of [sentryHubLink:*sentry.Hub] to the [echoContextCode:echo.Context], which makes it available throughout the rest of the request's lifetime. You can access it by using the [getHubFromContextCode:sentryecho.GetHubFromContext()] method on the context itself in any of your proceeding middleware and routes. And it should be used instead of the global [captureMessageCode:sentry.CaptureMessage], [captureExceptionCode:sentry.CaptureException] or any other calls, as it keeps the separation of data between the requests.",
-            {
-              sentryEchoCode: <code />,
-              sentryHubLink: (
-                <ExternalLink href="https://godoc.org/github.com/getsentry/sentry-go#Hub" />
-              ),
-              echoContextCode: <code />,
-              getHubFromContextCode: <code />,
-              captureMessageCode: <code />,
-              captureExceptionCode: <code />,
-            }
-          )}
-        </p>
-        <AlertWithoutMarginBottom>
-          {tct(
-            "Keep in mind that [sentryHubCode:*sentry.Hub] won't be available in middleware attached before [sentryEchoCode:sentryecho]!",
-            {sentryEchoCode: <code />, sentryHubCode: <code />}
-          )}
-        </AlertWithoutMarginBottom>
-      </Fragment>
-    ),
-    configurations: [
-      {
-        language: 'go',
-        code: `
+Timeout time.Duration`;
+
+const getUsageSnippet = () => `
 app := echo.New()
 
 app.Use(middleware.Logger())
@@ -169,21 +98,11 @@ app.GET("/foo", func(ctx echo.Context) error {
   panic("y tho")
 })
 
-app.Logger.Fatal(app.Start(":3000"))
-        `,
-      },
-      {
-        description: (
-          <strong>
-            {tct('Accessing Request in [beforeSendCode:BeforeSend] callback', {
-              beforeSendCode: <code />,
-            })}
-          </strong>
-        ),
-        language: 'go',
-        code: `
+app.Logger.Fatal(app.Start(":3000"))`;
+
+const getBeforeSendSnippet = params => `
 sentry.Init(sentry.ClientOptions{
-  Dsn: "${dsn}",
+  Dsn: "${params.dsn}",
   BeforeSend: func(event *sentry.Event, hint *sentry.EventHint) *sentry.Event {
     if hint.Context != nil {
       if req, ok := hint.Context.Value(sentry.RequestContextKey).(*http.Request); ok {
@@ -193,19 +112,106 @@ sentry.Init(sentry.ClientOptions{
 
     return event
   },
-})
-        `,
-      },
-    ],
-  },
-];
-// Configuration End
-
-export function GettingStartedWithEcho({dsn, ...props}: ModuleProps) {
-  return <Layout steps={steps({dsn})} {...props} />;
-}
-
-export default GettingStartedWithEcho;
+})`;
+
+const onboarding: OnboardingConfig = {
+  install: () => [
+    {
+      type: StepType.INSTALL,
+      description: tct('Install our Go Echo SDK using [code:go get]:', {
+        code: <code />,
+      }),
+      configurations: [
+        {
+          language: 'bash',
+          code: 'go get github.com/getsentry/sentry-go/echo',
+        },
+      ],
+    },
+  ],
+  configure: params => [
+    {
+      type: StepType.CONFIGURE,
+      description: t(
+        "Import and initialize the Sentry SDK early in your application's setup:"
+      ),
+      configurations: [
+        {
+          language: 'go',
+          code: getConfigureSnippet(params),
+        },
+        {
+          description: (
+            <Fragment>
+              <strong>{t('Options')}</strong>
+              <p>
+                {tct(
+                  '[sentryEchoCode:sentryecho] accepts a struct of [optionsCode:Options] that allows you to configure how the handler will behave.',
+                  {sentryEchoCode: <code />, optionsCode: <code />}
+                )}
+              </p>
+              {t('Currently it respects 3 options:')}
+            </Fragment>
+          ),
+          language: 'go',
+          code: getOptionsSnippet(),
+        },
+      ],
+    },
+    {
+      title: t('Usage'),
+      description: (
+        <Fragment>
+          <p>
+            {tct(
+              "[sentryEchoCode:sentryecho] attaches an instance of [sentryHubLink:*sentry.Hub] to the [echoContextCode:echo.Context], which makes it available throughout the rest of the request's lifetime. You can access it by using the [getHubFromContextCode:sentryecho.GetHubFromContext()] method on the context itself in any of your proceeding middleware and routes. And it should be used instead of the global [captureMessageCode:sentry.CaptureMessage], [captureExceptionCode:sentry.CaptureException] or any other calls, as it keeps the separation of data between the requests.",
+              {
+                sentryEchoCode: <code />,
+                sentryHubLink: (
+                  <ExternalLink href="https://godoc.org/github.com/getsentry/sentry-go#Hub" />
+                ),
+                echoContextCode: <code />,
+                getHubFromContextCode: <code />,
+                captureMessageCode: <code />,
+                captureExceptionCode: <code />,
+              }
+            )}
+          </p>
+          <AlertWithoutMarginBottom>
+            {tct(
+              "Keep in mind that [sentryHubCode:*sentry.Hub] won't be available in middleware attached before [sentryEchoCode:sentryecho]!",
+              {sentryEchoCode: <code />, sentryHubCode: <code />}
+            )}
+          </AlertWithoutMarginBottom>
+        </Fragment>
+      ),
+      configurations: [
+        {
+          language: 'go',
+          code: getUsageSnippet(),
+        },
+        {
+          description: (
+            <strong>
+              {tct('Accessing Request in [beforeSendCode:BeforeSend] callback', {
+                beforeSendCode: <code />,
+              })}
+            </strong>
+          ),
+          language: 'go',
+          code: getBeforeSendSnippet(params),
+        },
+      ],
+    },
+  ],
+  verify: () => [],
+};
+
+const docs: Docs = {
+  onboarding,
+};
+
+export default docs;
 
 const AlertWithoutMarginBottom = styled(Alert)`
   margin-bottom: 0;

+ 10 - 13
static/app/gettingStartedDocs/go/fasthttp.spec.tsx

@@ -1,18 +1,15 @@
-import {render, screen} from 'sentry-test/reactTestingLibrary';
+import {renderWithOnboardingLayout} from 'sentry-test/onboarding/renderWithOnboardingLayout';
+import {screen} from 'sentry-test/reactTestingLibrary';
 
-import {StepTitle} from 'sentry/components/onboarding/gettingStartedDoc/step';
+import docs from './fasthttp';
 
-import {GettingStartedWithFastHttp, steps} from './fasthttp';
+describe('fasthttp onboarding docs', function () {
+  it('renders docs correctly', function () {
+    renderWithOnboardingLayout(docs);
 
-describe('GettingStartedWithFastHttp', function () {
-  it('renders doc correctly', function () {
-    render(<GettingStartedWithFastHttp dsn="test-dsn" projectSlug="test-project" />);
-
-    // Steps
-    for (const step of steps()) {
-      expect(
-        screen.getByRole('heading', {name: step.title ?? StepTitle[step.type]})
-      ).toBeInTheDocument();
-    }
+    // Renders main headings
+    expect(screen.getByRole('heading', {name: 'Install'})).toBeInTheDocument();
+    expect(screen.getByRole('heading', {name: 'Configure SDK'})).toBeInTheDocument();
+    expect(screen.getByRole('heading', {name: 'Usage'})).toBeInTheDocument();
   });
 });

+ 118 - 112
static/app/gettingStartedDocs/go/fasthttp.tsx

@@ -3,40 +3,17 @@ import styled from '@emotion/styled';
 
 import {Alert} from 'sentry/components/alert';
 import ExternalLink from 'sentry/components/links/externalLink';
-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 type {
+  Docs,
+  DocsParams,
+  OnboardingConfig,
+} from 'sentry/components/onboarding/gettingStartedDoc/types';
 import {t, tct} from 'sentry/locale';
 
-// Configuration Start
-export const steps = ({
-  dsn,
-}: Partial<Pick<ModuleProps, 'dsn'>> = {}): LayoutProps['steps'] => [
-  {
-    type: StepType.INSTALL,
-    description: (
-      <p>
-        {tct('Install our Go FastHTTP SDK using [code:go get]:', {
-          code: <code />,
-        })}
-      </p>
-    ),
-    configurations: [
-      {
-        language: 'bash',
-        code: 'go get github.com/getsentry/sentry-go/fasthttp',
-      },
-    ],
-  },
-  {
-    type: StepType.CONFIGURE,
-    description: t(
-      "Import and initialize the Sentry SDK early in your application's setup:"
-    ),
-    configurations: [
-      {
-        language: 'go',
-        code: `
+type Params = DocsParams;
+
+const getConfigureSnippet = (params: Params) => `
 import (
   "fmt"
   "net/http"
@@ -47,7 +24,7 @@ import (
 
 // To initialize Sentry's handler, you need to initialize Sentry itself beforehand
 if err := sentry.Init(sentry.ClientOptions{
-  Dsn: "${dsn}",
+  Dsn: "${params.dsn}",
   EnableTracing: true,
   // Set TracesSampleRate to 1.0 to capture 100%
   // of transactions for performance monitoring.
@@ -70,24 +47,9 @@ fmt.Println("Listening and serving HTTP on :3000")
 // And run it
 if err := fasthttp.ListenAndServe(":3000", fastHTTPHandler); err != nil {
   panic(err)
-}
-        `,
-      },
-      {
-        description: (
-          <Fragment>
-            <strong>{t('Options')}</strong>
-            <p>
-              {tct(
-                '[sentryfasthttpCode:sentryfasthttp] accepts a struct of [optionsCode:Options] that allows you to configure how the handler will behave.',
-                {sentryfasthttpCode: <code />, optionsCode: <code />}
-              )}
-            </p>
-            {t('Currently it respects 3 options:')}
-          </Fragment>
-        ),
-        language: 'go',
-        code: `
+}`;
+
+const getOptionsSnippet = () => `
 // Repanic configures whether Sentry should repanic after recovery, in most cases, it defaults to false,
 // as fasthttp doesn't include its own Recovery handler.
 Repanic bool
@@ -96,41 +58,9 @@ Repanic bool
 // and the event won't be delivered otherwise.
 WaitForDelivery bool
 // Timeout for the event delivery requests.
-Timeout time.Duration
-        `,
-      },
-    ],
-  },
-  {
-    title: t('Usage'),
-    description: (
-      <Fragment>
-        <p>
-          {tct(
-            "[sentryfasthttpCode:sentryfasthttp] attaches an instance of [sentryHubLink:*sentry.Hub] to the request's context, which makes it available throughout the rest of the request's lifetime. You can access it by using the [getHubFromContextCode:sentryfasthttp.GetHubFromContext()] method on the context itself in any of your proceeding middleware and routes. And it should be used instead of the global [captureMessageCode:sentry.CaptureMessage], [captureExceptionCode:sentry.CaptureException], or any other calls, as it keeps the separation of data between the requests.",
-            {
-              sentryfasthttpCode: <code />,
-              sentryHubLink: (
-                <ExternalLink href="https://godoc.org/github.com/getsentry/sentry-go#Hub" />
-              ),
-              getHubFromContextCode: <code />,
-              captureMessageCode: <code />,
-              captureExceptionCode: <code />,
-            }
-          )}
-        </p>
-        <AlertWithoutMarginBottom>
-          {tct(
-            "Keep in mind that [sentryHubCode:*sentry.Hub] won't be available in middleware attached before [sentryfasthttpCode:sentryfasthttp]!",
-            {sentryfasthttpCode: <code />, sentryHubCode: <code />}
-          )}
-        </AlertWithoutMarginBottom>
-      </Fragment>
-    ),
-    configurations: [
-      {
-        language: 'go',
-        code: `
+Timeout time.Duration`;
+
+const getUsageSnippet = () => `
 func enhanceSentryEvent(handler fasthttp.RequestHandler) fasthttp.RequestHandler {
   return func(ctx *fasthttp.RequestCtx) {
     if hub := sentryfasthttp.GetHubFromContext(ctx); hub != nil {
@@ -173,21 +103,11 @@ fmt.Println("Listening and serving HTTP on :3000")
 
 if err := fasthttp.ListenAndServe(":3000", sentryHandler.Handle(fastHTTPHandler)); err != nil {
   panic(err)
-}
-        `,
-      },
-      {
-        description: (
-          <strong>
-            {tct('Accessing Request in [beforeSendCode:BeforeSend] callback', {
-              beforeSendCode: <code />,
-            })}
-          </strong>
-        ),
-        language: 'go',
-        code: `
+}`;
+
+const getBeforeSendSnippet = params => `
 sentry.Init(sentry.ClientOptions{
-  Dsn: "${dsn}",
+  Dsn: "${params.dsn}",
   BeforeSend: func(event *sentry.Event, hint *sentry.EventHint) *sentry.Event {
     if hint.Context != nil {
       if ctx, ok := hint.Context.Value(sentry.RequestContextKey).(*fasthttp.RequestCtx); ok {
@@ -197,19 +117,105 @@ sentry.Init(sentry.ClientOptions{
     }
     return event
   },
-})
-        `,
-      },
-    ],
-  },
-];
-// Configuration End
-
-export function GettingStartedWithFastHttp({dsn, ...props}: ModuleProps) {
-  return <Layout steps={steps({dsn})} {...props} />;
-}
-
-export default GettingStartedWithFastHttp;
+})`;
+
+const onboarding: OnboardingConfig = {
+  install: () => [
+    {
+      type: StepType.INSTALL,
+      description: tct('Install our Go FastHTTP SDK using [code:go get]:', {
+        code: <code />,
+      }),
+      configurations: [
+        {
+          language: 'bash',
+          code: 'go get github.com/getsentry/sentry-go/fasthttp',
+        },
+      ],
+    },
+  ],
+  configure: params => [
+    {
+      type: StepType.CONFIGURE,
+      description: t(
+        "Import and initialize the Sentry SDK early in your application's setup:"
+      ),
+      configurations: [
+        {
+          language: 'go',
+          code: getConfigureSnippet(params),
+        },
+        {
+          description: (
+            <Fragment>
+              <strong>{t('Options')}</strong>
+              <p>
+                {tct(
+                  '[sentryfasthttpCode:sentryfasthttp] accepts a struct of [optionsCode:Options] that allows you to configure how the handler will behave.',
+                  {sentryfasthttpCode: <code />, optionsCode: <code />}
+                )}
+              </p>
+              {t('Currently it respects 3 options:')}
+            </Fragment>
+          ),
+          language: 'go',
+          code: getOptionsSnippet(),
+        },
+      ],
+    },
+    {
+      title: t('Usage'),
+      description: (
+        <Fragment>
+          <p>
+            {tct(
+              "[sentryfasthttpCode:sentryfasthttp] attaches an instance of [sentryHubLink:*sentry.Hub] to the request's context, which makes it available throughout the rest of the request's lifetime. You can access it by using the [getHubFromContextCode:sentryfasthttp.GetHubFromContext()] method on the context itself in any of your proceeding middleware and routes. And it should be used instead of the global [captureMessageCode:sentry.CaptureMessage], [captureExceptionCode:sentry.CaptureException], or any other calls, as it keeps the separation of data between the requests.",
+              {
+                sentryfasthttpCode: <code />,
+                sentryHubLink: (
+                  <ExternalLink href="https://godoc.org/github.com/getsentry/sentry-go#Hub" />
+                ),
+                getHubFromContextCode: <code />,
+                captureMessageCode: <code />,
+                captureExceptionCode: <code />,
+              }
+            )}
+          </p>
+          <AlertWithoutMarginBottom>
+            {tct(
+              "Keep in mind that [sentryHubCode:*sentry.Hub] won't be available in middleware attached before [sentryfasthttpCode:sentryfasthttp]!",
+              {sentryfasthttpCode: <code />, sentryHubCode: <code />}
+            )}
+          </AlertWithoutMarginBottom>
+        </Fragment>
+      ),
+      configurations: [
+        {
+          language: 'go',
+          code: getUsageSnippet(),
+        },
+        {
+          description: (
+            <strong>
+              {tct('Accessing Request in [beforeSendCode:BeforeSend] callback', {
+                beforeSendCode: <code />,
+              })}
+            </strong>
+          ),
+          language: 'go',
+          code: getBeforeSendSnippet(params),
+        },
+      ],
+    },
+  ],
+  verify: () => [],
+};
+
+const docs: Docs = {
+  onboarding,
+};
+
+export default docs;
 
 const AlertWithoutMarginBottom = styled(Alert)`
   margin-bottom: 0;

+ 10 - 13
static/app/gettingStartedDocs/go/gin.spec.tsx

@@ -1,18 +1,15 @@
-import {render, screen} from 'sentry-test/reactTestingLibrary';
+import {renderWithOnboardingLayout} from 'sentry-test/onboarding/renderWithOnboardingLayout';
+import {screen} from 'sentry-test/reactTestingLibrary';
 
-import {StepTitle} from 'sentry/components/onboarding/gettingStartedDoc/step';
+import docs from './gin';
 
-import {GettingStartedWithGin, steps} from './gin';
+describe('gin onboarding docs', function () {
+  it('renders docs correctly', function () {
+    renderWithOnboardingLayout(docs);
 
-describe('GettingStartedWithGin', function () {
-  it('renders doc correctly', function () {
-    render(<GettingStartedWithGin dsn="test-dsn" projectSlug="test-project" />);
-
-    // Steps
-    for (const step of steps()) {
-      expect(
-        screen.getByRole('heading', {name: step.title ?? StepTitle[step.type]})
-      ).toBeInTheDocument();
-    }
+    // Renders main headings
+    expect(screen.getByRole('heading', {name: 'Install'})).toBeInTheDocument();
+    expect(screen.getByRole('heading', {name: 'Configure SDK'})).toBeInTheDocument();
+    expect(screen.getByRole('heading', {name: 'Usage'})).toBeInTheDocument();
   });
 });

+ 119 - 113
static/app/gettingStartedDocs/go/gin.tsx

@@ -3,40 +3,17 @@ import styled from '@emotion/styled';
 
 import {Alert} from 'sentry/components/alert';
 import ExternalLink from 'sentry/components/links/externalLink';
-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 type {
+  Docs,
+  DocsParams,
+  OnboardingConfig,
+} from 'sentry/components/onboarding/gettingStartedDoc/types';
 import {t, tct} from 'sentry/locale';
 
-// Configuration Start
-export const steps = ({
-  dsn,
-}: Partial<Pick<ModuleProps, 'dsn'>> = {}): LayoutProps['steps'] => [
-  {
-    type: StepType.INSTALL,
-    description: (
-      <p>
-        {tct('Install our Go Gin SDK using [code:go get]:', {
-          code: <code />,
-        })}
-      </p>
-    ),
-    configurations: [
-      {
-        language: 'bash',
-        code: 'go get github.com/getsentry/sentry-go/gin',
-      },
-    ],
-  },
-  {
-    type: StepType.CONFIGURE,
-    description: t(
-      "Import and initialize the Sentry SDK early in your application's setup:"
-    ),
-    configurations: [
-      {
-        language: 'go',
-        code: `
+type Params = DocsParams;
+
+const getConfigureSnippet = (params: Params) => `
 import (
   "fmt"
   "net/http"
@@ -48,7 +25,7 @@ import (
 
 // To initialize Sentry's handler, you need to initialize Sentry itself beforehand
 if err := sentry.Init(sentry.ClientOptions{
-  Dsn: "${dsn}",
+  Dsn: "${params.dsn}",
   EnableTracing: true,
   // Set TracesSampleRate to 1.0 to capture 100%
   // of transactions for performance monitoring.
@@ -70,24 +47,9 @@ app.GET("/", func(ctx *gin.Context) {
 })
 
 // And run it
-app.Run(":3000")
-        `,
-      },
-      {
-        description: (
-          <Fragment>
-            <strong>{t('Options')}</strong>
-            <p>
-              {tct(
-                '[sentryGinCode:sentrygin] accepts a struct of [optionsCode:Options] that allows you to configure how the handler will behave.',
-                {sentryGinCode: <code />, optionsCode: <code />}
-              )}
-            </p>
-            {t('Currently it respects 3 options:')}
-          </Fragment>
-        ),
-        language: 'go',
-        code: `
+app.Run(":3000")`;
+
+const getOptionsSnippet = () => `
 // Whether Sentry should repanic after recovery, in most cases it should be set to true,
 // as gin.Default includes its own Recovery middleware that handles http responses.
 Repanic bool
@@ -96,42 +58,9 @@ Repanic bool
 // it's safe to either skip this option or set it to "false".
 WaitForDelivery bool
 // Timeout for the event delivery requests.
-Timeout time.Duration
-        `,
-      },
-    ],
-  },
-  {
-    title: t('Usage'),
-    description: (
-      <Fragment>
-        <p>
-          {tct(
-            "[sentryGinCode:sentrygin] attaches an instance of [sentryHubLink:*sentry.Hub] to the [ginContextCode:*gin.Context], which makes it available throughout the rest of the request's lifetime. You can access it by using the [getHubFromContextCode:sentrygin.GetHubFromContext()] method on the context itself in any of your proceeding middleware and routes. And it should be used instead of the global [captureMessageCode:sentry.CaptureMessage], [captureExceptionCode:sentry.CaptureException], or any other calls, as it keeps the separation of data between the requests.",
-            {
-              sentryGinCode: <code />,
-              sentryHubLink: (
-                <ExternalLink href="https://godoc.org/github.com/getsentry/sentry-go#Hub" />
-              ),
-              ginContextCode: <code />,
-              getHubFromContextCode: <code />,
-              captureMessageCode: <code />,
-              captureExceptionCode: <code />,
-            }
-          )}
-        </p>
-        <AlertWithoutMarginBottom>
-          {tct(
-            "Keep in mind that [sentryHubCode:*sentry.Hub] won't be available in middleware attached before [sentryGinCode:sentrygin]!",
-            {sentryGinCode: <code />, sentryHubCode: <code />}
-          )}
-        </AlertWithoutMarginBottom>
-      </Fragment>
-    ),
-    configurations: [
-      {
-        language: 'go',
-        code: `
+Timeout time.Duration`;
+
+const getUsageSnippet = () => `
 app := gin.Default()
 
 app.Use(sentrygin.New(sentrygin.Options{
@@ -161,21 +90,11 @@ app.GET("/foo", func(ctx *gin.Context) {
   panic("y tho")
 })
 
-app.Run(":3000")
-        `,
-      },
-      {
-        description: (
-          <strong>
-            {tct('Accessing Request in [beforeSendCode:BeforeSend] callback', {
-              beforeSendCode: <code />,
-            })}
-          </strong>
-        ),
-        language: 'go',
-        code: `
+app.Run(":3000")`;
+
+const getBeforeSendSnippet = params => `
 sentry.Init(sentry.ClientOptions{
-  Dsn: "${dsn}",
+  Dsn: "${params.dsn}",
   BeforeSend: func(event *sentry.Event, hint *sentry.EventHint) *sentry.Event {
     if hint.Context != nil {
       if req, ok := hint.Context.Value(sentry.RequestContextKey).(*http.Request); ok {
@@ -185,19 +104,106 @@ sentry.Init(sentry.ClientOptions{
 
     return event
   },
-})
-        `,
-      },
-    ],
-  },
-];
-// Configuration End
-
-export function GettingStartedWithGin({dsn, ...props}: ModuleProps) {
-  return <Layout steps={steps({dsn})} {...props} />;
-}
-
-export default GettingStartedWithGin;
+})`;
+
+const onboarding: OnboardingConfig = {
+  install: () => [
+    {
+      type: StepType.INSTALL,
+      description: tct('Install our Go Gin SDK using [code:go get]:', {
+        code: <code />,
+      }),
+      configurations: [
+        {
+          language: 'bash',
+          code: 'go get github.com/getsentry/sentry-go/gin',
+        },
+      ],
+    },
+  ],
+  configure: params => [
+    {
+      type: StepType.CONFIGURE,
+      description: t(
+        "Import and initialize the Sentry SDK early in your application's setup:"
+      ),
+      configurations: [
+        {
+          language: 'go',
+          code: getConfigureSnippet(params),
+        },
+        {
+          description: (
+            <Fragment>
+              <strong>{t('Options')}</strong>
+              <p>
+                {tct(
+                  '[sentryGinCode:sentrygin] accepts a struct of [optionsCode:Options] that allows you to configure how the handler will behave.',
+                  {sentryGinCode: <code />, optionsCode: <code />}
+                )}
+              </p>
+              {t('Currently it respects 3 options:')}
+            </Fragment>
+          ),
+          language: 'go',
+          code: getOptionsSnippet(),
+        },
+      ],
+    },
+    {
+      title: t('Usage'),
+      description: (
+        <Fragment>
+          <p>
+            {tct(
+              "[sentryGinCode:sentrygin] attaches an instance of [sentryHubLink:*sentry.Hub] to the [ginContextCode:*gin.Context], which makes it available throughout the rest of the request's lifetime. You can access it by using the [getHubFromContextCode:sentrygin.GetHubFromContext()] method on the context itself in any of your proceeding middleware and routes. And it should be used instead of the global [captureMessageCode:sentry.CaptureMessage], [captureExceptionCode:sentry.CaptureException], or any other calls, as it keeps the separation of data between the requests.",
+              {
+                sentryGinCode: <code />,
+                sentryHubLink: (
+                  <ExternalLink href="https://godoc.org/github.com/getsentry/sentry-go#Hub" />
+                ),
+                ginContextCode: <code />,
+                getHubFromContextCode: <code />,
+                captureMessageCode: <code />,
+                captureExceptionCode: <code />,
+              }
+            )}
+          </p>
+          <AlertWithoutMarginBottom>
+            {tct(
+              "Keep in mind that [sentryHubCode:*sentry.Hub] won't be available in middleware attached before [sentryGinCode:sentrygin]!",
+              {sentryGinCode: <code />, sentryHubCode: <code />}
+            )}
+          </AlertWithoutMarginBottom>
+        </Fragment>
+      ),
+      configurations: [
+        {
+          language: 'go',
+          code: getUsageSnippet(),
+        },
+        {
+          description: (
+            <strong>
+              {tct('Accessing Request in [beforeSendCode:BeforeSend] callback', {
+                beforeSendCode: <code />,
+              })}
+            </strong>
+          ),
+          language: 'go',
+          code: getBeforeSendSnippet(params),
+        },
+      ],
+    },
+  ],
+  verify: () => [],
+};
+
+const docs: Docs = {
+  onboarding,
+};
+
+export default docs;
 
 const AlertWithoutMarginBottom = styled(Alert)`
   margin-bottom: 0;

+ 10 - 13
static/app/gettingStartedDocs/go/go.spec.tsx

@@ -1,18 +1,15 @@
-import {render, screen} from 'sentry-test/reactTestingLibrary';
+import {renderWithOnboardingLayout} from 'sentry-test/onboarding/renderWithOnboardingLayout';
+import {screen} from 'sentry-test/reactTestingLibrary';
 
-import {StepTitle} from 'sentry/components/onboarding/gettingStartedDoc/step';
+import docs from './go';
 
-import {GettingStartedWithGo, steps} from './go';
+describe('go onboarding docs', function () {
+  it('renders docs correctly', function () {
+    renderWithOnboardingLayout(docs);
 
-describe('GettingStartedWithGo', function () {
-  it('renders doc correctly', function () {
-    render(<GettingStartedWithGo dsn="test-dsn" projectSlug="test-project" />);
-
-    // Steps
-    for (const step of steps()) {
-      expect(
-        screen.getByRole('heading', {name: step.title ?? StepTitle[step.type]})
-      ).toBeInTheDocument();
-    }
+    // Renders main headings
+    expect(screen.getByRole('heading', {name: 'Install'})).toBeInTheDocument();
+    expect(screen.getByRole('heading', {name: 'Configure SDK'})).toBeInTheDocument();
+    expect(screen.getByRole('heading', {name: 'Verify'})).toBeInTheDocument();
   });
 });

+ 62 - 57
static/app/gettingStartedDocs/go/go.tsx

@@ -1,37 +1,14 @@
-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 type {
+  Docs,
+  DocsParams,
+  OnboardingConfig,
+} from 'sentry/components/onboarding/gettingStartedDoc/types';
 import {t, tct} from 'sentry/locale';
 
-// Configuration Start
-export const steps = ({
-  dsn,
-}: Partial<Pick<ModuleProps, 'dsn'>> = {}): LayoutProps['steps'] => [
-  {
-    type: StepType.INSTALL,
-    description: (
-      <p>
-        {tct('Install our Go SDK using [code:go get]:', {
-          code: <code />,
-        })}
-      </p>
-    ),
-    configurations: [
-      {
-        language: 'bash',
-        code: 'go get github.com/getsentry/sentry-go',
-      },
-    ],
-  },
-  {
-    type: StepType.CONFIGURE,
-    description: t(
-      "Import and initialize the Sentry SDK early in your application's setup:"
-    ),
-    configurations: [
-      {
-        language: 'go',
-        code: `
+type Params = DocsParams;
+
+const getConfigureSnippet = (params: Params) => `
 package main
 
 import (
@@ -42,7 +19,7 @@ import (
 
 func main() {
   err := sentry.Init(sentry.ClientOptions{
-    Dsn: "${dsn}",
+    Dsn: "${params.dsn}",
     // Set TracesSampleRate to 1.0 to capture 100%
     // of transactions for performance monitoring.
     // We recommend adjusting this value in production,
@@ -51,20 +28,9 @@ func main() {
   if err != nil {
     log.Fatalf("sentry.Init: %s", err)
   }
-}
-        `,
-      },
-    ],
-  },
-  {
-    type: StepType.VERIFY,
-    description: t(
-      'The quickest way to verify Sentry in your Go program is to capture a message:'
-    ),
-    configurations: [
-      {
-        language: 'go',
-        code: `
+}`;
+
+const getVerifySnippet = () => `
 package main
 
 import (
@@ -89,16 +55,55 @@ func main() {
   defer sentry.Flush(2 * time.Second)
 
   sentry.CaptureMessage("It works!")
-}
-        `,
-      },
-    ],
-  },
-];
-// Configuration End
+}`;
+
+const onboarding: OnboardingConfig = {
+  install: () => [
+    {
+      type: StepType.INSTALL,
+      description: tct('Install our Go SDK using [code:go get]:', {
+        code: <code />,
+      }),
+      configurations: [
+        {
+          language: 'bash',
+          code: 'go get github.com/getsentry/sentry-go',
+        },
+      ],
+    },
+  ],
+  configure: params => [
+    {
+      type: StepType.CONFIGURE,
+      description: t(
+        "Import and initialize the Sentry SDK early in your application's setup:"
+      ),
+      configurations: [
+        {
+          language: 'go',
+          code: getConfigureSnippet(params),
+        },
+      ],
+    },
+  ],
+  verify: () => [
+    {
+      type: StepType.VERIFY,
+      description: t(
+        'The quickest way to verify Sentry in your Go program is to capture a message:'
+      ),
+      configurations: [
+        {
+          language: 'go',
+          code: getVerifySnippet(),
+        },
+      ],
+    },
+  ],
+};
 
-export function GettingStartedWithGo({dsn, ...props}: ModuleProps) {
-  return <Layout steps={steps({dsn})} {...props} />;
-}
+const docs: Docs = {
+  onboarding,
+};
 
-export default GettingStartedWithGo;
+export default docs;