Commit 9b2e17ac authored by Tiago Botelho's avatar Tiago Botelho

Adds WebIDE commits to UsagePing

Implements UsageCounters model to track feature usage counters
and makes easy to extend for future counters
parent d9241761
# 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
---
title: Adds Web IDE commits to usage ping
merge_request: 22007
author:
type: added
# 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
......@@ -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
......
......@@ -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)
......
......@@ -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 },
......
# frozen_string_literal: true
FactoryBot.define do
factory :usage_counters, class: 'UsageCounters' do
end
end
......@@ -330,3 +330,6 @@ resource_label_events:
- merge_request
- epic
- label
usage_counters:
- project
- web_ide_commits
......@@ -46,6 +46,7 @@ describe Gitlab::UsageData do
git
database
avg_cycle_analytics
web_ide_commits
))
end
......
# 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
......@@ -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
......
# 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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment