Commit 2a131ae6 authored by Pavel Shutsin's avatar Pavel Shutsin

Add separate tab tracking for devops adoption

We need to have devops_score and
devops_adoption separated
parent c30fc3d8
# frozen_string_literal: true # frozen_string_literal: true
class Admin::DevOpsReportController < Admin::ApplicationController class Admin::DevOpsReportController < Admin::ApplicationController
include Analytics::UniqueVisitsHelper include RedisTracking
helper_method :show_adoption? helper_method :show_adoption?
track_unique_visits :show, target_id: 'i_analytics_dev_ops_score' track_redis_hll_event :show, name: 'i_analytics_dev_ops_score', if: -> { should_track_devops_score? }
feature_category :devops_reports feature_category :devops_reports
...@@ -18,6 +18,10 @@ class Admin::DevOpsReportController < Admin::ApplicationController ...@@ -18,6 +18,10 @@ class Admin::DevOpsReportController < Admin::ApplicationController
def show_adoption? def show_adoption?
false false
end end
def should_track_devops_score?
true
end
end end
Admin::DevOpsReportController.prepend_if_ee('EE::Admin::DevOpsReportController') Admin::DevOpsReportController.prepend_if_ee('EE::Admin::DevOpsReportController')
...@@ -16,7 +16,7 @@ module Analytics ...@@ -16,7 +16,7 @@ module Analytics
def track_visit(target_id) def track_visit(target_id)
return unless visitor_id return unless visitor_id
Gitlab::Analytics::UniqueVisits.new.track_visit(visitor_id, target_id) Gitlab::Analytics::UniqueVisits.new.track_visit(target_id, values: visitor_id)
end end
class_methods do class_methods do
......
---
name: usage_data_i_analytics_dev_ops_adoption
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/57104
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/326450
milestone: '13.11'
type: development
group: group::optimize
default_enabled: true
...@@ -7364,6 +7364,30 @@ Status: `data_available` ...@@ -7364,6 +7364,30 @@ Status: `data_available`
Tiers: Tiers:
### `redis_hll_counters.analytics.i_analytics_dev_ops_adoption_monthly`
Counts visits to DevOps Adoption page per month
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210401092244_i_analytics_dev_ops_adoption_monthly.yml)
Group: `group::optimize`
Status: `implemented`
Tiers: `premium`, `ultimate`
### `redis_hll_counters.analytics.i_analytics_dev_ops_adoption_weekly`
Counts visits to DevOps Adoption page per week
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_7d/20210401092244_i_analytics_dev_ops_adoption_weekly.yml)
Group: `group::optimize`
Status: `implemented`
Tiers: `premium`, `ultimate`
### `redis_hll_counters.analytics.i_analytics_dev_ops_score_monthly` ### `redis_hll_counters.analytics.i_analytics_dev_ops_score_monthly`
Missing description Missing description
......
import Api from '~/api';
import { historyPushState } from '~/lib/utils/common_utils'; import { historyPushState } from '~/lib/utils/common_utils';
import { mergeUrlParams } from '~/lib/utils/url_utility'; import { mergeUrlParams } from '~/lib/utils/url_utility';
const DEVOPS_ADOPTION_PANE = 'devops-adoption'; const DEVOPS_ADOPTION_PANE = 'devops-adoption';
const DEVOPS_ADOPTION_PANE_TAB_CLICK_EVENT = 'i_analytics_dev_ops_adoption';
const tabClickHandler = (e) => { const tabClickHandler = (e) => {
const { hash } = e.currentTarget; const { hash } = e.currentTarget;
const tab = hash === `#${DEVOPS_ADOPTION_PANE}` ? DEVOPS_ADOPTION_PANE : null; let tab = null;
if (hash === `#${DEVOPS_ADOPTION_PANE}`) {
tab = DEVOPS_ADOPTION_PANE;
Api.trackRedisHllUserEvent(DEVOPS_ADOPTION_PANE_TAB_CLICK_EVENT);
}
const newUrl = mergeUrlParams({ tab }, window.location.href); const newUrl = mergeUrlParams({ tab }, window.location.href);
historyPushState(newUrl); historyPushState(newUrl);
}; };
......
...@@ -3,6 +3,15 @@ ...@@ -3,6 +3,15 @@
module EE module EE
module Admin module Admin
module DevOpsReportController module DevOpsReportController
extend ActiveSupport::Concern
prepended do
track_redis_hll_event :show, name: 'i_analytics_dev_ops_adoption', if: -> { params[:tab] == 'devops-adoption' }
end
def should_track_devops_score?
params[:tab] != 'devops-adoption'
end
def show_adoption? def show_adoption?
feature_already_in_use = ::Analytics::DevopsAdoption::Segment.any? feature_already_in_use = ::Analytics::DevopsAdoption::Segment.any?
......
---
title: Add separate tab tracking for devops adoption
merge_request: 57104
author:
type: added
---
# See Usage Ping metrics dictionary docs https://docs.gitlab.com/ee/development/usage_ping/metrics_dictionary.html
key_path: redis_hll_counters.analytics.i_analytics_dev_ops_adoption_monthly
description: Counts visits to DevOps Adoption page per month
product_section: dev
product_stage: manage
product_group: group::optimize
product_category: devops_reports
value_type: number
status: implemented
milestone: "13.11"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/57104
time_frame: 28d
data_source: redis_hll
distribution:
- ee
tier:
- premium
- ultimate
---
# See Usage Ping metrics dictionary docs https://docs.gitlab.com/ee/development/usage_ping/metrics_dictionary.html
key_path: redis_hll_counters.analytics.i_analytics_dev_ops_adoption_weekly
description: Counts visits to DevOps Adoption page per week
product_section: dev
product_stage: manage
product_group: group::optimize
product_category: devops_reports
value_type: number
status: implemented
milestone: "13.11"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/57104
time_frame: 7d
data_source: redis_hll
distribution:
- ee
tier:
- premium
- ultimate
...@@ -30,4 +30,21 @@ RSpec.describe Admin::DevOpsReportController do ...@@ -30,4 +30,21 @@ RSpec.describe Admin::DevOpsReportController do
end end
end end
end end
describe '#show' do
let(:user) { create(:admin) }
before do
sign_in(user)
end
context 'when devops_adoption tab selected' do
it 'tracks devops_adoption usage event' do
expect(Gitlab::UsageDataCounters::HLLRedisCounter)
.to receive(:track_event).with('i_analytics_dev_ops_adoption', values: kind_of(String))
get :show, params: { tab: 'devops-adoption' }, format: :html
end
end
end
end end
import initTabs from 'ee/analytics/devops_report/tabs';
import Api from '~/api';
jest.mock('~/api.js');
jest.mock('~/lib/utils/common_utils');
describe('tabs', () => {
beforeEach(() => {
setFixtures(`
<div>
<div class="js-devops-tab-item">
<a href="#devops-score" data-testid='score-tab'>Score</a>
</div>
<div class="js-devops-tab-item">
<a href="#devops-adoption" data-testid='devops-adoption-tab'>Adoption</a>
</div>
</div`);
initTabs();
});
afterEach(() => {});
describe('tracking', () => {
it('tracks event when adoption tab is clicked', () => {
document.querySelector('[data-testid="devops-adoption-tab"]').click();
expect(Api.trackRedisHllUserEvent).toHaveBeenCalledWith('i_analytics_dev_ops_adoption');
});
it('does not track an event when score tab is clicked', () => {
document.querySelector('[data-testid="score-tab"]').click();
expect(Api.trackRedisHllUserEvent).not.toHaveBeenCalled();
});
});
});
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
module Gitlab module Gitlab
module Analytics module Analytics
class UniqueVisits class UniqueVisits
def track_visit(visitor_id, target_id, time = Time.zone.now) def track_visit(*args, **kwargs)
Gitlab::UsageDataCounters::HLLRedisCounter.track_event(target_id, values: visitor_id, time: time) Gitlab::UsageDataCounters::HLLRedisCounter.track_event(*args, **kwargs)
end end
# Returns number of unique visitors for given targets in given time frame # Returns number of unique visitors for given targets in given time frame
......
...@@ -91,6 +91,11 @@ ...@@ -91,6 +91,11 @@
redis_slot: analytics redis_slot: analytics
aggregation: weekly aggregation: weekly
feature_flag: track_unique_visits feature_flag: track_unique_visits
- name: i_analytics_dev_ops_adoption
category: analytics
redis_slot: analytics
aggregation: weekly
feature_flag: track_unique_visits
- name: g_analytics_merge_request - name: g_analytics_merge_request
category: analytics category: analytics
redis_slot: analytics redis_slot: analytics
......
...@@ -5,7 +5,13 @@ require 'spec_helper' ...@@ -5,7 +5,13 @@ require 'spec_helper'
RSpec.describe Admin::DevOpsReportController do RSpec.describe Admin::DevOpsReportController do
describe 'show_adoption?' do describe 'show_adoption?' do
it 'is always false' do it 'is always false' do
expect(controller.show_adoption?).to be false expect(controller.show_adoption?).to be_falsey
end
end
describe 'should_track_devops_score?' do
it 'is always true' do
expect(controller.should_track_devops_score?).to be_truthy
end end
end end
......
...@@ -24,18 +24,18 @@ RSpec.describe Gitlab::Analytics::UniqueVisits, :clean_gitlab_redis_shared_state ...@@ -24,18 +24,18 @@ RSpec.describe Gitlab::Analytics::UniqueVisits, :clean_gitlab_redis_shared_state
describe '#track_visit' do describe '#track_visit' do
it 'tracks the unique weekly visits for targets' do it 'tracks the unique weekly visits for targets' do
unique_visits.track_visit(visitor1_id, target1_id, 7.days.ago) unique_visits.track_visit(target1_id, values: visitor1_id, time: 7.days.ago)
unique_visits.track_visit(visitor1_id, target1_id, 7.days.ago) unique_visits.track_visit(target1_id, values: visitor1_id, time: 7.days.ago)
unique_visits.track_visit(visitor2_id, target1_id, 7.days.ago) unique_visits.track_visit(target1_id, values: visitor2_id, time: 7.days.ago)
unique_visits.track_visit(visitor2_id, target2_id, 7.days.ago) unique_visits.track_visit(target2_id, values: visitor2_id, time: 7.days.ago)
unique_visits.track_visit(visitor1_id, target2_id, 8.days.ago) unique_visits.track_visit(target2_id, values: visitor1_id, time: 8.days.ago)
unique_visits.track_visit(visitor1_id, target2_id, 15.days.ago) unique_visits.track_visit(target2_id, values: visitor1_id, time: 15.days.ago)
unique_visits.track_visit(visitor3_id, target4_id, 7.days.ago) unique_visits.track_visit(target4_id, values: visitor3_id, time: 7.days.ago)
unique_visits.track_visit(visitor3_id, target5_id, 15.days.ago) unique_visits.track_visit(target5_id, values: visitor3_id, time: 15.days.ago)
unique_visits.track_visit(visitor2_id, target5_id, 15.days.ago) unique_visits.track_visit(target5_id, values: visitor2_id, time: 15.days.ago)
expect(unique_visits.unique_visits_for(targets: target1_id)).to eq(2) expect(unique_visits.unique_visits_for(targets: target1_id)).to eq(2)
expect(unique_visits.unique_visits_for(targets: target2_id)).to eq(1) expect(unique_visits.unique_visits_for(targets: target2_id)).to eq(1)
...@@ -61,7 +61,7 @@ RSpec.describe Gitlab::Analytics::UniqueVisits, :clean_gitlab_redis_shared_state ...@@ -61,7 +61,7 @@ RSpec.describe Gitlab::Analytics::UniqueVisits, :clean_gitlab_redis_shared_state
end end
it 'sets the keys in Redis to expire automatically after 12 weeks' do it 'sets the keys in Redis to expire automatically after 12 weeks' do
unique_visits.track_visit(visitor1_id, target1_id) unique_visits.track_visit(target1_id, values: visitor1_id)
Gitlab::Redis::SharedState.with do |redis| Gitlab::Redis::SharedState.with do |redis|
redis.scan_each(match: "{#{target1_id}}-*").each do |key| redis.scan_each(match: "{#{target1_id}}-*").each do |key|
...@@ -74,7 +74,7 @@ RSpec.describe Gitlab::Analytics::UniqueVisits, :clean_gitlab_redis_shared_state ...@@ -74,7 +74,7 @@ RSpec.describe Gitlab::Analytics::UniqueVisits, :clean_gitlab_redis_shared_state
invalid_target_id = "x_invalid" invalid_target_id = "x_invalid"
expect do expect do
unique_visits.track_visit(visitor1_id, invalid_target_id) unique_visits.track_visit(invalid_target_id, values: visitor1_id)
end.to raise_error(Gitlab::UsageDataCounters::HLLRedisCounter::UnknownEvent) end.to raise_error(Gitlab::UsageDataCounters::HLLRedisCounter::UnknownEvent)
end end
end end
......
...@@ -1291,6 +1291,7 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do ...@@ -1291,6 +1291,7 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
'p_analytics_repo' => 123, 'p_analytics_repo' => 123,
'i_analytics_cohorts' => 123, 'i_analytics_cohorts' => 123,
'i_analytics_dev_ops_score' => 123, 'i_analytics_dev_ops_score' => 123,
'i_analytics_dev_ops_adoption' => 123,
'i_analytics_instance_statistics' => 123, 'i_analytics_instance_statistics' => 123,
'p_analytics_merge_request' => 123, 'p_analytics_merge_request' => 123,
'g_analytics_merge_request' => 123, 'g_analytics_merge_request' => 123,
......
...@@ -4,27 +4,30 @@ RSpec.shared_examples 'tracking unique visits' do |method| ...@@ -4,27 +4,30 @@ RSpec.shared_examples 'tracking unique visits' do |method|
let(:request_params) { {} } let(:request_params) { {} }
it 'tracks unique visit if the format is HTML' do it 'tracks unique visit if the format is HTML' do
expect_any_instance_of(Gitlab::Analytics::UniqueVisits).to receive(:track_visit).with(instance_of(String), target_id) expect(Gitlab::UsageDataCounters::HLLRedisCounter)
.to receive(:track_event).with(target_id, values: kind_of(String))
get method, params: request_params, format: :html get method, params: request_params, format: :html
end end
it 'tracks unique visit if DNT is not enabled' do it 'tracks unique visit if DNT is not enabled' do
expect_any_instance_of(Gitlab::Analytics::UniqueVisits).to receive(:track_visit).with(instance_of(String), target_id) expect(Gitlab::UsageDataCounters::HLLRedisCounter)
.to receive(:track_event).with(target_id, values: kind_of(String))
request.headers['DNT'] = '0' request.headers['DNT'] = '0'
get method, params: request_params, format: :html get method, params: request_params, format: :html
end end
it 'does not track unique visit if DNT is enabled' do it 'does not track unique visit if DNT is enabled' do
expect_any_instance_of(Gitlab::Analytics::UniqueVisits).not_to receive(:track_visit) expect(Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event)
request.headers['DNT'] = '1' request.headers['DNT'] = '1'
get method, params: request_params, format: :html get method, params: request_params, format: :html
end end
it 'does not track unique visit if the format is JSON' do it 'does not track unique visit if the format is JSON' do
expect_any_instance_of(Gitlab::Analytics::UniqueVisits).not_to receive(:track_visit) expect(Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event)
get method, params: request_params, format: :json get method, params: request_params, format: :json
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