Browse Source

SONAR-13480 Add jenkins tutorial for GitHub imported projects

tags/8.5.0.37579
Jeremy Davis 4 years ago
parent
commit
0a90ec05aa
29 changed files with 1329 additions and 518 deletions
  1. 7
    3
      server/sonar-web/src/main/js/components/tutorials/TutorialSelection.tsx
  2. 2
    2
      server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelectionRenderer-test.tsx
  3. 41
    15
      server/sonar-web/src/main/js/components/tutorials/__tests__/utils-test.ts
  4. 0
    143
      server/sonar-web/src/main/js/components/tutorials/jenkins/BitbucketWebhookStep.tsx
  5. 17
    12
      server/sonar-web/src/main/js/components/tutorials/jenkins/JenkinsTutorial.tsx
  6. 54
    22
      server/sonar-web/src/main/js/components/tutorials/jenkins/MultiBranchPipelineStep.tsx
  7. 6
    2
      server/sonar-web/src/main/js/components/tutorials/jenkins/PreRequisitesStep.tsx
  8. 102
    0
      server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStep.tsx
  9. 98
    0
      server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStepBitbucket.tsx
  10. 88
    0
      server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStepGithub.tsx
  11. 14
    13
      server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/JenkinsTutorial-test.tsx
  12. 9
    3
      server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/MultiBranchPipelineStep-test.tsx
  13. 2
    0
      server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/PreRequisitesStep-test.tsx
  14. 67
    0
      server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/WebhookStep-test.tsx
  15. 8
    17
      server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/WebhookStepBitbucket-test.tsx
  16. 42
    0
      server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/WebhookStepGithub-test.tsx
  17. 0
    228
      server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/BitbucketWebhookStep-test.tsx.snap
  18. 4
    3
      server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/JenkinsTutorial-test.tsx.snap
  19. 112
    13
      server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/MultiBranchPipelineStep-test.tsx.snap
  20. 1
    1
      server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/PreRequisitesStep-test.tsx.snap
  21. 211
    0
      server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/WebhookStep-test.tsx.snap
  22. 161
    0
      server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/WebhookStepBitbucket-test.tsx.snap
  23. 143
    0
      server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/WebhookStepGithub-test.tsx.snap
  24. 14
    0
      server/sonar-web/src/main/js/components/tutorials/utils.ts
  25. 30
    4
      server/sonar-web/src/main/js/helpers/__tests__/alm-settings-test.ts
  26. 24
    3
      server/sonar-web/src/main/js/helpers/alm-settings.ts
  27. 14
    2
      server/sonar-web/src/main/js/helpers/mocks/alm-settings.ts
  28. 5
    0
      server/sonar-web/src/main/js/types/alm-settings.ts
  29. 53
    32
      sonar-core/src/main/resources/org/sonar/l10n/core.properties

+ 7
- 3
server/sonar-web/src/main/js/components/tutorials/TutorialSelection.tsx View File

]); ]);


if (this.mounted) { 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 }); this.setState({ loading: false, forceManual: true });
} else { } else {
let almBinding; let almBinding;
if (almDefinitions !== undefined) { 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 }); this.setState({ almBinding, forceManual: false, projectBinding, loading: false });
} }

+ 2
- 2
server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelectionRenderer-test.tsx View File

import { click } from 'sonar-ui-common/helpers/testUtils'; import { click } from 'sonar-ui-common/helpers/testUtils';
import { import {
mockBitbucketBindingDefinition, mockBitbucketBindingDefinition,
mockProjectBitbucketBindingGet
mockProjectBitbucketBindingResponse
} from '../../../helpers/mocks/alm-settings'; } from '../../../helpers/mocks/alm-settings';
import { mockComponent, mockLoggedInUser } from '../../../helpers/testMocks'; import { mockComponent, mockLoggedInUser } from '../../../helpers/testMocks';
import TutorialSelectionRenderer, { import TutorialSelectionRenderer, {
expect( expect(
shallowRender({ shallowRender({
selectedTutorial: TutorialModes.Jenkins, selectedTutorial: TutorialModes.Jenkins,
projectBinding: mockProjectBitbucketBindingGet()
projectBinding: mockProjectBitbucketBindingResponse()
}) })
).toMatchSnapshot('jenkins tutorial'); ).toMatchSnapshot('jenkins tutorial');
}); });

