diff options
author | jejacks0n <jjackson@gitlab.com> | 2019-07-29 18:01:24 -0600 |
---|---|---|
committer | jejacks0n <jjackson@gitlab.com> | 2019-08-13 14:14:59 -0600 |
commit | b8b0a87fc3dfee285b2e9f5ab3dde5a779affd8b (patch) | |
tree | 14073accc46bb53756f8692466ce9385b43a7964 | |
parent | df35d772c655587eecbe7b3e387c8b8bc287b23c (diff) | |
download | gitlab-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.yml | 2 | ||||
-rw-r--r-- | Gemfile | 3 | ||||
-rw-r--r-- | Gemfile.lock | 4 | ||||
-rw-r--r-- | app/helpers/application_settings_helper.rb | 6 | ||||
-rw-r--r-- | app/helpers/tracking_helper.rb | 21 | ||||
-rw-r--r-- | app/models/application_setting.rb | 4 | ||||
-rw-r--r-- | app/models/application_setting_implementation.rb | 4 | ||||
-rw-r--r-- | app/views/admin/application_settings/_snowplow.html.haml | 43 | ||||
-rw-r--r-- | app/views/admin/application_settings/integrations.html.haml | 11 | ||||
-rw-r--r-- | lib/api/settings.rb | 11 | ||||
-rw-r--r-- | lib/gitlab/snowplow_tracker.rb | 35 | ||||
-rw-r--r-- | locale/gitlab.pot | 6 | ||||
-rw-r--r-- | spec/lib/gitlab/snowplow_tracker_spec.rb | 45 | ||||
-rw-r--r-- | spec/requests/api/settings_spec.rb | 49 |
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' @@ -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 } |