aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMathieu Suen <mathieu.suen@sonarsource.com>2021-03-19 15:56:31 +0100
committersonartech <sonartech@sonarsource.com>2021-03-23 20:08:24 +0000
commitae89e66cf02c6c12ed45b6980e3779be19e2e54b (patch)
treed717c1f7344a79aba9cfedaaf6289233a8b2aacb
parentd56c808b272298f349fcbe4d943e528f0251518a (diff)
downloadsonarqube-ae89e66cf02c6c12ed45b6980e3779be19e2e54b.tar.gz
sonarqube-ae89e66cf02c6c12ed45b6980e3779be19e2e54b.zip
SONAR-14590 Adding GitHub Action tutorial
-rw-r--r--server/sonar-web/public/images/tutorials/github-actions.svg16
-rw-r--r--server/sonar-web/src/main/js/app/styles/init/misc.css4
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx27
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelectionRenderer-test.tsx21
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/__tests__/__snapshots__/TutorialSelectionRenderer-test.tsx.snap351
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/AllSet.tsx83
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/DefaultProjectKey.tsx41
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/TokenStepGenerator.tsx60
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/__tests__/AllSet-test.tsx34
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/__tests__/DefaultProjectKey-test.tsx33
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/__tests__/TokenStepGenerator-test.tsx33
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/__tests__/__snapshots__/AllSet-test.tsx.snap135
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/__tests__/__snapshots__/DefaultProjectKey-test.tsx.snap15
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/__tests__/__snapshots__/TokenStepGenerator-test.tsx.snap28
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/AnalysisCommand.tsx58
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/GitHubActionTutorial.tsx70
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/SecretStep.tsx128
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/YamlFileStep.tsx60
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/AnalysisCommand-test.tsx41
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/GitHubActionTutorial-test.tsx45
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/SecretStep-test.tsx41
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/YamlFileStep-test.tsx31
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/__snapshots__/AnalysisCommand-test.tsx.snap113
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/__snapshots__/GitHubActionTutorial-test.tsx.snap41
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/__snapshots__/SecretStep-test.tsx.snap175
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/__snapshots__/YamlFileStep-test.tsx.snap50
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/commands/CreateYmlFile.tsx49
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/commands/DotNet.tsx77
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/commands/Gradle.tsx93
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/commands/JavaMaven.tsx92
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/commands/Others.tsx57
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/CreateYmlFile-test.tsx31
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/DotNet-test.tsx34
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/Gradle-test.tsx34
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/JavaMaven-test.tsx34
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/Others-test.tsx34
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/__snapshots__/CreateYmlFile-test.tsx.snap29
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/__snapshots__/DotNet-test.tsx.snap102
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/__snapshots__/Gradle-test.tsx.snap164
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/__snapshots__/JavaMaven-test.tsx.snap142
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/__snapshots__/Others-test.tsx.snap102
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/gitlabci/EnvironmentVariablesStep.tsx65
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/__snapshots__/EnvironmentVariablesStep-test.tsx.snap87
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/JenkinsfileStep.tsx60
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/JenkinsfileStep-test.tsx17
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/JenkinsTutorial-test.tsx.snap4
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/JenkinsfileStep-test.tsx.snap381
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/Gradle.tsx11
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/Maven.tsx7
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/Other.tsx13
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/__tests__/__snapshots__/Other-test.tsx.snap35
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/types.ts1
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/utils.ts18
-rw-r--r--sonar-core/src/main/resources/org/sonar/l10n/core.properties43
54 files changed, 2917 insertions, 633 deletions
diff --git a/server/sonar-web/public/images/tutorials/github-actions.svg b/server/sonar-web/public/images/tutorials/github-actions.svg
new file mode 100644
index 00000000000..6f0c864641a
--- /dev/null
+++ b/server/sonar-web/public/images/tutorials/github-actions.svg
@@ -0,0 +1,16 @@
+<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M10 1C14.9707 1 19 5.02932 19 10C19 14.9707 14.9707 19 10 19C5.02932 19 1 14.9707 1 10C1 5.02932 5.02932 1 10 1Z" stroke="#236a97" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M23 19C26.3137 19 29 21.6863 29 25C29 28.3137 26.3137 31 23 31C19.6863 31 17 28.3137 17 25C17 21.6863 19.6863 19 23 19Z" stroke="#236a97" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M23 35C26.3137 35 29 37.6863 29 41C29 44.3137 26.3137 47 23 47C19.6863 47 17 44.3137 17 41C17 37.6863 19.6863 35 23 35Z" stroke="#236a97" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M41 35C44.3137 35 47 37.6863 47 41C47 44.3137 44.3137 47 41 47C37.6863 47 35 44.3137 35 41C35 37.6863 37.6863 35 41 35Z" stroke="#cae3f2" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M25.0365 23.6069L21.9673 26.672L20.4766 25.1866" stroke="#236a97" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M41 19C44.3137 19 47 21.6863 47 25C47 28.3137 44.3137 31 41 31C37.6863 31 35 28.3137 35 25C35 21.6863 37.6863 19 41 19Z" stroke="#236a97" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M43.0365 23.6069L39.9673 26.672L38.4766 25.1866" stroke="#236a97" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M7 6.81201C7 6.02498 7.86709 5.54641 8.533 5.9659L13.6462 9.18692C14.2715 9.58082 14.2682 10.4935 13.6402 10.8829L8.52697 14.0534C7.8608 14.4664 7 13.9873 7 13.2035V6.81201Z" stroke="#236a97" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M9 19V34C9 37.866 12.1772 41 16 41H17" stroke="#236a97" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M16.949 26C17.5013 26 17.949 25.5523 17.949 25C17.949 24.4477 17.5013 24 16.949 24V26ZM8 19.0352C8 22.8817 11.1183 26 14.9648 26V24C12.2228 24 10 21.7772 10 19.0352H8ZM14.9648 26H16.949V24H14.9648V26Z" fill="#236a97"/>
+<path d="M29.0547 25H34.9993" stroke="#236a97" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M21 40C21.5518 40 22 40.4482 22 41C22 41.5526 21.5518 42 21 42C20.4482 42 20 41.5526 20 41C20 40.4482 20.4482 40 21 40Z" fill="#cae3f2"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M25 40C25.5518 40 26 40.4482 26 41C26 41.5526 25.5518 42 25 42C24.4482 42 24 41.5526 24 41C24 40.4482 24.4482 40 25 40Z" fill="#cae3f2"/>
+<path d="M34.0048 41.0069L32.9922 41.0399" stroke="#cae3f2" stroke-width="2" stroke-linecap="round"/>
+</svg>
diff --git a/server/sonar-web/src/main/js/app/styles/init/misc.css b/server/sonar-web/src/main/js/app/styles/init/misc.css
index 6e6ba4d39c8..ae61dfde85c 100644
--- a/server/sonar-web/src/main/js/app/styles/init/misc.css
+++ b/server/sonar-web/src/main/js/app/styles/init/misc.css
@@ -361,6 +361,10 @@ th.huge-spacer-right {
width: 600px !important;
}
+.abs-width-800 {
+ width: 800px !important;
+}
+
.abs-height-50 {
height: 50px !important;
}
diff --git a/server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx b/server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx
index 323c6a682cc..bd1f9862b8a 100644
--- a/server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx
+++ b/server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx
@@ -22,6 +22,7 @@ import { translate } from 'sonar-ui-common/helpers/l10n';
import { getBaseUrl } from 'sonar-ui-common/helpers/urls';
import { AlmBindingDefinition, AlmKeys, ProjectAlmBindingResponse } from '../../types/alm-settings';
import AzurePipelinesTutorial from './azure-pipelines/AzurePipelinesTutorial';
+import GitHubActionTutorial from './github-action/GitHubActionTutorial';
import GitLabCITutorial from './gitlabci/GitLabCITutorial';
import JenkinsTutorial from './jenkins/JenkinsTutorial';
import ManualTutorial from './manual/ManualTutorial';
@@ -68,6 +69,23 @@ export default function TutorialSelectionRenderer(props: TutorialSelectionRender
</header>
<div className="display-flex-justify-center">
+ {projectBinding?.alm === AlmKeys.GitHub && (
+ <button
+ className="button button-huge display-flex-column spacer-left spacer-right tutorial-mode-github"
+ onClick={() => props.onSelectTutorial(TutorialModes.GitHubActions)}
+ type="button">
+ <img
+ alt="" // Should be ignored by screen readers
+ height={64}
+ className="spacer-bottom spacer-top"
+ src={`${getBaseUrl()}/images/tutorials/github-actions.svg`}
+ />
+ <div className="medium big-spacer-top">
+ {translate('onboarding.tutorial.choose_method.github_action')}
+ </div>
+ </button>
+ )}
+
{projectBinding?.alm === AlmKeys.GitLab && (
<button
className="button button-huge display-flex-column spacer-left spacer-right tutorial-mode-gitlab"
@@ -137,6 +155,15 @@ export default function TutorialSelectionRenderer(props: TutorialSelectionRender
<ManualTutorial component={component} currentUser={currentUser} />
)}
+ {selectedTutorial === TutorialModes.GitHubActions && projectBinding !== undefined && (
+ <GitHubActionTutorial
+ baseUrl={baseUrl}
+ component={component}
+ currentUser={currentUser}
+ projectBinding={projectBinding}
+ />
+ )}
+
{selectedTutorial === TutorialModes.Jenkins && projectBinding !== undefined && (
<JenkinsTutorial
almBinding={almBinding}
diff --git a/server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelectionRenderer-test.tsx b/server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelectionRenderer-test.tsx
index 5ff0893230d..4709f308631 100644
--- a/server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelectionRenderer-test.tsx
+++ b/server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelectionRenderer-test.tsx
@@ -33,11 +33,17 @@ import TutorialSelectionRenderer, {
} from '../TutorialSelectionRenderer';
import { TutorialModes } from '../types';
+it.each([
+ ['bitbucket server', mockProjectBitbucketBindingResponse()],
+ ['github', mockProjectGithubBindingResponse()],
+ ['gitlab', mockProjectGitLabBindingResponse()],
+ ['azure', mockProjectAzureBindingResponse()]
+])('should render correctly for %s', (_, projectBinding) => {
+ expect(shallowRender({ projectBinding })).toMatchSnapshot();
+});
+
it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot('selection');
- expect(shallowRender({ projectBinding: mockProjectBitbucketBindingResponse() })).toMatchSnapshot(
- 'selection with jenkins available'
- );
expect(shallowRender({ loading: true })).toMatchSnapshot('loading');
expect(shallowRender({ selectedTutorial: TutorialModes.Manual })).toMatchSnapshot(
'manual tutorial'
@@ -50,6 +56,12 @@ it('should render correctly', () => {
).toMatchSnapshot('jenkins tutorial');
expect(
shallowRender({
+ selectedTutorial: TutorialModes.GitHubActions,
+ projectBinding: mockProjectGitLabBindingResponse()
+ })
+ ).toMatchSnapshot('github actions tutorial');
+ expect(
+ shallowRender({
selectedTutorial: TutorialModes.GitLabCI,
projectBinding: mockProjectGitLabBindingResponse()
})
@@ -88,6 +100,9 @@ it('should allow mode selection for Github', () => {
click(wrapper.find('button.tutorial-mode-manual'));
expect(onSelectTutorial).toHaveBeenLastCalledWith(TutorialModes.Manual);
+
+ click(wrapper.find('button.tutorial-mode-github'));
+ expect(onSelectTutorial).toHaveBeenLastCalledWith(TutorialModes.GitHubActions);
});
it('should allow mode selection for GitLab', () => {
diff --git a/server/sonar-web/src/main/js/components/tutorials/__tests__/__snapshots__/TutorialSelectionRenderer-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/__tests__/__snapshots__/TutorialSelectionRenderer-test.tsx.snap
index bcdfec2e016..69f3cb08ae5 100644
--- a/server/sonar-web/src/main/js/components/tutorials/__tests__/__snapshots__/TutorialSelectionRenderer-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/tutorials/__tests__/__snapshots__/TutorialSelectionRenderer-test.tsx.snap
@@ -1,5 +1,254 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
+exports[`should render correctly for azure 1`] = `
+<Fragment>
+ <div
+ className="tutorial-selection"
+ >
+ <header
+ className="spacer-top spacer-bottom padded"
+ >
+ <h1
+ className="text-center big-spacer-bottom"
+ >
+ onboarding.tutorial.choose_method
+ </h1>
+ </header>
+ <div
+ className="display-flex-justify-center"
+ >
+ <button
+ className="button button-huge display-flex-column spacer-left spacer-right azure-pipelines"
+ onClick={[Function]}
+ type="button"
+ >
+ <img
+ alt=""
+ height={80}
+ src="/images/alm/azure.svg"
+ />
+ <div
+ className="medium big-spacer-top"
+ >
+ onboarding.tutorial.choose_method.azure_pipelines
+ </div>
+ </button>
+ <button
+ className="button button-huge display-flex-column spacer-left spacer-right tutorial-mode-manual"
+ onClick={[Function]}
+ type="button"
+ >
+ <img
+ alt=""
+ height={80}
+ src="/images/sonarcloud/analysis/manual.svg"
+ />
+ <div
+ className="medium big-spacer-top"
+ >
+ onboarding.tutorial.choose_method.manual
+ </div>
+ </button>
+ </div>
+ </div>
+</Fragment>
+`;
+
+exports[`should render correctly for bitbucket server 1`] = `
+<Fragment>
+ <div
+ className="tutorial-selection"
+ >
+ <header
+ className="spacer-top spacer-bottom padded"
+ >
+ <h1
+ className="text-center big-spacer-bottom"
+ >
+ onboarding.tutorial.choose_method
+ </h1>
+ </header>
+ <div
+ className="display-flex-justify-center"
+ >
+ <button
+ className="button button-huge display-flex-column spacer-left spacer-right tutorial-mode-jenkins"
+ onClick={[Function]}
+ type="button"
+ >
+ <img
+ alt=""
+ height={80}
+ src="/images/tutorials/jenkins.svg"
+ />
+ <div
+ className="medium big-spacer-top"
+ >
+ onboarding.tutorial.choose_method.jenkins
+ </div>
+ </button>
+ <button
+ className="button button-huge display-flex-column spacer-left spacer-right tutorial-mode-manual"
+ onClick={[Function]}
+ type="button"
+ >
+ <img
+ alt=""
+ height={80}
+ src="/images/sonarcloud/analysis/manual.svg"
+ />
+ <div
+ className="medium big-spacer-top"
+ >
+ onboarding.tutorial.choose_method.manual
+ </div>
+ </button>
+ </div>
+ </div>
+</Fragment>
+`;
+
+exports[`should render correctly for github 1`] = `
+<Fragment>
+ <div
+ className="tutorial-selection"
+ >
+ <header
+ className="spacer-top spacer-bottom padded"
+ >
+ <h1
+ className="text-center big-spacer-bottom"
+ >
+ onboarding.tutorial.choose_method
+ </h1>
+ </header>
+ <div
+ className="display-flex-justify-center"
+ >
+ <button
+ className="button button-huge display-flex-column spacer-left spacer-right tutorial-mode-github"
+ onClick={[Function]}
+ type="button"
+ >
+ <img
+ alt=""
+ className="spacer-bottom spacer-top"
+ height={64}
+ src="/images/tutorials/github-actions.svg"
+ />
+ <div
+ className="medium big-spacer-top"
+ >
+ onboarding.tutorial.choose_method.github_action
+ </div>
+ </button>
+ <button
+ className="button button-huge display-flex-column spacer-left spacer-right tutorial-mode-jenkins"
+ onClick={[Function]}
+ type="button"
+ >
+ <img
+ alt=""
+ height={80}
+ src="/images/tutorials/jenkins.svg"
+ />
+ <div
+ className="medium big-spacer-top"
+ >
+ onboarding.tutorial.choose_method.jenkins
+ </div>
+ </button>
+ <button
+ className="button button-huge display-flex-column spacer-left spacer-right tutorial-mode-manual"
+ onClick={[Function]}
+ type="button"
+ >
+ <img
+ alt=""
+ height={80}
+ src="/images/sonarcloud/analysis/manual.svg"
+ />
+ <div
+ className="medium big-spacer-top"
+ >
+ onboarding.tutorial.choose_method.manual
+ </div>
+ </button>
+ </div>
+ </div>
+</Fragment>
+`;
+
+exports[`should render correctly for gitlab 1`] = `
+<Fragment>
+ <div
+ className="tutorial-selection"
+ >
+ <header
+ className="spacer-top spacer-bottom padded"
+ >
+ <h1
+ className="text-center big-spacer-bottom"
+ >
+ onboarding.tutorial.choose_method
+ </h1>
+ </header>
+ <div
+ className="display-flex-justify-center"
+ >
+ <button
+ className="button button-huge display-flex-column spacer-left spacer-right tutorial-mode-gitlab"
+ onClick={[Function]}
+ type="button"
+ >
+ <img
+ alt=""
+ height={80}
+ src="/images/alm/gitlab.svg"
+ />
+ <div
+ className="medium big-spacer-top"
+ >
+ onboarding.tutorial.choose_method.gitlab_ci
+ </div>
+ </button>
+ <button
+ className="button button-huge display-flex-column spacer-left spacer-right tutorial-mode-jenkins"
+ onClick={[Function]}
+ type="button"
+ >
+ <img
+ alt=""
+ height={80}
+ src="/images/tutorials/jenkins.svg"
+ />
+ <div
+ className="medium big-spacer-top"
+ >
+ onboarding.tutorial.choose_method.jenkins
+ </div>
+ </button>
+ <button
+ className="button button-huge display-flex-column spacer-left spacer-right tutorial-mode-manual"
+ onClick={[Function]}
+ type="button"
+ >
+ <img
+ alt=""
+ height={80}
+ src="/images/sonarcloud/analysis/manual.svg"
+ />
+ <div
+ className="medium big-spacer-top"
+ >
+ onboarding.tutorial.choose_method.manual
+ </div>
+ </button>
+ </div>
+ </div>
+</Fragment>
+`;
+
exports[`should render correctly: azure pipelines tutorial 1`] = `
<Fragment>
<AzurePipelinesTutorial
@@ -49,6 +298,54 @@ exports[`should render correctly: azure pipelines tutorial 1`] = `
</Fragment>
`;
+exports[`should render correctly: github actions tutorial 1`] = `
+<Fragment>
+ <GitHubActionTutorial
+ baseUrl="http://localhost:9000"
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ currentUser={
+ Object {
+ "groups": Array [],
+ "isLoggedIn": true,
+ "login": "luke",
+ "name": "Skywalker",
+ "scmAccounts": Array [],
+ }
+ }
+ projectBinding={
+ Object {
+ "alm": "gitlab",
+ "key": "foo",
+ "monorepo": true,
+ "repository": "PROJECT_KEY",
+ "url": "https://gitlab.com/api/v4",
+ }
+ }
+ />
+</Fragment>
+`;
+
exports[`should render correctly: gitlab tutorial 1`] = `
<Fragment>
<GitLabCITutorial
@@ -223,57 +520,3 @@ exports[`should render correctly: selection 1`] = `
</div>
</Fragment>
`;
-
-exports[`should render correctly: selection with jenkins available 1`] = `
-<Fragment>
- <div
- className="tutorial-selection"
- >
- <header
- className="spacer-top spacer-bottom padded"
- >
- <h1
- className="text-center big-spacer-bottom"
- >
- onboarding.tutorial.choose_method
- </h1>
- </header>
- <div
- className="display-flex-justify-center"
- >
- <button
- className="button button-huge display-flex-column spacer-left spacer-right tutorial-mode-jenkins"
- onClick={[Function]}
- type="button"
- >
- <img
- alt=""
- height={80}
- src="/images/tutorials/jenkins.svg"
- />
- <div
- className="medium big-spacer-top"
- >
- onboarding.tutorial.choose_method.jenkins
- </div>
- </button>
- <button
- className="button button-huge display-flex-column spacer-left spacer-right tutorial-mode-manual"
- onClick={[Function]}
- type="button"
- >
- <img
- alt=""
- height={80}
- src="/images/sonarcloud/analysis/manual.svg"
- />
- <div
- className="medium big-spacer-top"
- >
- onboarding.tutorial.choose_method.manual
- </div>
- </button>
- </div>
- </div>
-</Fragment>
-`;
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/AllSet.tsx b/server/sonar-web/src/main/js/components/tutorials/components/AllSet.tsx
new file mode 100644
index 00000000000..74dd138b77b
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/components/AllSet.tsx
@@ -0,0 +1,83 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 { translate } from 'sonar-ui-common/helpers/l10n';
+import { getBaseUrl } from 'sonar-ui-common/helpers/urls';
+import { withAppState } from '../../hoc/withAppState';
+import SentenceWithHighlights from './SentenceWithHighlights';
+
+export interface AllSetProps {
+ appState: T.AppState;
+}
+
+export function AllSet(props: AllSetProps) {
+ const {
+ appState: { branchesEnabled }
+ } = props;
+
+ return (
+ <div className="abs-width-600">
+ <p className="big-spacer-bottom">
+ <SentenceWithHighlights
+ highlightKeys={['all_set']}
+ translationKey="onboarding.tutorial.ci_outro.all_set"
+ />
+ </p>
+ <div className="display-flex-row big-spacer-bottom">
+ <div>
+ <img
+ alt="" // Should be ignored by screen readers
+ className="big-spacer-right"
+ width={30}
+ src={`${getBaseUrl()}/images/tutorials/commit.svg`}
+ />
+ </div>
+ <div>
+ <p className="little-spacer-bottom">
+ <strong>{translate('onboarding.tutorial.ci_outro.commit')}</strong>
+ </p>
+ <p>
+ {branchesEnabled
+ ? translate('onboarding.tutorial.ci_outro.commit.why')
+ : translate('onboarding.tutorial.ci_outro.commit.why.no_branches')}
+ </p>
+ </div>
+ </div>
+ <div className="display-flex-row huge-spacer-bottom">
+ <div>
+ <img
+ alt="" // Should be ignored by screen readers
+ className="big-spacer-right"
+ width={30}
+ src={`${getBaseUrl()}/images/tutorials/refresh.svg`}
+ />
+ </div>
+ <div>
+ <p className="little-spacer-bottom">
+ <strong>{translate('onboarding.tutorial.ci_outro.refresh')}</strong>
+ </p>
+ <p>{translate('onboarding.tutorial.ci_outro.refresh.why')}</p>
+ </div>
+ </div>
+ </div>
+ );
+}
+
+export default withAppState(AllSet);
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/DefaultProjectKey.tsx b/server/sonar-web/src/main/js/components/tutorials/components/DefaultProjectKey.tsx
new file mode 100644
index 00000000000..70f457f5798
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/components/DefaultProjectKey.tsx
@@ -0,0 +1,41 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 CodeSnippet from '../../common/CodeSnippet';
+import SentenceWithFilename from './SentenceWithFilename';
+
+export interface DefaultProjectKeyProps {
+ component: T.Component;
+}
+
+const sonarProjectSnippet = (key: string) => `sonar.projectKey=${key}`;
+
+export default function DefaultProjectKey(props: DefaultProjectKeyProps) {
+ const { component } = props;
+ return (
+ <li className="abs-width-600">
+ <SentenceWithFilename
+ filename="sonar-project.properties"
+ translationKey="onboarding.tutorial.other.project_key"
+ />
+ <CodeSnippet snippet={sonarProjectSnippet(component.key)} />
+ </li>
+ );
+}
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/TokenStepGenerator.tsx b/server/sonar-web/src/main/js/components/tutorials/components/TokenStepGenerator.tsx
new file mode 100644
index 00000000000..dea0fa4a8c6
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/components/TokenStepGenerator.tsx
@@ -0,0 +1,60 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 } from 'sonar-ui-common/components/controls/buttons';
+import { translate } from 'sonar-ui-common/helpers/l10n';
+import EditTokenModal from './EditTokenModal';
+
+export interface TokenStepGeneratorProps {
+ component: T.Component;
+ currentUser: T.LoggedInUser;
+}
+
+export default function TokenStepGenerator(props: TokenStepGeneratorProps) {
+ const { component, currentUser } = props;
+ const [isModalVisible, toggleModal] = React.useState(false);
+
+ const toggleTokenModal = () => toggleModal(visible => !visible);
+ const closeTokenModal = () => toggleModal(false);
+
+ return (
+ <>
+ <li className="big-spacer-bottom">
+ <FormattedMessage
+ defaultMessage={translate('onboarding.tutorial.env_variables')}
+ id="onboarding.tutorial.env_variables"
+ values={{
+ extra: (
+ <Button className="spacer-left" onClick={toggleTokenModal}>
+ {translate('onboarding.token.generate_token')}
+ </Button>
+ ),
+ field: <strong>{translate('onboarding.tutorial.env_variables.field')}</strong>,
+ value: translate('onboarding.tutorial.env_variables.token_generator.value')
+ }}
+ />
+ </li>
+ {isModalVisible && (
+ <EditTokenModal component={component} currentUser={currentUser} onClose={closeTokenModal} />
+ )}
+ </>
+ );
+}
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/__tests__/AllSet-test.tsx b/server/sonar-web/src/main/js/components/tutorials/components/__tests__/AllSet-test.tsx
new file mode 100644
index 00000000000..1616135a49a
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/components/__tests__/AllSet-test.tsx
@@ -0,0 +1,34 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 { mockAppState } from '../../../../helpers/testMocks';
+import { AllSet, AllSetProps } from '../AllSet';
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot();
+ expect(shallowRender({ appState: mockAppState({ branchesEnabled: false }) })).toMatchSnapshot(
+ 'without branch'
+ );
+});
+
+function shallowRender(props: Partial<AllSetProps> = {}) {
+ return shallow<AllSetProps>(<AllSet appState={mockAppState()} {...props} />);
+}
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/__tests__/DefaultProjectKey-test.tsx b/server/sonar-web/src/main/js/components/tutorials/components/__tests__/DefaultProjectKey-test.tsx
new file mode 100644
index 00000000000..e4e023f0bd5
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/components/__tests__/DefaultProjectKey-test.tsx
@@ -0,0 +1,33 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 { mockComponent } from '../../../../helpers/testMocks';
+import DefaultProjectKey, { DefaultProjectKeyProps } from '../DefaultProjectKey';
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot();
+});
+
+function shallowRender(props: Partial<DefaultProjectKeyProps> = {}) {
+ return shallow<DefaultProjectKeyProps>(
+ <DefaultProjectKey component={mockComponent()} {...props} />
+ );
+}
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/__tests__/TokenStepGenerator-test.tsx b/server/sonar-web/src/main/js/components/tutorials/components/__tests__/TokenStepGenerator-test.tsx
new file mode 100644
index 00000000000..b93f00bcdb2
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/components/__tests__/TokenStepGenerator-test.tsx
@@ -0,0 +1,33 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 { mockComponent, mockLoggedInUser } from '../../../../helpers/testMocks';
+import TokenStepGenerator, { TokenStepGeneratorProps } from '../TokenStepGenerator';
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot();
+});
+
+function shallowRender(props: Partial<TokenStepGeneratorProps> = {}) {
+ return shallow<TokenStepGeneratorProps>(
+ <TokenStepGenerator component={mockComponent()} currentUser={mockLoggedInUser()} {...props} />
+ );
+}
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/__tests__/__snapshots__/AllSet-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/components/__tests__/__snapshots__/AllSet-test.tsx.snap
new file mode 100644
index 00000000000..6afe9cd744c
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/components/__tests__/__snapshots__/AllSet-test.tsx.snap
@@ -0,0 +1,135 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<div
+ className="abs-width-600"
+>
+ <p
+ className="big-spacer-bottom"
+ >
+ <SentenceWithHighlights
+ highlightKeys={
+ Array [
+ "all_set",
+ ]
+ }
+ translationKey="onboarding.tutorial.ci_outro.all_set"
+ />
+ </p>
+ <div
+ className="display-flex-row big-spacer-bottom"
+ >
+ <div>
+ <img
+ alt=""
+ className="big-spacer-right"
+ src="/images/tutorials/commit.svg"
+ width={30}
+ />
+ </div>
+ <div>
+ <p
+ className="little-spacer-bottom"
+ >
+ <strong>
+ onboarding.tutorial.ci_outro.commit
+ </strong>
+ </p>
+ <p>
+ onboarding.tutorial.ci_outro.commit.why.no_branches
+ </p>
+ </div>
+ </div>
+ <div
+ className="display-flex-row huge-spacer-bottom"
+ >
+ <div>
+ <img
+ alt=""
+ className="big-spacer-right"
+ src="/images/tutorials/refresh.svg"
+ width={30}
+ />
+ </div>
+ <div>
+ <p
+ className="little-spacer-bottom"
+ >
+ <strong>
+ onboarding.tutorial.ci_outro.refresh
+ </strong>
+ </p>
+ <p>
+ onboarding.tutorial.ci_outro.refresh.why
+ </p>
+ </div>
+ </div>
+</div>
+`;
+
+exports[`should render correctly: without branch 1`] = `
+<div
+ className="abs-width-600"
+>
+ <p
+ className="big-spacer-bottom"
+ >
+ <SentenceWithHighlights
+ highlightKeys={
+ Array [
+ "all_set",
+ ]
+ }
+ translationKey="onboarding.tutorial.ci_outro.all_set"
+ />
+ </p>
+ <div
+ className="display-flex-row big-spacer-bottom"
+ >
+ <div>
+ <img
+ alt=""
+ className="big-spacer-right"
+ src="/images/tutorials/commit.svg"
+ width={30}
+ />
+ </div>
+ <div>
+ <p
+ className="little-spacer-bottom"
+ >
+ <strong>
+ onboarding.tutorial.ci_outro.commit
+ </strong>
+ </p>
+ <p>
+ onboarding.tutorial.ci_outro.commit.why.no_branches
+ </p>
+ </div>
+ </div>
+ <div
+ className="display-flex-row huge-spacer-bottom"
+ >
+ <div>
+ <img
+ alt=""
+ className="big-spacer-right"
+ src="/images/tutorials/refresh.svg"
+ width={30}
+ />
+ </div>
+ <div>
+ <p
+ className="little-spacer-bottom"
+ >
+ <strong>
+ onboarding.tutorial.ci_outro.refresh
+ </strong>
+ </p>
+ <p>
+ onboarding.tutorial.ci_outro.refresh.why
+ </p>
+ </div>
+ </div>
+</div>
+`;
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/__tests__/__snapshots__/DefaultProjectKey-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/components/__tests__/__snapshots__/DefaultProjectKey-test.tsx.snap
new file mode 100644
index 00000000000..cb21627f326
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/components/__tests__/__snapshots__/DefaultProjectKey-test.tsx.snap
@@ -0,0 +1,15 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<li
+ className="abs-width-600"
+>
+ <SentenceWithFilename
+ filename="sonar-project.properties"
+ translationKey="onboarding.tutorial.other.project_key"
+ />
+ <CodeSnippet
+ snippet="sonar.projectKey=my-project"
+ />
+</li>
+`;
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/__tests__/__snapshots__/TokenStepGenerator-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/components/__tests__/__snapshots__/TokenStepGenerator-test.tsx.snap
new file mode 100644
index 00000000000..f7a17687227
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/components/__tests__/__snapshots__/TokenStepGenerator-test.tsx.snap
@@ -0,0 +1,28 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<Fragment>
+ <li
+ className="big-spacer-bottom"
+ >
+ <FormattedMessage
+ defaultMessage="onboarding.tutorial.env_variables"
+ id="onboarding.tutorial.env_variables"
+ values={
+ Object {
+ "extra": <Button
+ className="spacer-left"
+ onClick={[Function]}
+ >
+ onboarding.token.generate_token
+ </Button>,
+ "field": <strong>
+ onboarding.tutorial.env_variables.field
+ </strong>,
+ "value": "onboarding.tutorial.env_variables.token_generator.value",
+ }
+ }
+ />
+ </li>
+</Fragment>
+`;
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/AnalysisCommand.tsx b/server/sonar-web/src/main/js/components/tutorials/github-action/AnalysisCommand.tsx
new file mode 100644
index 00000000000..c0147f4be56
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/github-action/AnalysisCommand.tsx
@@ -0,0 +1,58 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 { withAppState } from '../../hoc/withAppState';
+import { BuildTools } from '../types';
+import DotNet from './commands/DotNet';
+import Gradle from './commands/Gradle';
+import JavaMaven from './commands/JavaMaven';
+import Others from './commands/Others';
+
+export interface AnalysisCommandProps {
+ appState: T.AppState;
+ buildTool?: BuildTools;
+ component: T.Component;
+}
+
+export function AnalysisCommand(props: AnalysisCommandProps) {
+ const {
+ buildTool,
+ component,
+ appState: { branchesEnabled }
+ } = props;
+
+ if (!buildTool) {
+ return null;
+ }
+
+ switch (buildTool) {
+ case BuildTools.Maven:
+ return <JavaMaven branchesEnabled={branchesEnabled} component={component} />;
+ case BuildTools.Gradle:
+ return <Gradle branchesEnabled={branchesEnabled} component={component} />;
+ case BuildTools.DotNet:
+ return <DotNet branchesEnabled={branchesEnabled} component={component} />;
+ case BuildTools.Other:
+ return <Others branchesEnabled={branchesEnabled} component={component} />;
+ }
+ return null;
+}
+
+export default withAppState(AnalysisCommand);
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/GitHubActionTutorial.tsx b/server/sonar-web/src/main/js/components/tutorials/github-action/GitHubActionTutorial.tsx
new file mode 100644
index 00000000000..dc176fd64e4
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/github-action/GitHubActionTutorial.tsx
@@ -0,0 +1,70 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 { translate } from 'sonar-ui-common/helpers/l10n';
+import { ProjectAlmBindingResponse } from '../../../types/alm-settings';
+import Step from '../components/Step';
+import SecretStep from './SecretStep';
+import YamlFileStep from './YamlFileStep';
+
+export enum Steps {
+ CREATE_SECRET = 1,
+ YAML = 2
+}
+
+export interface GitHubActionTutorialProps {
+ baseUrl: string;
+ component: T.Component;
+ currentUser: T.LoggedInUser;
+ projectBinding: ProjectAlmBindingResponse;
+}
+
+export default function GitHubActionTutorial(props: GitHubActionTutorialProps) {
+ const { baseUrl, currentUser, component, projectBinding } = props;
+
+ const [step, setStep] = React.useState<Steps>(Steps.CREATE_SECRET);
+ return (
+ <>
+ <Step
+ finished={step > Steps.CREATE_SECRET}
+ onOpen={() => setStep(Steps.CREATE_SECRET)}
+ open={step === Steps.CREATE_SECRET}
+ renderForm={() => (
+ <SecretStep
+ baseUrl={baseUrl}
+ component={component}
+ currentUser={currentUser}
+ projectBinding={projectBinding}
+ onDone={() => setStep(Steps.YAML)}
+ />
+ )}
+ stepNumber={Steps.CREATE_SECRET}
+ stepTitle={translate('onboarding.tutorial.with.github_action.create_secret.title')}
+ />
+ <Step
+ onOpen={() => setStep(Steps.YAML)}
+ open={step === Steps.YAML}
+ renderForm={() => <YamlFileStep component={component} />}
+ stepNumber={Steps.YAML}
+ stepTitle={translate('onboarding.tutorial.with.github_action.yaml.title')}
+ />
+ </>
+ );
+}
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/SecretStep.tsx b/server/sonar-web/src/main/js/components/tutorials/github-action/SecretStep.tsx
new file mode 100644
index 00000000000..67796e981bb
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/github-action/SecretStep.tsx
@@ -0,0 +1,128 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 } from 'sonar-ui-common/components/controls/buttons';
+import { ClipboardIconButton } from 'sonar-ui-common/components/controls/clipboard';
+import { translate } from 'sonar-ui-common/helpers/l10n';
+import { ProjectAlmBindingResponse } from '../../../types/alm-settings';
+import SentenceWithHighlights from '../components/SentenceWithHighlights';
+import TokenStepGenerator from '../components/TokenStepGenerator';
+
+export interface SecretStepProps {
+ baseUrl: string;
+ component: T.Component;
+ currentUser: T.LoggedInUser;
+ projectBinding: ProjectAlmBindingResponse;
+ onDone: () => void;
+}
+
+export default function SecretStep(props: SecretStepProps) {
+ const {
+ baseUrl,
+ component,
+ currentUser,
+ projectBinding: { repository }
+ } = props;
+
+ return (
+ <div className="boxed-group-inner">
+ <p className="big-spacer-bottom">
+ <FormattedMessage
+ defaultMessage={translate('onboarding.tutorial.with.github_action.secret.intro')}
+ id="onboarding.tutorial.with.github_action.secret.intro"
+ values={{
+ settings_secret: repository ? (
+ <a
+ href={`https://github.com/${repository}/settings/secrets`}
+ target="_blank"
+ rel="noopener noreferrer">
+ {translate('onboarding.tutorial.with.github_action.secret.intro.link')}
+ </a>
+ ) : (
+ translate('onboarding.tutorial.with.github_action.secret.intro.link')
+ )
+ }}
+ />
+ </p>
+ <ol className="list-styled">
+ <li>
+ <SentenceWithHighlights
+ translationKey="onboarding.tutorial.with.github_action.secret.new"
+ highlightKeys={['new_secret']}
+ />
+ </li>
+ <li>
+ <SentenceWithHighlights
+ translationKey="onboarding.tutorial.with.github_action.secret.name"
+ highlightKeys={['name']}
+ />
+ <code className="rule little-spacer-left">SONAR_TOKEN</code>
+ <ClipboardIconButton copyValue="SONAR_TOKEN" />
+ </li>
+ <TokenStepGenerator component={component} currentUser={currentUser} />
+ <li>
+ <SentenceWithHighlights
+ translationKey="onboarding.tutorial.with.github_action.secret.add"
+ highlightKeys={['add_secret']}
+ />
+ </li>
+ </ol>
+
+ <hr className="no-horizontal-margins" />
+
+ <ol className="list-styled big-spacer-top big-spacer-bottom">
+ <li>
+ <SentenceWithHighlights
+ translationKey="onboarding.tutorial.with.github_action.secret.new"
+ highlightKeys={['new_secret']}
+ />
+ </li>
+ <li>
+ <SentenceWithHighlights
+ translationKey="onboarding.tutorial.with.github_action.secret.name"
+ highlightKeys={['name']}
+ />
+
+ <code className="rule little-spacer-left">SONAR_HOST_URL</code>
+ <ClipboardIconButton copyValue="SONAR_HOST_URL" />
+ </li>
+ <li className="big-spacer-bottom">
+ <FormattedMessage
+ defaultMessage={translate('onboarding.tutorial.env_variables')}
+ id="onboarding.tutorial.env_variables"
+ values={{
+ extra: <ClipboardIconButton copyValue={baseUrl} />,
+ field: <strong>{translate('onboarding.tutorial.env_variables.field')}</strong>,
+ value: <code className="rule">{baseUrl}</code>
+ }}
+ />
+ </li>
+ <li>
+ <SentenceWithHighlights
+ translationKey="onboarding.tutorial.with.github_action.secret.add"
+ highlightKeys={['add_secret']}
+ />
+ </li>
+ </ol>
+ <Button onClick={props.onDone}>{translate('continue')}</Button>
+ </div>
+ );
+}
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/YamlFileStep.tsx b/server/sonar-web/src/main/js/components/tutorials/github-action/YamlFileStep.tsx
new file mode 100644
index 00000000000..e76055a96e3
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/github-action/YamlFileStep.tsx
@@ -0,0 +1,60 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 { translate } from 'sonar-ui-common/helpers/l10n';
+import AllSet from '../components/AllSet';
+import RenderOptions from '../components/RenderOptions';
+import { BuildTools } from '../types';
+import AnalysisCommand from './AnalysisCommand';
+
+export interface YamlFileStepProps {
+ component: T.Component;
+}
+
+export default function YamlFileStep(props: YamlFileStepProps) {
+ const { component } = props;
+ const buildTools = [BuildTools.Maven, BuildTools.Gradle, BuildTools.DotNet, BuildTools.Other];
+ const [buildToolSelected, setBuildToolSelected] = React.useState<BuildTools>();
+
+ return (
+ <>
+ <ol className="list-styled big-spacer-top big-spacer-bottom">
+ <li>
+ {translate('onboarding.build')}
+
+ <RenderOptions
+ checked={buildToolSelected}
+ name="language"
+ onCheck={value => setBuildToolSelected(value as BuildTools)}
+ options={buildTools}
+ optionLabelKey="onboarding.build"
+ />
+ </li>
+ <AnalysisCommand buildTool={buildToolSelected} component={component} />
+ </ol>
+ {buildToolSelected !== undefined && (
+ <>
+ <hr className="huge-spacer-top huge-spacer-bottom" />
+ <AllSet />
+ </>
+ )}
+ </>
+ );
+}
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/AnalysisCommand-test.tsx b/server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/AnalysisCommand-test.tsx
new file mode 100644
index 00000000000..461b5ac519c
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/AnalysisCommand-test.tsx
@@ -0,0 +1,41 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 { mockAppState, mockComponent } from '../../../../helpers/testMocks';
+import { BuildTools } from '../../types';
+import { AnalysisCommand, AnalysisCommandProps } from '../AnalysisCommand';
+
+it.each([
+ undefined,
+ BuildTools.CFamily,
+ BuildTools.DotNet,
+ BuildTools.Gradle,
+ BuildTools.Maven,
+ BuildTools.Other
+])('should render correctly for %p', buildTool => {
+ expect(shallowRender({ buildTool })).toMatchSnapshot();
+});
+
+function shallowRender(props: Partial<AnalysisCommandProps> = {}) {
+ return shallow<AnalysisCommandProps>(
+ <AnalysisCommand appState={mockAppState()} component={mockComponent()} {...props} />
+ );
+}
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/GitHubActionTutorial-test.tsx b/server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/GitHubActionTutorial-test.tsx
new file mode 100644
index 00000000000..cc7f4a33e99
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/GitHubActionTutorial-test.tsx
@@ -0,0 +1,45 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 { mockProjectGithubBindingResponse } from '../../../../helpers/mocks/alm-settings';
+import { mockComponent, mockLoggedInUser } from '../../../../helpers/testMocks';
+import Step from '../../components/Step';
+import GitHubActionTutorial, { GitHubActionTutorialProps } from '../GitHubActionTutorial';
+
+it('should render correctly', () => {
+ const wrapper = shallowRender();
+ expect(wrapper).toMatchSnapshot('For secret steps');
+ const stepYaml = wrapper.find(Step).at(1);
+ stepYaml.simulate('open');
+ expect(wrapper).toMatchSnapshot('For yaml steps');
+});
+
+function shallowRender(props: Partial<GitHubActionTutorialProps> = {}) {
+ return shallow<GitHubActionTutorialProps>(
+ <GitHubActionTutorial
+ baseUrl="test"
+ currentUser={mockLoggedInUser()}
+ component={mockComponent()}
+ projectBinding={mockProjectGithubBindingResponse()}
+ {...props}
+ />
+ );
+}
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/SecretStep-test.tsx b/server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/SecretStep-test.tsx
new file mode 100644
index 00000000000..57b80abbc28
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/SecretStep-test.tsx
@@ -0,0 +1,41 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 { mockProjectGithubBindingResponse } from '../../../../helpers/mocks/alm-settings';
+import { mockComponent, mockLoggedInUser } from '../../../../helpers/testMocks';
+import SecretStep, { SecretStepProps } from '../SecretStep';
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot();
+});
+
+function shallowRender(props: Partial<SecretStepProps> = {}) {
+ return shallow<SecretStepProps>(
+ <SecretStep
+ baseUrl="test"
+ component={mockComponent()}
+ currentUser={mockLoggedInUser()}
+ projectBinding={mockProjectGithubBindingResponse()}
+ onDone={jest.fn()}
+ {...props}
+ />
+ );
+}
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/YamlFileStep-test.tsx b/server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/YamlFileStep-test.tsx
new file mode 100644
index 00000000000..1d1f3c07d1b
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/YamlFileStep-test.tsx
@@ -0,0 +1,31 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 { mockComponent } from '../../../../helpers/testMocks';
+import YamlFileStep, { YamlFileStepProps } from '../YamlFileStep';
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot();
+});
+
+function shallowRender(props: Partial<YamlFileStepProps> = {}) {
+ return shallow<YamlFileStepProps>(<YamlFileStep component={mockComponent()} {...props} />);
+}
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/__snapshots__/AnalysisCommand-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/__snapshots__/AnalysisCommand-test.tsx.snap
new file mode 100644
index 00000000000..4f86247edbf
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/__snapshots__/AnalysisCommand-test.tsx.snap
@@ -0,0 +1,113 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly for "cfamily" 1`] = `""`;
+
+exports[`should render correctly for "dotnet" 1`] = `
+<DotNet
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+/>
+`;
+
+exports[`should render correctly for "gradle" 1`] = `
+<Gradle
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+/>
+`;
+
+exports[`should render correctly for "maven" 1`] = `
+<JavaMaven
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+/>
+`;
+
+exports[`should render correctly for "other" 1`] = `
+<Others
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+/>
+`;
+
+exports[`should render correctly for undefined 1`] = `""`;
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/__snapshots__/GitHubActionTutorial-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/__snapshots__/GitHubActionTutorial-test.tsx.snap
new file mode 100644
index 00000000000..caec4a2f43f
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/__snapshots__/GitHubActionTutorial-test.tsx.snap
@@ -0,0 +1,41 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly: For secret steps 1`] = `
+<Fragment>
+ <Step
+ finished={false}
+ onOpen={[Function]}
+ open={true}
+ renderForm={[Function]}
+ stepNumber={1}
+ stepTitle="onboarding.tutorial.with.github_action.create_secret.title"
+ />
+ <Step
+ onOpen={[Function]}
+ open={false}
+ renderForm={[Function]}
+ stepNumber={2}
+ stepTitle="onboarding.tutorial.with.github_action.yaml.title"
+ />
+</Fragment>
+`;
+
+exports[`should render correctly: For yaml steps 1`] = `
+<Fragment>
+ <Step
+ finished={true}
+ onOpen={[Function]}
+ open={false}
+ renderForm={[Function]}
+ stepNumber={1}
+ stepTitle="onboarding.tutorial.with.github_action.create_secret.title"
+ />
+ <Step
+ onOpen={[Function]}
+ open={true}
+ renderForm={[Function]}
+ stepNumber={2}
+ stepTitle="onboarding.tutorial.with.github_action.yaml.title"
+ />
+</Fragment>
+`;
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/__snapshots__/SecretStep-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/__snapshots__/SecretStep-test.tsx.snap
new file mode 100644
index 00000000000..357fd880db0
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/__snapshots__/SecretStep-test.tsx.snap
@@ -0,0 +1,175 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<div
+ className="boxed-group-inner"
+>
+ <p
+ className="big-spacer-bottom"
+ >
+ <FormattedMessage
+ defaultMessage="onboarding.tutorial.with.github_action.secret.intro"
+ id="onboarding.tutorial.with.github_action.secret.intro"
+ values={
+ Object {
+ "settings_secret": <a
+ href="https://github.com/PROJECT_KEY/settings/secrets"
+ rel="noopener noreferrer"
+ target="_blank"
+ >
+ onboarding.tutorial.with.github_action.secret.intro.link
+ </a>,
+ }
+ }
+ />
+ </p>
+ <ol
+ className="list-styled"
+ >
+ <li>
+ <SentenceWithHighlights
+ highlightKeys={
+ Array [
+ "new_secret",
+ ]
+ }
+ translationKey="onboarding.tutorial.with.github_action.secret.new"
+ />
+ </li>
+ <li>
+ <SentenceWithHighlights
+ highlightKeys={
+ Array [
+ "name",
+ ]
+ }
+ translationKey="onboarding.tutorial.with.github_action.secret.name"
+ />
+ <code
+ className="rule little-spacer-left"
+ >
+ SONAR_TOKEN
+ </code>
+ <ClipboardIconButton
+ copyValue="SONAR_TOKEN"
+ />
+ </li>
+ <TokenStepGenerator
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ currentUser={
+ Object {
+ "groups": Array [],
+ "isLoggedIn": true,
+ "login": "luke",
+ "name": "Skywalker",
+ "scmAccounts": Array [],
+ }
+ }
+ />
+ <li>
+ <SentenceWithHighlights
+ highlightKeys={
+ Array [
+ "add_secret",
+ ]
+ }
+ translationKey="onboarding.tutorial.with.github_action.secret.add"
+ />
+ </li>
+ </ol>
+ <hr
+ className="no-horizontal-margins"
+ />
+ <ol
+ className="list-styled big-spacer-top big-spacer-bottom"
+ >
+ <li>
+ <SentenceWithHighlights
+ highlightKeys={
+ Array [
+ "new_secret",
+ ]
+ }
+ translationKey="onboarding.tutorial.with.github_action.secret.new"
+ />
+ </li>
+ <li>
+ <SentenceWithHighlights
+ highlightKeys={
+ Array [
+ "name",
+ ]
+ }
+ translationKey="onboarding.tutorial.with.github_action.secret.name"
+ />
+ <code
+ className="rule little-spacer-left"
+ >
+ SONAR_HOST_URL
+ </code>
+ <ClipboardIconButton
+ copyValue="SONAR_HOST_URL"
+ />
+ </li>
+ <li
+ className="big-spacer-bottom"
+ >
+ <FormattedMessage
+ defaultMessage="onboarding.tutorial.env_variables"
+ id="onboarding.tutorial.env_variables"
+ values={
+ Object {
+ "extra": <ClipboardIconButton
+ copyValue="test"
+ />,
+ "field": <strong>
+ onboarding.tutorial.env_variables.field
+ </strong>,
+ "value": <code
+ className="rule"
+ >
+ test
+ </code>,
+ }
+ }
+ />
+ </li>
+ <li>
+ <SentenceWithHighlights
+ highlightKeys={
+ Array [
+ "add_secret",
+ ]
+ }
+ translationKey="onboarding.tutorial.with.github_action.secret.add"
+ />
+ </li>
+ </ol>
+ <Button
+ onClick={[MockFunction]}
+ >
+ continue
+ </Button>
+</div>
+`;
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/__snapshots__/YamlFileStep-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/__snapshots__/YamlFileStep-test.tsx.snap
new file mode 100644
index 00000000000..8f3bfa8a26a
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/__snapshots__/YamlFileStep-test.tsx.snap
@@ -0,0 +1,50 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<Fragment>
+ <ol
+ className="list-styled big-spacer-top big-spacer-bottom"
+ >
+ <li>
+ onboarding.build
+ <RenderOptions
+ name="language"
+ onCheck={[Function]}
+ optionLabelKey="onboarding.build"
+ options={
+ Array [
+ "maven",
+ "gradle",
+ "dotnet",
+ "other",
+ ]
+ }
+ />
+ </li>
+ <Connect(withAppState(AnalysisCommand))
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ />
+ </ol>
+</Fragment>
+`;
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/commands/CreateYmlFile.tsx b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/CreateYmlFile.tsx
new file mode 100644
index 00000000000..e7c47ed263d
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/CreateYmlFile.tsx
@@ -0,0 +1,49 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 { ClipboardIconButton } from 'sonar-ui-common/components/controls/clipboard';
+import { translate } from 'sonar-ui-common/helpers/l10n';
+import CodeSnippet from '../../../common/CodeSnippet';
+
+export interface CreateYmlFileProps {
+ yamlTemplate: string;
+}
+
+export default function CreateYmlFile(props: CreateYmlFileProps) {
+ const { yamlTemplate } = props;
+ return (
+ <li className="abs-width-800">
+ <FormattedMessage
+ defaultMessage={translate('onboarding.tutorial.with.github_action.yaml.create_yml')}
+ id="onboarding.tutorial.with.github_action.yaml.create_yml"
+ values={{
+ file: (
+ <>
+ <code className="rule">.github/workflows/build.yml</code>
+ <ClipboardIconButton copyValue=".github/workflows/build.yml" />
+ </>
+ )
+ }}
+ />
+ <CodeSnippet snippet={yamlTemplate} />
+ </li>
+ );
+}
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/commands/DotNet.tsx b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/DotNet.tsx
new file mode 100644
index 00000000000..f8a5d5edb14
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/DotNet.tsx
@@ -0,0 +1,77 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 CreateYmlFile from './CreateYmlFile';
+
+export interface DotNetProps {
+ branchesEnabled?: boolean;
+ component: T.Component;
+}
+
+const dotnetYamlTemplate = (projectKey: string, branchesEnabled: boolean) => `name: Build
+on:
+ push:
+ branches:
+ - master # or the name of your main branch
+${branchesEnabled ? ' pull_request:\n types: [opened, synchronize, reopened]' : ''}
+jobs:
+ build:
+ name: Build
+ runs-on: windows-latest
+ steps:
+ - name: Set up JDK 11
+ uses: actions/setup-java@v1
+ with:
+ java-version: 1.11
+ - uses: actions/checkout@v2
+ with:
+ fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
+ - name: Cache SonarQube packages
+ uses: actions/cache@v1
+ with:
+ path: ~\\sonar\\cache
+ key: \${{ runner.os }}-sonar
+ restore-keys: \${{ runner.os }}-sonar
+ - name: Cache SonarQube scanner
+ id: cache-sonar-scanner
+ uses: actions/cache@v1
+ with:
+ path: .\\.sonar\\scanner
+ key: \${{ runner.os }}-sonar-scanner
+ restore-keys: \${{ runner.os }}-sonar-scanner
+ - name: Install SonarQube scanner
+ if: steps.cache-sonar-scanner.outputs.cache-hit != 'true'
+ shell: powershell
+ run: |
+ New-Item -Path .\\.sonar\\scanner -ItemType Directory
+ dotnet tool update dotnet-sonarscanner --tool-path .\\.sonar\\scanner
+ - name: Build and analyze
+ env:
+ GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
+ shell: powershell
+ run: |
+ .\\.sonar\\scanner\\dotnet-sonarscanner begin /k:"${projectKey}" /d:sonar.login="\${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="\${{ secrets.SONAR_HOST_URL }}"
+ dotnet build
+ .\\.sonar\\scanner\\dotnet-sonarscanner end /d:sonar.login="\${{ secrets.SONAR_TOKEN }}"`;
+
+export default function DotNet(props: DotNetProps) {
+ const { component, branchesEnabled } = props;
+ return <CreateYmlFile yamlTemplate={dotnetYamlTemplate(component.key, !!branchesEnabled)} />;
+}
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/commands/Gradle.tsx b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/Gradle.tsx
new file mode 100644
index 00000000000..6f3d323f13f
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/Gradle.tsx
@@ -0,0 +1,93 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 { ClipboardIconButton } from 'sonar-ui-common/components/controls/clipboard';
+import { translate } from 'sonar-ui-common/helpers/l10n';
+import CodeSnippet from '../../../common/CodeSnippet';
+import { buildGradleSnippet } from '../../utils';
+import CreateYmlFile from './CreateYmlFile';
+
+export interface GradleProps {
+ branchesEnabled?: boolean;
+ component: T.Component;
+}
+const gradleYamlTemplate = (branchesEnabled: boolean) => `name: Build
+on:
+ push:
+ branches:
+ - master # or the name of your main branch
+${branchesEnabled ? ' pull_request:\n types: [opened, synchronize, reopened]' : ''}
+jobs:
+ build:
+ name: Build
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ with:
+ fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
+ - name: Set up JDK 11
+ uses: actions/setup-java@v1
+ with:
+ java-version: 11
+ - name: Cache SonarQube packages
+ uses: actions/cache@v1
+ with:
+ path: ~/.sonar/cache
+ key: \${{ runner.os }}-sonar
+ restore-keys: \${{ runner.os }}-sonar
+ - name: Cache Gradle packages
+ uses: actions/cache@v1
+ with:
+ path: ~/.gradle/caches
+ key: \${{ runner.os }}-gradle-\${{ hashFiles('**/*.gradle') }}
+ restore-keys: \${{ runner.os }}-gradle
+ - name: Build and analyze
+ env:
+ GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
+ SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
+ SONAR_HOST_URL: \${{ secrets.SONAR_HOST_URL }}
+ run: ./gradlew build sonarqube --info`;
+
+export default function Gradle(props: GradleProps) {
+ const { component, branchesEnabled } = props;
+
+ return (
+ <>
+ <li className="abs-width-600">
+ <FormattedMessage
+ defaultMessage={translate('onboarding.tutorial.with.github_action.yaml.gradle')}
+ id="onboarding.tutorial.with.github_action.yaml.gradle"
+ values={{
+ gradle: (
+ <>
+ <code className="rule">build.gradle</code>
+ <ClipboardIconButton copyValue="build.gradle" />
+ </>
+ ),
+ sq: <code className="rule">org.sonarqube</code>
+ }}
+ />
+ <CodeSnippet snippet={buildGradleSnippet(component.key)} />
+ </li>
+ <CreateYmlFile yamlTemplate={gradleYamlTemplate(!!branchesEnabled)} />
+ </>
+ );
+}
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/commands/JavaMaven.tsx b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/JavaMaven.tsx
new file mode 100644
index 00000000000..cbafc007bf5
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/JavaMaven.tsx
@@ -0,0 +1,92 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 { ClipboardIconButton } from 'sonar-ui-common/components/controls/clipboard';
+import { translate } from 'sonar-ui-common/helpers/l10n';
+import CodeSnippet from '../../../common/CodeSnippet';
+import { mavenPomSnippet } from '../../utils';
+import CreateYmlFile from './CreateYmlFile';
+
+export interface JavaMavenProps {
+ branchesEnabled?: boolean;
+ component: T.Component;
+}
+
+const mavenYamlTemplte = (branchesEnabled: boolean) => `name: Build
+on:
+ push:
+ branches:
+ - master # or the name of your main branch
+${branchesEnabled ? ' pull_request:\n types: [opened, synchronize, reopened]' : ''}
+jobs:
+ build:
+ name: Build
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ with:
+ fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
+ - name: Set up JDK 11
+ uses: actions/setup-java@v1
+ with:
+ java-version: 11
+ - name: Cache SonarQube packages
+ uses: actions/cache@v1
+ with:
+ path: ~/.sonar/cache
+ key: \${{ runner.os }}-sonar
+ restore-keys: \${{ runner.os }}-sonar
+ - name: Cache Maven packages
+ uses: actions/cache@v1
+ with:
+ path: ~/.m2
+ key: \${{ runner.os }}-m2-\${{ hashFiles('**/pom.xml') }}
+ restore-keys: \${{ runner.os }}-m2
+ - name: Build and analyze
+ env:
+ GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
+ SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
+ SONAR_HOST_URL: \${{ secrets.SONAR_HOST_URL }}
+ run: mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar`;
+
+export default function JavaMaven(props: JavaMavenProps) {
+ const { component, branchesEnabled } = props;
+ return (
+ <>
+ <li className="abs-width-600">
+ <FormattedMessage
+ defaultMessage={translate('onboarding.tutorial.with.github_action.yaml.maven.pom')}
+ id="onboarding.tutorial.with.github_action.yaml.maven.pom"
+ values={{
+ pom: (
+ <>
+ <code className="rule">pom.xml</code>
+ <ClipboardIconButton copyValue="pom.xml" />
+ </>
+ )
+ }}
+ />
+ <CodeSnippet snippet={mavenPomSnippet(component.key)} />
+ </li>
+ <CreateYmlFile yamlTemplate={mavenYamlTemplte(!!branchesEnabled)} />
+ </>
+ );
+}
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/commands/Others.tsx b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/Others.tsx
new file mode 100644
index 00000000000..b2de4454b8b
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/Others.tsx
@@ -0,0 +1,57 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 DefaultProjectKey from '../../components/DefaultProjectKey';
+import CreateYmlFile from './CreateYmlFile';
+
+export interface OthersProps {
+ branchesEnabled?: boolean;
+ component: T.Component;
+}
+
+const dotnetYamlTemplate = (branchesEnabled: boolean) => `name: Build
+on:
+ push:
+ branches:
+ - master # or the name of your main branch
+${branchesEnabled ? ' pull_request:\n types: [opened, synchronize, reopened]' : ''}
+jobs:
+ build:
+ name: Build
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+ - uses: docker://sonarsource/sonar-scanner-cli:latest
+ env:
+ GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}
+ SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
+ SONAR_HOST_URL: \${{ secrets.SONAR_HOST_URL }}`;
+
+export default function Others(props: OthersProps) {
+ const { component, branchesEnabled } = props;
+ return (
+ <>
+ <DefaultProjectKey component={component} />
+ <CreateYmlFile yamlTemplate={dotnetYamlTemplate(!!branchesEnabled)} />
+ </>
+ );
+}
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/CreateYmlFile-test.tsx b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/CreateYmlFile-test.tsx
new file mode 100644
index 00000000000..9dfe3cbcb55
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/CreateYmlFile-test.tsx
@@ -0,0 +1,31 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 CreateYmlFile, { CreateYmlFileProps } from '../CreateYmlFile';
+import { GradleProps } from '../Gradle';
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot();
+});
+
+function shallowRender(props: Partial<CreateYmlFileProps> = {}) {
+ return shallow<GradleProps>(<CreateYmlFile yamlTemplate="temaplate" {...props} />);
+}
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/DotNet-test.tsx b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/DotNet-test.tsx
new file mode 100644
index 00000000000..64f0b1e4517
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/DotNet-test.tsx
@@ -0,0 +1,34 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 { mockComponent } from '../../../../../helpers/testMocks';
+import DotNet, { DotNetProps } from '../DotNet';
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot();
+ expect(shallowRender({ branchesEnabled: false })).toMatchSnapshot('without branch enabled');
+});
+
+function shallowRender(props: Partial<DotNetProps> = {}) {
+ return shallow<DotNetProps>(
+ <DotNet branchesEnabled={true} component={mockComponent()} {...props} />
+ );
+}
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/Gradle-test.tsx b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/Gradle-test.tsx
new file mode 100644
index 00000000000..cc1adcff93c
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/Gradle-test.tsx
@@ -0,0 +1,34 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 { mockComponent } from '../../../../../helpers/testMocks';
+import Gradle, { GradleProps } from '../Gradle';
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot();
+ expect(shallowRender({ branchesEnabled: false })).toMatchSnapshot('without branch enabled');
+});
+
+function shallowRender(props: Partial<GradleProps> = {}) {
+ return shallow<GradleProps>(
+ <Gradle branchesEnabled={true} component={mockComponent()} {...props} />
+ );
+}
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/JavaMaven-test.tsx b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/JavaMaven-test.tsx
new file mode 100644
index 00000000000..809996402a8
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/JavaMaven-test.tsx
@@ -0,0 +1,34 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 { mockComponent } from '../../../../../helpers/testMocks';
+import JavaMaven, { JavaMavenProps } from '../../commands/JavaMaven';
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot();
+ expect(shallowRender({ branchesEnabled: false })).toMatchSnapshot('without branch enabled');
+});
+
+function shallowRender(props: Partial<JavaMavenProps> = {}) {
+ return shallow<JavaMavenProps>(
+ <JavaMaven branchesEnabled={true} component={mockComponent()} {...props} />
+ );
+}
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/Others-test.tsx b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/Others-test.tsx
new file mode 100644
index 00000000000..8130c93369e
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/Others-test.tsx
@@ -0,0 +1,34 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 { mockComponent } from '../../../../../helpers/testMocks';
+import Others, { OthersProps } from '../../commands/Others';
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot();
+ expect(shallowRender({ branchesEnabled: false })).toMatchSnapshot('without branch enabled');
+});
+
+function shallowRender(props: Partial<OthersProps> = {}) {
+ return shallow<OthersProps>(
+ <Others branchesEnabled={true} component={mockComponent()} {...props} />
+ );
+}
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/__snapshots__/CreateYmlFile-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/__snapshots__/CreateYmlFile-test.tsx.snap
new file mode 100644
index 00000000000..61e32f72b14
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/__snapshots__/CreateYmlFile-test.tsx.snap
@@ -0,0 +1,29 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<li
+ className="abs-width-800"
+>
+ <FormattedMessage
+ defaultMessage="onboarding.tutorial.with.github_action.yaml.create_yml"
+ id="onboarding.tutorial.with.github_action.yaml.create_yml"
+ values={
+ Object {
+ "file": <React.Fragment>
+ <code
+ className="rule"
+ >
+ .github/workflows/build.yml
+ </code>
+ <ClipboardIconButton
+ copyValue=".github/workflows/build.yml"
+ />
+ </React.Fragment>,
+ }
+ }
+ />
+ <CodeSnippet
+ snippet="temaplate"
+ />
+</li>
+`;
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/__snapshots__/DotNet-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/__snapshots__/DotNet-test.tsx.snap
new file mode 100644
index 00000000000..ae1bd7ae9cd
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/__snapshots__/DotNet-test.tsx.snap
@@ -0,0 +1,102 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<CreateYmlFile
+ yamlTemplate="name: Build
+on:
+ push:
+ branches:
+ - master # or the name of your main branch
+ pull_request:
+ types: [opened, synchronize, reopened]
+jobs:
+ build:
+ name: Build
+ runs-on: windows-latest
+ steps:
+ - name: Set up JDK 11
+ uses: actions/setup-java@v1
+ with:
+ java-version: 1.11
+ - uses: actions/checkout@v2
+ with:
+ fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
+ - name: Cache SonarQube packages
+ uses: actions/cache@v1
+ with:
+ path: ~\\\\sonar\\\\cache
+ key: \${{ runner.os }}-sonar
+ restore-keys: \${{ runner.os }}-sonar
+ - name: Cache SonarQube scanner
+ id: cache-sonar-scanner
+ uses: actions/cache@v1
+ with:
+ path: .\\\\.sonar\\\\scanner
+ key: \${{ runner.os }}-sonar-scanner
+ restore-keys: \${{ runner.os }}-sonar-scanner
+ - name: Install SonarQube scanner
+ if: steps.cache-sonar-scanner.outputs.cache-hit != 'true'
+ shell: powershell
+ run: |
+ New-Item -Path .\\\\.sonar\\\\scanner -ItemType Directory
+ dotnet tool update dotnet-sonarscanner --tool-path .\\\\.sonar\\\\scanner
+ - name: Build and analyze
+ env:
+ GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
+ shell: powershell
+ run: |
+ .\\\\.sonar\\\\scanner\\\\dotnet-sonarscanner begin /k:\\"my-project\\" /d:sonar.login=\\"\${{ secrets.SONAR_TOKEN }}\\" /d:sonar.host.url=\\"\${{ secrets.SONAR_HOST_URL }}\\"
+ dotnet build
+ .\\\\.sonar\\\\scanner\\\\dotnet-sonarscanner end /d:sonar.login=\\"\${{ secrets.SONAR_TOKEN }}\\""
+/>
+`;
+
+exports[`should render correctly: without branch enabled 1`] = `
+<CreateYmlFile
+ yamlTemplate="name: Build
+on:
+ push:
+ branches:
+ - master # or the name of your main branch
+
+jobs:
+ build:
+ name: Build
+ runs-on: windows-latest
+ steps:
+ - name: Set up JDK 11
+ uses: actions/setup-java@v1
+ with:
+ java-version: 1.11
+ - uses: actions/checkout@v2
+ with:
+ fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
+ - name: Cache SonarQube packages
+ uses: actions/cache@v1
+ with:
+ path: ~\\\\sonar\\\\cache
+ key: \${{ runner.os }}-sonar
+ restore-keys: \${{ runner.os }}-sonar
+ - name: Cache SonarQube scanner
+ id: cache-sonar-scanner
+ uses: actions/cache@v1
+ with:
+ path: .\\\\.sonar\\\\scanner
+ key: \${{ runner.os }}-sonar-scanner
+ restore-keys: \${{ runner.os }}-sonar-scanner
+ - name: Install SonarQube scanner
+ if: steps.cache-sonar-scanner.outputs.cache-hit != 'true'
+ shell: powershell
+ run: |
+ New-Item -Path .\\\\.sonar\\\\scanner -ItemType Directory
+ dotnet tool update dotnet-sonarscanner --tool-path .\\\\.sonar\\\\scanner
+ - name: Build and analyze
+ env:
+ GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
+ shell: powershell
+ run: |
+ .\\\\.sonar\\\\scanner\\\\dotnet-sonarscanner begin /k:\\"my-project\\" /d:sonar.login=\\"\${{ secrets.SONAR_TOKEN }}\\" /d:sonar.host.url=\\"\${{ secrets.SONAR_HOST_URL }}\\"
+ dotnet build
+ .\\\\.sonar\\\\scanner\\\\dotnet-sonarscanner end /d:sonar.login=\\"\${{ secrets.SONAR_TOKEN }}\\""
+/>
+`;
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/__snapshots__/Gradle-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/__snapshots__/Gradle-test.tsx.snap
new file mode 100644
index 00000000000..1c61bf06e9f
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/__snapshots__/Gradle-test.tsx.snap
@@ -0,0 +1,164 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<Fragment>
+ <li
+ className="abs-width-600"
+ >
+ <FormattedMessage
+ defaultMessage="onboarding.tutorial.with.github_action.yaml.gradle"
+ id="onboarding.tutorial.with.github_action.yaml.gradle"
+ values={
+ Object {
+ "gradle": <React.Fragment>
+ <code
+ className="rule"
+ >
+ build.gradle
+ </code>
+ <ClipboardIconButton
+ copyValue="build.gradle"
+ />
+ </React.Fragment>,
+ "sq": <code
+ className="rule"
+ >
+ org.sonarqube
+ </code>,
+ }
+ }
+ />
+ <CodeSnippet
+ snippet="plugins {
+ id \\"org.sonarqube\\" version \\"3.1.1\\"
+}
+
+sonarqube {
+ properties {
+ property \\"sonar.projectKey\\", \\"my-project\\"
+ }
+}"
+ />
+ </li>
+ <CreateYmlFile
+ yamlTemplate="name: Build
+on:
+ push:
+ branches:
+ - master # or the name of your main branch
+ pull_request:
+ types: [opened, synchronize, reopened]
+jobs:
+ build:
+ name: Build
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ with:
+ fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
+ - name: Set up JDK 11
+ uses: actions/setup-java@v1
+ with:
+ java-version: 11
+ - name: Cache SonarQube packages
+ uses: actions/cache@v1
+ with:
+ path: ~/.sonar/cache
+ key: \${{ runner.os }}-sonar
+ restore-keys: \${{ runner.os }}-sonar
+ - name: Cache Gradle packages
+ uses: actions/cache@v1
+ with:
+ path: ~/.gradle/caches
+ key: \${{ runner.os }}-gradle-\${{ hashFiles('**/*.gradle') }}
+ restore-keys: \${{ runner.os }}-gradle
+ - name: Build and analyze
+ env:
+ GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
+ SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
+ SONAR_HOST_URL: \${{ secrets.SONAR_HOST_URL }}
+ run: ./gradlew build sonarqube --info"
+ />
+</Fragment>
+`;
+
+exports[`should render correctly: without branch enabled 1`] = `
+<Fragment>
+ <li
+ className="abs-width-600"
+ >
+ <FormattedMessage
+ defaultMessage="onboarding.tutorial.with.github_action.yaml.gradle"
+ id="onboarding.tutorial.with.github_action.yaml.gradle"
+ values={
+ Object {
+ "gradle": <React.Fragment>
+ <code
+ className="rule"
+ >
+ build.gradle
+ </code>
+ <ClipboardIconButton
+ copyValue="build.gradle"
+ />
+ </React.Fragment>,
+ "sq": <code
+ className="rule"
+ >
+ org.sonarqube
+ </code>,
+ }
+ }
+ />
+ <CodeSnippet
+ snippet="plugins {
+ id \\"org.sonarqube\\" version \\"3.1.1\\"
+}
+
+sonarqube {
+ properties {
+ property \\"sonar.projectKey\\", \\"my-project\\"
+ }
+}"
+ />
+ </li>
+ <CreateYmlFile
+ yamlTemplate="name: Build
+on:
+ push:
+ branches:
+ - master # or the name of your main branch
+
+jobs:
+ build:
+ name: Build
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ with:
+ fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
+ - name: Set up JDK 11
+ uses: actions/setup-java@v1
+ with:
+ java-version: 11
+ - name: Cache SonarQube packages
+ uses: actions/cache@v1
+ with:
+ path: ~/.sonar/cache
+ key: \${{ runner.os }}-sonar
+ restore-keys: \${{ runner.os }}-sonar
+ - name: Cache Gradle packages
+ uses: actions/cache@v1
+ with:
+ path: ~/.gradle/caches
+ key: \${{ runner.os }}-gradle-\${{ hashFiles('**/*.gradle') }}
+ restore-keys: \${{ runner.os }}-gradle
+ - name: Build and analyze
+ env:
+ GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
+ SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
+ SONAR_HOST_URL: \${{ secrets.SONAR_HOST_URL }}
+ run: ./gradlew build sonarqube --info"
+ />
+</Fragment>
+`;
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/__snapshots__/JavaMaven-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/__snapshots__/JavaMaven-test.tsx.snap
new file mode 100644
index 00000000000..66617347189
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/__snapshots__/JavaMaven-test.tsx.snap
@@ -0,0 +1,142 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<Fragment>
+ <li
+ className="abs-width-600"
+ >
+ <FormattedMessage
+ defaultMessage="onboarding.tutorial.with.github_action.yaml.maven.pom"
+ id="onboarding.tutorial.with.github_action.yaml.maven.pom"
+ values={
+ Object {
+ "pom": <React.Fragment>
+ <code
+ className="rule"
+ >
+ pom.xml
+ </code>
+ <ClipboardIconButton
+ copyValue="pom.xml"
+ />
+ </React.Fragment>,
+ }
+ }
+ />
+ <CodeSnippet
+ snippet="<properties>
+ <sonar.projectKey>my-project</sonar.projectKey>
+</properties>"
+ />
+ </li>
+ <CreateYmlFile
+ yamlTemplate="name: Build
+on:
+ push:
+ branches:
+ - master # or the name of your main branch
+ pull_request:
+ types: [opened, synchronize, reopened]
+jobs:
+ build:
+ name: Build
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ with:
+ fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
+ - name: Set up JDK 11
+ uses: actions/setup-java@v1
+ with:
+ java-version: 11
+ - name: Cache SonarQube packages
+ uses: actions/cache@v1
+ with:
+ path: ~/.sonar/cache
+ key: \${{ runner.os }}-sonar
+ restore-keys: \${{ runner.os }}-sonar
+ - name: Cache Maven packages
+ uses: actions/cache@v1
+ with:
+ path: ~/.m2
+ key: \${{ runner.os }}-m2-\${{ hashFiles('**/pom.xml') }}
+ restore-keys: \${{ runner.os }}-m2
+ - name: Build and analyze
+ env:
+ GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
+ SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
+ SONAR_HOST_URL: \${{ secrets.SONAR_HOST_URL }}
+ run: mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar"
+ />
+</Fragment>
+`;
+
+exports[`should render correctly: without branch enabled 1`] = `
+<Fragment>
+ <li
+ className="abs-width-600"
+ >
+ <FormattedMessage
+ defaultMessage="onboarding.tutorial.with.github_action.yaml.maven.pom"
+ id="onboarding.tutorial.with.github_action.yaml.maven.pom"
+ values={
+ Object {
+ "pom": <React.Fragment>
+ <code
+ className="rule"
+ >
+ pom.xml
+ </code>
+ <ClipboardIconButton
+ copyValue="pom.xml"
+ />
+ </React.Fragment>,
+ }
+ }
+ />
+ <CodeSnippet
+ snippet="<properties>
+ <sonar.projectKey>my-project</sonar.projectKey>
+</properties>"
+ />
+ </li>
+ <CreateYmlFile
+ yamlTemplate="name: Build
+on:
+ push:
+ branches:
+ - master # or the name of your main branch
+
+jobs:
+ build:
+ name: Build
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ with:
+ fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
+ - name: Set up JDK 11
+ uses: actions/setup-java@v1
+ with:
+ java-version: 11
+ - name: Cache SonarQube packages
+ uses: actions/cache@v1
+ with:
+ path: ~/.sonar/cache
+ key: \${{ runner.os }}-sonar
+ restore-keys: \${{ runner.os }}-sonar
+ - name: Cache Maven packages
+ uses: actions/cache@v1
+ with:
+ path: ~/.m2
+ key: \${{ runner.os }}-m2-\${{ hashFiles('**/pom.xml') }}
+ restore-keys: \${{ runner.os }}-m2
+ - name: Build and analyze
+ env:
+ GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
+ SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
+ SONAR_HOST_URL: \${{ secrets.SONAR_HOST_URL }}
+ run: mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar"
+ />
+</Fragment>
+`;
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/__snapshots__/Others-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/__snapshots__/Others-test.tsx.snap
new file mode 100644
index 00000000000..27415bab1ff
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/__tests__/__snapshots__/Others-test.tsx.snap
@@ -0,0 +1,102 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<Fragment>
+ <DefaultProjectKey
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ />
+ <CreateYmlFile
+ yamlTemplate="name: Build
+on:
+ push:
+ branches:
+ - master # or the name of your main branch
+ pull_request:
+ types: [opened, synchronize, reopened]
+jobs:
+ build:
+ name: Build
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+ - uses: docker://sonarsource/sonar-scanner-cli:latest
+ env:
+ GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}
+ SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
+ SONAR_HOST_URL: \${{ secrets.SONAR_HOST_URL }}"
+ />
+</Fragment>
+`;
+
+exports[`should render correctly: without branch enabled 1`] = `
+<Fragment>
+ <DefaultProjectKey
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ />
+ <CreateYmlFile
+ yamlTemplate="name: Build
+on:
+ push:
+ branches:
+ - master # or the name of your main branch
+
+jobs:
+ build:
+ name: Build
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+ - uses: docker://sonarsource/sonar-scanner-cli:latest
+ env:
+ GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}
+ SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
+ SONAR_HOST_URL: \${{ secrets.SONAR_HOST_URL }}"
+ />
+</Fragment>
+`;
diff --git a/server/sonar-web/src/main/js/components/tutorials/gitlabci/EnvironmentVariablesStep.tsx b/server/sonar-web/src/main/js/components/tutorials/gitlabci/EnvironmentVariablesStep.tsx
index 47e02fc1dc1..beb4f2f9ae6 100644
--- a/server/sonar-web/src/main/js/components/tutorials/gitlabci/EnvironmentVariablesStep.tsx
+++ b/server/sonar-web/src/main/js/components/tutorials/gitlabci/EnvironmentVariablesStep.tsx
@@ -22,8 +22,8 @@ import { FormattedMessage } from 'react-intl';
import { Button } from 'sonar-ui-common/components/controls/buttons';
import { ClipboardIconButton } from 'sonar-ui-common/components/controls/clipboard';
import { translate } from 'sonar-ui-common/helpers/l10n';
-import EditTokenModal from '../components/EditTokenModal';
import Step from '../components/Step';
+import TokenStepGenerator from '../components/TokenStepGenerator';
export interface EnvironmentVariablesStepProps {
baseUrl: string;
@@ -42,14 +42,7 @@ const pipelineDescriptionLinkLabel = translate(
export default function EnvironmentVariablesStep(props: EnvironmentVariablesStepProps) {
const { baseUrl, component, currentUser, finished, open } = props;
- const [isModalVisible, toggleModal] = React.useState(false);
-
- const toggleTokenModal = () => toggleModal(!isModalVisible);
- const closeTokenModal = () => toggleModal(false);
-
- const fieldValueTranslation = translate(
- 'onboarding.tutorial.with.gitlab_ci.env_variables.enter_field_value'
- );
+ const fieldValueTranslation = translate('onboarding.tutorial.env_variables');
const renderForm = () => (
<div className="boxed-group-inner">
@@ -75,28 +68,16 @@ export default function EnvironmentVariablesStep(props: EnvironmentVariablesStep
id="onboarding.tutorial.with.gitlab_ci.env_variables.step1"
values={{
extra: <ClipboardIconButton copyValue="SONAR_TOKEN" />,
- field: translate('onboarding.tutorial.with.gitlab_ci.env_variables.step1'),
- value: <code className="rule">SONAR_TOKEN</code>
- }}
- />
- </li>
- <li className="big-spacer-bottom">
- <FormattedMessage
- defaultMessage={fieldValueTranslation}
- id="onboarding.tutorial.with.gitlab_ci.env_variables.step2"
- values={{
- extra: (
- <Button className="spacer-left" onClick={toggleTokenModal}>
- {translate('onboarding.token.generate_token')}
- </Button>
+ field: (
+ <strong>
+ {translate('onboarding.tutorial.with.gitlab_ci.env_variables.step1')}
+ </strong>
),
- field: translate('onboarding.tutorial.with.gitlab_ci.env_variables.step2'),
- value: translate(
- 'onboarding.tutorial.with.gitlab_ci.env_variables.section.step2.value'
- )
+ value: <code className="rule">SONAR_TOKEN</code>
}}
/>
</li>
+ <TokenStepGenerator component={component} currentUser={currentUser} />
<li className="big-spacer-bottom">
{translate('onboarding.tutorial.with.gitlab_ci.env_variables.step3')}
</li>
@@ -129,7 +110,11 @@ export default function EnvironmentVariablesStep(props: EnvironmentVariablesStep
id="onboarding.tutorial.with.gitlab_ci.env_variables.step1"
values={{
extra: <ClipboardIconButton copyValue="SONAR_HOST_URL" />,
- field: translate('onboarding.tutorial.with.gitlab_ci.env_variables.step1'),
+ field: (
+ <strong>
+ {translate('onboarding.tutorial.with.gitlab_ci.env_variables.step1')}
+ </strong>
+ ),
value: <code className="rule">SONAR_HOST_URL</code>
}}
/>
@@ -140,7 +125,7 @@ export default function EnvironmentVariablesStep(props: EnvironmentVariablesStep
id="onboarding.tutorial.with.gitlab_ci.env_variables.step2"
values={{
extra: <ClipboardIconButton copyValue={baseUrl} />,
- field: translate('onboarding.tutorial.with.gitlab_ci.env_variables.step2'),
+ field: <strong>{translate('onboarding.tutorial.env_variables.field')}</strong>,
value: <code className="rule">{baseUrl}</code>
}}
/>
@@ -160,19 +145,13 @@ export default function EnvironmentVariablesStep(props: EnvironmentVariablesStep
);
return (
- <>
- {isModalVisible && (
- <EditTokenModal component={component} currentUser={currentUser} onClose={closeTokenModal} />
- )}
-
- <Step
- finished={finished}
- onOpen={props.onOpen}
- open={open}
- renderForm={renderForm}
- stepNumber={2}
- stepTitle={translate('onboarding.tutorial.with.gitlab_ci.env_variables.title')}
- />
- </>
+ <Step
+ finished={finished}
+ onOpen={props.onOpen}
+ open={open}
+ renderForm={renderForm}
+ stepNumber={2}
+ stepTitle={translate('onboarding.tutorial.with.gitlab_ci.env_variables.title')}
+ />
);
}
diff --git a/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/__snapshots__/EnvironmentVariablesStep-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/__snapshots__/EnvironmentVariablesStep-test.tsx.snap
index c1e8ff710f1..3def93d2518 100644
--- a/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/__snapshots__/EnvironmentVariablesStep-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/__snapshots__/EnvironmentVariablesStep-test.tsx.snap
@@ -1,16 +1,14 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should render correctly: Step wrapper 1`] = `
-<Fragment>
- <Step
- finished={false}
- onOpen={[MockFunction]}
- open={true}
- renderForm={[Function]}
- stepNumber={2}
- stepTitle="onboarding.tutorial.with.gitlab_ci.env_variables.title"
- />
-</Fragment>
+<Step
+ finished={false}
+ onOpen={[MockFunction]}
+ open={true}
+ renderForm={[Function]}
+ stepNumber={2}
+ stepTitle="onboarding.tutorial.with.gitlab_ci.env_variables.title"
+/>
`;
exports[`should render correctly: initial content 1`] = `
@@ -40,14 +38,16 @@ exports[`should render correctly: initial content 1`] = `
className="big-spacer-bottom"
>
<FormattedMessage
- defaultMessage="onboarding.tutorial.with.gitlab_ci.env_variables.enter_field_value"
+ defaultMessage="onboarding.tutorial.env_variables"
id="onboarding.tutorial.with.gitlab_ci.env_variables.step1"
values={
Object {
"extra": <ClipboardIconButton
copyValue="SONAR_TOKEN"
/>,
- "field": "onboarding.tutorial.with.gitlab_ci.env_variables.step1",
+ "field": <strong>
+ onboarding.tutorial.with.gitlab_ci.env_variables.step1
+ </strong>,
"value": <code
className="rule"
>
@@ -57,26 +57,39 @@ exports[`should render correctly: initial content 1`] = `
}
/>
</li>
- <li
- className="big-spacer-bottom"
- >
- <FormattedMessage
- defaultMessage="onboarding.tutorial.with.gitlab_ci.env_variables.enter_field_value"
- id="onboarding.tutorial.with.gitlab_ci.env_variables.step2"
- values={
- Object {
- "extra": <Button
- className="spacer-left"
- onClick={[Function]}
- >
- onboarding.token.generate_token
- </Button>,
- "field": "onboarding.tutorial.with.gitlab_ci.env_variables.step2",
- "value": "onboarding.tutorial.with.gitlab_ci.env_variables.section.step2.value",
- }
+ <TokenStepGenerator
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
}
- />
- </li>
+ }
+ currentUser={
+ Object {
+ "groups": Array [],
+ "isLoggedIn": true,
+ "login": "luke",
+ "name": "Skywalker",
+ "scmAccounts": Array [],
+ }
+ }
+ />
<li
className="big-spacer-bottom"
>
@@ -114,14 +127,16 @@ exports[`should render correctly: initial content 1`] = `
className="big-spacer-bottom"
>
<FormattedMessage
- defaultMessage="onboarding.tutorial.with.gitlab_ci.env_variables.enter_field_value"
+ defaultMessage="onboarding.tutorial.env_variables"
id="onboarding.tutorial.with.gitlab_ci.env_variables.step1"
values={
Object {
"extra": <ClipboardIconButton
copyValue="SONAR_HOST_URL"
/>,
- "field": "onboarding.tutorial.with.gitlab_ci.env_variables.step1",
+ "field": <strong>
+ onboarding.tutorial.with.gitlab_ci.env_variables.step1
+ </strong>,
"value": <code
className="rule"
>
@@ -135,14 +150,16 @@ exports[`should render correctly: initial content 1`] = `
className="big-spacer-bottom"
>
<FormattedMessage
- defaultMessage="onboarding.tutorial.with.gitlab_ci.env_variables.enter_field_value"
+ defaultMessage="onboarding.tutorial.env_variables"
id="onboarding.tutorial.with.gitlab_ci.env_variables.step2"
values={
Object {
"extra": <ClipboardIconButton
copyValue="http://localhost:9000"
/>,
- "field": "onboarding.tutorial.with.gitlab_ci.env_variables.step2",
+ "field": <strong>
+ onboarding.tutorial.env_variables.field
+ </strong>,
"value": <code
className="rule"
>
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/JenkinsfileStep.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/JenkinsfileStep.tsx
index 576463cf716..4a2c4e2cf95 100644
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/JenkinsfileStep.tsx
+++ b/server/sonar-web/src/main/js/components/tutorials/jenkins/JenkinsfileStep.tsx
@@ -19,10 +19,8 @@
*/
import * as React from 'react';
import { translate } from 'sonar-ui-common/helpers/l10n';
-import { getBaseUrl } from 'sonar-ui-common/helpers/urls';
-import { withAppState } from '../../hoc/withAppState';
+import AllSet from '../components/AllSet';
import RenderOptions from '../components/RenderOptions';
-import SentenceWithHighlights from '../components/SentenceWithHighlights';
import Step from '../components/Step';
import { BuildTools } from '../types';
import DotNet from './buildtool-steps/DotNet';
@@ -31,7 +29,6 @@ import Maven from './buildtool-steps/Maven';
import Other from './buildtool-steps/Other';
export interface JenkinsfileStepProps {
- appState: T.AppState;
component: T.Component;
open: boolean;
}
@@ -48,12 +45,8 @@ const BUILDTOOL_COMPONENT_MAP: {
[BuildTools.Other]: Other
};
-export function JenkinsfileStep(props: JenkinsfileStepProps) {
- const {
- appState: { branchesEnabled },
- component,
- open
- } = props;
+export default function JenkinsfileStep(props: JenkinsfileStepProps) {
+ const { component, open } = props;
const [buildTool, setBuildTool] = React.useState<BuildToolsWithoutCFamily | undefined>(undefined);
return (
<Step
@@ -78,50 +71,7 @@ export function JenkinsfileStep(props: JenkinsfileStepProps) {
{buildTool !== undefined && (
<>
<hr className="huge-spacer-top huge-spacer-bottom" />
- <div className="abs-width-600">
- <p className="big-spacer-bottom">
- <SentenceWithHighlights
- highlightKeys={['all_set']}
- translationKey="onboarding.tutorial.with.jenkins.all_set"
- />
- </p>
- <div className="display-flex-row big-spacer-bottom">
- <div>
- <img
- alt="" // Should be ignored by screen readers
- className="big-spacer-right"
- width={30}
- src={`${getBaseUrl()}/images/tutorials/commit.svg`}
- />
- </div>
- <div>
- <p className="little-spacer-bottom">
- <strong>{translate('onboarding.tutorial.with.jenkins.commit')}</strong>
- </p>
- <p>
- {branchesEnabled
- ? translate('onboarding.tutorial.with.jenkins.commit.why')
- : translate('onboarding.tutorial.with.jenkins.commit.why.no_branches')}
- </p>
- </div>
- </div>
- <div className="display-flex-row huge-spacer-bottom">
- <div>
- <img
- alt="" // Should be ignored by screen readers
- className="big-spacer-right"
- width={30}
- src={`${getBaseUrl()}/images/tutorials/refresh.svg`}
- />
- </div>
- <div>
- <p className="little-spacer-bottom">
- <strong>{translate('onboarding.tutorial.with.jenkins.refresh')}</strong>
- </p>
- <p>{translate('onboarding.tutorial.with.jenkins.refresh.why')}</p>
- </div>
- </div>
- </div>
+ <AllSet />
</>
)}
</div>
@@ -131,5 +81,3 @@ export function JenkinsfileStep(props: JenkinsfileStepProps) {
/>
);
}
-
-export default withAppState(JenkinsfileStep);
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/JenkinsfileStep-test.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/JenkinsfileStep-test.tsx
index bdab1582f60..d738038d7c5 100644
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/JenkinsfileStep-test.tsx
+++ b/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/JenkinsfileStep-test.tsx
@@ -19,11 +19,11 @@
*/
import { shallow, ShallowWrapper } from 'enzyme';
import * as React from 'react';
-import { mockAppState, mockComponent } from '../../../../helpers/testMocks';
+import { mockComponent } from '../../../../helpers/testMocks';
import RenderOptions from '../../components/RenderOptions';
import Step from '../../components/Step';
import { BuildTools } from '../../types';
-import { JenkinsfileStep, JenkinsfileStepProps } from '../JenkinsfileStep';
+import JenkinsfileStep, { JenkinsfileStepProps } from '../JenkinsfileStep';
import { renderStepContent } from '../test-utils';
it('should render correctly', () => {
@@ -32,12 +32,6 @@ it('should render correctly', () => {
expect(renderStepContent(wrapper)).toMatchSnapshot('initial content');
});
-it('should render correctly with no branches', () => {
- const wrapper = shallowRender({ appState: mockAppState({ branchesEnabled: false }) });
- selectBuildTool(wrapper, BuildTools.Gradle);
- expect(renderStepContent(wrapper)).toMatchSnapshot();
-});
-
it('should render correctly for Maven', () => {
const wrapper = shallowRender();
selectBuildTool(wrapper, BuildTools.Maven);
@@ -74,11 +68,6 @@ function selectBuildTool(wrapper: ShallowWrapper<JenkinsfileStepProps>, tool: Bu
function shallowRender(props: Partial<JenkinsfileStepProps> = {}) {
return shallow<JenkinsfileStepProps>(
- <JenkinsfileStep
- appState={mockAppState({ branchesEnabled: true })}
- component={mockComponent()}
- open={true}
- {...props}
- />
+ <JenkinsfileStep component={mockComponent()} open={true} {...props} />
);
}
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/JenkinsTutorial-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/JenkinsTutorial-test.tsx.snap
index b6759ddfa38..a7ecadf597a 100644
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/JenkinsTutorial-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/JenkinsTutorial-test.tsx.snap
@@ -43,7 +43,7 @@ exports[`should render correctly: branches not enabled 1`] = `
}
}
/>
- <Connect(withAppState(JenkinsfileStep))
+ <JenkinsfileStep
component={
Object {
"breadcrumbs": Array [],
@@ -122,7 +122,7 @@ exports[`should render correctly: default 1`] = `
}
}
/>
- <Connect(withAppState(JenkinsfileStep))
+ <JenkinsfileStep
component={
Object {
"breadcrumbs": Array [],
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/JenkinsfileStep-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/JenkinsfileStep-test.tsx.snap
index a4610804993..909464f7296 100644
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/JenkinsfileStep-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/JenkinsfileStep-test.tsx.snap
@@ -53,70 +53,7 @@ exports[`should render correctly for .NET 1`] = `
<hr
className="huge-spacer-top huge-spacer-bottom"
/>
- <div
- className="abs-width-600"
- >
- <p
- className="big-spacer-bottom"
- >
- <SentenceWithHighlights
- highlightKeys={
- Array [
- "all_set",
- ]
- }
- translationKey="onboarding.tutorial.with.jenkins.all_set"
- />
- </p>
- <div
- className="display-flex-row big-spacer-bottom"
- >
- <div>
- <img
- alt=""
- className="big-spacer-right"
- src="/images/tutorials/commit.svg"
- width={30}
- />
- </div>
- <div>
- <p
- className="little-spacer-bottom"
- >
- <strong>
- onboarding.tutorial.with.jenkins.commit
- </strong>
- </p>
- <p>
- onboarding.tutorial.with.jenkins.commit.why
- </p>
- </div>
- </div>
- <div
- className="display-flex-row huge-spacer-bottom"
- >
- <div>
- <img
- alt=""
- className="big-spacer-right"
- src="/images/tutorials/refresh.svg"
- width={30}
- />
- </div>
- <div>
- <p
- className="little-spacer-bottom"
- >
- <strong>
- onboarding.tutorial.with.jenkins.refresh
- </strong>
- </p>
- <p>
- onboarding.tutorial.with.jenkins.refresh.why
- </p>
- </div>
- </div>
- </div>
+ <Connect(withAppState(AllSet)) />
</React.Fragment>
</div>
`;
@@ -174,70 +111,7 @@ exports[`should render correctly for Gradle 1`] = `
<hr
className="huge-spacer-top huge-spacer-bottom"
/>
- <div
- className="abs-width-600"
- >
- <p
- className="big-spacer-bottom"
- >
- <SentenceWithHighlights
- highlightKeys={
- Array [
- "all_set",
- ]
- }
- translationKey="onboarding.tutorial.with.jenkins.all_set"
- />
- </p>
- <div
- className="display-flex-row big-spacer-bottom"
- >
- <div>
- <img
- alt=""
- className="big-spacer-right"
- src="/images/tutorials/commit.svg"
- width={30}
- />
- </div>
- <div>
- <p
- className="little-spacer-bottom"
- >
- <strong>
- onboarding.tutorial.with.jenkins.commit
- </strong>
- </p>
- <p>
- onboarding.tutorial.with.jenkins.commit.why
- </p>
- </div>
- </div>
- <div
- className="display-flex-row huge-spacer-bottom"
- >
- <div>
- <img
- alt=""
- className="big-spacer-right"
- src="/images/tutorials/refresh.svg"
- width={30}
- />
- </div>
- <div>
- <p
- className="little-spacer-bottom"
- >
- <strong>
- onboarding.tutorial.with.jenkins.refresh
- </strong>
- </p>
- <p>
- onboarding.tutorial.with.jenkins.refresh.why
- </p>
- </div>
- </div>
- </div>
+ <Connect(withAppState(AllSet)) />
</React.Fragment>
</div>
`;
@@ -295,70 +169,7 @@ exports[`should render correctly for Maven 1`] = `
<hr
className="huge-spacer-top huge-spacer-bottom"
/>
- <div
- className="abs-width-600"
- >
- <p
- className="big-spacer-bottom"
- >
- <SentenceWithHighlights
- highlightKeys={
- Array [
- "all_set",
- ]
- }
- translationKey="onboarding.tutorial.with.jenkins.all_set"
- />
- </p>
- <div
- className="display-flex-row big-spacer-bottom"
- >
- <div>
- <img
- alt=""
- className="big-spacer-right"
- src="/images/tutorials/commit.svg"
- width={30}
- />
- </div>
- <div>
- <p
- className="little-spacer-bottom"
- >
- <strong>
- onboarding.tutorial.with.jenkins.commit
- </strong>
- </p>
- <p>
- onboarding.tutorial.with.jenkins.commit.why
- </p>
- </div>
- </div>
- <div
- className="display-flex-row huge-spacer-bottom"
- >
- <div>
- <img
- alt=""
- className="big-spacer-right"
- src="/images/tutorials/refresh.svg"
- width={30}
- />
- </div>
- <div>
- <p
- className="little-spacer-bottom"
- >
- <strong>
- onboarding.tutorial.with.jenkins.refresh
- </strong>
- </p>
- <p>
- onboarding.tutorial.with.jenkins.refresh.why
- </p>
- </div>
- </div>
- </div>
+ <Connect(withAppState(AllSet)) />
</React.Fragment>
</div>
`;
@@ -416,191 +227,7 @@ exports[`should render correctly for Other 1`] = `
<hr
className="huge-spacer-top huge-spacer-bottom"
/>
- <div
- className="abs-width-600"
- >
- <p
- className="big-spacer-bottom"
- >
- <SentenceWithHighlights
- highlightKeys={
- Array [
- "all_set",
- ]
- }
- translationKey="onboarding.tutorial.with.jenkins.all_set"
- />
- </p>
- <div
- className="display-flex-row big-spacer-bottom"
- >
- <div>
- <img
- alt=""
- className="big-spacer-right"
- src="/images/tutorials/commit.svg"
- width={30}
- />
- </div>
- <div>
- <p
- className="little-spacer-bottom"
- >
- <strong>
- onboarding.tutorial.with.jenkins.commit
- </strong>
- </p>
- <p>
- onboarding.tutorial.with.jenkins.commit.why
- </p>
- </div>
- </div>
- <div
- className="display-flex-row huge-spacer-bottom"
- >
- <div>
- <img
- alt=""
- className="big-spacer-right"
- src="/images/tutorials/refresh.svg"
- width={30}
- />
- </div>
- <div>
- <p
- className="little-spacer-bottom"
- >
- <strong>
- onboarding.tutorial.with.jenkins.refresh
- </strong>
- </p>
- <p>
- onboarding.tutorial.with.jenkins.refresh.why
- </p>
- </div>
- </div>
- </div>
- </React.Fragment>
-</div>
-`;
-
-exports[`should render correctly with no branches 1`] = `
-<div
- className="boxed-group-inner"
->
- <ol
- className="list-styled"
- >
- <li>
- onboarding.build
- <RenderOptions
- checked="gradle"
- name="buildtool"
- onCheck={[Function]}
- optionLabelKey="onboarding.build"
- options={
- Array [
- "maven",
- "gradle",
- "dotnet",
- "other",
- ]
- }
- />
- </li>
- <Gradle
- component={
- Object {
- "breadcrumbs": Array [],
- "key": "my-project",
- "name": "MyProject",
- "qualifier": "TRK",
- "qualityGate": Object {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": Array [
- Object {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": Array [],
- }
- }
- />
- </ol>
- <React.Fragment>
- <hr
- className="huge-spacer-top huge-spacer-bottom"
- />
- <div
- className="abs-width-600"
- >
- <p
- className="big-spacer-bottom"
- >
- <SentenceWithHighlights
- highlightKeys={
- Array [
- "all_set",
- ]
- }
- translationKey="onboarding.tutorial.with.jenkins.all_set"
- />
- </p>
- <div
- className="display-flex-row big-spacer-bottom"
- >
- <div>
- <img
- alt=""
- className="big-spacer-right"
- src="/images/tutorials/commit.svg"
- width={30}
- />
- </div>
- <div>
- <p
- className="little-spacer-bottom"
- >
- <strong>
- onboarding.tutorial.with.jenkins.commit
- </strong>
- </p>
- <p>
- onboarding.tutorial.with.jenkins.commit.why.no_branches
- </p>
- </div>
- </div>
- <div
- className="display-flex-row huge-spacer-bottom"
- >
- <div>
- <img
- alt=""
- className="big-spacer-right"
- src="/images/tutorials/refresh.svg"
- width={30}
- />
- </div>
- <div>
- <p
- className="little-spacer-bottom"
- >
- <strong>
- onboarding.tutorial.with.jenkins.refresh
- </strong>
- </p>
- <p>
- onboarding.tutorial.with.jenkins.refresh.why
- </p>
- </div>
- </div>
- </div>
+ <Connect(withAppState(AllSet)) />
</React.Fragment>
</div>
`;
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/Gradle.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/Gradle.tsx
index 9ecebd02c11..9436298c2f8 100644
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/Gradle.tsx
+++ b/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/Gradle.tsx
@@ -20,22 +20,13 @@
import * as React from 'react';
import CodeSnippet from '../../../common/CodeSnippet';
import SentenceWithFilename from '../../components/SentenceWithFilename';
+import { buildGradleSnippet } from '../../utils';
import CreateJenkinsfileBulletPoint from './CreateJenkinsfileBulletPoint';
export interface GradleProps {
component: T.Component;
}
-const buildGradleSnippet = (key: string) => `plugins {
- id "org.sonarqube" version "3.1.1"
-}
-
-sonarqube {
- properties {
- property "sonar.projectKey", "${key}"
- }
-}`;
-
const JENKINSFILE_SNIPPET = `node {
stage('SCM') {
checkout scm
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/Maven.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/Maven.tsx
index 1f074b12121..669ed20f4c9 100644
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/Maven.tsx
+++ b/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/Maven.tsx
@@ -20,16 +20,13 @@
import * as React from 'react';
import CodeSnippet from '../../../common/CodeSnippet';
import SentenceWithFilename from '../../components/SentenceWithFilename';
+import { mavenPomSnippet } from '../../utils';
import CreateJenkinsfileBulletPoint from './CreateJenkinsfileBulletPoint';
export interface MavenProps {
component: T.Component;
}
-const pomSnippet = (key: string) => `<properties>
- <sonar.projectKey>${key}</sonar.projectKey>
-</properties>`;
-
const JENKINSFILE_SNIPPET = `node {
stage('SCM') {
checkout scm
@@ -50,7 +47,7 @@ export default function Maven({ component }: MavenProps) {
filename="pom.xml"
translationKey="onboarding.tutorial.with.jenkins.jenkinsfile.maven.step2"
/>
- <CodeSnippet snippet={pomSnippet(component.key)} />
+ <CodeSnippet snippet={mavenPomSnippet(component.key)} />
</li>
<CreateJenkinsfileBulletPoint
alertTranslationKeyPart="onboarding.tutorial.with.jenkins.jenkinsfile.maven.step3"
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/Other.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/Other.tsx
index 9fa8d96c280..c66cd92cca6 100644
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/Other.tsx
+++ b/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/Other.tsx
@@ -18,16 +18,13 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import CodeSnippet from '../../../common/CodeSnippet';
-import SentenceWithFilename from '../../components/SentenceWithFilename';
+import DefaultProjectKey from '../../components/DefaultProjectKey';
import CreateJenkinsfileBulletPoint from './CreateJenkinsfileBulletPoint';
export interface OtherProps {
component: T.Component;
}
-const sonarProjectSnippet = (key: string) => `sonar.projectKey=${key}`;
-
const JENKINSFILE_SNIPPET = `node {
stage('SCM') {
checkout scm
@@ -43,13 +40,7 @@ const JENKINSFILE_SNIPPET = `node {
export default function Other({ component }: OtherProps) {
return (
<>
- <li className="abs-width-600">
- <SentenceWithFilename
- filename="sonar-project.properties"
- translationKey="onboarding.tutorial.with.jenkins.jenkinsfile.other.step2"
- />
- <CodeSnippet snippet={sonarProjectSnippet(component.key)} />
- </li>
+ <DefaultProjectKey component={component} />
<CreateJenkinsfileBulletPoint
alertTranslationKeyPart="onboarding.tutorial.with.jenkins.jenkinsfile.other.step3"
snippet={JENKINSFILE_SNIPPET}
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/__tests__/__snapshots__/Other-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/__tests__/__snapshots__/Other-test.tsx.snap
index c5a549388dd..d77f4bc3a58 100644
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/__tests__/__snapshots__/Other-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/__tests__/__snapshots__/Other-test.tsx.snap
@@ -2,17 +2,30 @@
exports[`should render correctly 1`] = `
<Fragment>
- <li
- className="abs-width-600"
- >
- <SentenceWithFilename
- filename="sonar-project.properties"
- translationKey="onboarding.tutorial.with.jenkins.jenkinsfile.other.step2"
- />
- <CodeSnippet
- snippet="sonar.projectKey=my-project"
- />
- </li>
+ <DefaultProjectKey
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ />
<CreateJenkinsfileBulletPoint
alertTranslationKeyPart="onboarding.tutorial.with.jenkins.jenkinsfile.other.step3"
snippet="node {
diff --git a/server/sonar-web/src/main/js/components/tutorials/types.ts b/server/sonar-web/src/main/js/components/tutorials/types.ts
index 5f9ba566b61..ddfe8881ade 100644
--- a/server/sonar-web/src/main/js/components/tutorials/types.ts
+++ b/server/sonar-web/src/main/js/components/tutorials/types.ts
@@ -21,6 +21,7 @@ export enum TutorialModes {
Manual = 'manual',
Jenkins = 'jenkins',
GitLabCI = 'gitlab-ci',
+ GitHubActions = 'github-actions',
AzurePipelines = 'azure-pipelines'
}
diff --git a/server/sonar-web/src/main/js/components/tutorials/utils.ts b/server/sonar-web/src/main/js/components/tutorials/utils.ts
index 825a08e8d2a..463538e36a7 100644
--- a/server/sonar-web/src/main/js/components/tutorials/utils.ts
+++ b/server/sonar-web/src/main/js/components/tutorials/utils.ts
@@ -23,6 +23,24 @@ export function quote(os: string): (s: string) => string {
return os === 'win' ? (s: string) => `"${s}"` : (s: string) => s;
}
+export function mavenPomSnippet(key: string) {
+ return `<properties>
+ <sonar.projectKey>${key}</sonar.projectKey>
+</properties>`;
+}
+
+export function buildGradleSnippet(key: string) {
+ return `plugins {
+ id "org.sonarqube" version "3.1.1"
+}
+
+sonarqube {
+ properties {
+ property "sonar.projectKey", "${key}"
+ }
+}`;
+}
+
export function getUniqueTokenName(tokens: T.UserToken[], initialTokenName = '') {
const hasToken = (name: string) => tokens.find(token => token.name === name) !== undefined;
diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
index 35e787a8e89..8fc86bed269 100644
--- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties
+++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
@@ -3296,6 +3296,10 @@ onboarding.token.use_existing_token.placeholder=Enter your existing token
onboarding.token.use_existing_token.label=Existing token value
onboarding.token.invalid_format=The token you have entered has invalid format.
+onboarding.tutorial.env_variables=In the {field} field, enter {value} {extra}
+onboarding.tutorial.env_variables.field=Value
+onboarding.tutorial.env_variables.token_generator.value=an existing token, or a newly generated one:
+
onboarding.analysis.header=Run analysis on your project
onboarding.analysis.auto_refresh_after_analysis=Once the analysis is completed, this page will automatically refresh and you will be able to browse the analysis results.
@@ -3383,13 +3387,37 @@ onboarding.analysis.dotnetcore.global.text=As a prerequisite you need to have th
onboarding.analysis.dotnetcore.global.text.path=Make sure dotnet tools folder is in your path. See dotnet global tools documentation for more information.
onboarding.tutorial.return_to_list=Choose another option
+onboarding.tutorial.ci_outro.all_set.sentence={all_set} and ready to improve the quality and security of your code!
+onboarding.tutorial.ci_outro.all_set.sentence.all_set=You're all set
+onboarding.tutorial.ci_outro.commit=Commit and push your code to start the analysis.
+onboarding.tutorial.ci_outro.commit.why=Each new push you make on your branches or pull requests will trigger a new analysis in SonarQube.
+onboarding.tutorial.ci_outro.commit.why.no_branches=Each new push you make on your main branch will trigger a new analysis in SonarQube.
+onboarding.tutorial.ci_outro.refresh=This page will then refresh with your analysis results.
+onboarding.tutorial.ci_outro.refresh.why=If the page doesn't refresh after a while, please double-check the analysis configuration.
+onboarding.tutorial.other.project_key.sentence=Create a {file} file in your repository and paste the following code:
onboarding.tutorial.choose_method=How do you want to analyze your repository?
onboarding.tutorial.choose_method.manual=Manually
onboarding.tutorial.choose_method.jenkins=With Jenkins
+onboarding.tutorial.choose_method.github_action=With GitHub Actions
onboarding.tutorial.choose_method.gitlab_ci=With GitLab CI
onboarding.tutorial.choose_method.azure_pipelines=With Azure Pipelines
+onboarding.tutorial.with.github_action.create_secret.title=Create GitHub Secrets
+onboarding.tutorial.with.github_action.secret.intro=In your GitHub repository, go to {settings_secret} and create two new secrets:
+onboarding.tutorial.with.github_action.secret.intro.link=Settings > Secrets
+onboarding.tutorial.with.github_action.secret.name.sentence=In the {name} field, enter
+onboarding.tutorial.with.github_action.secret.name.sentence.name=Name
+onboarding.tutorial.with.github_action.secret.new.sentence=Click on {new_secret}
+onboarding.tutorial.with.github_action.secret.new.sentence.new_secret=New repository secret
+onboarding.tutorial.with.github_action.secret.add.sentence=Click on {add_secret}
+onboarding.tutorial.with.github_action.secret.add.sentence.add_secret=Add secret
+onboarding.tutorial.with.github_action.yaml.title=Create Workflow YAML File
+onboarding.tutorial.with.github_action.yaml.create_yml=Create or update your {file} YAML file with the following content:
+onboarding.tutorial.with.github_action.yaml.maven.pom=Update your {pom} file with the following properties:
+onboarding.tutorial.with.github_action.yaml.gradle=Update your {gradle} file with the {sq} plugin and it's configuration:
+
+
onboarding.tutorial.with.gitlab_ci.title=Analyze your project with GitLab CI
onboarding.tutorial.with.gitlab_ci.unsupported=This tutorial is only available for projects bound to GitLab.
onboarding.tutorial.with.gitlab_ci.project_key.title=Set your project key
@@ -3400,14 +3428,12 @@ onboarding.tutorial.with.gitlab_ci.project_key.dotnet.step2=Create a {file} file
onboarding.tutorial.with.gitlab_ci.env_variables.title=Add environment variables
-onboarding.tutorial.with.gitlab_ci.env_variables.enter_field_value=In the {field} field, enter {value} {extra}
onboarding.tutorial.with.gitlab_ci.env_variables.description.link=Settings > CI/CD > Variables
onboarding.tutorial.with.gitlab_ci.env_variables.section.title=a. Define the SonarQube Token environment variable
onboarding.tutorial.with.gitlab_ci.env_variables.section.description=In GitLab, go to {link} to add the following variable and make sure it is available for your project:
onboarding.tutorial.with.gitlab_ci.env_variables.edit.token.tooltip=Use an existing token or generate a new one.
onboarding.tutorial.with.gitlab_ci.env_variables.step1=Key
-onboarding.tutorial.with.gitlab_ci.env_variables.step2=Value
-onboarding.tutorial.with.gitlab_ci.env_variables.section.step2.value=an existing token, or a newly generated one:
+
onboarding.tutorial.with.gitlab_ci.env_variables.step3=Uncheck the "Protect Variable" checkbox
onboarding.tutorial.with.gitlab_ci.env_variables.section.step4=Check the "Mask Variable" checkbox
onboarding.tutorial.with.gitlab_ci.env_variables.section2.title=b. Define the SonarQube URL environment variable
@@ -3620,7 +3646,6 @@ onboarding.tutorial.with.jenkins.dotnet.scanner.prereqs.step5.sentence=Under {in
onboarding.tutorial.with.jenkins.dotnet.scanner.prereqs.step5.sentence.install_from=Install from GitHub
onboarding.tutorial.with.jenkins.dotnet.scanner.prereqs.step5.sentence.install_auto=Install automatically
-onboarding.tutorial.with.jenkins.jenkinsfile.other.step2.sentence=Create a {file} file in your repository and paste the following code:
onboarding.tutorial.with.jenkins.jenkinsfile.other.step3.replace.sentence=Make sure to replace {default} with the name you gave to your SonarQube Scanner tool {in_jenkins}.
onboarding.tutorial.with.jenkins.jenkinsfile.other.step3.replace.sentence.default=SonarScanner
onboarding.tutorial.with.jenkins.jenkinsfile.other.step3.replace.sentence.in_jenkins=in Jenkins
@@ -3629,13 +3654,7 @@ onboarding.tutorial.with.jenkins.jenkinsfile.other.step3.help1.sentence.path=Man
onboarding.tutorial.with.jenkins.jenkinsfile.other.step3.help2.sentence=The name is located under the {path} section, in the {name} field.
onboarding.tutorial.with.jenkins.jenkinsfile.other.step3.help2.sentence.path=SonarQube Scanner > SonarQube Scanner installations
onboarding.tutorial.with.jenkins.jenkinsfile.other.step3.help2.sentence.name=Name
-onboarding.tutorial.with.jenkins.all_set.sentence={all_set} and ready to improve the quality and security of your code!
-onboarding.tutorial.with.jenkins.all_set.sentence.all_set=You're all set
-onboarding.tutorial.with.jenkins.commit=Commit and push your code to start the analysis.
-onboarding.tutorial.with.jenkins.commit.why=Each new push you make on your branches or pull requests will trigger a new analysis in SonarQube.
-onboarding.tutorial.with.jenkins.commit.why.no_branches=Each new push you make on your main branch will trigger a new analysis in SonarQube.
-onboarding.tutorial.with.jenkins.refresh=This page will then refresh with your analysis results.
-onboarding.tutorial.with.jenkins.refresh.why=If the page doesn't refresh after a while, please double-check the analysis configuration.
+
onboarding.tutorial.with.azure_pipelines.os=What is your agent host?
onboarding.tutorial.with.azure_pipelines.title=Analyze your project with Azure DevOps Pipelines
@@ -3654,7 +3673,7 @@ onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.step4.sentence=Enter yo
onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.step5.sentence=Enter an existing token, or a newly generated one
onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.step6.sentence=Create the service connection
onboarding.tutorial.with.azure_pipelines.BranchAnalysis.title=Configure analysis
-onboarding.tutorial.with.azure_pipelines.BranchAnalysis.info=The following steps assume you are using the Azure Pipelines classic editor. Check out our {doc_link} for the yaml counterpart.
+onboarding.tutorial.with.azure_pipelines.BranchAnalysis.info=The following steps assume you are using the Azure Pipelines classic editor. Check out our {doc_link} for the YAML counterpart.
onboarding.tutorial.with.azure_pipelines.BranchAnalysis.info.doc_link=Azure DevOps integration page
onboarding.tutorial.with.azure_pipelines.BranchAnalysis.build_wrapper.ccpp.sentence=In Azure DevOps, create or edit a build {pipeline} to make Build Wrapper available on the build agent.