]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-13297 Allow users to skip the prerequisites step
authorWouter Admiraal <wouter.admiraal@sonarsource.com>
Fri, 24 Apr 2020 13:11:23 +0000 (15:11 +0200)
committersonartech <sonartech@sonarsource.com>
Mon, 4 May 2020 20:03:53 +0000 (20:03 +0000)
server/sonar-web/src/main/js/app/styles/init/misc.css
server/sonar-web/src/main/js/components/tutorials/__tests__/__snapshots__/TutorialSelectionRenderer-test.tsx.snap
server/sonar-web/src/main/js/components/tutorials/jenkins/JenkinsTutorial.tsx
server/sonar-web/src/main/js/components/tutorials/jenkins/PreRequisitesStep.tsx
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/JenkinsTutorial-test.tsx
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/PreRequisitesStep-test.tsx
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/JenkinsTutorial-test.tsx.snap
server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/PreRequisitesStep-test.tsx.snap
server/sonar-web/src/main/js/types/types.d.ts
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index 83b3148fd36aefb3a96aeceade97f08b72764108..97a9bb9c2a27eea083301b4693a0528fb317fdc7 100644 (file)
@@ -524,6 +524,10 @@ th.huge-spacer-right {
   text-transform: capitalize !important;
 }
 
+.cursor-pointer {
+  cursor: pointer;
+}
+
 .cursor-not-allowed {
   cursor: not-allowed !important;
 }
