diff options
-rw-r--r-- | app/models/usage_counters.rb | 42 | ||||
-rw-r--r-- | changelogs/unreleased/45016-add-web-ide-commits-to-usage-ping.yml | 5 | ||||
-rw-r--r-- | db/migrate/20180929102611_create_usage_counters.rb | 13 | ||||
-rw-r--r-- | db/schema.rb | 8 | ||||
-rw-r--r-- | lib/api/commits.rb | 3 | ||||
-rw-r--r-- | lib/gitlab/usage_data.rb | 5 | ||||
-rw-r--r-- | spec/factories/usage_counters.rb | 6 | ||||
-rw-r--r-- | spec/lib/gitlab/import_export/all_models.yml | 3 | ||||
-rw-r--r-- | spec/lib/gitlab/usage_data_spec.rb | 1 | ||||
-rw-r--r-- | spec/models/usage_counters_spec.rb | 31 | ||||
-rw-r--r-- | spec/requests/api/commits_spec.rb | 6 | ||||
-rw-r--r-- | spec/services/projects/usage_counters_increment_service_spec.rb | 27 |
12 files changed, 149 insertions, 1 deletions
diff --git a/app/models/usage_counters.rb b/app/models/usage_counters.rb new file mode 100644 index 00000000000..90f9c2a976e --- /dev/null +++ b/app/models/usage_counters.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +class UsageCounters < ActiveRecord::Base + RECORD_LIMIT = 1.freeze + BY = 1.freeze + BLACKLIST_ATTRIBUTES = %w(id created_at updated_at).freeze + + validate :ensure_only_one, on: :create + + default_value_for :web_ide_commits, 0 + + # This method supports concurrency so that several + # requests are able to increment the counter without + # us having inconsistent data + def increment_counters(attrs) + # We want to be able to use the service to increment + # both a single and multiple counters + attrs = Array(attrs) + + attrs_with_by = + attrs.each_with_object({}) do |attr, hsh| + hsh[attr] = BY + end + + self.class.update_counters(id, attrs_with_by) + end + + # Every attribute in this table except the blacklisted + # attributes is a counter + def totals + attributes.except(*BLACKLIST_ATTRIBUTES).symbolize_keys + end + + private + + # We only want one UsageCounters per instance + def ensure_only_one + return unless UsageCounters.count >= RECORD_LIMIT + + errors.add(:base, 'There can only be one usage counters record per instance') + end +end diff --git a/changelogs/unreleased/45016-add-web-ide-commits-to-usage-ping.yml b/changelogs/unreleased/45016-add-web-ide-commits-to-usage-ping.yml new file mode 100644 index 00000000000..a7f24742588 --- /dev/null +++ b/changelogs/unreleased/45016-add-web-ide-commits-to-usage-ping.yml @@ -0,0 +1,5 @@ +--- +title: Adds Web IDE commits to usage ping +merge_request: 22007 +author: +type: added diff --git a/db/migrate/20180929102611_create_usage_counters.rb b/db/migrate/20180929102611_create_usage_counters.rb new file mode 100644 index 00000000000..f17486bb513 --- /dev/null +++ b/db/migrate/20180929102611_create_usage_counters.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class CreateUsageCounters < ActiveRecord::Migration + DOWNTIME = false + + def change + create_table :usage_counters do |t| + t.integer :web_ide_commits + + t.timestamps_with_timezone null: false + end + end +end diff --git a/db/schema.rb b/db/schema.rb index f92d8005dfb..fb57f2452d7 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20180917172041) do +ActiveRecord::Schema.define(version: 20180929102611) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -2080,6 +2080,12 @@ ActiveRecord::Schema.define(version: 20180917172041) do add_index "uploads", ["model_id", "model_type"], name: "index_uploads_on_model_id_and_model_type", using: :btree add_index "uploads", ["uploader", "path"], name: "index_uploads_on_uploader_and_path", using: :btree + create_table "usage_counters", force: :cascade do |t| + t.integer "web_ide_commits" + t.datetime_with_timezone "created_at", null: false + t.datetime_with_timezone "updated_at", null: false + end + create_table "user_agent_details", force: :cascade do |t| t.string "user_agent", null: false t.string "ip_address", null: false diff --git a/lib/api/commits.rb b/lib/api/commits.rb index 5aeffc8fb99..e16dd29d138 100644 --- a/lib/api/commits.rb +++ b/lib/api/commits.rb @@ -108,6 +108,9 @@ module API if result[:status] == :success commit_detail = user_project.repository.commit(result[:result]) + + UsageCounters.first_or_create.increment_counters(:web_ide_commits) if find_user_from_warden + present commit_detail, with: Entities::CommitDetail else render_api_error!(result[:message], 400) diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb index f7d8ee571cd..afab36e89dd 100644 --- a/lib/gitlab/usage_data.rb +++ b/lib/gitlab/usage_data.rb @@ -10,6 +10,7 @@ module Gitlab .merge(features_usage_data) .merge(components_usage_data) .merge(cycle_analytics_usage_data) + .merge(usage_counters) end def to_json(force_refresh: false) @@ -106,6 +107,10 @@ module Gitlab } end + def usage_counters + UsageCounters.first_or_create.totals + end + def components_usage_data { gitlab_pages: { enabled: Gitlab.config.pages.enabled, version: Gitlab::Pages::VERSION }, diff --git a/spec/factories/usage_counters.rb b/spec/factories/usage_counters.rb new file mode 100644 index 00000000000..23277fd741e --- /dev/null +++ b/spec/factories/usage_counters.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :usage_counters, class: 'UsageCounters' do + end +end diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index ec2bdbe22e1..b2a0afcb827 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -330,3 +330,6 @@ resource_label_events: - merge_request - epic - label +usage_counters: +- project +- web_ide_commits diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb index 1ec1fe10744..d669c42ab4a 100644 --- a/spec/lib/gitlab/usage_data_spec.rb +++ b/spec/lib/gitlab/usage_data_spec.rb @@ -46,6 +46,7 @@ describe Gitlab::UsageData do git database avg_cycle_analytics + web_ide_commits )) end diff --git a/spec/models/usage_counters_spec.rb b/spec/models/usage_counters_spec.rb new file mode 100644 index 00000000000..0adbfe3cef7 --- /dev/null +++ b/spec/models/usage_counters_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe UsageCounters do + let!(:usage_counters) { create(:usage_counters) } + + describe 'maximum number of records' do + it 'allows for one single record to be created' do + expect do + described_class.create! + end.to raise_error(ActiveRecord::RecordInvalid, 'Validation failed: There can only be one usage counters record per instance') + end + end + + describe '#totals' do + subject { usage_counters.totals } + + it 'returns counters' do + is_expected.to include(web_ide_commits: 0) + end + end + + describe '#increment_counters' do + it 'increments specified counters by 1' do + expect do + usage_counters.increment_counters(:web_ide_commits) + end.to change { usage_counters.reload.web_ide_commits }.from(0).to(1) + end + end +end diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb index f3fb88474a4..aebc24dd9a2 100644 --- a/spec/requests/api/commits_spec.rb +++ b/spec/requests/api/commits_spec.rb @@ -278,6 +278,12 @@ describe API::Commits do } end + it 'does not increment the usage counters using access token authentication' do + post api(url, user), valid_c_params + + expect_any_instance_of(::UsageCounters).not_to receive(:increment_counters) + end + it 'a new file in project repo' do post api(url, user), valid_c_params diff --git a/spec/services/projects/usage_counters_increment_service_spec.rb b/spec/services/projects/usage_counters_increment_service_spec.rb new file mode 100644 index 00000000000..d82a7337665 --- /dev/null +++ b/spec/services/projects/usage_counters_increment_service_spec.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Projects::UsageCountersIncrementService do + let(:project) { create(:usage_counters) } + + subject(:service) { described_class.new(project) } + + context '#execute' do + context 'when single attribute is passed' do + it 'increments attribute' do + expect do + service.execute(:web_ide_commits) + end.to change { project.usage_counters.reload.web_ide_commits }.from(0).to(1) + end + end + + context 'when array is passed' do + it 'increments specified attributes' do + expect do + service.execute(%i(web_ide_commits)) + end.to change { project.usage_counters.reload.web_ide_commits }.from(0).to(1) + end + end + end +end |