+ 41
- 15
server/sonar-web/src/main/js/components/tutorials/__tests__/utils-test.ts View File

* along with this program; if not, write to the Free Software Foundation, * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * 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');
});
}); });

+ 0
- 143
server/sonar-web/src/main/js/components/tutorials/jenkins/BitbucketWebhookStep.tsx View File

/*
* 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')}
/>
);
}

+ 17
- 12
server/sonar-web/src/main/js/components/tutorials/jenkins/JenkinsTutorial.tsx View File

import { Alert } from 'sonar-ui-common/components/ui/Alert'; import { Alert } from 'sonar-ui-common/components/ui/Alert';
import { translate } from 'sonar-ui-common/helpers/l10n'; import { translate } from 'sonar-ui-common/helpers/l10n';
import { import {
isBitbucketBindingDefinition,
isProjectBitbucketBindingResponse
isProjectBitbucketBindingResponse,
isProjectGitHubBindingResponse
} from '../../../helpers/alm-settings'; } from '../../../helpers/alm-settings';
import { getCurrentUserSetting, Store } from '../../../store/rootReducer'; import { getCurrentUserSetting, Store } from '../../../store/rootReducer';
import { setCurrentUserSetting } from '../../../store/users'; import { setCurrentUserSetting } from '../../../store/users';
import { AlmBindingDefinition, ProjectAlmBindingResponse } from '../../../types/alm-settings'; import { AlmBindingDefinition, ProjectAlmBindingResponse } from '../../../types/alm-settings';
import BitbucketWebhookStep from './BitbucketWebhookStep';
import JenkinsfileStep from './JenkinsfileStep'; import JenkinsfileStep from './JenkinsfileStep';
import MultiBranchPipelineStep from './MultiBranchPipelineStep'; import MultiBranchPipelineStep from './MultiBranchPipelineStep';
import PreRequisitesStep from './PreRequisitesStep'; import PreRequisitesStep from './PreRequisitesStep';
import WebhookStep from './WebhookStep';


export interface JenkinsTutorialProps { export interface JenkinsTutorialProps {
almBinding?: AlmBindingDefinition; almBinding?: AlmBindingDefinition;
enum Steps { enum Steps {
PreRequisites = 0, PreRequisites = 0,
MultiBranchPipeline = 1, MultiBranchPipeline = 1,
BitbucketWebhook = 2,
Webhook = 2,
Jenkinsfile = 3 Jenkinsfile = 3
} }


); );


// Failsafe; should never happen. // Failsafe; should never happen.
if (!isProjectBitbucketBindingResponse(projectBinding)) {
if (
!isProjectBitbucketBindingResponse(projectBinding) &&
!isProjectGitHubBindingResponse(projectBinding)
) {
return ( return (
<Alert variant="error">{translate('onboarding.tutorial.with.jenkins.only_bitbucket')}</Alert>
<Alert variant="error">{translate('onboarding.tutorial.with.jenkins.unsupported')}</Alert>
); );
} }


</div> </div>


<PreRequisitesStep <PreRequisitesStep
alm={projectBinding.alm}
onDone={() => setStep(Steps.MultiBranchPipeline)} onDone={() => setStep(Steps.MultiBranchPipeline)}
onOpen={() => setStep(Steps.PreRequisites)} onOpen={() => setStep(Steps.PreRequisites)}
onChangeSkipNextTime={skip => { onChangeSkipNextTime={skip => {
/> />


<MultiBranchPipelineStep <MultiBranchPipelineStep
almBinding={almBinding}
finished={step > Steps.MultiBranchPipeline} finished={step > Steps.MultiBranchPipeline}
onDone={() => setStep(Steps.BitbucketWebhook)}
onDone={() => setStep(Steps.Webhook)}
onOpen={() => setStep(Steps.MultiBranchPipeline)} onOpen={() => setStep(Steps.MultiBranchPipeline)}
open={step === Steps.MultiBranchPipeline} open={step === Steps.MultiBranchPipeline}
projectBinding={projectBinding} projectBinding={projectBinding}
/> />


<BitbucketWebhookStep
almBinding={almBinding && isBitbucketBindingDefinition(almBinding) ? almBinding : undefined}
finished={step > Steps.BitbucketWebhook}
<WebhookStep
almBinding={almBinding}
finished={step > Steps.Webhook}
onDone={() => setStep(Steps.Jenkinsfile)} onDone={() => setStep(Steps.Jenkinsfile)}
onOpen={() => setStep(Steps.BitbucketWebhook)}
open={step === Steps.BitbucketWebhook}
onOpen={() => setStep(Steps.Webhook)}
open={step === Steps.Webhook}
projectBinding={projectBinding} projectBinding={projectBinding}
/> />



+ 54
- 22
server/sonar-web/src/main/js/components/tutorials/jenkins/MultiBranchPipelineStep.tsx View File

import * as React from 'react'; import * as React from 'react';
import { Button } from 'sonar-ui-common/components/controls/buttons'; import { Button } from 'sonar-ui-common/components/controls/buttons';
import { translate } from 'sonar-ui-common/helpers/l10n'; 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 LabelActionPair from '../components/LabelActionPair';
import LabelValuePair from '../components/LabelValuePair'; import LabelValuePair from '../components/LabelValuePair';
import SentenceWithHighlights from '../components/SentenceWithHighlights'; import SentenceWithHighlights from '../components/SentenceWithHighlights';
import Step from '../components/Step'; import Step from '../components/Step';
import { buildGithubLink } from '../utils';


export interface MultiBranchPipelineStepProps { export interface MultiBranchPipelineStepProps {
almBinding?: AlmBindingDefinition;
finished: boolean; finished: boolean;
onDone: () => void; onDone: () => void;
onOpen: () => void; onOpen: () => void;
open: boolean; open: boolean;
projectBinding: ProjectBitbucketBindingResponse;
projectBinding: ProjectBitbucketBindingResponse | ProjectGitHubBindingResponse;
} }


export default function MultiBranchPipelineStep(props: MultiBranchPipelineStepProps) { export default function MultiBranchPipelineStep(props: MultiBranchPipelineStepProps) {
const { finished, open, projectBinding } = props;
const { almBinding, finished, open, projectBinding } = props;
return ( return (
<Step <Step
finished={finished} finished={finished}
<li> <li>
<SentenceWithHighlights <SentenceWithHighlights
highlightKeys={['tab']} 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"> <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> <li>
<LabelActionPair translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.behaviour" /> <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.behaviour" />
</li> </li>

+ 6
- 2
server/sonar-web/src/main/js/components/tutorials/jenkins/PreRequisitesStep.tsx View File

import { Button } from 'sonar-ui-common/components/controls/buttons'; import { Button } from 'sonar-ui-common/components/controls/buttons';
import Checkbox from 'sonar-ui-common/components/controls/Checkbox'; import Checkbox from 'sonar-ui-common/components/controls/Checkbox';
import { translate } from 'sonar-ui-common/helpers/l10n'; import { translate } from 'sonar-ui-common/helpers/l10n';
import { AlmKeys } from '../../../types/alm-settings';
import SentenceWithHighlights from '../components/SentenceWithHighlights'; import SentenceWithHighlights from '../components/SentenceWithHighlights';
import Step from '../components/Step'; import Step from '../components/Step';


export interface PreRequisitesStepProps { export interface PreRequisitesStepProps {
alm: AlmKeys;
onChangeSkipNextTime: (skip: boolean) => void; onChangeSkipNextTime: (skip: boolean) => void;
onDone: () => void; onDone: () => void;
onOpen: () => void; onOpen: () => void;
} }


export default function PreRequisitesStep(props: PreRequisitesStepProps) { export default function PreRequisitesStep(props: PreRequisitesStepProps) {
const { open, skipNextTime } = props;
const { alm, open, skipNextTime } = props;
return ( return (
<Step <Step
finished={!open} finished={!open}
/> />
</p> </p>
<ul className="list-styled big-spacer-bottom"> <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> <li>{translate('onboarding.tutorial.with.jenkins.prereqs.plugins.sonar_scanner')}</li>
</ul> </ul>
<p className="big-spacer-bottom"> <p className="big-spacer-bottom">

+ 102
- 0
server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStep.tsx View File

/*
* 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')}
/>
);
}

+ 98
- 0
server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStepBitbucket.tsx View File

/*
* 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>
</>
);
}

+ 88
- 0
server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStepGithub.tsx View File

/*
* 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>
</>
);
}

+ 14
- 13
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/JenkinsTutorial-test.tsx View File

import * as React from 'react'; import * as React from 'react';
import { import {
mockProjectAlmBindingResponse, mockProjectAlmBindingResponse,
mockProjectBitbucketBindingGet
mockProjectBitbucketBindingResponse
} from '../../../../helpers/mocks/alm-settings'; } from '../../../../helpers/mocks/alm-settings';
import { mockComponent } from '../../../../helpers/testMocks'; import { mockComponent } from '../../../../helpers/testMocks';
import BitbucketWebhookStep from '../BitbucketWebhookStep';
import { AlmKeys } from '../../../../types/alm-settings';
import JenkinsfileStep from '../JenkinsfileStep'; import JenkinsfileStep from '../JenkinsfileStep';
import { JenkinsTutorial, JenkinsTutorialProps } from '../JenkinsTutorial'; import { JenkinsTutorial, JenkinsTutorialProps } from '../JenkinsTutorial';
import MultiBranchPipelineStep from '../MultiBranchPipelineStep'; import MultiBranchPipelineStep from '../MultiBranchPipelineStep';
import PreRequisitesStep from '../PreRequisitesStep'; import PreRequisitesStep from '../PreRequisitesStep';
import WebhookStep from '../WebhookStep';


it('should render correctly', () => { it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot('default'); 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', () => { it('should correctly navigate between steps', () => {


expect(wrapper.find(PreRequisitesStep).prop('open')).toBe(true); expect(wrapper.find(PreRequisitesStep).prop('open')).toBe(true);
expect(wrapper.find(MultiBranchPipelineStep).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(false); expect(wrapper.find(JenkinsfileStep).prop('open')).toBe(false);


// Pre-reqs done. // Pre-reqs done.
wrapper.find(PreRequisitesStep).prop('onDone')(); wrapper.find(PreRequisitesStep).prop('onDone')();
expect(wrapper.find(PreRequisitesStep).prop('open')).toBe(false); expect(wrapper.find(PreRequisitesStep).prop('open')).toBe(false);
expect(wrapper.find(MultiBranchPipelineStep).prop('open')).toBe(true); 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); expect(wrapper.find(JenkinsfileStep).prop('open')).toBe(false);


// Multibranch done. // Multibranch done.
wrapper.find(MultiBranchPipelineStep).prop('onDone')(); wrapper.find(MultiBranchPipelineStep).prop('onDone')();
expect(wrapper.find(PreRequisitesStep).prop('open')).toBe(false); expect(wrapper.find(PreRequisitesStep).prop('open')).toBe(false);
expect(wrapper.find(MultiBranchPipelineStep).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); expect(wrapper.find(JenkinsfileStep).prop('open')).toBe(false);


// Webhook done. // Webhook done.
wrapper.find(BitbucketWebhookStep).prop('onDone')();
wrapper.find(WebhookStep).prop('onDone')();
expect(wrapper.find(PreRequisitesStep).prop('open')).toBe(false); expect(wrapper.find(PreRequisitesStep).prop('open')).toBe(false);
expect(wrapper.find(MultiBranchPipelineStep).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); expect(wrapper.find(JenkinsfileStep).prop('open')).toBe(true);


// Open Pre-reqs. // Open Pre-reqs.
expect(wrapper.find(MultiBranchPipelineStep).prop('open')).toBe(true); expect(wrapper.find(MultiBranchPipelineStep).prop('open')).toBe(true);


// Open Webhook. // 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', () => { it('should correctly store the user setting', () => {
return shallow<JenkinsTutorialProps>( return shallow<JenkinsTutorialProps>(
<JenkinsTutorial <JenkinsTutorial
component={mockComponent()} component={mockComponent()}
projectBinding={mockProjectBitbucketBindingGet()}
projectBinding={mockProjectBitbucketBindingResponse()}
setCurrentUserSetting={jest.fn()} setCurrentUserSetting={jest.fn()}
skipPreReqs={false} skipPreReqs={false}
{...props} {...props}

+ 9
- 3
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/MultiBranchPipelineStep-test.tsx View File



import { shallow } from 'enzyme'; import { shallow } from 'enzyme';
import * as React from 'react'; 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 MultiBranchPipelineStep, { MultiBranchPipelineStepProps } from '../MultiBranchPipelineStep';
import { renderStepContent } from '../test-utils'; import { renderStepContent } from '../test-utils';


it('should render correctly', () => { it('should render correctly', () => {
const wrapper = shallowRender(); const wrapper = shallowRender();
expect(wrapper).toMatchSnapshot('Step wrapper'); 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> = {}) { function shallowRender(props: Partial<MultiBranchPipelineStepProps> = {}) {
onDone={jest.fn()} onDone={jest.fn()}
onOpen={jest.fn()} onOpen={jest.fn()}
open={true} open={true}
projectBinding={mockProjectBitbucketBindingGet()}
projectBinding={mockProjectBitbucketBindingResponse()}
{...props} {...props}
/> />
); );

+ 2
- 0
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/PreRequisitesStep-test.tsx View File



import { shallow } from 'enzyme'; import { shallow } from 'enzyme';
import * as React from 'react'; import * as React from 'react';
import { AlmKeys } from '../../../../types/alm-settings';
import PreRequisitesStep, { PreRequisitesStepProps } from '../PreRequisitesStep'; import PreRequisitesStep, { PreRequisitesStepProps } from '../PreRequisitesStep';
import { renderStepContent } from '../test-utils'; import { renderStepContent } from '../test-utils';


function shallowRender(props: Partial<PreRequisitesStepProps> = {}) { function shallowRender(props: Partial<PreRequisitesStepProps> = {}) {
return shallow<PreRequisitesStepProps>( return shallow<PreRequisitesStepProps>(
<PreRequisitesStep <PreRequisitesStep
alm={AlmKeys.Bitbucket}
onChangeSkipNextTime={jest.fn()} onChangeSkipNextTime={jest.fn()}
onDone={jest.fn()} onDone={jest.fn()}
onOpen={jest.fn()} onOpen={jest.fn()}

+ 67
- 0
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/WebhookStep-test.tsx View File

/*
* 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}
/>
);
}

server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/BitbucketWebhookStep-test.tsx → server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/WebhookStepBitbucket-test.tsx View File

import * as React from 'react'; import * as React from 'react';
import { import {
mockBitbucketBindingDefinition, mockBitbucketBindingDefinition,
mockProjectBitbucketBindingGet
mockProjectBitbucketBindingResponse
} from '../../../../helpers/mocks/alm-settings'; } from '../../../../helpers/mocks/alm-settings';
import BitbucketWebhookStep, { BitbucketWebhookStepProps } from '../BitbucketWebhookStep';
import { renderStepContent } from '../test-utils';
import WebhookStepBitbucket, { WebhookStepBitbucketProps } from '../WebhookStepBitbucket';


it('should render correctly', () => { 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'
);
expect(shallowRender()).toMatchSnapshot();
expect(shallowRender({ almBinding: undefined })).toMatchSnapshot('with no alm binding');
}); });


function shallowRender(props: Partial<BitbucketWebhookStepProps> = {}) {
return shallow<BitbucketWebhookStepProps>(
<BitbucketWebhookStep
function shallowRender(props: Partial<WebhookStepBitbucketProps> = {}) {
return shallow<WebhookStepBitbucketProps>(
<WebhookStepBitbucket
almBinding={mockBitbucketBindingDefinition()} almBinding={mockBitbucketBindingDefinition()}
finished={false}
onDone={jest.fn()}
onOpen={jest.fn()}
open={true}
projectBinding={mockProjectBitbucketBindingGet()}
projectBinding={mockProjectBitbucketBindingResponse()}
{...props} {...props}
/> />
); );

+ 42
- 0
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/WebhookStepGithub-test.tsx View File

/*
* 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}
/>
);
}

+ 0
- 228
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/BitbucketWebhookStep-test.tsx.snap View File

// 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>
`;

+ 4
- 3
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/JenkinsTutorial-test.tsx.snap View File

</h1> </h1>
</div> </div>
<PreRequisitesStep <PreRequisitesStep
alm="bitbucket"
onChangeSkipNextTime={[Function]} onChangeSkipNextTime={[Function]}
onDone={[Function]} onDone={[Function]}
onOpen={[Function]} onOpen={[Function]}
} }
} }
/> />
<BitbucketWebhookStep
<WebhookStep
finished={false} finished={false}
onDone={[Function]} onDone={[Function]}
onOpen={[Function]} onOpen={[Function]}
</Fragment> </Fragment>
`; `;


exports[`should render correctly: not Bitbucket binding 1`] = `
exports[`should render correctly: unsupported alm 1`] = `
<Alert <Alert
variant="error" variant="error"
> >
onboarding.tutorial.with.jenkins.only_bitbucket
onboarding.tutorial.with.jenkins.unsupported
</Alert> </Alert>
`; `;

+ 112
- 13
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/MultiBranchPipelineStep-test.tsx.snap View File

/> />
`; `;


exports[`should render correctly: content 1`] = `
exports[`should render correctly: content for bitbucket 1`] = `
<div <div
className="boxed-group-inner" className="boxed-group-inner"
> >
"tab", "tab",
] ]
} }
translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2"
translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucket"
/> />
<ul <ul
className="list-styled" 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> <li>
<LabelActionPair <LabelActionPair
translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.server"
translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.behaviour"
/> />
</li> </li>
</ul>
</li>
<li>
<SentenceWithHighlights
highlightKeys={
Array [
"tab",
]
}
translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step3"
/>
<ul
className="list-styled"
>
<li> <li>
<LabelActionPair <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>
<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> </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> <li>
<LabelActionPair <LabelActionPair
translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.behaviour" translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.behaviour"

+ 1
- 1
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/PreRequisitesStep-test.tsx.snap View File

className="list-styled big-spacer-bottom" className="list-styled big-spacer-bottom"
> >
<li> <li>
onboarding.tutorial.with.jenkins.prereqs.plugins.branch_source
onboarding.tutorial.with.jenkins.prereqs.plugins.branch_source.bitbucket
</li> </li>
<li> <li>
onboarding.tutorial.with.jenkins.prereqs.plugins.sonar_scanner onboarding.tutorial.with.jenkins.prereqs.plugins.sonar_scanner

+ 211
- 0
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/WebhookStep-test.tsx.snap View File

// 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"
/>
`;

+ 161
- 0
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/WebhookStepBitbucket-test.tsx.snap View File

// 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>
`;

+ 143
- 0
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/WebhookStepGithub-test.tsx.snap View File

// 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>
`;

+ 14
- 0
server/sonar-web/src/main/js/components/tutorials/utils.ts View File

* along with this program; if not, write to the Free Software Foundation, * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
import { GithubBindingDefinition, ProjectAlmBindingResponse } from '../../types/alm-settings';
import { LanguageConfig } from './types'; import { LanguageConfig } from './types';


export function isLanguageConfigured(config?: LanguageConfig) { export function isLanguageConfigured(config?: LanguageConfig) {
} }
return `${initialTokenName} ${i}`; 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}`;
}

server/sonar-web/src/main/js/helpers/__tests__/alm-settings.ts → server/sonar-web/src/main/js/helpers/__tests__/alm-settings-test.ts View File

* along with this program; if not, write to the Free Software Foundation, * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */

