Commit 8192b99b authored by Alper Akgun's avatar Alper Akgun

Merge branch...

Merge branch '322025-engineering-implement-tracking-for-continuous-onboarding-experiment' into 'master'

Measure continuous onboarding experiment

See merge request gitlab-org/gitlab!58689
parents ed5eedf5 cf7ed3a5
import Tracking from '~/tracking';
export default function trackLearnGitlab(learnGitlabA) {
Tracking.event('projects:learn_gitlab:index', 'page_init', {
label: 'learn_gitlab',
property: learnGitlabA
? 'Growth::Conversion::Experiment::LearnGitLabA'
: 'Growth::Activation::Experiment::LearnGitLabB',
});
}
......@@ -64,7 +64,15 @@ export default {
<img :src="svg" :alt="actionLabel" />
<h6>{{ title }}</h6>
<p class="gl-font-sm gl-text-gray-700">{{ description }}</p>
<gl-link :href="url" target="_blank">{{ actionLabel }}</gl-link>
<gl-link
:href="url"
target="_blank"
rel="noopener noreferrer"
data-track-action="click_link"
:data-track-label="actionLabel"
data-track-property="Growth::Activation::Experiment::LearnGitLabB"
>{{ actionLabel }}</gl-link
>
</div>
</gl-card>
</template>
......@@ -34,7 +34,15 @@ export default {
{{ $options.i18n.ACTION_LABELS[action].title }}
</span>
<span v-else>
<gl-link :href="value.url">{{ $options.i18n.ACTION_LABELS[action].title }}</gl-link>
<gl-link
target="_blank"
:href="value.url"
data-track-action="click_link"
:data-track-label="$options.i18n.ACTION_LABELS[action].title"
data-track-property="Growth::Conversion::Experiment::LearnGitLabA"
>
{{ $options.i18n.ACTION_LABELS[action].title }}
</gl-link>
</span>
<span v-if="trialOnly" class="gl-font-style-italic gl-text-gray-500" data-testid="trial-only">
- {{ $options.i18n.trialOnly }}
......
import Vue from 'vue';
import trackLearnGitlab from '~/learn_gitlab/track_learn_gitlab';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import LearnGitlabA from '../components/learn_gitlab_a.vue';
import LearnGitlabB from '../components/learn_gitlab_b.vue';
......@@ -14,6 +15,8 @@ function initLearnGitlab() {
const { learnGitlabA } = gon.experiments;
trackLearnGitlab(learnGitlabA);
return new Vue({
el,
render(createElement) {
......
......@@ -8,6 +8,16 @@ module LearnGitlabHelper
learn_gitlab_onboarding_available?(project)
end
def learn_gitlab_experiment_tracking_category
return unless current_user
if Gitlab::Experimentation.in_experiment_group?(:learn_gitlab_a, subject: current_user)
Gitlab::Experimentation.get_experiment(:learn_gitlab_a).tracking_category
elsif Gitlab::Experimentation.in_experiment_group?(:learn_gitlab_b, subject: current_user)
Gitlab::Experimentation.get_experiment(:learn_gitlab_b).tracking_category
end
end
def onboarding_actions_data(project)
attributes = onboarding_progress(project).attributes.symbolize_keys
......
......@@ -39,6 +39,7 @@ module SidebarsHelper
current_user: user,
container: project,
learn_gitlab_experiment_enabled: learn_gitlab_experiment_enabled?(project),
learn_gitlab_experiment_tracking_category: learn_gitlab_experiment_tracking_category,
current_ref: current_ref,
jira_issues_integration: project_jira_issues_integration?,
can_view_pipeline_editor: can_view_pipeline_editor?(project),
......
......@@ -3,6 +3,7 @@
module Registrations
class GroupsController < ApplicationController
include GroupInviteMembers
include ::Gitlab::Utils::StrongMemoize
layout 'checkout'
......@@ -13,6 +14,8 @@ module Registrations
def new
record_experiment_user(:trial_during_signup)
record_experiment_user(:learn_gitlab_a, learn_gitlab_context)
record_experiment_user(:learn_gitlab_b, learn_gitlab_context)
@group = Group.new(visibility_level: helpers.default_group_visibility)
end
......@@ -73,6 +76,8 @@ module Registrations
def registration_onboarding_flow
record_experiment_user(:trial_during_signup, trial_chosen: helpers.in_trial_during_signup_flow?, namespace_id: @group.id)
record_experiment_conversion_event(:learn_gitlab_a, namespace_id: @group.id)
record_experiment_conversion_event(:learn_gitlab_b, namespace_id: @group.id)
if experiment_enabled?(:trial_during_signup)
trial_during_signup_flow
......@@ -146,10 +151,10 @@ module Registrations
apply_trial_params = {
uid: current_user.id,
trial_user: params.permit(:glm_source, :glm_content).merge({
namespace_id: @group.id,
gitlab_com_trial: true,
sync_to_gl: true
})
namespace_id: @group.id,
gitlab_com_trial: true,
sync_to_gl: true
})
}
result = GitlabSubscriptions::ApplyTrialService.new.execute(apply_trial_params)
......@@ -157,5 +162,14 @@ module Registrations
result&.dig(:success)
end
def learn_gitlab_context
strong_memoize(:learn_gitlab_context) do
in_experiment_group_a = Gitlab::Experimentation.in_experiment_group?(:learn_gitlab_a, subject: current_user)
in_experiment_group_b = !in_experiment_group_a && Gitlab::Experimentation.in_experiment_group?(:learn_gitlab_b, subject: current_user)
{ in_experiment_group_a: in_experiment_group_a, in_experiment_group_b: in_experiment_group_b }
end
end
end
end
......@@ -25,22 +25,24 @@ module Registrations
if @project.saved?
learn_gitlab_project = create_learn_gitlab_project
onboarding_context = {
namespace_id: learn_gitlab_project.namespace_id,
project_id: @project.id,
learn_gitlab_project_id: learn_gitlab_project.id
}
experiment(:registrations_group_invite, actor: current_user)
.track(:signup_successful, property: @project.namespace_id.to_s)
if helpers.in_trial_onboarding_flow?
trial_onboarding_context = {
namespace_id: learn_gitlab_project.namespace_id,
project_id: @project.id,
learn_gitlab_project_id: learn_gitlab_project.id
}
record_experiment_user(:trial_onboarding_issues, trial_onboarding_context)
record_experiment_user(:trial_onboarding_issues, onboarding_context)
record_experiment_conversion_event(:trial_onboarding_issues)
redirect_to trial_getting_started_users_sign_up_welcome_path(learn_gitlab_project_id: learn_gitlab_project.id)
else
record_experiment_user(:learn_gitlab_a, onboarding_context)
record_experiment_user(:learn_gitlab_b, onboarding_context)
if continous_onboarding_experiment_enabled_for_user?
redirect_to continuous_onboarding_getting_started_users_sign_up_welcome_path(project_id: @project.id)
else
......
......@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe Registrations::GroupsController do
using RSpec::Parameterized::TableSyntax
let_it_be(:user) { create(:user) }
shared_examples 'hides email confirmation warning' do
......@@ -25,8 +27,14 @@ RSpec.describe Registrations::GroupsController do
end
end
describe 'GET #new' do
describe 'GET #new', :aggregate_failures do
let(:signup_onboarding_enabled) { true }
let(:learn_gitlab_context) do
{
in_experiment_group_a: false,
in_experiment_group_b: false
}
end
subject { get :new }
......@@ -51,10 +59,27 @@ RSpec.describe Registrations::GroupsController do
expect(assigns(:group).visibility_level).to eq(Gitlab::CurrentSettings.default_group_visibility)
end
it 'calls the record user method for trial_during_signup experiment' do
expect(controller).to receive(:record_experiment_user).with(:trial_during_signup)
context 'with different experiment rollouts' do
before do
stub_experiment_for_subject(learn_gitlab_a: experiment_a, learn_gitlab_b: experiment_b)
end
subject
where(:experiment_a, :experiment_b, :context) do
false | false | { in_experiment_group_a: false, in_experiment_group_b: false }
false | true | { in_experiment_group_a: false, in_experiment_group_b: true }
true | false | { in_experiment_group_a: true, in_experiment_group_b: false }
true | true | { in_experiment_group_a: true, in_experiment_group_b: false }
end
with_them do
it 'sets the correct context', :aggregate_failures do
expect(controller).to receive(:record_experiment_user).with(:trial_during_signup)
expect(controller).to receive(:record_experiment_user).with(:learn_gitlab_a, context)
expect(controller).to receive(:record_experiment_user).with(:learn_gitlab_b, context)
subject
end
end
end
context 'user without the ability to create a group' do
......@@ -73,7 +98,7 @@ RSpec.describe Registrations::GroupsController do
end
end
describe 'POST #create' do
describe 'POST #create', :aggregate_failure do
let_it_be(:glm_params) { {} }
let_it_be(:trial_form_params) { { trial: 'false' } }
let_it_be(:trial_onboarding_issues_enabled) { false }
......@@ -184,6 +209,8 @@ RSpec.describe Registrations::GroupsController do
expect(service).to receive(:execute).and_return(group)
end
expect(controller).to receive(:record_experiment_user).with(:trial_during_signup, trial_chosen: false, namespace_id: group.id)
expect(controller).to receive(:record_experiment_conversion_event).with(:learn_gitlab_a, namespace_id: group.id)
expect(controller).to receive(:record_experiment_conversion_event).with(:learn_gitlab_b, namespace_id: group.id)
subject
end
......
......@@ -65,6 +65,10 @@ RSpec.describe Registrations::ProjectsController do
context 'with an authenticated user', :sidekiq_inline do
let_it_be(:trial_onboarding_issues_enabled) { true }
let_it_be(:first_project) { create(:project) }
let_it_be(:onboarding_context) do
{ learn_gitlab_project_id: project.id, namespace_id: project.namespace_id, project_id: first_project.id }
end
before do
namespace.add_owner(user)
......@@ -80,6 +84,19 @@ RSpec.describe Registrations::ProjectsController do
expect(namespace.projects.find_by_name(s_('Learn GitLab'))).to be_import_finished
end
it 'tracks learn gitlab experiments' do
allow_next_instance_of(::Projects::CreateService) do |service|
allow(service).to receive(:execute).and_return(first_project)
end
allow_next_instance_of(::Projects::GitlabProjectsImportService) do |service|
allow(service).to receive(:execute).and_return(project)
end
expect(controller).to receive(:record_experiment_user).with(:learn_gitlab_a, onboarding_context)
expect(controller).to receive(:record_experiment_user).with(:learn_gitlab_b, onboarding_context)
subject
end
it 'tracks the registrations_group_invite experiment as expected', :experiment do
expect(experiment(:registrations_group_invite))
.to track(:signup_successful, { property: namespace.id.to_s })
......@@ -123,10 +140,6 @@ RSpec.describe Registrations::ProjectsController do
context 'when the trial onboarding is active' do
let_it_be(:trial_onboarding_flow_params) { { trial_onboarding_flow: true } }
let_it_be(:trial_onboarding_issues_enabled) { true }
let_it_be(:first_project) { create(:project) }
let_it_be(:trial_onboarding_context) do
{ learn_gitlab_project_id: project.id, namespace_id: project.namespace_id, project_id: first_project.id }
end
it 'creates a new project, a "Learn GitLab - Ultimate trial" project, does not set a cookie' do
expect { subject }.to change { namespace.projects.pluck(:name) }.from([]).to(['New project', s_('Learn GitLab - Ultimate trial')])
......@@ -141,7 +154,7 @@ RSpec.describe Registrations::ProjectsController do
expect_next_instance_of(::Projects::GitlabProjectsImportService) do |service|
expect(service).to receive(:execute).and_return(project)
end
expect(controller).to receive(:record_experiment_user).with(:trial_onboarding_issues, trial_onboarding_context)
expect(controller).to receive(:record_experiment_user).with(:trial_onboarding_issues, onboarding_context)
expect(controller).to receive(:record_experiment_conversion_event).with(:trial_onboarding_issues)
expect(subject).to redirect_to(trial_getting_started_users_sign_up_welcome_path(learn_gitlab_project_id: project.id))
end
......
......@@ -37,7 +37,14 @@ module Sidebars
override :extra_container_html_options
def nav_link_html_options
{ class: 'home' }
{
class: 'home',
data: {
track_action: 'click_menu',
track_property: context.learn_gitlab_experiment_tracking_category,
track_label: 'learn_gitlab'
}
}
end
override :image_path
......
import { mockTracking } from 'helpers/tracking_helper';
import trackLearnGitlab from '~/learn_gitlab/track_learn_gitlab';
describe('trackTrialUserErrors', () => {
let spy;
describe('when an error is present', () => {
beforeEach(() => {
spy = mockTracking('projects:learn_gitlab_index', document.body, jest.spyOn);
});
it('tracks the error message', () => {
trackLearnGitlab();
expect(spy).toHaveBeenCalledWith('projects:learn_gitlab:index', 'page_init', {
label: 'learn_gitlab',
property: 'Growth::Activation::Experiment::LearnGitLabB',
});
});
});
});
......@@ -134,9 +134,16 @@ exports[`Learn GitLab Design A renders correctly 1`] = `
<span>
<a
class="gl-link"
data-track-action="click_link"
data-track-label="Set up CI/CD"
data-track-property="Growth::Conversion::Experiment::LearnGitLabA"
href="http://example.com/"
rel="noopener noreferrer"
target="_blank"
>
Set up CI/CD
Set up CI/CD
</a>
</span>
......@@ -148,9 +155,16 @@ exports[`Learn GitLab Design A renders correctly 1`] = `
<span>
<a
class="gl-link"
data-track-action="click_link"
data-track-label="Start a free Ultimate trial"
data-track-property="Growth::Conversion::Experiment::LearnGitLabA"
href="http://example.com/"
rel="noopener noreferrer"
target="_blank"
>
Start a free Ultimate trial
Start a free Ultimate trial
</a>
</span>
......@@ -162,9 +176,16 @@ exports[`Learn GitLab Design A renders correctly 1`] = `
<span>
<a
class="gl-link"
data-track-action="click_link"
data-track-label="Add code owners"
data-track-property="Growth::Conversion::Experiment::LearnGitLabA"
href="http://example.com/"
rel="noopener noreferrer"
target="_blank"
>
Add code owners
Add code owners
</a>
</span>
......@@ -183,9 +204,16 @@ exports[`Learn GitLab Design A renders correctly 1`] = `
<span>
<a
class="gl-link"
data-track-action="click_link"
data-track-label="Add merge request approval"
data-track-property="Growth::Conversion::Experiment::LearnGitLabA"
href="http://example.com/"
rel="noopener noreferrer"
target="_blank"
>
Add merge request approval
Add merge request approval
</a>
</span>
......@@ -240,9 +268,16 @@ exports[`Learn GitLab Design A renders correctly 1`] = `
<span>
<a
class="gl-link"
data-track-action="click_link"
data-track-label="Create an issue"
data-track-property="Growth::Conversion::Experiment::LearnGitLabA"
href="http://example.com/"
rel="noopener noreferrer"
target="_blank"
>
Create an issue
Create an issue
</a>
</span>
......@@ -254,9 +289,16 @@ exports[`Learn GitLab Design A renders correctly 1`] = `
<span>
<a
class="gl-link"
data-track-action="click_link"
data-track-label="Submit a merge request"
data-track-property="Growth::Conversion::Experiment::LearnGitLabA"
href="http://example.com/"
rel="noopener noreferrer"
target="_blank"
>
Submit a merge request
Submit a merge request
</a>
</span>
......@@ -304,9 +346,16 @@ exports[`Learn GitLab Design A renders correctly 1`] = `
<span>
<a
class="gl-link"
data-track-action="click_link"
data-track-label="Run a Security scan using CI/CD"
data-track-property="Growth::Conversion::Experiment::LearnGitLabA"
href="http://example.com/"
rel="noopener noreferrer"
target="_blank"
>
Run a Security scan using CI/CD
Run a Security scan using CI/CD
</a>
</span>
......
......@@ -110,6 +110,9 @@ exports[`Learn GitLab Design B renders correctly 1`] = `
<a
class="gl-link"
data-track-action="click_link"
data-track-label="Invite your colleagues"
data-track-property="Growth::Activation::Experiment::LearnGitLabB"
href="http://example.com/"
rel="noopener noreferrer"
target="_blank"
......@@ -168,6 +171,9 @@ exports[`Learn GitLab Design B renders correctly 1`] = `
<a
class="gl-link"
data-track-action="click_link"
data-track-label="Create or import a repository"
data-track-property="Growth::Activation::Experiment::LearnGitLabB"
href="http://example.com/"
rel="noopener noreferrer"
target="_blank"
......@@ -218,6 +224,9 @@ exports[`Learn GitLab Design B renders correctly 1`] = `
<a
class="gl-link"
data-track-action="click_link"
data-track-label="Set-up CI/CD"
data-track-property="Growth::Activation::Experiment::LearnGitLabB"
href="http://example.com/"
rel="noopener noreferrer"
target="_blank"
......@@ -268,6 +277,9 @@ exports[`Learn GitLab Design B renders correctly 1`] = `
<a
class="gl-link"
data-track-action="click_link"
data-track-label="Try GitLab Ultimate for free"
data-track-property="Growth::Activation::Experiment::LearnGitLabB"
href="http://example.com/"
rel="noopener noreferrer"
target="_blank"
......@@ -323,6 +335,9 @@ exports[`Learn GitLab Design B renders correctly 1`] = `
<a
class="gl-link"
data-track-action="click_link"
data-track-label="Add code owners"
data-track-property="Growth::Activation::Experiment::LearnGitLabB"
href="http://example.com/"
rel="noopener noreferrer"
target="_blank"
......@@ -378,6 +393,9 @@ exports[`Learn GitLab Design B renders correctly 1`] = `
<a
class="gl-link"
data-track-action="click_link"
data-track-label="Enable require merge approvals"
data-track-property="Growth::Activation::Experiment::LearnGitLabB"
href="http://example.com/"
rel="noopener noreferrer"
target="_blank"
......@@ -444,6 +462,9 @@ exports[`Learn GitLab Design B renders correctly 1`] = `
<a
class="gl-link"
data-track-action="click_link"
data-track-label="Create an issue"
data-track-property="Growth::Activation::Experiment::LearnGitLabB"
href="http://example.com/"
rel="noopener noreferrer"
target="_blank"
......@@ -494,6 +515,9 @@ exports[`Learn GitLab Design B renders correctly 1`] = `
<a
class="gl-link"
data-track-action="click_link"
data-track-label="Submit a merge request (MR)"
data-track-property="Growth::Activation::Experiment::LearnGitLabB"
href="http://example.com/"
rel="noopener noreferrer"
target="_blank"
......@@ -560,6 +584,9 @@ exports[`Learn GitLab Design B renders correctly 1`] = `
<a
class="gl-link"
data-track-action="click_link"
data-track-label="Run a Security scan using CI/CD"
data-track-property="Growth::Activation::Experiment::LearnGitLabB"
href="http://example.com/"
rel="noopener noreferrer"
target="_blank"
......
......@@ -91,4 +91,37 @@ RSpec.describe LearnGitlabHelper do
end
end
end
describe '.learn_gitlab_experiment_tracking_category' do
using RSpec::Parameterized::TableSyntax
let_it_be(:user) { create(:user) }
subject { helper.learn_gitlab_experiment_tracking_category }
where(:experiment_a, :experiment_b, :result) do
false | false | nil
false | true | 'Growth::Activation::Experiment::LearnGitLabB'
true | false | 'Growth::Conversion::Experiment::LearnGitLabA'
true | true | 'Growth::Conversion::Experiment::LearnGitLabA'
end
with_them do
before do
stub_experiment_for_subject(learn_gitlab_a: experiment_a, learn_gitlab_b: experiment_b)
end
context 'when signed in' do
before do
sign_in(user)
end
it { is_expected.to eq(result) }
end
context 'when not signed in' do
it { is_expected.to eq(nil) }
end
end
end
end
......@@ -3,9 +3,18 @@
require 'spec_helper'
RSpec.describe Sidebars::Projects::Menus::LearnGitlabMenu do
let(:project) { build(:project) }
let(:experiment_enabled) { true }
let(:context) { Sidebars::Projects::Context.new(current_user: nil, container: project, learn_gitlab_experiment_enabled: experiment_enabled) }
let_it_be(:project) { build(:project) }
let_it_be(:experiment_enabled) { true }
let_it_be(:tracking_category) { 'Growth::Activation::Experiment::LearnGitLabB' }
let(:context) do
Sidebars::Projects::Context.new(
current_user: nil,
container: project,
learn_gitlab_experiment_enabled: experiment_enabled,
learn_gitlab_experiment_tracking_category: tracking_category
)
end
subject { described_class.new(context) }
......@@ -13,6 +22,23 @@ RSpec.describe Sidebars::Projects::Menus::LearnGitlabMenu do
expect(subject.instance_variable_get(:@items)).to be_empty
end
describe '#nav_link_html_options' do
let_it_be(:data_tracking) do
{
class: 'home',
data: {
track_action: 'click_menu',
track_property: tracking_category,
track_label: 'learn_gitlab'
}
}
end
specify do
expect(subject.nav_link_html_options).to eq(data_tracking)
end
end
describe '#render?' do
context 'when learn gitlab experiment is enabled' do
it 'returns true' do
......
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