index b78bf9196d32dfa0ec17f48eecc5ece676b20f62..c73bf30606cbc3f78fd7315201ec713786574734 100644 (file)
@@ -2,7 +2,7 @@
 
 exports[`should render correctly: jenkins tutorial 1`] = `
 <Fragment>
-  <JenkinsTutorial
+  <Connect(JenkinsTutorial)
     almBinding={
       Object {
         "key": "key",
index 47d994cc6aa7a270c9a6295ade9e85716aa8a6eb..db0303bcff296a67e079edf58d2afe56a6539929 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
+import { connect } from 'react-redux';
 import { Alert } from 'sonar-ui-common/components/ui/Alert';
 import { translate } from 'sonar-ui-common/helpers/l10n';
 import {
   isBitbucketBindingDefinition,
   isProjectBitbucketBindingResponse
 } from '../../../helpers/alm-settings';
+import { getCurrentUserSetting, Store } from '../../../store/rootReducer';
+import { setCurrentUserSetting } from '../../../store/users';
 import { AlmBindingDefinition, ProjectAlmBindingResponse } from '../../../types/alm-settings';
 import BitbucketWebhookStep from './BitbucketWebhookStep';
 import JenkinsfileStep from './JenkinsfileStep';
@@ -34,6 +37,8 @@ export interface JenkinsTutorialProps {
   almBinding?: AlmBindingDefinition;
   component: T.Component;
   projectBinding: ProjectAlmBindingResponse;
+  setCurrentUserSetting: (setting: T.CurrentUserSetting) => void;
+  skipPreReqs: boolean;
 }
 
 enum Steps {
@@ -43,9 +48,13 @@ enum Steps {
   Jenkinsfile = 3
 }
 
-export default function JenkinsTutorial(props: JenkinsTutorialProps) {
-  const { almBinding, component, projectBinding } = props;
-  const [step, setStep] = React.useState(Steps.PreRequisites);
+const USER_SETTING_SKIP_BITBUCKET_PREREQS = 'tutorials.jenkins.skipBitbucketPreReqs';
+
+export function JenkinsTutorial(props: JenkinsTutorialProps) {
+  const { almBinding, component, projectBinding, skipPreReqs } = props;
+  const [step, setStep] = React.useState(
+    skipPreReqs ? Steps.MultiBranchPipeline : Steps.PreRequisites
+  );
 
   // Failsafe; should never happen.
   if (!isProjectBitbucketBindingResponse(projectBinding)) {
@@ -63,7 +72,14 @@ export default function JenkinsTutorial(props: JenkinsTutorialProps) {
       <PreRequisitesStep
         onDone={() => setStep(Steps.MultiBranchPipeline)}
         onOpen={() => setStep(Steps.PreRequisites)}
+        onChangeSkipNextTime={skip => {
+          props.setCurrentUserSetting({
+            key: USER_SETTING_SKIP_BITBUCKET_PREREQS,
+            value: skip.toString()
+          });
+        }}
         open={step === Steps.PreRequisites}
+        skipNextTime={skipPreReqs}
       />
 
       <MultiBranchPipelineStep
@@ -87,3 +103,13 @@ export default function JenkinsTutorial(props: JenkinsTutorialProps) {
     </>
   );
 }
+
+const mapStateToProps = (state: Store): Pick<JenkinsTutorialProps, 'skipPreReqs'> => {
+  return {
+    skipPreReqs: getCurrentUserSetting(state, USER_SETTING_SKIP_BITBUCKET_PREREQS) === 'true'
+  };
+};
+
+const mapDispatchToProps = { setCurrentUserSetting };
+
+export default connect(mapStateToProps, mapDispatchToProps)(JenkinsTutorial);
index 5dbe039be20f0d3f228c242b212c5a6ce014ccd4..46da8b3a8c59e6349495232d5686c5fa3157a725 100644 (file)
@@ -21,18 +21,21 @@ import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
 import { Link } from 'react-router';
 import { Button } from 'sonar-ui-common/components/controls/buttons';
+import Checkbox from 'sonar-ui-common/components/controls/Checkbox';
 import { translate } from 'sonar-ui-common/helpers/l10n';
 import SentenceWithHighlights from '../components/SentenceWithHighlights';
 import Step from '../components/Step';
 
 export interface PreRequisitesStepProps {
+  onChangeSkipNextTime: (skip: boolean) => void;
   onDone: () => void;
   onOpen: () => void;
   open: boolean;
+  skipNextTime: boolean;
 }
 
 export default function PreRequisitesStep(props: PreRequisitesStepProps) {
-  const { open } = props;
+  const { open, skipNextTime } = props;
   return (
     <Step
       finished={!open}
@@ -68,6 +71,22 @@ export default function PreRequisitesStep(props: PreRequisitesStepProps) {
           <p className="big-spacer-bottom">
             {translate('onboarding.tutorial.with.jenkins.prereqs.following_are_recommendations')}
           </p>
+          <p className="big-spacer-bottom display-flex-center">
+            <label
+              className="cursor-pointer"
+              htmlFor="skip-prereqs"
+              onClick={() => {
+                props.onChangeSkipNextTime(!skipNextTime);
+              }}>
+              {translate('onboarding.tutorial.with.jenkins.prereqs.skip_next_time')}
+            </label>
+            <Checkbox
+              checked={skipNextTime}
+              className="little-spacer-left"
+              id="skip-prereqs"
+              onCheck={props.onChangeSkipNextTime}
+            />
+          </p>
           <Button onClick={props.onDone}>
             {translate('onboarding.tutorial.with.jenkins.prereqs.done')}
           </Button>
index 495218b8a4942ffa5e69c43d8ce762a94f7f0d82..b87fa44d764980271297ed4f0fa5290cd0f62a59 100644 (file)
@@ -27,7 +27,7 @@ import {
 import { mockComponent } from '../../../../helpers/testMocks';
 import BitbucketWebhookStep from '../BitbucketWebhookStep';
 import JenkinsfileStep from '../JenkinsfileStep';
-import JenkinsTutorial, { JenkinsTutorialProps } from '../JenkinsTutorial';
+import { JenkinsTutorial, JenkinsTutorialProps } from '../JenkinsTutorial';
 import MultiBranchPipelineStep from '../MultiBranchPipelineStep';
 import PreRequisitesStep from '../PreRequisitesStep';
 
@@ -80,11 +80,36 @@ it('should correctly navigate between steps', () => {
   expect(wrapper.find(BitbucketWebhookStep).prop('open')).toBe(true);
 });
 
+it('should correctly store the user setting', () => {
+  const setCurrentUserSetting = jest.fn();
+  const wrapper = shallowRender({ setCurrentUserSetting });
+
+  wrapper.find(PreRequisitesStep).prop('onChangeSkipNextTime')(true);
+  expect(setCurrentUserSetting).toBeCalledWith({
+    key: 'tutorials.jenkins.skipBitbucketPreReqs',
+    value: 'true'
+  });
+
+  wrapper.find(PreRequisitesStep).prop('onChangeSkipNextTime')(false);
+  expect(setCurrentUserSetting).toBeCalledWith({
+    key: 'tutorials.jenkins.skipBitbucketPreReqs',
+    value: 'false'
+  });
+});
+
+it('should correctly skip the pre-reqs step if the user requested it', () => {
+  const wrapper = shallowRender({ skipPreReqs: true });
+  expect(wrapper.find(PreRequisitesStep).prop('open')).toBe(false);
+  expect(wrapper.find(MultiBranchPipelineStep).prop('open')).toBe(true);
+});
+
 function shallowRender(props: Partial<JenkinsTutorialProps> = {}) {
   return shallow<JenkinsTutorialProps>(
     <JenkinsTutorial
       component={mockComponent()}
       projectBinding={mockProjectBitbucketBindingGet()}
+      setCurrentUserSetting={jest.fn()}
+      skipPreReqs={false}
       {...props}
     />
   );
index fcfcda72e88b2a0b6cd073f5b5004a8c41f4fa30..7bb73a2eb81d16b19362608db6a69196cdbb214e 100644 (file)
@@ -31,6 +31,13 @@ it('should render correctly', () => {
 
 function shallowRender(props: Partial<PreRequisitesStepProps> = {}) {
   return shallow<PreRequisitesStepProps>(
-    <PreRequisitesStep onDone={jest.fn()} onOpen={jest.fn()} open={false} {...props} />
+    <PreRequisitesStep
+      onChangeSkipNextTime={jest.fn()}
+      onDone={jest.fn()}
+      onOpen={jest.fn()}
+      open={false}
+      skipNextTime={true}
+      {...props}
+    />
   );
 }
index 7e1ac0e500c027a9b2ed1f829034d06589817c44..65604e9096db62cd97c7c15bbfb205052d48cbee 100644 (file)
@@ -12,9 +12,11 @@ exports[`should render correctly: default 1`] = `
     </h1>
   </div>
   <PreRequisitesStep