import { isBitbucketBindingDefinition, isProjectBitbucketBindingResponse } from '../alm-settings';
import { AlmKeys } from '../../types/alm-settings';
import {
isBitbucketBindingDefinition,
isGithubBindingDefinition,
isProjectBitbucketBindingResponse,
isProjectGitHubBindingResponse
} from '../alm-settings';
import { import {
mockBitbucketBindingDefinition, mockBitbucketBindingDefinition,
mockGithubBindingDefinition, mockGithubBindingDefinition,
mockProjectAlmBindingResponse, mockProjectAlmBindingResponse,
mockProjectBitbucketBindingGet
mockProjectBitbucketBindingResponse,
mockProjectGithubBindingResponse
} from '../mocks/alm-settings'; } from '../mocks/alm-settings';


/* eslint-disable sonarjs/no-duplicate-string */

describe('isProjectBitbucketBindingResponse', () => { describe('isProjectBitbucketBindingResponse', () => {
it('works as expected', () => { it('works as expected', () => {
expect(isProjectBitbucketBindingResponse(mockProjectAlmBindingResponse())).toBe(false); expect(isProjectBitbucketBindingResponse(mockProjectAlmBindingResponse())).toBe(false);
expect(isProjectBitbucketBindingResponse(mockProjectBitbucketBindingGet())).toBe(true);
expect(isProjectBitbucketBindingResponse(mockProjectBitbucketBindingResponse())).toBe(true);
}); });
}); });


describe('isBitbucketBindingDefinition', () => { describe('isBitbucketBindingDefinition', () => {
it('works as expected', () => { it('works as expected', () => {
expect(isBitbucketBindingDefinition(undefined)).toBe(false);
expect(isBitbucketBindingDefinition(mockGithubBindingDefinition())).toBe(false); expect(isBitbucketBindingDefinition(mockGithubBindingDefinition())).toBe(false);
expect(isBitbucketBindingDefinition(mockBitbucketBindingDefinition())).toBe(true); 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);
});
});

+ 24
- 3
server/sonar-web/src/main/js/helpers/alm-settings.ts View File

AlmBindingDefinition, AlmBindingDefinition,
AlmKeys, AlmKeys,
BitbucketBindingDefinition, BitbucketBindingDefinition,
GithubBindingDefinition,
ProjectAlmBindingResponse, ProjectAlmBindingResponse,
ProjectBitbucketBindingResponse
ProjectBitbucketBindingResponse,
ProjectGitHubBindingResponse
} from '../types/alm-settings'; } from '../types/alm-settings';


export function isProjectBitbucketBindingResponse( export function isProjectBitbucketBindingResponse(
return binding.alm === AlmKeys.Bitbucket; return binding.alm === AlmKeys.Bitbucket;
} }


export function isProjectGitHubBindingResponse(
binding: ProjectAlmBindingResponse
): binding is ProjectGitHubBindingResponse {
return binding.alm === AlmKeys.GitHub;
}

export function isBitbucketBindingDefinition( export function isBitbucketBindingDefinition(
binding: AlmBindingDefinition & { url?: string; personalAccessToken?: string }
binding?: AlmBindingDefinition & { url?: string; personalAccessToken?: string }
): binding is BitbucketBindingDefinition { ): 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
);
} }

