]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-13480 Add jenkins tutorial for GitHub imported projects
authorJeremy Davis <jeremy.davis@sonarsource.com>
Tue, 23 Jun 2020 08:28:45 +0000 (10:28 +0200)
committersonartech <sonartech@sonarsource.com>
Tue, 28 Jul 2020 20:06:06 +0000 (20:06 +0000)
31 files changed:
server/sonar-web/src/main/js/components/tutorials/TutorialSelection.tsx
server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelectionRenderer-test.tsx
server/sonar-web/src/main/js/components/tutorials/__tests__/utils-test.ts
server/sonar-web/src/main/js/components/tutorials/jenkins/BitbucketWebhookStep.tsx [deleted file]
server/sonar-web/src/main/js/components/tutorials/jenkins/JenkinsTutorial.tsx
server/sonar-web/src/main/js/components/tutorials/jenkins/MultiBranchPipelineStep.tsx
server/sonar-web/src/main/js/components/tutorials/jenkins/PreRequisitesStep.tsx
server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStep.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStepBitbucket.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStepGithub.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/BitbucketWebhookStep-test.tsx [deleted file]
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/JenkinsTutorial-test.tsx
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/MultiBranchPipelineStep-test.tsx
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/PreRequisitesStep-test.tsx
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/WebhookStep-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/WebhookStepBitbucket-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/WebhookStepGithub-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/BitbucketWebhookStep-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/JenkinsTutorial-test.tsx.snap
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/MultiBranchPipelineStep-test.tsx.snap
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/PreRequisitesStep-test.tsx.snap
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/WebhookStep-test.tsx.snap [new file with mode: 0644]
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/WebhookStepBitbucket-test.tsx.snap [new file with mode: 0644]
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/WebhookStepGithub-test.tsx.snap [new file with mode: 0644]
server/sonar-web/src/main/js/components/tutorials/utils.ts
server/sonar-web/src/main/js/helpers/__tests__/alm-settings-test.ts [new file with mode: 0644]
server/sonar-web/src/main/js/helpers/__tests__/alm-settings.ts [deleted file]
server/sonar-web/src/main/js/helpers/alm-settings.ts
server/sonar-web/src/main/js/helpers/mocks/alm-settings.ts
server/sonar-web/src/main/js/types/alm-settings.ts
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index 44891c3a6ffe5627a861e73ec23bbefac7ace4bd..865d08766b90ccd2ce8b96bffd6910e99b1168a2 100644 (file)
@@ -59,13 +59,17 @@ export class TutorialSelection extends React.PureComponent<Props, State> {
     ]);
 
     if (this.mounted) {
-      // We only support Bitbucket for now.
-      if (projectBinding === undefined || projectBinding.alm !== AlmKeys.Bitbucket) {
+      // We only support Bitbucket & GitHub for now.
+      if (
+        projectBinding === undefined ||
+        (projectBinding.alm !== AlmKeys.Bitbucket && projectBinding.alm !== AlmKeys.GitHub)
+      ) {
         this.setState({ loading: false, forceManual: true });
       } else {
         let almBinding;
         if (almDefinitions !== undefined) {
-          almBinding = almDefinitions[projectBinding.alm].find(d => d.key === projectBinding.key);
+          const specificDefinitions = almDefinitions[projectBinding.alm] as AlmBindingDefinition[];
+          almBinding = specificDefinitions.find(d => d.key === projectBinding.key);
         }
         this.setState({ almBinding, forceManual: false, projectBinding, loading: false });
       }
index 151db95278f8002de469e3745e41e5c9be9f9d13..f393bcb45c6110150c394fdd67ac40bb875e8ecb 100644 (file)
@@ -23,7 +23,7 @@ import * as React from 'react';
 import { click } from 'sonar-ui-common/helpers/testUtils';
 import {
   mockBitbucketBindingDefinition,
-  mockProjectBitbucketBindingGet
+  mockProjectBitbucketBindingResponse
 } from '../../../helpers/mocks/alm-settings';
 import { mockComponent, mockLoggedInUser } from '../../../helpers/testMocks';
 import TutorialSelectionRenderer, {
@@ -40,7 +40,7 @@ it('should render correctly', () => {
   expect(
     shallowRender({
       selectedTutorial: TutorialModes.Jenkins,
-      projectBinding: mockProjectBitbucketBindingGet()
+      projectBinding: mockProjectBitbucketBindingResponse()
     })
   ).toMatchSnapshot('jenkins tutorial');
 });
index f16f4b82ac4f19f640529d4d29fd0a0a6a7d29d1..d5d8762df5a20ea6c1187a568df84fd3f743a179 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
-import { getUniqueTokenName } from '../utils';
+import {
+  mockGithubBindingDefinition,
+  mockProjectGithubBindingResponse
+} from '../../../helpers/mocks/alm-settings';
+import { buildGithubLink, getUniqueTokenName } from '../utils';
 
-const initialTokenName = 'Analyze "lightsaber"';
+describe('getUniqueTokenName', () => {
+  const initialTokenName = 'Analyze "lightsaber"';
 
-it('should return the given name when the user has no token', () => {
-  const userTokens: T.UserToken[] = [];
+  it('should return the given name when the user has no token', () => {
+    const userTokens: T.UserToken[] = [];
 
-  expect(getUniqueTokenName(userTokens, initialTokenName)).toBe(initialTokenName);
-});
+    expect(getUniqueTokenName(userTokens, initialTokenName)).toBe(initialTokenName);
+  });
+
+  it('should generate a token with the given name', () => {
+    const userTokens = [{ name: initialTokenName, createdAt: '2019-06-14T09:45:52+0200' }];
+
+    expect(getUniqueTokenName(userTokens, 'Analyze "project"')).toBe('Analyze "project"');
+  });
 
-it('should generate a token with the given name', () => {
-  const userTokens = [{ name: initialTokenName, createdAt: '2019-06-14T09:45:52+0200' }];
+  it('should generate a unique token when the name already exists', () => {
+    const userTokens = [
+      { name: initialTokenName, createdAt: '2019-06-15T09:45:52+0200' },
+      { name: `${initialTokenName} 1`, createdAt: '2019-06-15T09:45:53+0200' }
+    ];
 
-  expect(getUniqueTokenName(userTokens, 'Analyze "project"')).toBe('Analyze "project"');
+    expect(getUniqueTokenName(userTokens, initialTokenName)).toBe('Analyze "lightsaber" 2');
+  });
 });
 
-it('should generate a unique token when the name already exists', () => {
-  const userTokens = [
-    { name: initialTokenName, createdAt: '2019-06-14T09:45:52+0200' },
-    { name: `${initialTokenName} 1`, createdAt: '2019-06-14T09:45:52+0200' }
-  ];
+describe('buildGithubLink', () => {
+  it('should work for GitHub Enterprise', () => {
+    expect(
+      buildGithubLink(
+        mockGithubBindingDefinition({ url: 'https://github.company.com/api/v3/' }),
+        mockProjectGithubBindingResponse({ repository: 'owner/reponame' })
+      )
+    ).toBe('https://github.company.com/owner/reponame');
+  });
 
-  expect(getUniqueTokenName(userTokens, initialTokenName)).toBe('Analyze "lightsaber" 2');
+  it('should work for github.com', () => {
+    expect(
+      buildGithubLink(
+        mockGithubBindingDefinition({ url: 'https://api.github.com/' }),
+        mockProjectGithubBindingResponse({ repository: 'owner/reponame' })
+      )
+    ).toBe('https://github.com/owner/reponame');
+  });
 });
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/BitbucketWebhookStep.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/BitbucketWebhookStep.tsx
deleted file mode 100644 (file)
index 5ce0941..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import { Button, ButtonLink } from 'sonar-ui-common/components/controls/buttons';
-import { Alert } from 'sonar-ui-common/components/ui/Alert';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import {
-  BitbucketBindingDefinition,
-  ProjectBitbucketBindingResponse
-} from '../../../types/alm-settings';
-import CodeSnippet from '../../common/CodeSnippet';
-import LabelActionPair from '../components/LabelActionPair';
-import SentenceWithHighlights from '../components/SentenceWithHighlights';
-import Step from '../components/Step';
-
-export interface BitbucketWebhookStepProps {
-  almBinding?: BitbucketBindingDefinition;
-  finished: boolean;
-  onDone: () => void;
-  onOpen: () => void;
-  open: boolean;
-  projectBinding: ProjectBitbucketBindingResponse;
-}
-
-export default function BitbucketWebhookStep(props: BitbucketWebhookStepProps) {
-  const { almBinding, finished, open, projectBinding } = props;
-  return (
-    <Step
-      finished={finished}
-      onOpen={props.onOpen}
-      open={open}
-      renderForm={() => (
-        <div className="boxed-group-inner">
-          <p className="big-spacer-bottom">
-            <FormattedMessage
-              defaultMessage={translate(
-                'onboarding.tutorial.with.jenkins.bitbucket_webhook.intro.sentence'
-              )}
-              id="onboarding.tutorial.with.jenkins.bitbucket_webhook.intro.sentence"
-              values={{
-                link: (
-                  <ButtonLink onClick={props.onDone}>
-                    {translate('onboarding.tutorial.with.jenkins.bitbucket_webhook.intro.link')}
-                  </ButtonLink>
-                )
-              }}
-            />
-          </p>
-          <ol className="list-styled">
-            <li>
-              <FormattedMessage
-                defaultMessage={translate(
-                  'onboarding.tutorial.with.jenkins.bitbucket_webhook.step1.sentence'
-                )}
-                id="onboarding.tutorial.with.jenkins.bitbucket_webhook.step1.sentence"
-                values={{
-                  link:
-                    almBinding !== undefined ? (
-                      <a
-                        href={`${almBinding.url.replace(
-                          /\/$/,
-                          ''
-                        )}/plugins/servlet/webhooks/projects/${projectBinding.repository}/repos/${
-                          projectBinding.slug
-                        }/create`}
-                        rel="noopener noreferrer"
-                        target="_blank">
-                        {translate('onboarding.tutorial.with.jenkins.bitbucket_webhook.step1.link')}
-                      </a>
-                    ) : (
-                      translate('onboarding.tutorial.with.jenkins.bitbucket_webhook.step1.link')
-                    )
-                }}
-              />
-              <ul className="list-styled">
-                <li>
-                  <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.bitbucket_webhook.step1.name" />
-                </li>
-                <li className="abs-width-600">
-                  <p>
-                    <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.bitbucket_webhook.step1.url" />
-                  </p>
-                  <CodeSnippet
-                    isOneLine={true}
-                    snippet={`***JENKINS_URL***/bitbucket-scmsource-hook/notify?server_url=${
-                      almBinding !== undefined ? almBinding.url : '***BITBUCKET_URL***'
-                    }`}
-                  />
-                  <Alert variant="info">
-                    {translate(
-                      'onboarding.tutorial.with.jenkins.bitbucket_webhook.step1.url.warning'
-                    )}
-                  </Alert>
-                </li>
-              </ul>
-            </li>
-            <li>
-              <SentenceWithHighlights
-                highlightKeys={['events']}
-                translationKey="onboarding.tutorial.with.jenkins.bitbucket_webhook.step2"
-              />
-              <ul className="list-styled">
-                <li>
-                  <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.bitbucket_webhook.step2.repo" />
-                </li>
-                <li>
-                  <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.bitbucket_webhook.step2.pr" />
-                </li>
-              </ul>
-            </li>
-            <li>
-              <SentenceWithHighlights
-                highlightKeys={['create']}
-                translationKey="onboarding.tutorial.with.jenkins.bitbucket_webhook.step3"
-              />
-            </li>
-          </ol>
-          <Button onClick={props.onDone}>{translate('continue')}</Button>
-        </div>
-      )}
-      stepNumber={2}
-      stepTitle={translate('onboarding.tutorial.with.jenkins.bitbucket_webhook.title')}
-    />
-  );
-}
index db0303bcff296a67e079edf58d2afe56a6539929..a516260891f7d1e25646f8052435fc11a0569054 100644 (file)
@@ -22,16 +22,16 @@ import { connect } from 'react-redux';
 import { Alert } from 'sonar-ui-common/components/ui/Alert';
 import { translate } from 'sonar-ui-common/helpers/l10n';
 import {
-  isBitbucketBindingDefinition,
-  isProjectBitbucketBindingResponse
+  isProjectBitbucketBindingResponse,
+  isProjectGitHubBindingResponse
 } from '../../../helpers/alm-settings';
 import { getCurrentUserSetting, Store } from '../../../store/rootReducer';
 import { setCurrentUserSetting } from '../../../store/users';
 import { AlmBindingDefinition, ProjectAlmBindingResponse } from '../../../types/alm-settings';
-import BitbucketWebhookStep from './BitbucketWebhookStep';
 import JenkinsfileStep from './JenkinsfileStep';
 import MultiBranchPipelineStep from './MultiBranchPipelineStep';
 import PreRequisitesStep from './PreRequisitesStep';
+import WebhookStep from './WebhookStep';
 
 export interface JenkinsTutorialProps {
   almBinding?: AlmBindingDefinition;
@@ -44,7 +44,7 @@ export interface JenkinsTutorialProps {
 enum Steps {
   PreRequisites = 0,
   MultiBranchPipeline = 1,
-  BitbucketWebhook = 2,
+  Webhook = 2,
   Jenkinsfile = 3
 }
 
@@ -57,9 +57,12 @@ export function JenkinsTutorial(props: JenkinsTutorialProps) {
   );
 
   // Failsafe; should never happen.
-  if (!isProjectBitbucketBindingResponse(projectBinding)) {
+  if (
+    !isProjectBitbucketBindingResponse(projectBinding) &&
+    !isProjectGitHubBindingResponse(projectBinding)
+  ) {
     return (
-      <Alert variant="error">{translate('onboarding.tutorial.with.jenkins.only_bitbucket')}</Alert>
+      <Alert variant="error">{translate('onboarding.tutorial.with.jenkins.unsupported')}</Alert>
     );
   }
 
@@ -70,6 +73,7 @@ export function JenkinsTutorial(props: JenkinsTutorialProps) {
       </div>
 
       <PreRequisitesStep
+        alm={projectBinding.alm}
         onDone={() => setStep(Steps.MultiBranchPipeline)}
         onOpen={() => setStep(Steps.PreRequisites)}
         onChangeSkipNextTime={skip => {
@@ -83,19 +87,20 @@ export function JenkinsTutorial(props: JenkinsTutorialProps) {
       />
 
       <MultiBranchPipelineStep
+        almBinding={almBinding}
         finished={step > Steps.MultiBranchPipeline}
-        onDone={() => setStep(Steps.BitbucketWebhook)}
+        onDone={() => setStep(Steps.Webhook)}
         onOpen={() => setStep(Steps.MultiBranchPipeline)}
         open={step === Steps.MultiBranchPipeline}
         projectBinding={projectBinding}
       />
 
-      <BitbucketWebhookStep
-        almBinding={almBinding && isBitbucketBindingDefinition(almBinding) ? almBinding : undefined}
-        finished={step > Steps.BitbucketWebhook}
+      <WebhookStep
+        almBinding={almBinding}
+        finished={step > Steps.Webhook}
         onDone={() => setStep(Steps.Jenkinsfile)}
-        onOpen={() => setStep(Steps.BitbucketWebhook)}
-        open={step === Steps.BitbucketWebhook}
+        onOpen={() => setStep(Steps.Webhook)}
+        open={step === Steps.Webhook}
         projectBinding={projectBinding}
       />
 
index 6deaaca4ac2d5ef1751fe9dc635660491725d7b2..d0feb3133bcdb7d2e731f52b1409cbc6c009f1cb 100644 (file)
 import * as React from 'react';
 import { Button } from 'sonar-ui-common/components/controls/buttons';
 import { translate } from 'sonar-ui-common/helpers/l10n';
-import { ProjectBitbucketBindingResponse } from '../../../types/alm-settings';
+import {
+  isGithubBindingDefinition,
+  isProjectBitbucketBindingResponse,
+  isProjectGitHubBindingResponse
+} from '../../../helpers/alm-settings';
+import {
+  AlmBindingDefinition,
+  ProjectBitbucketBindingResponse,
+  ProjectGitHubBindingResponse
+} from '../../../types/alm-settings';
 import LabelActionPair from '../components/LabelActionPair';
 import LabelValuePair from '../components/LabelValuePair';
 import SentenceWithHighlights from '../components/SentenceWithHighlights';
 import Step from '../components/Step';
+import { buildGithubLink } from '../utils';
 
 export interface MultiBranchPipelineStepProps {
+  almBinding?: AlmBindingDefinition;
   finished: boolean;
   onDone: () => void;
   onOpen: () => void;
   open: boolean;
-  projectBinding: ProjectBitbucketBindingResponse;
+  projectBinding: ProjectBitbucketBindingResponse | ProjectGitHubBindingResponse;
 }
 
 export default function MultiBranchPipelineStep(props: MultiBranchPipelineStepProps) {
-  const { finished, open, projectBinding } = props;
+  const { almBinding, finished, open, projectBinding } = props;
   return (
     <Step
       finished={finished}
@@ -56,27 +67,48 @@ export default function MultiBranchPipelineStep(props: MultiBranchPipelineStepPr
             <li>
               <SentenceWithHighlights
                 highlightKeys={['tab']}
-                translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2"
+                translationKey={`onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.${projectBinding.alm}`}
               />
               <ul className="list-styled">
-                <li>
-                  <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.server" />
-                </li>
-                <li>
-                  <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.creds" />
-                </li>
-                <li>
-                  <LabelValuePair
-                    translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.owner"
-                    value={projectBinding.repository}
-                  />
-                </li>
-                <li>
-                  <LabelValuePair
-                    translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.repo"
-                    value={projectBinding.slug}
-                  />
-                </li>
+                {isProjectBitbucketBindingResponse(projectBinding) && (
+                  <>
+                    <li>
+                      <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucket.server" />
+                    </li>
+                    <li>
+                      <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucket.creds" />
+                    </li>
+                    <li>
+                      <LabelValuePair
+                        translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucket.owner"
+                        value={projectBinding.repository}
+                      />
+                    </li>
+                    <li>
+                      <LabelValuePair
+                        translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucket.repo"
+                        value={projectBinding.slug}
+                      />
+                    </li>
+                  </>
+                )}
+                {isProjectGitHubBindingResponse(projectBinding) && (
+                  <>
+                    <li>
+                      <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.github.creds" />
+                    </li>
+                    <li>
+                      {isGithubBindingDefinition(almBinding) ? (
+                        <LabelValuePair
+                          translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.github.repo_url"
+                          value={buildGithubLink(almBinding, projectBinding)}
+                        />
+                      ) : (
+                        <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.github.repo_url" />
+                      )}
+                    </li>
+                  </>
+                )}
                 <li>
                   <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.behaviour" />
                 </li>
index 46da8b3a8c59e6349495232d5686c5fa3157a725..d70d167124e90db51da5bf102c06aeb4da5f455f 100644 (file)
@@ -23,10 +23,12 @@ import { Link } from 'react-router';
 import { Button } from 'sonar-ui-common/components/controls/buttons';
 import Checkbox from 'sonar-ui-common/components/controls/Checkbox';
 import { translate } from 'sonar-ui-common/helpers/l10n';
+import { AlmKeys } from '../../../types/alm-settings';
 import SentenceWithHighlights from '../components/SentenceWithHighlights';
 import Step from '../components/Step';
 
 export interface PreRequisitesStepProps {
+  alm: AlmKeys;
   onChangeSkipNextTime: (skip: boolean) => void;
   onDone: () => void;
   onOpen: () => void;
@@ -35,7 +37,7 @@ export interface PreRequisitesStepProps {
 }
 
 export default function PreRequisitesStep(props: PreRequisitesStepProps) {
-  const { open, skipNextTime } = props;
+  const { alm, open, skipNextTime } = props;
   return (
     <Step
       finished={!open}
@@ -50,7 +52,9 @@ export default function PreRequisitesStep(props: PreRequisitesStepProps) {
             />
           </p>
           <ul className="list-styled big-spacer-bottom">
-            <li>{translate('onboarding.tutorial.with.jenkins.prereqs.plugins.branch_source')}</li>
+            <li>
+              {translate('onboarding.tutorial.with.jenkins.prereqs.plugins.branch_source', alm)}
+            </li>
             <li>{translate('onboarding.tutorial.with.jenkins.prereqs.plugins.sonar_scanner')}</li>
           </ul>
           <p className="big-spacer-bottom">
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStep.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStep.tsx
new file mode 100644 (file)
index 0000000..60dfc61
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import * as React from 'react';
+import { FormattedMessage } from 'react-intl';
+import { Button, ButtonLink } from 'sonar-ui-common/components/controls/buttons';
+import { translate } from 'sonar-ui-common/helpers/l10n';
+import {
+  isBitbucketBindingDefinition,
+  isGithubBindingDefinition
+} from '../../../helpers/alm-settings';
+import {
+  AlmBindingDefinition,
+  AlmKeys,
+  ProjectAlmBindingResponse
+} from '../../../types/alm-settings';
+import Step from '../components/Step';
+import WebhookStepBitbucket from './WebhookStepBitbucket';
+import WebhookStepGithub from './WebhookStepGithub';
+
+export interface WebhookStepProps {
+  almBinding?: AlmBindingDefinition;
+  finished: boolean;
+  onDone: () => void;
+  onOpen: () => void;
+  open: boolean;
+  projectBinding: ProjectAlmBindingResponse;
+}
+
+function renderAlmSpecificInstructions(props: WebhookStepProps) {
+  const { almBinding, projectBinding } = props;
+
+  switch (projectBinding.alm) {
+    case AlmKeys.Bitbucket:
+      return (
+        <WebhookStepBitbucket
+          almBinding={isBitbucketBindingDefinition(almBinding) ? almBinding : undefined}
+          projectBinding={projectBinding}
+        />
+      );
+
+    case AlmKeys.GitHub:
+      return (
+        <WebhookStepGithub
+          almBinding={isGithubBindingDefinition(almBinding) ? almBinding : undefined}
+          projectBinding={projectBinding}
+        />
+      );
+
+    default:
+      return null;
+  }
+}
+
+export default function WebhookStep(props: WebhookStepProps) {
+  const { finished, open, projectBinding } = props;
+
+  return (
+    <Step
+      finished={finished}
+      onOpen={props.onOpen}
+      open={open}
+      renderForm={() => (
+        <div className="boxed-group-inner">
+          <p className="big-spacer-bottom">
+            <FormattedMessage
+              defaultMessage={translate('onboarding.tutorial.with.jenkins.webhook.intro.sentence')}
+              id="onboarding.tutorial.with.jenkins.webhook.intro.sentence"
+              values={{
+                link: (
+                  <ButtonLink onClick={props.onDone}>
+                    {translate('onboarding.tutorial.with.jenkins.webhook.intro.link')}
+                  </ButtonLink>
+                )
+              }}
+            />
+          </p>
+          <ol className="list-styled">{renderAlmSpecificInstructions(props)}</ol>
+          <Button onClick={props.onDone}>{translate('continue')}</Button>
+        </div>
+      )}
+      stepNumber={2}
+      stepTitle={translate('onboarding.tutorial.with.jenkins.webhook', projectBinding.alm, 'title')}
+    />
+  );
+}
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStepBitbucket.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStepBitbucket.tsx
new file mode 100644 (file)
index 0000000..b10c4c5
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import * as React from 'react';
+import { FormattedMessage } from 'react-intl';
+import { Alert } from 'sonar-ui-common/components/ui/Alert';
+import { translate } from 'sonar-ui-common/helpers/l10n';
+import { BitbucketBindingDefinition, ProjectAlmBindingResponse } from '../../../types/alm-settings';
+import CodeSnippet from '../../common/CodeSnippet';
+import LabelActionPair from '../components/LabelActionPair';
+import SentenceWithHighlights from '../components/SentenceWithHighlights';
+
+export interface WebhookStepBitbucketProps {
+  almBinding?: BitbucketBindingDefinition;
+  projectBinding: ProjectAlmBindingResponse;
+}
+
+function buildUrlSnippet(ownUrl = '***BITBUCKET_URL***') {
+  return `***JENKINS_URL***/bitbucket-scmsource-hook/notify?server_url=${ownUrl}`;
+}
+
+export default function WebhookStepBitbucket(props: WebhookStepBitbucketProps) {
+  const { almBinding, projectBinding } = props;
+
+  const linkUrl =
+    almBinding &&
+    `${almBinding.url}/plugins/servlet/webhooks/projects/${projectBinding.repository}/repos/${projectBinding.slug}/create`;
+
+  return (
+    <>
+      <li>
+        <FormattedMessage
+          defaultMessage={translate('onboarding.tutorial.with.jenkins.webhook.step1.sentence')}
+          id="onboarding.tutorial.with.jenkins.webhook.step1.sentence"
+          values={{
+            link: linkUrl ? (
+              <a href={linkUrl} rel="noopener noreferrer" target="_blank">
+                {translate('onboarding.tutorial.with.jenkins.webhook.bitbucket.step1.link')}
+              </a>
+            ) : (
+              translate('onboarding.tutorial.with.jenkins.webhook.bitbucket.step1.link')
+            )
+          }}
+        />
+        <ul className="list-styled">
+          <li>
+            <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.webhook.step1.name" />
+          </li>
+          <li className="abs-width-600">
+            <p>
+              <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.webhook.bitbucket.step1.url" />
+            </p>
+            <CodeSnippet isOneLine={true} snippet={buildUrlSnippet(almBinding && almBinding.url)} />
+            <Alert variant="info">
+              {translate('onboarding.tutorial.with.jenkins.webhook.bitbucket.step1.url.warning')}
+            </Alert>
+          </li>
+        </ul>
+      </li>
+      <li>
+        <SentenceWithHighlights
+          highlightKeys={['events']}
+          translationKey="onboarding.tutorial.with.jenkins.webhook.bitbucket.step2"
+        />
+        <ul className="list-styled">
+          <li>
+            <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.webhook.bitbucket.step2.repo" />
+          </li>
+          <li>
+            <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.webhook.bitbucket.step2.pr" />
+          </li>
+        </ul>
+      </li>
+      <li>
+        <SentenceWithHighlights
+          highlightKeys={['create']}
+          translationKey="onboarding.tutorial.with.jenkins.webhook.step3"
+        />
+      </li>
+    </>
+  );
+}
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStepGithub.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStepGithub.tsx
new file mode 100644 (file)
index 0000000..5c986e1
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import * as React from 'react';
+import { FormattedMessage } from 'react-intl';
+import { translate } from 'sonar-ui-common/helpers/l10n';
+import { GithubBindingDefinition, ProjectAlmBindingResponse } from '../../../types/alm-settings';
+import CodeSnippet from '../../common/CodeSnippet';
+import LabelActionPair from '../components/LabelActionPair';
+import SentenceWithHighlights from '../components/SentenceWithHighlights';
+import { buildGithubLink } from '../utils';
+
+export interface WebhookStepGithubProps {
+  almBinding?: GithubBindingDefinition;
+  projectBinding: ProjectAlmBindingResponse;
+}
+
+export default function WebhookStepGithub(props: WebhookStepGithubProps) {
+  const { almBinding, projectBinding } = props;
+
+  const linkUrl = almBinding && `${buildGithubLink(almBinding, projectBinding)}/settings/hooks`;
+
+  return (
+    <>
+      <li>
+        <FormattedMessage
+          defaultMessage={translate('onboarding.tutorial.with.jenkins.webhook.step1.sentence')}
+          id="onboarding.tutorial.with.jenkins.webhook.step1.sentence"
+          values={{
+            link: linkUrl ? (
+              <a href={linkUrl} rel="noopener noreferrer" target="_blank">
+                {translate('onboarding.tutorial.with.jenkins.webhook.github.step1.link')}
+              </a>
+            ) : (
+              translate('onboarding.tutorial.with.jenkins.webhook.github.step1.link')
+            )
+          }}
+        />
+        <ul className="list-styled">
+          <li className="abs-width-600">
+            <p>
+              <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.webhook.github.step1.url" />
+            </p>
+            <CodeSnippet isOneLine={true} snippet="/github-webhook/" />
+          </li>
+        </ul>
+      </li>
+      <li>
+        <SentenceWithHighlights
+          highlightKeys={['events', 'option']}
+          translationKey="onboarding.tutorial.with.jenkins.webhook.github.step2"
+        />
+        <ul className="list-styled">
+          <li>
+            <strong>
+              {translate('onboarding.tutorial.with.jenkins.webhook.github.step2.repo')}
+            </strong>
+          </li>
+          <li>
+            <strong>{translate('onboarding.tutorial.with.jenkins.webhook.github.step2.pr')}</strong>
+          </li>
+        </ul>
+      </li>
+      <li>
+        <SentenceWithHighlights
+          highlightKeys={['create']}
+          translationKey="onboarding.tutorial.with.jenkins.webhook.step3"
+        />
+      </li>
+    </>
+  );
+}
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/BitbucketWebhookStep-test.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/BitbucketWebhookStep-test.tsx
deleted file mode 100644 (file)
index 6b9ed13..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import {
-  mockBitbucketBindingDefinition,
-  mockProjectBitbucketBindingGet
-} from '../../../../helpers/mocks/alm-settings';
-import BitbucketWebhookStep, { BitbucketWebhookStepProps } from '../BitbucketWebhookStep';
-import { renderStepContent } from '../test-utils';
-
-it('should render correctly', () => {
-  const wrapper = shallowRender();
-  expect(wrapper).toMatchSnapshot('Step wrapper');
-  expect(renderStepContent(wrapper)).toMatchSnapshot('content');
-  expect(renderStepContent(wrapper.setProps({ almBinding: undefined }))).toMatchSnapshot(
-    'no alm binding'
-  );
-});
-
-function shallowRender(props: Partial<BitbucketWebhookStepProps> = {}) {
-  return shallow<BitbucketWebhookStepProps>(
-    <BitbucketWebhookStep
-      almBinding={mockBitbucketBindingDefinition()}
-      finished={false}
-      onDone={jest.fn()}
-      onOpen={jest.fn()}
-      open={true}
-      projectBinding={mockProjectBitbucketBindingGet()}
-      {...props}
-    />
-  );
-}
index b87fa44d764980271297ed4f0fa5290cd0f62a59..792184c3255d35bf75141770371ea84ad5db4753 100644 (file)
@@ -22,20 +22,21 @@ import { shallow } from 'enzyme';
 import * as React from 'react';
 import {
   mockProjectAlmBindingResponse,
-  mockProjectBitbucketBindingGet
+  mockProjectBitbucketBindingResponse
 } from '../../../../helpers/mocks/alm-settings';
 import { mockComponent } from '../../../../helpers/testMocks';
-import BitbucketWebhookStep from '../BitbucketWebhookStep';
+import { AlmKeys } from '../../../../types/alm-settings';
 import JenkinsfileStep from '../JenkinsfileStep';
 import { JenkinsTutorial, JenkinsTutorialProps } from '../JenkinsTutorial';
 import MultiBranchPipelineStep from '../MultiBranchPipelineStep';
 import PreRequisitesStep from '../PreRequisitesStep';
+import WebhookStep from '../WebhookStep';
 
 it('should render correctly', () => {
   expect(shallowRender()).toMatchSnapshot('default');
-  expect(shallowRender({ projectBinding: mockProjectAlmBindingResponse() })).toMatchSnapshot(
-    'not Bitbucket binding'
-  );
+  expect(
+    shallowRender({ projectBinding: mockProjectAlmBindingResponse({ alm: AlmKeys.Azure }) })
+  ).toMatchSnapshot('unsupported alm');
 });
 
 it('should correctly navigate between steps', () => {
@@ -43,28 +44,28 @@ it('should correctly navigate between steps', () => {
 
   expect(wrapper.find(PreRequisitesStep).prop('open')).toBe(true);
   expect(wrapper.find(MultiBranchPipelineStep).prop('open')).toBe(false);
-  expect(wrapper.find(BitbucketWebhookStep).prop('open')).toBe(false);
+  expect(wrapper.find(WebhookStep).prop('open')).toBe(false);
   expect(wrapper.find(JenkinsfileStep).prop('open')).toBe(false);
 
   // Pre-reqs done.
   wrapper.find(PreRequisitesStep).prop('onDone')();
   expect(wrapper.find(PreRequisitesStep).prop('open')).toBe(false);
   expect(wrapper.find(MultiBranchPipelineStep).prop('open')).toBe(true);
-  expect(wrapper.find(BitbucketWebhookStep).prop('open')).toBe(false);
+  expect(wrapper.find(WebhookStep).prop('open')).toBe(false);
   expect(wrapper.find(JenkinsfileStep).prop('open')).toBe(false);
 
   // Multibranch done.
   wrapper.find(MultiBranchPipelineStep).prop('onDone')();
   expect(wrapper.find(PreRequisitesStep).prop('open')).toBe(false);
   expect(wrapper.find(MultiBranchPipelineStep).prop('open')).toBe(false);
-  expect(wrapper.find(BitbucketWebhookStep).prop('open')).toBe(true);
+  expect(wrapper.find(WebhookStep).prop('open')).toBe(true);
   expect(wrapper.find(JenkinsfileStep).prop('open')).toBe(false);
 
   // Webhook done.
-  wrapper.find(BitbucketWebhookStep).prop('onDone')();
+  wrapper.find(WebhookStep).prop('onDone')();
   expect(wrapper.find(PreRequisitesStep).prop('open')).toBe(false);
   expect(wrapper.find(MultiBranchPipelineStep).prop('open')).toBe(false);
-  expect(wrapper.find(BitbucketWebhookStep).prop('open')).toBe(false);
+  expect(wrapper.find(WebhookStep).prop('open')).toBe(false);
   expect(wrapper.find(JenkinsfileStep).prop('open')).toBe(true);
 
   // Open Pre-reqs.
@@ -76,8 +77,8 @@ it('should correctly navigate between steps', () => {
   expect(wrapper.find(MultiBranchPipelineStep).prop('open')).toBe(true);
 
   // Open Webhook.
-  wrapper.find(BitbucketWebhookStep).prop('onOpen')();
-  expect(wrapper.find(BitbucketWebhookStep).prop('open')).toBe(true);
+  wrapper.find(WebhookStep).prop('onOpen')();
+  expect(wrapper.find(WebhookStep).prop('open')).toBe(true);
 });
 
 it('should correctly store the user setting', () => {
@@ -107,7 +108,7 @@ function shallowRender(props: Partial<JenkinsTutorialProps> = {}) {
   return shallow<JenkinsTutorialProps>(
     <JenkinsTutorial
       component={mockComponent()}
-      projectBinding={mockProjectBitbucketBindingGet()}
+      projectBinding={mockProjectBitbucketBindingResponse()}
       setCurrentUserSetting={jest.fn()}
       skipPreReqs={false}
       {...props}
index 85f5e7e7e15713975028d1b6a3b7465235e37438..51bf46c790febfd1368524f35f7902fd9d7ed1ea 100644 (file)
 
 import { shallow } from 'enzyme';
 import * as React from 'react';
-import { mockProjectBitbucketBindingGet } from '../../../../helpers/mocks/alm-settings';
+import {
+  mockProjectBitbucketBindingResponse,
+  mockProjectGithubBindingResponse
+} from '../../../../helpers/mocks/alm-settings';
 import MultiBranchPipelineStep, { MultiBranchPipelineStepProps } from '../MultiBranchPipelineStep';
 import { renderStepContent } from '../test-utils';
 
 it('should render correctly', () => {
   const wrapper = shallowRender();
   expect(wrapper).toMatchSnapshot('Step wrapper');
-  expect(renderStepContent(wrapper)).toMatchSnapshot('content');
+  expect(renderStepContent(wrapper)).toMatchSnapshot('content for bitbucket');
+  expect(
+    renderStepContent(shallowRender({ projectBinding: mockProjectGithubBindingResponse() }))
+  ).toMatchSnapshot('content for github');
 });
 
 function shallowRender(props: Partial<MultiBranchPipelineStepProps> = {}) {
@@ -37,7 +43,7 @@ function shallowRender(props: Partial<MultiBranchPipelineStepProps> = {}) {
       onDone={jest.fn()}
       onOpen={jest.fn()}
       open={true}
-      projectBinding={mockProjectBitbucketBindingGet()}
+      projectBinding={mockProjectBitbucketBindingResponse()}
       {...props}
     />
   );
index 7bb73a2eb81d16b19362608db6a69196cdbb214e..3da21ab208270d2fb4e9f232e80b1266df9f03f1 100644 (file)
@@ -20,6 +20,7 @@
 
 import { shallow } from 'enzyme';
 import * as React from 'react';
+import { AlmKeys } from '../../../../types/alm-settings';
 import PreRequisitesStep, { PreRequisitesStepProps } from '../PreRequisitesStep';
 import { renderStepContent } from '../test-utils';
 
@@ -32,6 +33,7 @@ it('should render correctly', () => {
 function shallowRender(props: Partial<PreRequisitesStepProps> = {}) {
   return shallow<PreRequisitesStepProps>(
     <PreRequisitesStep
+      alm={AlmKeys.Bitbucket}
       onChangeSkipNextTime={jest.fn()}
       onDone={jest.fn()}
       onOpen={jest.fn()}
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/WebhookStep-test.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/WebhookStep-test.tsx
new file mode 100644 (file)
index 0000000..80bffaa
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+import { shallow } from 'enzyme';
+import * as React from 'react';
+import {
+  mockAzureBindingDefinition,
+  mockBitbucketBindingDefinition,
+  mockGithubBindingDefinition,
+  mockGitlabBindingDefinition,
+  mockProjectAlmBindingResponse,
+  mockProjectBitbucketBindingResponse,
+  mockProjectGithubBindingResponse
+} from '../../../../helpers/mocks/alm-settings';
+import { AlmKeys } from '../../../../types/alm-settings';
+import { renderStepContent } from '../test-utils';
+import WebhookStep, { WebhookStepProps } from '../WebhookStep';
+
+it.each([
+  [
+    AlmKeys.Azure,
+    mockAzureBindingDefinition(),
+    mockProjectAlmBindingResponse({ alm: AlmKeys.Azure })
+  ],
+  [AlmKeys.Bitbucket, mockBitbucketBindingDefinition(), mockProjectBitbucketBindingResponse()],
+  [AlmKeys.GitHub, mockGithubBindingDefinition(), mockProjectGithubBindingResponse()],
+  [
+    AlmKeys.GitLab,
+    mockGitlabBindingDefinition(),
+    mockProjectAlmBindingResponse({ alm: AlmKeys.GitLab })
+  ]
+])('it should render correctly for %s', (_, almBinding, projectBinding) => {
+  const wrapper = shallowRender({ almBinding, projectBinding });
+  expect(wrapper).toMatchSnapshot('wrapper');
+  expect(renderStepContent(wrapper)).toMatchSnapshot('content');
+});
+
+function shallowRender(props: Partial<WebhookStepProps> = {}) {
+  return shallow<WebhookStepProps>(
+    <WebhookStep
+      almBinding={mockBitbucketBindingDefinition()}
+      finished={false}
+      onDone={jest.fn()}
+      onOpen={jest.fn()}
+      open={false}
+      projectBinding={mockProjectBitbucketBindingResponse()}
+      {...props}
+    />
+  );
+}
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/WebhookStepBitbucket-test.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/WebhookStepBitbucket-test.tsx
new file mode 100644 (file)
index 0000000..df8ce0b
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+import { shallow } from 'enzyme';
+import * as React from 'react';
+import {
+  mockBitbucketBindingDefinition,
+  mockProjectBitbucketBindingResponse
+} from '../../../../helpers/mocks/alm-settings';
+import WebhookStepBitbucket, { WebhookStepBitbucketProps } from '../WebhookStepBitbucket';
+
+it('should render correctly', () => {
+  expect(shallowRender()).toMatchSnapshot();
+  expect(shallowRender({ almBinding: undefined })).toMatchSnapshot('with no alm binding');
+});
+
+function shallowRender(props: Partial<WebhookStepBitbucketProps> = {}) {
+  return shallow<WebhookStepBitbucketProps>(
+    <WebhookStepBitbucket
+      almBinding={mockBitbucketBindingDefinition()}
+      projectBinding={mockProjectBitbucketBindingResponse()}
+      {...props}
+    />
+  );
+}
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/WebhookStepGithub-test.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/WebhookStepGithub-test.tsx
new file mode 100644 (file)
index 0000000..b7e287f
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+import { shallow } from 'enzyme';
+import * as React from 'react';
+import {
+  mockGithubBindingDefinition,
+  mockProjectGithubBindingResponse
+} from '../../../../helpers/mocks/alm-settings';
+import WebhookStepGithub, { WebhookStepGithubProps } from '../WebhookStepGithub';
+
+it('should render correctly', () => {
+  expect(shallowRender()).toMatchSnapshot();
+  expect(shallowRender({ almBinding: undefined })).toMatchSnapshot('with no alm binding');
+});
+
+function shallowRender(props: Partial<WebhookStepGithubProps> = {}) {
+  return shallow<WebhookStepGithubProps>(
+    <WebhookStepGithub
+      almBinding={mockGithubBindingDefinition()}
+      projectBinding={mockProjectGithubBindingResponse()}
+      {...props}
+    />
+  );
+}
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/BitbucketWebhookStep-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/BitbucketWebhookStep-test.tsx.snap
deleted file mode 100644 (file)
index c736b26..0000000
+++ /dev/null
@@ -1,228 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly: Step wrapper 1`] = `
-<Step
-  finished={false}
-  onOpen={[MockFunction]}
-  open={true}
-  renderForm={[Function]}
-  stepNumber={2}
-  stepTitle="onboarding.tutorial.with.jenkins.bitbucket_webhook.title"
-/>
-`;
-
-exports[`should render correctly: content 1`] = `
-<div
-  className="boxed-group-inner"
->
-  <p
-    className="big-spacer-bottom"
-  >
-    <FormattedMessage
-      defaultMessage="onboarding.tutorial.with.jenkins.bitbucket_webhook.intro.sentence"
-      id="onboarding.tutorial.with.jenkins.bitbucket_webhook.intro.sentence"
-      values={
-        Object {
-          "link": <ButtonLink
-            onClick={[MockFunction]}
-          >
-            onboarding.tutorial.with.jenkins.bitbucket_webhook.intro.link
-          </ButtonLink>,
-        }
-      }
-    />
-  </p>
-  <ol
-    className="list-styled"
-  >
-    <li>
-      <FormattedMessage
-        defaultMessage="onboarding.tutorial.with.jenkins.bitbucket_webhook.step1.sentence"
-        id="onboarding.tutorial.with.jenkins.bitbucket_webhook.step1.sentence"
-        values={
-          Object {
-            "link": <a
-              href="http://bbs.enterprise.com/plugins/servlet/webhooks/projects/PROJECT_KEY/repos/repo-slug/create"
-              rel="noopener noreferrer"
-              target="_blank"
-            >
-              onboarding.tutorial.with.jenkins.bitbucket_webhook.step1.link
-            </a>,
-          }
-        }
-      />
-      <ul
-        className="list-styled"
-      >
-        <li>
-          <LabelActionPair
-            translationKey="onboarding.tutorial.with.jenkins.bitbucket_webhook.step1.name"
-          />
-        </li>
-        <li
-          className="abs-width-600"
-        >
-          <p>
-            <LabelActionPair
-              translationKey="onboarding.tutorial.with.jenkins.bitbucket_webhook.step1.url"
-            />
-          </p>
-          <CodeSnippet
-            isOneLine={true}
-            snippet="***JENKINS_URL***/bitbucket-scmsource-hook/notify?server_url=http://bbs.enterprise.com"
-          />
-          <Alert
-            variant="info"
-          >
-            onboarding.tutorial.with.jenkins.bitbucket_webhook.step1.url.warning
-          </Alert>
-        </li>
-      </ul>
-    </li>
-    <li>
-      <SentenceWithHighlights
-        highlightKeys={
-          Array [
-            "events",
-          ]
-        }
-        translationKey="onboarding.tutorial.with.jenkins.bitbucket_webhook.step2"
-      />
-      <ul
-        className="list-styled"
-      >
-        <li>
-          <LabelActionPair
-            translationKey="onboarding.tutorial.with.jenkins.bitbucket_webhook.step2.repo"
-          />
-        </li>
-        <li>
-          <LabelActionPair
-            translationKey="onboarding.tutorial.with.jenkins.bitbucket_webhook.step2.pr"
-          />
-        </li>
-      </ul>
-    </li>
-    <li>
-      <SentenceWithHighlights
-        highlightKeys={
-          Array [
-            "create",
-          ]
-        }
-        translationKey="onboarding.tutorial.with.jenkins.bitbucket_webhook.step3"
-      />
-    </li>
-  </ol>
-  <Button
-    onClick={[MockFunction]}
-  >
-    continue
-  </Button>
-</div>
-`;
-
-exports[`should render correctly: no alm binding 1`] = `
-<div
-  className="boxed-group-inner"
->
-  <p
-    className="big-spacer-bottom"
-  >
-    <FormattedMessage
-      defaultMessage="onboarding.tutorial.with.jenkins.bitbucket_webhook.intro.sentence"
-      id="onboarding.tutorial.with.jenkins.bitbucket_webhook.intro.sentence"
-      values={
-        Object {
-          "link": <ButtonLink
-            onClick={[MockFunction]}
-          >
-            onboarding.tutorial.with.jenkins.bitbucket_webhook.intro.link
-          </ButtonLink>,
-        }
-      }
-    />
-  </p>
-  <ol
-    className="list-styled"
-  >
-    <li>
-      <FormattedMessage
-        defaultMessage="onboarding.tutorial.with.jenkins.bitbucket_webhook.step1.sentence"
-        id="onboarding.tutorial.with.jenkins.bitbucket_webhook.step1.sentence"
-        values={
-          Object {
-            "link": "onboarding.tutorial.with.jenkins.bitbucket_webhook.step1.link",
-          }
-        }
-      />
-      <ul
-        className="list-styled"
-      >
-        <li>
-          <LabelActionPair
-            translationKey="onboarding.tutorial.with.jenkins.bitbucket_webhook.step1.name"
-          />
-        </li>
-        <li
-          className="abs-width-600"
-        >
-          <p>
-            <LabelActionPair
-              translationKey="onboarding.tutorial.with.jenkins.bitbucket_webhook.step1.url"
-            />
-          </p>
-          <CodeSnippet
-            isOneLine={true}
-            snippet="***JENKINS_URL***/bitbucket-scmsource-hook/notify?server_url=***BITBUCKET_URL***"
-          />
-          <Alert
-            variant="info"
-          >
-            onboarding.tutorial.with.jenkins.bitbucket_webhook.step1.url.warning
-          </Alert>
-        </li>
-      </ul>
-    </li>
-    <li>
-      <SentenceWithHighlights
-        highlightKeys={
-          Array [
-            "events",
-          ]
-        }
-        translationKey="onboarding.tutorial.with.jenkins.bitbucket_webhook.step2"
-      />
-      <ul
-        className="list-styled"
-      >
-        <li>
-          <LabelActionPair
-            translationKey="onboarding.tutorial.with.jenkins.bitbucket_webhook.step2.repo"
-          />
-        </li>
-        <li>
-          <LabelActionPair
-            translationKey="onboarding.tutorial.with.jenkins.bitbucket_webhook.step2.pr"
-          />
-        </li>
-      </ul>
-    </li>
-    <li>
-      <SentenceWithHighlights
-        highlightKeys={
-          Array [
-            "create",
-          ]
-        }
-        translationKey="onboarding.tutorial.with.jenkins.bitbucket_webhook.step3"
-      />
-    </li>
-  </ol>
-  <Button
-    onClick={[MockFunction]}
-  >
-    continue
-  </Button>
-</div>
-`;
index 65604e9096db62cd97c7c15bbfb205052d48cbee..11668639affa7545ed846aa7f39126f48414127e 100644 (file)
@@ -12,6 +12,7 @@ exports[`should render correctly: default 1`] = `
     </h1>
   </div>
   <PreRequisitesStep
+    alm="bitbucket"
     onChangeSkipNextTime={[Function]}
     onDone={[Function]}
     onOpen={[Function]}
@@ -32,7 +33,7 @@ exports[`should render correctly: default 1`] = `
       }
     }
   />
-  <BitbucketWebhookStep
+  <WebhookStep
     finished={false}
     onDone={[Function]}
     onOpen={[Function]}
@@ -75,10 +76,10 @@ exports[`should render correctly: default 1`] = `
 </Fragment>
 `;
 
-exports[`should render correctly: not Bitbucket binding 1`] = `
+exports[`should render correctly: unsupported alm 1`] = `
 <Alert
   variant="error"
 >
-  onboarding.tutorial.with.jenkins.only_bitbucket
+  onboarding.tutorial.with.jenkins.unsupported
 </Alert>
 `;
index ba91752f0fc15adc633834d0a154e51fef271e1a..cab0b2febbae16cd8d5b30b92b38b58b7cc6addf 100644 (file)
@@ -11,7 +11,7 @@ exports[`should render correctly: Step wrapper 1`] = `
 />
 `;
 
-exports[`should render correctly: content 1`] = `
+exports[`should render correctly: content for bitbucket 1`] = `
 <div
   className="boxed-group-inner"
 >
@@ -41,33 +41,132 @@ exports[`should render correctly: content 1`] = `
             "tab",
           ]
         }
-        translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2"
+        translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucket"
       />
       <ul
         className="list-styled"
       >
+        <React.Fragment>
+          <li>
+            <LabelActionPair
+              translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucket.server"
+            />
+          </li>
+          <li>
+            <LabelActionPair
+              translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucket.creds"
+            />
+          </li>
+          <li>
+            <LabelValuePair
+              translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucket.owner"
+              value="PROJECT_KEY"
+            />
+          </li>
+          <li>
+            <LabelValuePair
+              translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucket.repo"
+              value="repo-slug"
+            />
+          </li>
+        </React.Fragment>
         <li>
           <LabelActionPair
-            translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.server"
+            translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.behaviour"
           />
         </li>
+      </ul>
+    </li>
+    <li>
+      <SentenceWithHighlights
+        highlightKeys={
+          Array [
+            "tab",
+          ]
+        }
+        translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step3"
+      />
+      <ul
+        className="list-styled"
+      >
         <li>
           <LabelActionPair
-            translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.creds"
-          />
-        </li>
-        <li>
-          <LabelValuePair
-            translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.owner"
-            value="PROJECT_KEY"
+            translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step3.mode"
           />
         </li>
         <li>
-          <LabelValuePair
-            translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.repo"
-            value="repo-slug"
+          <LabelActionPair
+            translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step3.script_path"
           />
         </li>
+      </ul>
+    </li>
+    <li>
+      <SentenceWithHighlights
+        highlightKeys={
+          Array [
+            "save",
+          ]
+        }
+        translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step4"
+      />
+    </li>
+  </ol>
+  <Button
+    onClick={[MockFunction]}
+  >
+    continue
+  </Button>
+</div>
+`;
+
+exports[`should render correctly: content for github 1`] = `
+<div
+  className="boxed-group-inner"
+>
+  <p
+    className="big-spacer-bottom"
+  >
+    onboarding.tutorial.with.jenkins.multi_branch_pipeline.intro
+  </p>
+  <ol
+    className="list-styled"
+  >
+    <li>
+      <SentenceWithHighlights
+        highlightKeys={
+          Array [
+            "new_item",
+            "type",
+          ]
+        }
+        translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step1"
+      />
+    </li>
+    <li>
+      <SentenceWithHighlights
+        highlightKeys={
+          Array [
+            "tab",
+          ]
+        }
+        translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.github"
+      />
+      <ul
+        className="list-styled"
+      >
+        <React.Fragment>
+          <li>
+            <LabelActionPair
+              translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.github.creds"
+            />
+          </li>
+          <li>
+            <LabelActionPair
+              translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.github.repo_url"
+            />
+          </li>
+        </React.Fragment>
         <li>
           <LabelActionPair
             translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.behaviour"
index 184bd18139584bff536aa69b97b2ebc650813cd8..4e673fc52d45e959673adc6f3c7f9a9087def874 100644 (file)
@@ -30,7 +30,7 @@ exports[`should render correctly: content 1`] = `
     className="list-styled big-spacer-bottom"
   >
     <li>
-      onboarding.tutorial.with.jenkins.prereqs.plugins.branch_source
+      onboarding.tutorial.with.jenkins.prereqs.plugins.branch_source.bitbucket
     </li>
     <li>
       onboarding.tutorial.with.jenkins.prereqs.plugins.sonar_scanner
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/WebhookStep-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/WebhookStep-test.tsx.snap
new file mode 100644 (file)
index 0000000..0acde32
--- /dev/null
@@ -0,0 +1,211 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`it should render correctly for azure: content 1`] = `
+<div
+  className="boxed-group-inner"
+>
+  <p
+    className="big-spacer-bottom"
+  >
+    <FormattedMessage
+      defaultMessage="onboarding.tutorial.with.jenkins.webhook.intro.sentence"
+      id="onboarding.tutorial.with.jenkins.webhook.intro.sentence"
+      values={
+        Object {
+          "link": <ButtonLink
+            onClick={[MockFunction]}
+          >
+            onboarding.tutorial.with.jenkins.webhook.intro.link
+          </ButtonLink>,
+        }
+      }
+    />
+  </p>
+  <ol
+    className="list-styled"
+  />
+  <Button
+    onClick={[MockFunction]}
+  >
+    continue
+  </Button>
+</div>
+`;
+
+exports[`it should render correctly for azure: wrapper 1`] = `
+<Step
+  finished={false}
+  onOpen={[MockFunction]}
+  open={false}
+  renderForm={[Function]}
+  stepNumber={2}
+  stepTitle="onboarding.tutorial.with.jenkins.webhook.azure.title"
+/>
+`;
+
+exports[`it should render correctly for bitbucket: content 1`] = `
+<div
+  className="boxed-group-inner"
+>
+  <p
+    className="big-spacer-bottom"
+  >
+    <FormattedMessage
+      defaultMessage="onboarding.tutorial.with.jenkins.webhook.intro.sentence"
+      id="onboarding.tutorial.with.jenkins.webhook.intro.sentence"
+      values={
+        Object {
+          "link": <ButtonLink
+            onClick={[MockFunction]}
+          >
+            onboarding.tutorial.with.jenkins.webhook.intro.link
+          </ButtonLink>,
+        }
+      }
+    />
+  </p>
+  <ol
+    className="list-styled"
+  >
+    <WebhookStepBitbucket
+      almBinding={
+        Object {
+          "key": "key",
+          "personalAccessToken": "asdf1234",
+          "url": "http://bbs.enterprise.com",
+        }
+      }
+      projectBinding={
+        Object {
+          "alm": "bitbucket",
+          "key": "foo",
+          "repository": "PROJECT_KEY",
+          "slug": "repo-slug",
+        }
+      }
+    />
+  </ol>
+  <Button
+    onClick={[MockFunction]}
+  >
+    continue
+  </Button>
+</div>
+`;
+
+exports[`it should render correctly for bitbucket: wrapper 1`] = `
+<Step
+  finished={false}
+  onOpen={[MockFunction]}
+  open={false}
+  renderForm={[Function]}
+  stepNumber={2}
+  stepTitle="onboarding.tutorial.with.jenkins.webhook.bitbucket.title"
+/>
+`;
+
+exports[`it should render correctly for github: content 1`] = `
+<div
+  className="boxed-group-inner"
+>
+  <p
+    className="big-spacer-bottom"
+  >
+    <FormattedMessage
+      defaultMessage="onboarding.tutorial.with.jenkins.webhook.intro.sentence"
+      id="onboarding.tutorial.with.jenkins.webhook.intro.sentence"
+      values={
+        Object {
+          "link": <ButtonLink
+            onClick={[MockFunction]}
+          >
+            onboarding.tutorial.with.jenkins.webhook.intro.link
+          </ButtonLink>,
+        }
+      }
+    />
+  </p>
+  <ol
+    className="list-styled"
+  >
+    <WebhookStepGithub
+      almBinding={
+        Object {
+          "appId": "123456",
+          "clientId": "client1",
+          "clientSecret": "**clientsecret**",
+          "key": "key",
+          "privateKey": "asdf1234",
+          "url": "http://github.enterprise.com",
+        }
+      }
+      projectBinding={
+        Object {
+          "alm": "github",
+          "key": "foo",
+          "repository": "PROJECT_KEY",
+        }
+      }
+    />
+  </ol>
+  <Button
+    onClick={[MockFunction]}
+  >
+    continue
+  </Button>
+</div>
+`;
+
+exports[`it should render correctly for github: wrapper 1`] = `
+<Step
+  finished={false}
+  onOpen={[MockFunction]}
+  open={false}
+  renderForm={[Function]}
+  stepNumber={2}
+  stepTitle="onboarding.tutorial.with.jenkins.webhook.github.title"
+/>
+`;
+
+exports[`it should render correctly for gitlab: content 1`] = `
+<div
+  className="boxed-group-inner"
+>
+  <p
+    className="big-spacer-bottom"
+  >
+    <FormattedMessage
+      defaultMessage="onboarding.tutorial.with.jenkins.webhook.intro.sentence"
+      id="onboarding.tutorial.with.jenkins.webhook.intro.sentence"
+      values={
+        Object {
+          "link": <ButtonLink
+            onClick={[MockFunction]}
+          >
+            onboarding.tutorial.with.jenkins.webhook.intro.link
+          </ButtonLink>,
+        }
+      }
+    />
+  </p>
+  <ol
+    className="list-styled"
+  />
+  <Button
+    onClick={[MockFunction]}
+  >
+    continue
+  </Button>
+</div>
+`;
+
+exports[`it should render correctly for gitlab: wrapper 1`] = `
+<Step
+  finished={false}
+  onOpen={[MockFunction]}
+  open={false}
+  renderForm={[Function]}
+  stepNumber={2}
+  stepTitle="onboarding.tutorial.with.jenkins.webhook.gitlab.title"
+/>
+`;
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/WebhookStepBitbucket-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/WebhookStepBitbucket-test.tsx.snap
new file mode 100644 (file)
index 0000000..650389b
--- /dev/null
@@ -0,0 +1,161 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<Fragment>
+  <li>
+    <FormattedMessage
+      defaultMessage="onboarding.tutorial.with.jenkins.webhook.step1.sentence"
+      id="onboarding.tutorial.with.jenkins.webhook.step1.sentence"
+      values={
+        Object {
+          "link": <a
+            href="http://bbs.enterprise.com/plugins/servlet/webhooks/projects/PROJECT_KEY/repos/repo-slug/create"
+            rel="noopener noreferrer"
+            target="_blank"
+          >
+            onboarding.tutorial.with.jenkins.webhook.bitbucket.step1.link
+          </a>,
+        }
+      }
+    />
+    <ul
+      className="list-styled"
+    >
+      <li>
+        <LabelActionPair
+          translationKey="onboarding.tutorial.with.jenkins.webhook.step1.name"
+        />
+      </li>
+      <li
+        className="abs-width-600"
+      >
+        <p>
+          <LabelActionPair
+            translationKey="onboarding.tutorial.with.jenkins.webhook.bitbucket.step1.url"
+          />
+        </p>
+        <CodeSnippet
+          isOneLine={true}
+          snippet="***JENKINS_URL***/bitbucket-scmsource-hook/notify?server_url=http://bbs.enterprise.com"
+        />
+        <Alert
+          variant="info"
+        >
+          onboarding.tutorial.with.jenkins.webhook.bitbucket.step1.url.warning
+        </Alert>
+      </li>
+    </ul>
+  </li>
+  <li>
+    <SentenceWithHighlights
+      highlightKeys={
+        Array [
+          "events",
+        ]
+      }
+      translationKey="onboarding.tutorial.with.jenkins.webhook.bitbucket.step2"
+    />
+    <ul
+      className="list-styled"
+    >
+      <li>
+        <LabelActionPair
+          translationKey="onboarding.tutorial.with.jenkins.webhook.bitbucket.step2.repo"
+        />
+      </li>
+      <li>
+        <LabelActionPair
+          translationKey="onboarding.tutorial.with.jenkins.webhook.bitbucket.step2.pr"
+        />
+      </li>
+    </ul>
+  </li>
+  <li>
+    <SentenceWithHighlights
+      highlightKeys={
+        Array [
+          "create",
+        ]
+      }
+      translationKey="onboarding.tutorial.with.jenkins.webhook.step3"
+    />
+  </li>
+</Fragment>
+`;
+
+exports[`should render correctly: with no alm binding 1`] = `
+<Fragment>
+  <li>
+    <FormattedMessage
+      defaultMessage="onboarding.tutorial.with.jenkins.webhook.step1.sentence"
+      id="onboarding.tutorial.with.jenkins.webhook.step1.sentence"
+      values={
+        Object {
+          "link": "onboarding.tutorial.with.jenkins.webhook.bitbucket.step1.link",
+        }
+      }
+    />
+    <ul
+      className="list-styled"
+    >
+      <li>
+        <LabelActionPair
+          translationKey="onboarding.tutorial.with.jenkins.webhook.step1.name"
+        />
+      </li>
+      <li
+        className="abs-width-600"
+      >
+        <p>
+          <LabelActionPair
+            translationKey="onboarding.tutorial.with.jenkins.webhook.bitbucket.step1.url"
+          />
+        </p>
+        <CodeSnippet
+          isOneLine={true}
+          snippet="***JENKINS_URL***/bitbucket-scmsource-hook/notify?server_url=***BITBUCKET_URL***"
+        />
+        <Alert
+          variant="info"
+        >
+          onboarding.tutorial.with.jenkins.webhook.bitbucket.step1.url.warning
+        </Alert>
+      </li>
+    </ul>
+  </li>
+  <li>
+    <SentenceWithHighlights
+      highlightKeys={
+        Array [
+          "events",
+        ]
+      }
+      translationKey="onboarding.tutorial.with.jenkins.webhook.bitbucket.step2"
+    />
+    <ul
+      className="list-styled"
+    >
+      <li>
+        <LabelActionPair
+          translationKey="onboarding.tutorial.with.jenkins.webhook.bitbucket.step2.repo"
+        />
+      </li>
+      <li>
+        <LabelActionPair
+          translationKey="onboarding.tutorial.with.jenkins.webhook.bitbucket.step2.pr"
+        />
+      </li>
+    </ul>
+  </li>
+  <li>
+    <SentenceWithHighlights
+      highlightKeys={
+        Array [
+          "create",
+        ]
+      }
+      translationKey="onboarding.tutorial.with.jenkins.webhook.step3"
+    />
+  </li>
+</Fragment>
+`;
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/WebhookStepGithub-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/WebhookStepGithub-test.tsx.snap
new file mode 100644 (file)
index 0000000..86134f7
--- /dev/null
@@ -0,0 +1,143 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<Fragment>
+  <li>
+    <FormattedMessage
+      defaultMessage="onboarding.tutorial.with.jenkins.webhook.step1.sentence"
+      id="onboarding.tutorial.with.jenkins.webhook.step1.sentence"
+      values={
+        Object {
+          "link": <a
+            href="http://github.enterprise.com/PROJECT_KEY/settings/hooks"
+            rel="noopener noreferrer"
+            target="_blank"
+          >
+            onboarding.tutorial.with.jenkins.webhook.github.step1.link
+          </a>,
+        }
+      }
+    />
+    <ul
+      className="list-styled"
+    >
+      <li
+        className="abs-width-600"
+      >
+        <p>
+          <LabelActionPair
+            translationKey="onboarding.tutorial.with.jenkins.webhook.github.step1.url"
+          />
+        </p>
+        <CodeSnippet
+          isOneLine={true}
+          snippet="/github-webhook/"
+        />
+      </li>
+    </ul>
+  </li>
+  <li>
+    <SentenceWithHighlights
+      highlightKeys={
+        Array [
+          "events",
+          "option",
+        ]
+      }
+      translationKey="onboarding.tutorial.with.jenkins.webhook.github.step2"
+    />
+    <ul
+      className="list-styled"
+    >
+      <li>
+        <strong>
+          onboarding.tutorial.with.jenkins.webhook.github.step2.repo
+        </strong>
+      </li>
+      <li>
+        <strong>
+          onboarding.tutorial.with.jenkins.webhook.github.step2.pr
+        </strong>
+      </li>
+    </ul>
+  </li>
+  <li>
+    <SentenceWithHighlights
+      highlightKeys={
+        Array [
+          "create",
+        ]
+      }
+      translationKey="onboarding.tutorial.with.jenkins.webhook.step3"
+    />
+  </li>
+</Fragment>
+`;
+
+exports[`should render correctly: with no alm binding 1`] = `
+<Fragment>
+  <li>
+    <FormattedMessage
+      defaultMessage="onboarding.tutorial.with.jenkins.webhook.step1.sentence"
+      id="onboarding.tutorial.with.jenkins.webhook.step1.sentence"
+      values={
+        Object {
+          "link": "onboarding.tutorial.with.jenkins.webhook.github.step1.link",
+        }
+      }
+    />
+    <ul
+      className="list-styled"
+    >
+      <li
+        className="abs-width-600"
+      >
+        <p>
+          <LabelActionPair
+            translationKey="onboarding.tutorial.with.jenkins.webhook.github.step1.url"
+          />
+        </p>
+        <CodeSnippet
+          isOneLine={true}
+          snippet="/github-webhook/"
+        />
+      </li>
+    </ul>
+  </li>
+  <li>
+    <SentenceWithHighlights
+      highlightKeys={
+        Array [
+          "events",
+          "option",
+        ]
+      }
+      translationKey="onboarding.tutorial.with.jenkins.webhook.github.step2"
+    />
+    <ul
+      className="list-styled"
+    >
+      <li>
+        <strong>
+          onboarding.tutorial.with.jenkins.webhook.github.step2.repo
+        </strong>
+      </li>
+      <li>
+        <strong>
+          onboarding.tutorial.with.jenkins.webhook.github.step2.pr
+        </strong>
+      </li>
+    </ul>
+  </li>
+  <li>
+    <SentenceWithHighlights
+      highlightKeys={
+        Array [
+          "create",
+        ]
+      }
+      translationKey="onboarding.tutorial.with.jenkins.webhook.step3"
+    />
+  </li>
+</Fragment>
+`;
index 89394ecb80b0b4a45456e5b9a69527062d148394..7845d0ad6664dbadb744b3e879cdf868342c51e5 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+import { GithubBindingDefinition, ProjectAlmBindingResponse } from '../../types/alm-settings';
 import { LanguageConfig } from './types';
 
 export function isLanguageConfigured(config?: LanguageConfig) {
@@ -50,3 +51,16 @@ export function getUniqueTokenName(tokens: T.UserToken[], initialTokenName = '')
   }
   return `${initialTokenName} ${i}`;
 }
+
+export function buildGithubLink(
+  almBinding: GithubBindingDefinition,
+  projectBinding: ProjectAlmBindingResponse
+) {
+  // strip the api path:
+  const urlRoot = almBinding.url
+    .replace('/api/v3', '') // GH Enterprise
+    .replace('api.', '') // GH.com
+    .replace(/\/$/, '');
+
+  return `${urlRoot}/${projectBinding.repository}`;
+}
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/alm-settings-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/alm-settings-test.ts
new file mode 100644 (file)
index 0000000..2f8c1c4
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { AlmKeys } from '../../types/alm-settings';
+import {
+  isBitbucketBindingDefinition,
+  isGithubBindingDefinition,
+  isProjectBitbucketBindingResponse,
+  isProjectGitHubBindingResponse
+} from '../alm-settings';
+import {
+  mockBitbucketBindingDefinition,
+  mockGithubBindingDefinition,
+  mockProjectAlmBindingResponse,
+  mockProjectBitbucketBindingResponse,
+  mockProjectGithubBindingResponse
+} from '../mocks/alm-settings';
+
+/* eslint-disable sonarjs/no-duplicate-string */
+
+describe('isProjectBitbucketBindingResponse', () => {
+  it('works as expected', () => {
+    expect(isProjectBitbucketBindingResponse(mockProjectAlmBindingResponse())).toBe(false);
+    expect(isProjectBitbucketBindingResponse(mockProjectBitbucketBindingResponse())).toBe(true);
+  });
+});
+
+describe('isBitbucketBindingDefinition', () => {
+  it('works as expected', () => {
+    expect(isBitbucketBindingDefinition(undefined)).toBe(false);
+    expect(isBitbucketBindingDefinition(mockGithubBindingDefinition())).toBe(false);
+    expect(isBitbucketBindingDefinition(mockBitbucketBindingDefinition())).toBe(true);
+  });
+});
+
+describe('isProjectGithubBindingResponse', () => {
+  it('works as expected', () => {
+    expect(
+      isProjectGitHubBindingResponse(mockProjectAlmBindingResponse({ alm: AlmKeys.Azure }))
+    ).toBe(false);
+    expect(isProjectGitHubBindingResponse(mockProjectGithubBindingResponse())).toBe(true);
+  });
+});
+
+describe('isGithubBindingDefinition', () => {
+  it('works as expected', () => {
+    expect(isGithubBindingDefinition(undefined)).toBe(false);
+    expect(isGithubBindingDefinition(mockBitbucketBindingDefinition())).toBe(false);
+    expect(isGithubBindingDefinition(mockGithubBindingDefinition())).toBe(true);
+  });
+});
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/alm-settings.ts b/server/sonar-web/src/main/js/helpers/__tests__/alm-settings.ts
deleted file mode 100644 (file)
index f6be966..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-import { isBitbucketBindingDefinition, isProjectBitbucketBindingResponse } from '../alm-settings';
-import {
-  mockBitbucketBindingDefinition,
-  mockGithubBindingDefinition,
-  mockProjectAlmBindingResponse,
-  mockProjectBitbucketBindingGet
-} from '../mocks/alm-settings';
-
-describe('isProjectBitbucketBindingResponse', () => {
-  it('works as expected', () => {
-    expect(isProjectBitbucketBindingResponse(mockProjectAlmBindingResponse())).toBe(false);
-    expect(isProjectBitbucketBindingResponse(mockProjectBitbucketBindingGet())).toBe(true);
-  });
-});
-
-describe('isBitbucketBindingDefinition', () => {
-  it('works as expected', () => {
-    expect(isBitbucketBindingDefinition(mockGithubBindingDefinition())).toBe(false);
-    expect(isBitbucketBindingDefinition(mockBitbucketBindingDefinition())).toBe(true);
-  });
-});
index 0bb508267ab6cc69206d3d3451f545b99571751a..974968435f32701fdc36b03e83ca504fbc773371 100644 (file)
@@ -21,8 +21,10 @@ import {
   AlmBindingDefinition,
   AlmKeys,
   BitbucketBindingDefinition,
+  GithubBindingDefinition,
   ProjectAlmBindingResponse,
-  ProjectBitbucketBindingResponse
+  ProjectBitbucketBindingResponse,
+  ProjectGitHubBindingResponse
 } from '../types/alm-settings';
 
 export function isProjectBitbucketBindingResponse(
@@ -31,8 +33,27 @@ export function isProjectBitbucketBindingResponse(
   return binding.alm === AlmKeys.Bitbucket;
 }
 
+export function isProjectGitHubBindingResponse(
+  binding: ProjectAlmBindingResponse
+): binding is ProjectGitHubBindingResponse {
+  return binding.alm === AlmKeys.GitHub;
+}
+
 export function isBitbucketBindingDefinition(
-  binding: AlmBindingDefinition & { url?: string; personalAccessToken?: string }
+  binding?: AlmBindingDefinition & { url?: string; personalAccessToken?: string }
 ): binding is BitbucketBindingDefinition {
-  return binding.url !== undefined && binding.personalAccessToken !== undefined;
+  return (
+    binding !== undefined && binding.url !== undefined && binding.personalAccessToken !== undefined
+  );
+}
+
+export function isGithubBindingDefinition(
+  binding?: AlmBindingDefinition & { appId?: string; privateKey?: string; url?: string }
+): binding is GithubBindingDefinition {
+  return (
+    binding !== undefined &&
+    binding.appId !== undefined &&
+    binding.privateKey !== undefined &&
+    binding.url !== undefined
+  );
 }
index 3ca33106b3315d52e32757f4752d55df013aeb25..c89b8f0baa2a4be2db560316efe39fe1c0c746fc 100644 (file)
@@ -25,7 +25,8 @@ import {
   GithubBindingDefinition,
   GitlabBindingDefinition,
   ProjectAlmBindingResponse,
-  ProjectBitbucketBindingResponse
+  ProjectBitbucketBindingResponse,
+  ProjectGitHubBindingResponse
 } from '../../types/alm-settings';
 
 export function mockAlmSettingsInstance(
@@ -93,7 +94,7 @@ export function mockProjectAlmBindingResponse(
   };
 }
 
-export function mockProjectBitbucketBindingGet(
+export function mockProjectBitbucketBindingResponse(
   overrides: Partial<ProjectBitbucketBindingResponse> = {}
 ): ProjectBitbucketBindingResponse {
   return {
@@ -104,3 +105,14 @@ export function mockProjectBitbucketBindingGet(
     ...overrides
   };
 }
+
+export function mockProjectGithubBindingResponse(
+  overrides: Partial<ProjectGitHubBindingResponse> = {}
+): ProjectGitHubBindingResponse {
+  return {
+    alm: AlmKeys.GitHub,
+    key: 'foo',
+    repository: 'PROJECT_KEY',
+    ...overrides
+  };
+}
index 10030182e07350dd8f4ef031b29fcbe773f75689..18ce632b7853ec52370d83a24ba655490c4929c6 100644 (file)
@@ -64,6 +64,11 @@ export interface ProjectBitbucketBindingResponse extends ProjectAlmBindingRespon
   slug: string;
 }
 
+export interface ProjectGitHubBindingResponse extends ProjectAlmBindingResponse {
+  alm: AlmKeys.GitHub;
+  repository: string;
+}
+
 export interface ProjectAlmBindingParams {
   almSetting: string;
   project: string;
index 9c15f2e0e9501752367a994f7fa6193c116712ab..1570796fea474071ee6185f600e3f597a2b8b2cb 100644 (file)
@@ -3306,11 +3306,12 @@ onboarding.tutorial.choose_method.manual=Manually
 onboarding.tutorial.choose_method.jenkins=With Jenkins
 
 onboarding.tutorial.with.jenkins.title=Analyze your project with Jenkins
-onboarding.tutorial.with.jenkins.only_bitbucket=This tutorial is only available for projects bound to Bitbucket Server.
+onboarding.tutorial.with.jenkins.unsupported=This tutorial is only available for projects bound to Bitbucket Server or GitHub.
 onboarding.tutorial.with.jenkins.prereqs.title=Prerequisites
 onboarding.tutorial.with.jenkins.prereqs.intro.sentence=To run your project analyses with Jenkins, the following plugins {must_have}
 onboarding.tutorial.with.jenkins.prereqs.intro.sentence.must_have=must be installed and configured:
-onboarding.tutorial.with.jenkins.prereqs.plugins.branch_source=Bitbucket Branch Source plugin for Jenkins - version 2.7 or later
+onboarding.tutorial.with.jenkins.prereqs.plugins.branch_source.bitbucket=Bitbucket Branch Source plugin for Jenkins - version 2.7 or later
+onboarding.tutorial.with.jenkins.prereqs.plugins.branch_source.github=GitHub Branch Source plugin for Jenkins - version 2.7.1 or later
 onboarding.tutorial.with.jenkins.prereqs.plugins.sonar_scanner=SonarQube Scanner plugin for Jenkins - version 2.11 or later
 onboarding.tutorial.with.jenkins.prereqs.step_by_step_guide=For a step by step guide on installing and configuring those plugins in Jenkins, visit the {link} documentation page.
 onboarding.tutorial.with.jenkins.prereqs.step_by_step_guide.link=Analysis Prerequisites
@@ -3322,44 +3323,64 @@ onboarding.tutorial.with.jenkins.multi_branch_pipeline.intro=Create a Multibranc
 onboarding.tutorial.with.jenkins.multi_branch_pipeline.step1.sentence=From Jenkins' dashboard, click {new_item} and create a {type}.
 onboarding.tutorial.with.jenkins.multi_branch_pipeline.step1.sentence.new_item=New Item
 onboarding.tutorial.with.jenkins.multi_branch_pipeline.step1.sentence.type=Multibranch Pipeline Job
-onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.sentence=Under {tab}, add a Bitbucket source and enter the following information:
-onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.sentence.tab=Branch Sources
-onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.server.label=Server
-onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.server.action=select the instance hosting the repository you want to analyze.
-onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.creds.label=Credentials
-onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.creds.action=select the Bitbucket Server credentials.
-onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.owner.label=Owner
-onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.owner.action=enter your project key.
-onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.repo.label=Repository
-onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.repo.action=select the repository you want to analyze.
+
+onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucket.sentence=Under {tab}, add a Bitbucket source and enter the following information:
+onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucket.sentence.tab=Branch Sources
+onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucket.server.label=Server
+onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucket.server.action=select the instance hosting the repository you want to analyze.
+onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucket.creds.label=Credentials
+onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucket.creds.action=select the Bitbucket Server credentials.
+onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucket.owner.label=Owner
+onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucket.owner.action=enter your project key.
+onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucket.repo.label=Repository
+onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucket.repo.action=select the repository you want to analyze.
+
+onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.github.sentence=Under {tab}, add a GitHub source and enter the following information:
+onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.github.sentence.tab=Branch Sources
+onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.github.creds.label=Credentials
+onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.github.creds.action=select or add your GitHub credentials.
+onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.github.repo_url.label=Repository HTTPS URL
+onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.github.repo_url.action=enter your repository URL.
+
 onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.behaviour.label=Behavior
-onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.behaviour.action=select Exclude branches that are also filed as PRs.
-onboarding.tutorial.with.jenkins.multi_branch_pipeline.step3.sentence=Jump to the {tab} section and set the following parameters:
+onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.behaviour.action=make sure Exclude branches that are also filed as PRs is selected.
+
+onboarding.tutorial.with.jenkins.multi_branch_pipeline.step3.sentence=Jump to the {tab} section and make sure the parameters are set as follows:
 onboarding.tutorial.with.jenkins.multi_branch_pipeline.step3.sentence.tab=Build Configuration
 onboarding.tutorial.with.jenkins.multi_branch_pipeline.step3.mode.label=Mode
 onboarding.tutorial.with.jenkins.multi_branch_pipeline.step3.mode.action=by Jenkinsfile
 onboarding.tutorial.with.jenkins.multi_branch_pipeline.step3.script_path.label=Script Path
 onboarding.tutorial.with.jenkins.multi_branch_pipeline.step3.script_path.action=Jenkinsfile
+
 onboarding.tutorial.with.jenkins.multi_branch_pipeline.step4.sentence=Click {save}.
 onboarding.tutorial.with.jenkins.multi_branch_pipeline.step4.sentence.save=Save
-onboarding.tutorial.with.jenkins.bitbucket_webhook.title=Create a Bitbucket Server Webhook
-onboarding.tutorial.with.jenkins.bitbucket_webhook.intro.sentence=Create a Webhook in your repository to trigger the Jenkins job on push. Already have a Webhook configured? {link}
-onboarding.tutorial.with.jenkins.bitbucket_webhook.intro.link=Skip this step.
-onboarding.tutorial.with.jenkins.bitbucket_webhook.step1.sentence=Go to the {link} and enter the following information:
-onboarding.tutorial.with.jenkins.bitbucket_webhook.step1.link=Bitbucket Server Webhook creation page for your repository
-onboarding.tutorial.with.jenkins.bitbucket_webhook.step1.name.label=Name
-onboarding.tutorial.with.jenkins.bitbucket_webhook.step1.name.action=give a unique name.
-onboarding.tutorial.with.jenkins.bitbucket_webhook.step1.url.label=URL
-onboarding.tutorial.with.jenkins.bitbucket_webhook.step1.url.action=Enter the following URL, replacing the tokens as needed:
-onboarding.tutorial.with.jenkins.bitbucket_webhook.step1.url.warning=The Bitbucket Server URL must be identical to the one in your Jenkins configuration. Watch out for any missing or extra "/" at the end.
-onboarding.tutorial.with.jenkins.bitbucket_webhook.step2.sentence=Under {events}, make sure the following options are checked:
-onboarding.tutorial.with.jenkins.bitbucket_webhook.step2.sentence.events=Events
-onboarding.tutorial.with.jenkins.bitbucket_webhook.step2.repo.label=Repository
-onboarding.tutorial.with.jenkins.bitbucket_webhook.step2.repo.action=Push
-onboarding.tutorial.with.jenkins.bitbucket_webhook.step2.pr.label=Pull Request
-onboarding.tutorial.with.jenkins.bitbucket_webhook.step2.pr.action=Opened
-onboarding.tutorial.with.jenkins.bitbucket_webhook.step3.sentence=Click {create}.
-onboarding.tutorial.with.jenkins.bitbucket_webhook.step3.sentence.create=Create
+onboarding.tutorial.with.jenkins.webhook.bitbucket.title=Create a Bitbucket Server Webhook
+onboarding.tutorial.with.jenkins.webhook.github.title=Create a GitHub Webhook
+onboarding.tutorial.with.jenkins.webhook.intro.sentence=Create a Webhook in your repository to trigger the Jenkins job on push. Already have a Webhook configured? {link}
+onboarding.tutorial.with.jenkins.webhook.intro.link=Skip this step.
+onboarding.tutorial.with.jenkins.webhook.step1.sentence=Go to the {link} and enter the following information:
+onboarding.tutorial.with.jenkins.webhook.bitbucket.step1.link=Bitbucket Server Webhook creation page for your repository
+onboarding.tutorial.with.jenkins.webhook.github.step1.link=GitHub Webhook creation page for your repository
+onboarding.tutorial.with.jenkins.webhook.step1.name.label=Name
+onboarding.tutorial.with.jenkins.webhook.step1.name.action=give a unique name.
+onboarding.tutorial.with.jenkins.webhook.bitbucket.step1.url.label=URL
+onboarding.tutorial.with.jenkins.webhook.bitbucket.step1.url.action=Enter the following URL, replacing the tokens as needed:
+onboarding.tutorial.with.jenkins.webhook.bitbucket.step1.url.warning=The Bitbucket Server URL must be identical to the one in your Jenkins configuration. Watch out for any missing or extra "/" at the end.
+onboarding.tutorial.with.jenkins.webhook.github.step1.url.label=URL
+onboarding.tutorial.with.jenkins.webhook.github.step1.url.action=Enter your Jenkins instance URL and add the following path:
+onboarding.tutorial.with.jenkins.webhook.bitbucket.step2.sentence=Under {events}, make sure the following options are checked:
+onboarding.tutorial.with.jenkins.webhook.bitbucket.step2.sentence.events=Events
+onboarding.tutorial.with.jenkins.webhook.github.step2.sentence=Under {events} select {option} and check the following:
+onboarding.tutorial.with.jenkins.webhook.github.step2.sentence.events=Which events would you like to trigger this webhook?
+onboarding.tutorial.with.jenkins.webhook.github.step2.sentence.option=Let me select individual events
+onboarding.tutorial.with.jenkins.webhook.bitbucket.step2.repo.label=Repository
+onboarding.tutorial.with.jenkins.webhook.bitbucket.step2.repo.action=Push
+onboarding.tutorial.with.jenkins.webhook.bitbucket.step2.pr.label=Pull Request
+onboarding.tutorial.with.jenkins.webhook.bitbucket.step2.pr.action=Opened
+onboarding.tutorial.with.jenkins.webhook.github.step2.repo=Pushes
+onboarding.tutorial.with.jenkins.webhook.github.step2.pr=Pull Requests
+onboarding.tutorial.with.jenkins.webhook.step3.sentence=Click {create}.
+onboarding.tutorial.with.jenkins.webhook.step3.sentence.create=Create
 onboarding.tutorial.with.jenkins.jenkinsfile.title=Create a Jenkinsfile
 onboarding.tutorial.with.jenkins.jenkinsfile.jenkinsfile_step.sentence=Create a {file} file in your repository and paste the following code:
 onboarding.tutorial.with.jenkins.jenkinsfile.maven.step2.sentence=Add the following to your {file} file: