summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/models/usage_counters.rb42
-rw-r--r--changelogs/unreleased/45016-add-web-ide-commits-to-usage-ping.yml5
-rw-r--r--db/migrate/20180929102611_create_usage_counters.rb13
-rw-r--r--db/schema.rb8
-rw-r--r--lib/api/commits.rb3
-rw-r--r--lib/gitlab/usage_data.rb5
-rw-r--r--spec/factories/usage_counters.rb6
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml3
-rw-r--r--spec/lib/gitlab/usage_data_spec.rb1
-rw-r--r--spec/models/usage_counters_spec.rb31
-rw-r--r--spec/requests/api/commits_spec.rb6
-rw-r--r--spec/services/projects/usage_counters_increment_service_spec.rb27
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