summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjejacks0n <jjackson@gitlab.com>2019-07-29 18:01:24 -0600
committerjejacks0n <jjackson@gitlab.com>2019-08-13 14:14:59 -0600
commitb8b0a87fc3dfee285b2e9f5ab3dde5a779affd8b (patch)
tree14073accc46bb53756f8692466ce9385b43a7964
parentdf35d772c655587eecbe7b3e387c8b8bc287b23c (diff)
downloadgitlab-ce-b8b0a87fc3dfee285b2e9f5ab3dde5a779affd8b.tar.gz
Migrates Snowplow backend from EE to CE
This introduces several changes, but these are all just ported from the EE project.
-rw-r--r--.haml-lint_todo.yml2
-rw-r--r--Gemfile3
-rw-r--r--Gemfile.lock4
-rw-r--r--app/helpers/application_settings_helper.rb6
-rw-r--r--app/helpers/tracking_helper.rb21
-rw-r--r--app/models/application_setting.rb4
-rw-r--r--app/models/application_setting_implementation.rb4
-rw-r--r--app/views/admin/application_settings/_snowplow.html.haml43
-rw-r--r--app/views/admin/application_settings/integrations.html.haml11
-rw-r--r--lib/api/settings.rb11
-rw-r--r--lib/gitlab/snowplow_tracker.rb35
-rw-r--r--locale/gitlab.pot6
-rw-r--r--spec/lib/gitlab/snowplow_tracker_spec.rb45
-rw-r--r--spec/requests/api/settings_spec.rb49
14 files changed, 225 insertions, 19 deletions
diff --git a/.haml-lint_todo.yml b/.haml-lint_todo.yml
index d29cb8aa0b0..23036612d39 100644
--- a/.haml-lint_todo.yml
+++ b/.haml-lint_todo.yml
@@ -27,7 +27,7 @@ linters:
- 'app/views/admin/application_settings/_repository_check.html.haml'
- 'app/views/admin/application_settings/_repository_storage.html.haml'
- 'app/views/admin/application_settings/_signin.html.haml'
- - 'app/views/admin/application_settings/_signup.html.haml'
+ - 'app/views/admin/application_settings/_snowplow.html.haml'
- 'app/views/admin/application_settings/_spam.html.haml'
- 'app/views/admin/application_settings/_terminal.html.haml'
- 'app/views/admin/application_settings/_usage.html.haml'
diff --git a/Gemfile b/Gemfile
index 55143693d5c..ae9ee1cb333 100644
--- a/Gemfile
+++ b/Gemfile
@@ -297,6 +297,9 @@ gem 'batch-loader', '~> 1.4.0'
# Perf bar
gem 'peek', '~> 1.0.1'
+# Snowplow events tracking
+gem 'snowplow-tracker', '~> 0.6.1'
+
# Memory benchmarks
gem 'derailed_benchmarks', require: false
diff --git a/Gemfile.lock b/Gemfile.lock
index 6aa96d54abb..918115b3b01 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -152,6 +152,7 @@ GEM
concurrent-ruby-ext (1.1.5)
concurrent-ruby (= 1.1.5)
connection_pool (2.2.2)
+ contracts (0.11.0)
crack (0.4.3)
safe_yaml (~> 1.0.0)
crass (1.0.4)
@@ -901,6 +902,8 @@ GEM
simplecov-html (~> 0.10.0)
simplecov-html (0.10.2)
slack-notifier (1.5.1)
+ snowplow-tracker (0.6.1)
+ contracts (~> 0.7, <= 0.11)
spring (2.0.2)
activesupport (>= 4.2)
spring-commands-rspec (1.0.4)
@@ -1229,6 +1232,7 @@ DEPENDENCIES
simple_po_parser (~> 1.1.2)
simplecov (~> 0.16.1)
slack-notifier (~> 1.5.1)
+ snowplow-tracker (~> 0.6.1)
spring (~> 2.0.0)
spring-commands-rspec (~> 1.0.4)
sprockets (~> 3.7.0)
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index acbcf0ded17..36ad85ac9cc 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -270,7 +270,11 @@ module ApplicationSettingsHelper
:diff_max_patch_bytes,
:commit_email_hostname,
:protected_ci_variables,
- :local_markdown_version
+ :local_markdown_version,
+ :snowplow_collector_uri,
+ :snowplow_cookie_domain,
+ :snowplow_enabled,
+ :snowplow_site_id
]
end
diff --git a/app/helpers/tracking_helper.rb b/app/helpers/tracking_helper.rb
index 51ea79d1ddd..4de1aad364a 100644
--- a/app/helpers/tracking_helper.rb
+++ b/app/helpers/tracking_helper.rb
@@ -1,7 +1,26 @@
# frozen_string_literal: true
module TrackingHelper
+ extend ::Gitlab::Utils::Override
+
+ override :tracking_attrs
+
def tracking_attrs(label, event, property)
- {} # CE has no tracking features
+ return {} unless tracking_enabled?
+
+ {
+ data: {
+ track_label: label,
+ track_event: event,
+ track_property: property
+ }
+ }
+ end
+
+ private
+
+ def tracking_enabled?
+ Rails.env.production? &&
+ ::Gitlab::CurrentSettings.snowplow_enabled?
end
end
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index cb6346421ec..8956bb7c2ef 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -99,6 +99,10 @@ class ApplicationSetting < ApplicationRecord
presence: true,
if: :plantuml_enabled
+ validates :snowplow_collector_uri,
+ presence: true,
+ if: :snowplow_enabled
+
validates :max_attachment_size,
presence: true,
numericality: { only_integer: true, greater_than: 0 }
diff --git a/app/models/application_setting_implementation.rb b/app/models/application_setting_implementation.rb
index b7a4d7aa803..bfc0fa1046b 100644
--- a/app/models/application_setting_implementation.rb
+++ b/app/models/application_setting_implementation.rb
@@ -97,6 +97,10 @@ module ApplicationSettingImplementation
usage_stats_set_by_user_id: nil,
diff_max_patch_bytes: Gitlab::Git::Diff::DEFAULT_MAX_PATCH_BYTES,
commit_email_hostname: default_commit_email_hostname,
+ snowplow_collector_uri: nil,
+ snowplow_cookie_domain: nil,
+ snowplow_enabled: false,
+ snowplow_site_id: nil,
protected_ci_variables: false,
local_markdown_version: 0,
outbound_local_requests_whitelist: [],
diff --git a/app/views/admin/application_settings/_snowplow.html.haml b/app/views/admin/application_settings/_snowplow.html.haml
new file mode 100644
index 00000000000..7d640aadd99
--- /dev/null
+++ b/app/views/admin/application_settings/_snowplow.html.haml
@@ -0,0 +1,43 @@
+%section.settings.as-third-party-offers.no-animate#js-third-party-offers-settings{ class: ('expanded' if expanded_by_default?) }
+ .settings-header
+ %h4
+ = _('Third party offers')
+ %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ = expanded_by_default? ? _('Collapse') : _('Expand')
+ %p
+ = _('Control the display of third party offers.')
+ .settings-content
+ = render 'third_party_offers', application_setting: @application_setting
+
+%section.settings.as-snowplow.no-animate#js-snowplow-settings{ class: ('expanded' if expanded) }
+ .settings-header
+ %h4
+ = _('Snowplow')
+ %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ = expanded ? _('Collapse') : _('Expand')
+ %p
+ = _('Configure the %{link} integration.').html_safe % { link: link_to('Snowplow', 'https://snowplowanalytics.com/', target: '_blank') }
+ .settings-content
+
+ = form_for @application_setting, url: admin_application_settings_path, html: { class: 'fieldset-form' } do |f|
+ = form_errors(@application_setting)
+
+ %fieldset
+ .form-group
+ .form-check
+ = f.check_box :snowplow_enabled, class: 'form-check-input'
+ = f.label :snowplow_enabled, class: 'form-check-label' do
+ Enable Snowplow
+ .form-group
+ = f.label :snowplow_collector_uri, 'Collector URI', class: 'label-light'
+ = f.text_field :snowplow_collector_uri, class: 'form-control', placeholder: 'snowplow.example.com'
+ .form-group
+ = f.label :snowplow_site_id, class: 'label-light' do
+ Site ID
+ = f.text_field :snowplow_site_id, class: 'form-control'
+ .form-group
+ = f.label :snowplow_cookie_domain, class: 'label-light' do
+ Cookie domain
+ = f.text_field :snowplow_cookie_domain, class: 'form-control'
+
+ = f.submit 'Save changes', class: 'btn btn-success'
diff --git a/app/views/admin/application_settings/integrations.html.haml b/app/views/admin/application_settings/integrations.html.haml
index 310e86b1377..eec9c37ac64 100644
--- a/app/views/admin/application_settings/integrations.html.haml
+++ b/app/views/admin/application_settings/integrations.html.haml
@@ -17,15 +17,4 @@
= render_if_exists 'admin/application_settings/slack', expanded: expanded_by_default?
-%section.settings.as-third-party-offers.no-animate#js-third-party-offers-settings{ class: ('expanded' if expanded_by_default?) }
- .settings-header
- %h4
- = _('Third party offers')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
- = expanded_by_default? ? _('Collapse') : _('Expand')
- %p
- = _('Control the display of third party offers.')
- .settings-content
- = render 'third_party_offers', application_setting: @application_setting
-
= render_if_exists 'admin/application_settings/snowplow', expanded: expanded_by_default?
diff --git a/lib/api/settings.rb b/lib/api/settings.rb
index 196ef1fcdfa..f89188aa26e 100644
--- a/lib/api/settings.rb
+++ b/lib/api/settings.rb
@@ -125,6 +125,12 @@ module API
optional :instance_statistics_visibility_private, type: Boolean, desc: 'When set to `true` Instance statistics will only be available to admins'
optional :local_markdown_version, type: Integer, desc: "Local markdown version, increase this value when any cached markdown should be invalidated"
optional :allow_local_requests_from_hooks_and_services, type: Boolean, desc: 'Deprecated: Use :allow_local_requests_from_web_hooks_and_services instead. Allow requests to the local network from hooks and services.' # support legacy names, can be removed in v5
+ optional :snowplow_enabled, type: Grape::API::Boolean, desc: 'Enable Snowplow Tracking'
+ given snowplow_enabled: ->(val) { val } do
+ requires :snowplow_collector_uri, type: String, desc: 'Snowplow Collector URI'
+ optional :snowplow_cookie_domain, type: String, desc: 'Snowplow cookie domain'
+ optional :snowplow_site_id, type: String, desc: 'Snowplow Site/Application ID'
+ end
ApplicationSetting::SUPPORTED_KEY_TYPES.each do |type|
optional :"#{type}_key_restriction",
@@ -159,11 +165,6 @@ module API
attrs[:password_authentication_enabled_for_web] = attrs.delete(:password_authentication_enabled)
end
- # support legacy names, can be removed in v5
- if attrs.has_key?(:allow_local_requests_from_hooks_and_services)
- attrs[:allow_local_requests_from_web_hooks_and_services] = attrs.delete(:allow_local_requests_from_hooks_and_services)
- end
-
attrs = filter_attributes_using_license(attrs)
if ApplicationSettings::UpdateService.new(current_settings, current_user, attrs).execute
diff --git a/lib/gitlab/snowplow_tracker.rb b/lib/gitlab/snowplow_tracker.rb
new file mode 100644
index 00000000000..49d08656a05
--- /dev/null
+++ b/lib/gitlab/snowplow_tracker.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require 'snowplow-tracker'
+
+module Gitlab
+ module SnowplowTracker
+ NAMESPACE = 'cf'
+
+ class << self
+ def track_event(category, action, label: nil, property: nil, value: nil, context: nil)
+ tracker&.track_struct_event(category, action, label, property, value, context, Time.now.to_i)
+ end
+
+ private
+
+ def tracker
+ return unless enabled?
+
+ @tracker ||= ::SnowplowTracker::Tracker.new(emitter, subject, NAMESPACE, Gitlab::CurrentSettings.snowplow_site_id)
+ end
+
+ def subject
+ ::SnowplowTracker::Subject.new
+ end
+
+ def emitter
+ ::SnowplowTracker::Emitter.new(Gitlab::CurrentSettings.snowplow_collector_uri)
+ end
+
+ def enabled?
+ Gitlab::CurrentSettings.snowplow_enabled?
+ end
+ end
+ end
+end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index d33c62031c4..bef7244c059 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -3120,6 +3120,9 @@ msgstr ""
msgid "Configure storage path settings."
msgstr ""
+msgid "Configure the %{link} integration."
+msgstr ""
+
msgid "Configure the way a user creates a new account."
msgstr ""
@@ -10310,6 +10313,9 @@ msgstr ""
msgid "SnippetsEmptyState|They can be either public or private."
msgstr ""
+msgid "Snowplow"
+msgstr ""
+
msgid "Some email servers do not support overriding the email sender name. Enable this option to include the name of the author of the issue, merge request or comment in the email body instead."
msgstr ""
diff --git a/spec/lib/gitlab/snowplow_tracker_spec.rb b/spec/lib/gitlab/snowplow_tracker_spec.rb
new file mode 100644
index 00000000000..a5ada8471bb
--- /dev/null
+++ b/spec/lib/gitlab/snowplow_tracker_spec.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+describe Gitlab::SnowplowTracker do
+ let(:timestamp) { Time.utc(2017, 3, 22) }
+
+ around do |example|
+ Timecop.freeze(timestamp) { example.run }
+ end
+
+ subject { described_class.track_event('epics', 'action', property: 'what', value: 'doit') }
+
+ context '.track_event' do
+ context 'when Snowplow tracker is disabled' do
+ it 'does not track the event' do
+ expect(SnowplowTracker::Tracker).not_to receive(:new)
+
+ subject
+ end
+ end
+
+ context 'when Snowplow tracker is enabled' do
+ before do
+ stub_application_setting(snowplow_enabled: true)
+ stub_application_setting(snowplow_site_id: 'awesome gitlab')
+ stub_application_setting(snowplow_collector_uri: 'url.com')
+ end
+
+ it 'tracks the event' do
+ tracker = double
+
+ expect(::SnowplowTracker::Tracker).to receive(:new)
+ .with(
+ an_instance_of(::SnowplowTracker::Emitter),
+ an_instance_of(::SnowplowTracker::Subject),
+ 'cf', 'awesome gitlab'
+ ).and_return(tracker)
+ expect(tracker).to receive(:track_struct_event)
+ .with('epics', 'action', nil, 'what', 'doit', nil, timestamp.to_i)
+
+ subject
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb
index 184c00a356a..08b956d68fe 100644
--- a/spec/requests/api/settings_spec.rb
+++ b/spec/requests/api/settings_spec.rb
@@ -165,6 +165,55 @@ describe API::Settings, 'Settings' do
end
end
+ context "snowplow tracking settings" do
+ let(:settings) do
+ {
+ snowplow_collector_uri: "https://snowplow.example.com",
+ snowplow_cookie_domain: ".example.com",
+ snowplow_enabled: true,
+ snowplow_site_id: "site_id"
+ }
+ end
+ let(:attribute_names) { settings.keys.map(&:to_s) }
+
+ it "includes the attributes in the API" do
+ get api("/application/settings", admin)
+
+ expect(response).to have_gitlab_http_status(200)
+ attribute_names.each do |attribute|
+ expect(json_response.keys).to include(attribute)
+ end
+ end
+
+ it "allows updating the settings" do
+ put api("/application/settings", admin), params: settings
+
+ expect(response).to have_gitlab_http_status(200)
+ settings.each do |attribute, value|
+ expect(ApplicationSetting.current.public_send(attribute)).to eq(value)
+ end
+ end
+
+ context "missing snowplow_collector_uri value when snowplow_enabled is true" do
+ it "returns a blank parameter error message" do
+ put api("/application/settings", admin), params: { snowplow_enabled: true }
+
+ expect(response).to have_gitlab_http_status(400)
+ expect(json_response["error"]).to eq("snowplow_collector_uri is missing")
+ end
+
+ it "handles validation errors" do
+ put api("/application/settings", admin), params: settings.merge({
+ snowplow_collector_uri: nil
+ })
+
+ expect(response).to have_gitlab_http_status(400)
+ message = json_response["message"]
+ expect(message["snowplow_collector_uri"]).to include("can't be blank")
+ end
+ end
+ end
+
context "missing plantuml_url value when plantuml_enabled is true" do
it "returns a blank parameter error message" do
put api("/application/settings", admin), params: { plantuml_enabled: true }