+ 14
- 2
server/sonar-web/src/main/js/helpers/mocks/alm-settings.ts View File

GithubBindingDefinition, GithubBindingDefinition,
GitlabBindingDefinition, GitlabBindingDefinition,
ProjectAlmBindingResponse, ProjectAlmBindingResponse,
ProjectBitbucketBindingResponse
ProjectBitbucketBindingResponse,
ProjectGitHubBindingResponse
} from '../../types/alm-settings'; } from '../../types/alm-settings';


export function mockAlmSettingsInstance( export function mockAlmSettingsInstance(
}; };
} }


export function mockProjectBitbucketBindingGet(
export function mockProjectBitbucketBindingResponse(
overrides: Partial<ProjectBitbucketBindingResponse> = {} overrides: Partial<ProjectBitbucketBindingResponse> = {}
): ProjectBitbucketBindingResponse { ): ProjectBitbucketBindingResponse {
return { return {
...overrides ...overrides
}; };
} }

export function mockProjectGithubBindingResponse(
overrides: Partial<ProjectGitHubBindingResponse> = {}
): ProjectGitHubBindingResponse {
return {
alm: AlmKeys.GitHub,
key: 'foo',
repository: 'PROJECT_KEY',
...overrides
};
}

+ 5
- 0
server/sonar-web/src/main/js/types/alm-settings.ts View File

