]> source.dussan.org Git - sonarqube.git/commitdiff
SONARCLOUD-68 Add google analytics to SonarCloud
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>
Wed, 20 Jun 2018 13:22:23 +0000 (15:22 +0200)
committerSonarTech <sonartech@sonarsource.com>
Thu, 21 Jun 2018 18:21:29 +0000 (20:21 +0200)
server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java
server/sonar-server/src/main/java/org/sonar/server/ui/ws/GlobalAction.java
server/sonar-server/src/test/java/org/sonar/server/ui/ws/GlobalActionTest.java
server/sonar-web/package.json
server/sonar-web/src/main/js/app/components/App.tsx
server/sonar-web/src/main/js/app/components/PageTracker.tsx [new file with mode: 0644]
server/sonar-web/yarn.lock

index 6c5deb927c7403771b4729db9de28f89b6aff3c5..9cec2c0a2b5a8da3029bd2aefba051b2b85f17bd 100644 (file)
@@ -108,8 +108,8 @@ public class ProcessProperties {
     SONAR_UPDATECENTER_ACTIVATE("sonar.updatecenter.activate", "true"),
 
     SONARCLOUD_ENABLED("sonar.sonarcloud.enabled", "false"),
-
     SONAR_PRISMIC_ACCESS_TOKEN("sonar.prismic.accessToken", ""),
+    SONAR_ANALYTICS_TRACKING_ID("sonar.analytics.trackingId", ""),
 
     BITBUCKETCLOUD_APP_KEY("sonar.bitbucketcloud.appKey", "sonarcloud"),
     BITBUCKETCLOUD_ENDPOINT("sonar.bitbucketcloud.endpoint", "https://api.bitbucket.org"),
@@ -122,8 +122,6 @@ public class ProcessProperties {
     // whether the blue/green deployment of server is enabled
     BLUE_GREEN_ENABLED("sonar.blueGreenEnabled", "false");
 
-
-
     private final String key;
     private final String defaultValue;
 
index f69de5baed515cb5117ca337dbc9d745009c5beb..841840822d7677af08b8431354988bfa9ba42c63 100644 (file)
@@ -52,6 +52,7 @@ import static org.sonar.core.config.WebConstants.SONAR_LF_GRAVATAR_SERVER_URL;
 import static org.sonar.core.config.WebConstants.SONAR_LF_LOGO_URL;
 import static org.sonar.core.config.WebConstants.SONAR_LF_LOGO_WIDTH_PX;
 import static org.sonar.process.ProcessProperties.Property.SONARCLOUD_ENABLED;
+import static org.sonar.process.ProcessProperties.Property.SONAR_ANALYTICS_TRACKING_ID;
 import static org.sonar.process.ProcessProperties.Property.SONAR_PRISMIC_ACCESS_TOKEN;
 import static org.sonar.process.ProcessProperties.Property.SONAR_UPDATECENTER_ACTIVATE;
 
@@ -101,6 +102,7 @@ public class GlobalAction implements NavigationWsAction, Startable {
     boolean isOnSonarCloud = config.getBoolean(SONARCLOUD_ENABLED.getKey()).orElse(false);
     if (isOnSonarCloud) {
       this.systemSettingValuesByKey.put(SONAR_PRISMIC_ACCESS_TOKEN.getKey(), config.get(SONAR_PRISMIC_ACCESS_TOKEN.getKey()).orElse(null));
+      this.systemSettingValuesByKey.put(SONAR_ANALYTICS_TRACKING_ID.getKey(), config.get(SONAR_ANALYTICS_TRACKING_ID.getKey()).orElse(null));
     }
   }
 
index b0cb60037e90fc9d29ada5b22c0fd4829cb2d05e..aed04367e5add75a27fd4cd5e9c0c1179ee53a4e 100644 (file)
@@ -130,11 +130,13 @@ public class GlobalActionTest {
   public void return_prismic_setting_on_sonarcloud_only() {
     settings.setProperty("sonar.sonarcloud.enabled", true);
     settings.setProperty("sonar.prismic.accessToken", "secret");
+    settings.setProperty("sonar.analytics.trackingId", "ga_id");
     init();
 
     assertJson(call()).isSimilarTo("{" +
       "  \"settings\": {" +
       "    \"sonar.prismic.accessToken\": \"secret\"" +
+      "    \"sonar.analytics.trackingId\": \"ga_id\"" +
       "  }" +
       "}");
   }
@@ -248,7 +250,6 @@ public class GlobalActionTest {
     userSession.logIn().setRoot();
     when(webServer.isStandalone()).thenReturn(true);
 
-
     assertJson(call()).isSimilarTo("{\"standalone\":true}");
   }
 
@@ -258,7 +259,6 @@ public class GlobalActionTest {
     userSession.logIn().setRoot();
     when(webServer.isStandalone()).thenReturn(false);
 
-
     assertJson(call()).isSimilarTo("{\"standalone\":false}");
   }
 
index 241641cf9047dd35edefb5dc477a27fbe1d40c9a..a8b603c90d820a42410574409c49b1b7b925ecd4 100644 (file)
@@ -26,6 +26,7 @@
     "react-day-picker": "7.1.8",
     "react-dom": "16.2.0",
     "react-draggable": "3.0.5",
+    "react-ga": "2.5.3",
     "react-helmet": "5.2.0",
     "react-intl": "2.4.0",
     "react-modal": "3.4.4",
index 3930b084f79784198bb85ec8a356e93ddf70c1d3..91c65cc4e6c3fa4e5740ba7510831232a143167f 100644 (file)
@@ -26,7 +26,10 @@ import { CurrentUser } from '../types';
 import { fetchCurrentUser } from '../../store/users/actions';
 import { fetchLanguages, fetchAppState } from '../../store/rootActions';
 import { fetchMyOrganizations } from '../../apps/account/organizations/actions';
-import { getInstance } from '../../helpers/system';
+import { getInstance, isSonarCloud } from '../../helpers/system';
+import { lazyLoad } from '../../components/lazyLoad';
+
+const PageTracker = lazyLoad(() => import('./PageTracker'));
 
 interface Props {
   children: JSX.Element;
@@ -115,6 +118,7 @@ class App extends React.PureComponent<Props, State> {
     return (
       <>
         <Helmet defaultTitle={getInstance()} />
+        {isSonarCloud() && <PageTracker />}
         {this.props.children}
       </>
     );
diff --git a/server/sonar-web/src/main/js/app/components/PageTracker.tsx b/server/sonar-web/src/main/js/app/components/PageTracker.tsx
new file mode 100644 (file)
index 0000000..e2a4f0c
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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 * as GoogleAnalytics from 'react-ga';
+import { withRouter, WithRouterProps } from 'react-router';
+import { connect } from 'react-redux';
+import { getGlobalSettingValue } from '../../store/rootReducer';
+
+interface StateProps {
+  trackingId?: string;
+}
+
+type Props = WithRouterProps & StateProps;
+
+export class PageTracker extends React.PureComponent<Props> {
+  componentDidMount() {
+    if (this.props.trackingId) {
+      GoogleAnalytics.initialize(this.props.trackingId);
+      this.trackPage();
+    }
+  }
+
+  componentDidUpdate(prevProps: Props) {
+    const currentPage = this.props.location.pathname;
+    const prevPage = prevProps.location.pathname;
+
+    if (currentPage !== prevPage) {
+      this.trackPage();
+    }
+  }
+
+  trackPage = () => {
+    const { location, trackingId } = this.props;
+    if (trackingId) {
+      GoogleAnalytics.pageview(location.pathname);
+    }
+  };
+
+  render() {
+    return null;
+  }
+}
+
+const mapStateToProps = (state: any): StateProps => ({
+  trackingId: (getGlobalSettingValue(state, 'sonar.analytics.trackingId') || {}).value
+});
+
+export default withRouter<{}>(connect<StateProps>(mapStateToProps)(PageTracker));
index e99a7491fcfc936511f202496eaf441c085c2fd2..33dd4edc00b628d73f86da62161ebcf779f11ad2 100644 (file)
@@ -6971,6 +6971,13 @@ react-error-overlay@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-4.0.0.tgz#d198408a85b4070937a98667f500c832f86bd5d4"
 
+react-ga@2.5.3:
+  version "2.5.3"
+  resolved "https://registry.yarnpkg.com/react-ga/-/react-ga-2.5.3.tgz#0f447c73664c069a5fc341f6f431262e3d4c23c4"
+  optionalDependencies:
+    prop-types "^15.6.0"
+    react "^15.6.2 || ^16.0"
+
 react-helmet@5.2.0:
   version "5.2.0"
   resolved "https://registry.yarnpkg.com/react-helmet/-/react-helmet-5.2.0.tgz#a81811df21313a6d55c5f058c4aeba5d6f3d97a7"
@@ -7082,6 +7089,15 @@ react@16.2.0:
     object-assign "^4.1.1"
     prop-types "^15.6.0"
 
+"react@^15.6.2 || ^16.0":
+  version "16.4.1"
+  resolved "https://registry.yarnpkg.com/react/-/react-16.4.1.tgz#de51ba5764b5dbcd1f9079037b862bd26b82fe32"
+  dependencies:
+    fbjs "^0.8.16"
+    loose-envify "^1.1.0"
+    object-assign "^4.1.1"
+    prop-types "^15.6.0"
+
 read-pkg-up@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"