Commit b9035d04 authored by Furkan Ayhan's avatar Furkan Ayhan Committed by Nick Thomas

Add tracking to measure the number of unique users committing CI config

Whenever a user's commit merged/pushed into the main branch,
we send a track event to Redis HHL.
parent c8141f4c
...@@ -44,11 +44,7 @@ module Git ...@@ -44,11 +44,7 @@ module Git
def invalidated_file_types def invalidated_file_types
return super unless default_branch? && !creating_branch? return super unless default_branch? && !creating_branch?
paths = limited_commits.each_with_object(Set.new) do |commit, set| paths = commit_paths.values.reduce(&:merge) || Set.new
commit.raw_deltas.each do |diff|
set << diff.new_path
end
end
Gitlab::FileDetector.types_in_paths(paths) Gitlab::FileDetector.types_in_paths(paths)
end end
...@@ -77,6 +73,7 @@ module Git ...@@ -77,6 +73,7 @@ module Git
enqueue_process_commit_messages enqueue_process_commit_messages
enqueue_jira_connect_sync_messages enqueue_jira_connect_sync_messages
enqueue_metrics_dashboard_sync enqueue_metrics_dashboard_sync
track_ci_config_change_event
end end
def branch_remove_hooks def branch_remove_hooks
...@@ -89,6 +86,18 @@ module Git ...@@ -89,6 +86,18 @@ module Git
::Metrics::Dashboard::SyncDashboardsWorker.perform_async(project.id) ::Metrics::Dashboard::SyncDashboardsWorker.perform_async(project.id)
end end
def track_ci_config_change_event
return unless Gitlab::CurrentSettings.usage_ping_enabled?
return unless ::Feature.enabled?(:usage_data_unique_users_committing_ciconfigfile, project, default_enabled: :yaml)
return unless default_branch?
commits_changing_ci_config.each do |commit|
Gitlab::UsageDataCounters::HLLRedisCounter.track_event(
'o_pipeline_authoring_unique_users_committing_ciconfigfile', values: commit.author&.id
)
end
end
# Schedules processing of commit messages # Schedules processing of commit messages
def enqueue_process_commit_messages def enqueue_process_commit_messages
referencing_commits = limited_commits.select(&:matches_cross_reference_regex?) referencing_commits = limited_commits.select(&:matches_cross_reference_regex?)
...@@ -190,6 +199,23 @@ module Git ...@@ -190,6 +199,23 @@ module Git
set set
end end
def commits_changing_ci_config
commit_paths.select do |commit, paths|
next if commit.merge_commit?
paths.include?(project.ci_config_path_or_default)
end.keys
end
def commit_paths
strong_memoize(:commit_paths) do
limited_commits.map do |commit|
paths = Set.new(commit.raw_deltas.map(&:new_path))
[commit, paths]
end.to_h
end
end
end end
end end
......
---
name: usage_data_unique_users_committing_ciconfigfile
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/52172
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/299403
milestone: '13.9'
type: development
group: group::pipeline authoring
default_enabled: false
...@@ -603,3 +603,9 @@ ...@@ -603,3 +603,9 @@
redis_slot: ci_templates redis_slot: ci_templates
aggregation: weekly aggregation: weekly
feature_flag: usage_data_track_ci_templates_unique_projects feature_flag: usage_data_track_ci_templates_unique_projects
# Pipeline Authoring
- name: o_pipeline_authoring_unique_users_committing_ciconfigfile
category: pipeline_authoring
redis_slot: pipeline_authoring
aggregation: weekly
feature_flag: usage_data_unique_users_committing_ciconfigfile
...@@ -40,7 +40,8 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s ...@@ -40,7 +40,8 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
'code_review', 'code_review',
'terraform', 'terraform',
'ci_templates', 'ci_templates',
'quickactions' 'quickactions',
'pipeline_authoring'
) )
end end
end end
......
...@@ -1324,7 +1324,9 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do ...@@ -1324,7 +1324,9 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
subject { described_class.redis_hll_counters } subject { described_class.redis_hll_counters }
let(:categories) { ::Gitlab::UsageDataCounters::HLLRedisCounter.categories } let(:categories) { ::Gitlab::UsageDataCounters::HLLRedisCounter.categories }
let(:ineligible_total_categories) { %w[source_code ci_secrets_management incident_management_alerts snippets terraform] } let(:ineligible_total_categories) do
%w[source_code ci_secrets_management incident_management_alerts snippets terraform pipeline_authoring]
end
it 'has all known_events' do it 'has all known_events' do
expect(subject).to have_key(:redis_hll_counters) expect(subject).to have_key(:redis_hll_counters)
......
...@@ -93,12 +93,12 @@ RSpec.describe Git::BranchHooksService do ...@@ -93,12 +93,12 @@ RSpec.describe Git::BranchHooksService do
describe 'Push Event' do describe 'Push Event' do
let(:event) { Event.pushed_action.first } let(:event) { Event.pushed_action.first }
before do subject(:execute_service) { service.execute }
service.execute
end
context "with an existing branch" do context "with an existing branch" do
it 'generates a push event with one commit' do it 'generates a push event with one commit' do
execute_service
expect(event).to be_an_instance_of(PushEvent) expect(event).to be_an_instance_of(PushEvent)
expect(event.project).to eq(project) expect(event.project).to eq(project)
expect(event).to be_pushed_action expect(event).to be_pushed_action
...@@ -109,12 +109,87 @@ RSpec.describe Git::BranchHooksService do ...@@ -109,12 +109,87 @@ RSpec.describe Git::BranchHooksService do
expect(event.push_event_payload.ref).to eq('master') expect(event.push_event_payload.ref).to eq('master')
expect(event.push_event_payload.commit_count).to eq(1) expect(event.push_event_payload.commit_count).to eq(1)
end end
context 'with changing CI config' do
before do
allow_next_instance_of(Gitlab::Git::Diff) do |diff|
allow(diff).to receive(:new_path).and_return('.gitlab-ci.yml')
end
allow(Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:track_event)
end
let!(:commit_author) { create(:user, email: sample_commit.author_email) }
let(:tracking_params) do
['o_pipeline_authoring_unique_users_committing_ciconfigfile', values: commit_author.id]
end
it 'tracks the event' do
execute_service
expect(Gitlab::UsageDataCounters::HLLRedisCounter)
.to have_received(:track_event).with(*tracking_params)
end
context 'when the FF usage_data_unique_users_committing_ciconfigfile is disabled' do
before do
stub_feature_flags(usage_data_unique_users_committing_ciconfigfile: false)
end
it 'does not track the event' do
execute_service
expect(Gitlab::UsageDataCounters::HLLRedisCounter)
.not_to have_received(:track_event).with(*tracking_params)
end
end
context 'when usage ping is disabled' do
before do
stub_application_setting(usage_ping_enabled: false)
end
it 'does not track the event' do
execute_service
expect(Gitlab::UsageDataCounters::HLLRedisCounter)
.not_to have_received(:track_event).with(*tracking_params)
end
end
context 'when the branch is not the main branch' do
let(:branch) { 'feature' }
it 'does not track the event' do
execute_service
expect(Gitlab::UsageDataCounters::HLLRedisCounter)
.not_to have_received(:track_event).with(*tracking_params)
end
end
context 'when the CI config is a different path' do
before do
project.ci_config_path = 'config/ci.yml'
end
it 'does not track the event' do
execute_service
expect(Gitlab::UsageDataCounters::HLLRedisCounter)
.not_to have_received(:track_event).with(*tracking_params)
end
end
end
end end
context "with a new branch" do context "with a new branch" do
let(:oldrev) { Gitlab::Git::BLANK_SHA } let(:oldrev) { Gitlab::Git::BLANK_SHA }
it 'generates a push event with more than one commit' do it 'generates a push event with more than one commit' do
execute_service
expect(event).to be_an_instance_of(PushEvent) expect(event).to be_an_instance_of(PushEvent)
expect(event.project).to eq(project) expect(event.project).to eq(project)
expect(event).to be_pushed_action expect(event).to be_pushed_action
...@@ -131,6 +206,8 @@ RSpec.describe Git::BranchHooksService do ...@@ -131,6 +206,8 @@ RSpec.describe Git::BranchHooksService do
let(:newrev) { Gitlab::Git::BLANK_SHA } let(:newrev) { Gitlab::Git::BLANK_SHA }
it 'generates a push event with no commits' do it 'generates a push event with no commits' do
execute_service
expect(event).to be_an_instance_of(PushEvent) expect(event).to be_an_instance_of(PushEvent)
expect(event.project).to eq(project) expect(event.project).to eq(project)
expect(event).to be_pushed_action expect(event).to be_pushed_action
......
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