slug: string; slug: string;
} }


export interface ProjectGitHubBindingResponse extends ProjectAlmBindingResponse {
alm: AlmKeys.GitHub;
repository: string;
}

export interface ProjectAlmBindingParams { export interface ProjectAlmBindingParams {
almSetting: string; almSetting: string;
project: string; project: string;

+ 53
- 32
sonar-core/src/main/resources/org/sonar/l10n/core.properties View File

onboarding.tutorial.choose_method.jenkins=With Jenkins onboarding.tutorial.choose_method.jenkins=With Jenkins


onboarding.tutorial.with.jenkins.title=Analyze your project 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.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=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.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.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=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 onboarding.tutorial.with.jenkins.prereqs.step_by_step_guide.link=Analysis Prerequisites
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=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.new_item=New Item
onboarding.tutorial.with.jenkins.multi_branch_pipeline.step1.sentence.type=Multibranch Pipeline Job 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.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.sentence.tab=Build Configuration
onboarding.tutorial.with.jenkins.multi_branch_pipeline.step3.mode.label=Mode 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.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.label=Script Path
onboarding.tutorial.with.jenkins.multi_branch_pipeline.step3.script_path.action=Jenkinsfile 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=Click {save}.
onboarding.tutorial.with.jenkins.multi_branch_pipeline.step4.sentence.save=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.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.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: onboarding.tutorial.with.jenkins.jenkinsfile.maven.step2.sentence=Add the following to your {file} file:

Loading…
Cancel
Save