+    onChangeSkipNextTime={[Function]}
     onDone={[Function]}
     onOpen={[Function]}
     open={true}
+    skipNextTime={false}
   />
   <MultiBranchPipelineStep
     finished={false}
index 01eb4afe997fe65efcc20cc1318d41acf7432268..184bd18139584bff536aa69b97b2ebc650813cd8 100644 (file)
@@ -61,6 +61,24 @@ exports[`should render correctly: content 1`] = `
   >
     onboarding.tutorial.with.jenkins.prereqs.following_are_recommendations
   </p>
+  <p
+    className="big-spacer-bottom display-flex-center"
+  >
+    <label
+      className="cursor-pointer"
+      htmlFor="skip-prereqs"
+      onClick={[Function]}
+    >
+      onboarding.tutorial.with.jenkins.prereqs.skip_next_time
+    </label>
+    <Checkbox
+      checked={true}
+      className="little-spacer-left"
+      id="skip-prereqs"
+      onCheck={[MockFunction]}
+      thirdState={false}
+    />
+  </p>
   <Button
     onClick={[MockFunction]}
   >
index b1dcc3c788ce0624f25ed6991b1e56994e2822f1..3559864277ff3f33465d186b943b6164cff7eb8a 100644 (file)
@@ -218,7 +218,10 @@ declare namespace T {
     value: string;
   }
 
-  type CurrentUserSettingNames = 'notifications.optOut' | 'notifications.readDate';
+  type CurrentUserSettingNames =
+    | 'notifications.optOut'
+    | 'notifications.readDate'
+    | 'tutorials.jenkins.skipBitbucketPreReqs';
 
   export interface CustomMeasure {
     createdAt?: string;
index d13c038a540097b5713824441b4adf155d9bc60e..54e43cc737870f7a66cba4d811d731ebab48c75b 100644 (file)
@@ -3267,6 +3267,7 @@ onboarding.tutorial.with.jenkins.prereqs.plugins.sonar_scanner=SonarQube Scanner
 onboarding.tutorial.with.jenkins.prereqs.step_by_step_guide=For a step by step guide on installing and configuring those plugins in Jenkins, visit the {link} documentation page.
 onboarding.tutorial.with.jenkins.prereqs.step_by_step_guide.link=Analysis Prerequisites
 onboarding.tutorial.with.jenkins.prereqs.following_are_recommendations=We recommend using the configuration in the following steps for the best results, but you can customize it as needed.
+onboarding.tutorial.with.jenkins.prereqs.skip_next_time=Don't show me the prerequisites next time
 onboarding.tutorial.with.jenkins.prereqs.done=Configure Analysis
 onboarding.tutorial.with.jenkins.multi_branch_pipeline.title=Create a Multibranch Pipeline Job
 onboarding.tutorial.with.jenkins.multi_branch_pipeline.intro=Create a Multibranch Pipeline in order to automatically analyze all your branches and pull requests.