Commit 6b51acec authored by Thong Kuah's avatar Thong Kuah

Merge branch '14671-analytics-feature-flags' into 'master'

Separate feature flag for each analytics feature

Closes #14671

See merge request gitlab-org/gitlab-ee!16102
parents a762049d 458ea66f
# Cycle Analytics
> - Introduced prior to GitLab 12.2 at the project level.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/12077) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.2 at the group level (enabled by feature flag `analytics`).
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/12077) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.2 at the group level.
NOTE: **Note:**
As of GitLab 12.3 this feature is enabled by the `cycle_analytics` feature flag.
Cycle Analytics measures the time spent to go from an [idea to production] - also known
as cycle time - for each of your projects. Cycle Analytics displays the median time for an idea to
......@@ -24,9 +27,6 @@ Cycle Analytics is available:
In the future, multiple groups will be selectable which will effectively make this an
instance-level feature.
NOTE: **Note:**
Requires the [analytics workspace](index.md) to be enabled.
- At the project level via **Project > Cycle Analytics**.
There are seven stages that are tracked as part of the Cycle Analytics calculations.
......
# Analytics workspace
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/12077) in GitLab 12.2 (enabled using `analytics` feature flag).
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/12077) in GitLab 12.2.
The Analytics workspace will make it possible to aggregate analytics across
GitLab, so that users can view information across multiple projects and groups
in one place.
To access the centralized analytics workspace:
1. Ensure it's enabled. Requires a GitLab administrator to enable it with the `analytics` feature
flag.
1. Once enabled, click on **Analytics** from the top navigation bar.
To access the centralized analytics workspace, click on **Analytics** from the top navigation bar.
## Available analytics
From the centralized analytics workspace, the following analytics are available:
- [Cycle Analytics](cycle_analytics.md).
- [Cycle Analytics](cycle_analytics.md):
1. Requires a GitLab administrator to enable it with the `cycle_analytics` feature flag.
1. Once enabled, click on **Analytics** and then **Cycle Analytics** from the top navigation bar.
NOTE: **Note:**
Project-level Cycle Analytics are still available at a project's **Project > Cycle Analytics**.
# frozen_string_literal: true
class Analytics::AnalyticsController < Analytics::ApplicationController
def index
if Gitlab::Analytics.productivity_analytics_enabled?
redirect_to analytics_productivity_analytics_path
elsif Gitlab::Analytics.cycle_analytics_enabled?
redirect_to analytics_cycle_analytics_path
else
render_404
end
end
end
......@@ -4,4 +4,12 @@ class Analytics::ApplicationController < ApplicationController
include RoutableActions
layout 'analytics'
private
def self.check_feature_flag(flag, *args)
before_action(*args) { render_404 unless Feature.enabled?(flag) }
end
private_class_method :check_feature_flag
end
# frozen_string_literal: true
class Analytics::CycleAnalyticsController < Analytics::ApplicationController
check_feature_flag Gitlab::Analytics::CYCLE_ANALYTICS_FEATURE_FLAG
end
# frozen_string_literal: true
class Analytics::ProductivityAnalyticsController < Analytics::ApplicationController
check_feature_flag Gitlab::Analytics::PRODUCTIVITY_ANALYTICS_FEATURE_FLAG
before_action :load_group
before_action :load_project
before_action :check_feature_availability!
......
......@@ -36,7 +36,7 @@ module EE
override :get_dashboard_nav_links
def get_dashboard_nav_links
super.tap do |links|
links << :analytics if ::Feature.enabled?(:analytics)
links << :analytics if ::Gitlab::Analytics.any_features_enabled?
end
end
end
......
......@@ -5,31 +5,30 @@
.avatar-container.s40.settings-avatar
= sprite_icon('log', size: 24)
.sidebar-context-title= _('Analytics')
%ul.sidebar-top-level-items
- if Feature.enabled?(:productivity_analytics)
= nav_link(controller: :productivity_analytics) do
= link_to analytics_productivity_analytics_path, class: 'qa-sidebar-productivity-analytics' do
.nav-icon-container
= sprite_icon('comment')
%span.nav-item-name
= _('Productivity Analytics')
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :productivity_analytics, html_options: { class: "fly-out-top-item qa-sidebar-productivity-analytics-fly-out" } ) do
= link_to analytics_productivity_analytics_path do
%strong.fly-out-top-item-name
= _('Productivity Analytics')
- if Feature.enabled?(:cycle_analytics)
= nav_link(controller: :cycle_analytics) do
= link_to analytics_cycle_analytics_path, class: 'qa-sidebar-cycle-analytics' do
.nav-icon-container
= sprite_icon('repeat')
%span.nav-item-name
= _('Cycle Analytics')
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :cycle_analytics, html_options: { class: "fly-out-top-item qa-sidebar-cycle-analytics-fly-out" } ) do
= link_to analytics_cycle_analytics_path do
%strong.fly-out-top-item-name
= _('Cycle Analytics')
%ul.sidebar-top-level-items
- if Gitlab::Analytics.productivity_analytics_enabled?
= nav_link(controller: :productivity_analytics) do
= link_to analytics_productivity_analytics_path, class: 'qa-sidebar-productivity-analytics' do
.nav-icon-container
= sprite_icon('comment')
%span.nav-item-name
= _('Productivity Analytics')
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :productivity_analytics, html_options: { class: "fly-out-top-item qa-sidebar-productivity-analytics-fly-out" } ) do
= link_to analytics_productivity_analytics_path do
%strong.fly-out-top-item-name
= _('Productivity Analytics')
- if Gitlab::Analytics.cycle_analytics_enabled?
= nav_link(controller: :cycle_analytics) do
= link_to analytics_cycle_analytics_path, class: 'qa-sidebar-cycle-analytics' do
.nav-icon-container
= sprite_icon('repeat')
%span.nav-item-name
= _('Cycle Analytics')
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :cycle_analytics, html_options: { class: "fly-out-top-item qa-sidebar-cycle-analytics-fly-out" } ) do
= link_to analytics_cycle_analytics_path do
%strong.fly-out-top-item-name
= _('Cycle Analytics')
= render 'shared/sidebar_toggle_button'
---
title: Eliminating `analytics` feature flag and introduce separate feature flags for Analytics features.
merge_request: 16102
author:
type: changed
# frozen_string_literal: true
namespace :analytics do
constraints(::Constraints::FeatureConstrainer.new(:productivity_analytics)) do
root to: redirect('-/analytics/productivity_analytics')
root to: 'analytics#index'
constraints(::Constraints::FeatureConstrainer.new(:productivity_analytics)) do
resource :productivity_analytics, only: :show
end
......
# frozen_string_literal: true
module Gitlab
module Analytics
# Normally each analytics feature should be guarded with a feature flag.
CYCLE_ANALYTICS_FEATURE_FLAG = :cycle_analytics
PRODUCTIVITY_ANALYTICS_FEATURE_FLAG = :productivity_analytics
FEATURE_FLAGS = [
CYCLE_ANALYTICS_FEATURE_FLAG,
PRODUCTIVITY_ANALYTICS_FEATURE_FLAG
].freeze
def self.any_features_enabled?
FEATURE_FLAGS.any? { |flag| Feature.enabled?(flag) }
end
def self.cycle_analytics_enabled?
Feature.enabled?(CYCLE_ANALYTICS_FEATURE_FLAG)
end
def self.productivity_analytics_enabled?
Feature.enabled?(PRODUCTIVITY_ANALYTICS_FEATURE_FLAG)
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Analytics::AnalyticsController do
include AnalyticsHelpers
let(:user) { create(:user) }
before do
sign_in(user)
end
describe 'GET index' do
describe 'redirects to the first enabled analytics page' do
it 'redirects to cycle analytics' do
disable_all_analytics_feature_flags
stub_feature_flags(Gitlab::Analytics::CYCLE_ANALYTICS_FEATURE_FLAG => true)
get :index
expect(response).to redirect_to(analytics_cycle_analytics_path)
end
it 'redirects to productivity analytics' do
disable_all_analytics_feature_flags
stub_feature_flags(Gitlab::Analytics::PRODUCTIVITY_ANALYTICS_FEATURE_FLAG => true)
get :index
expect(response).to redirect_to(analytics_productivity_analytics_path)
end
end
it 'renders 404 all the analytics feature flags are disabled' do
disable_all_analytics_feature_flags
get :index
expect(response).to have_gitlab_http_status(404)
end
end
end
......@@ -11,9 +11,19 @@ describe Analytics::CycleAnalyticsController do
describe 'GET show' do
it 'renders `show` template' do
stub_feature_flags(Gitlab::Analytics::CYCLE_ANALYTICS_FEATURE_FLAG => true)
get :show
expect(response).to render_template :show
end
it 'renders `404` when feature flag is disabled' do
stub_feature_flags(Gitlab::Analytics::CYCLE_ANALYTICS_FEATURE_FLAG => false)
get :show
expect(response).to have_gitlab_http_status(404)
end
end
end
......@@ -35,6 +35,15 @@ describe Analytics::ProductivityAnalyticsController do
expect(response).to render_template :show
end
it 'renders `404` when feature flag is disabled' do
stub_licensed_features(productivity_analytics: true)
stub_feature_flags(Gitlab::Analytics::PRODUCTIVITY_ANALYTICS_FEATURE_FLAG => false)
get :show
expect(response).to have_gitlab_http_status(404)
end
end
describe 'GET show.json' do
......
......@@ -3,6 +3,8 @@
require 'spec_helper'
describe DashboardHelper, type: :helper do
include AnalyticsHelpers
let(:user) { build(:user) }
before do
......@@ -11,9 +13,9 @@ describe DashboardHelper, type: :helper do
end
describe '#dashboard_nav_links' do
context 'when analytics is enabled' do
context 'when at least one analytics feature is enabled' do
before do
stub_feature_flags(analytics: true)
enable_only_one_analytics_feature_flag
end
it 'includes analytics' do
......@@ -21,9 +23,9 @@ describe DashboardHelper, type: :helper do
end
end
context 'when analytics is disabled' do
context 'when all analytics features are disabled' do
before do
stub_feature_flags(analytics: false)
disable_all_analytics_feature_flags
end
it 'does not include analytics' do
......
......@@ -6,25 +6,7 @@ describe 'Analytics' do
include RSpec::Rails::RequestExampleGroup
include Warden::Test::Helpers
let(:user) { create(:user) }
it "redirects to productivity_analytics" do
expect(get('/-/analytics')).to redirect_to('/-/analytics/productivity_analytics')
end
context ':analytics feature is disabled' do
before do
stub_feature_flags(analytics: false)
end
it 'redirects to sign_in if user is not authenticated' do
expect(get('/-/analytics')).to redirect_to('/users/sign_in')
end
it 'returns 404 if user is authenticated' do
login_as(user)
expect(get('/-/analytics')).to eq(404)
end
it 'redirects to sign_in if user is not authenticated' do
expect(get('/-/analytics')).to redirect_to('/users/sign_in')
end
end
# frozen_string_literal: true
# Helper for analytics related features
module AnalyticsHelpers
def disable_all_analytics_feature_flags
Gitlab::Analytics::FEATURE_FLAGS.each do |flag|
stub_feature_flags(flag => false)
end
end
def enable_only_one_analytics_feature_flag
Gitlab::Analytics::FEATURE_FLAGS.each_with_index do |flag, i|
stub_feature_flags(flag => i == 0)
end
end
end
......@@ -3,29 +3,50 @@
require 'spec_helper'
describe 'layouts/nav/sidebar/_analytics' do
include AnalyticsHelpers
it_behaves_like 'has nav sidebar'
context 'top-level items' do
before do
render
end
context 'when feature flags are enabled' do
it 'has `Analytics` link' do
stub_feature_flags(Gitlab::Analytics::PRODUCTIVITY_ANALYTICS_FEATURE_FLAG => true)
it 'has `Analytics` link' do
expect(rendered).to have_content('Analytics')
expect(rendered).to include(analytics_root_path)
expect(rendered).to match(/<use xlink:href=".+?icons-.+?#log">/)
end
render
expect(rendered).to have_content('Analytics')
expect(rendered).to include(analytics_root_path)
expect(rendered).to match(/<use xlink:href=".+?icons-.+?#log">/)
end
it 'has `Productivity Analytics` link' do
stub_feature_flags(Gitlab::Analytics::PRODUCTIVITY_ANALYTICS_FEATURE_FLAG => true)
it 'has `Productivity Analytics` link' do
expect(rendered).to have_content('Productivity Analytics')
expect(rendered).to include(analytics_productivity_analytics_path)
expect(rendered).to match(/<use xlink:href=".+?icons-.+?#comment">/)
render
expect(rendered).to have_content('Productivity Analytics')
expect(rendered).to include(analytics_productivity_analytics_path)
expect(rendered).to match(/<use xlink:href=".+?icons-.+?#comment">/)
end
it 'has `Cycle Analytics` link' do
stub_feature_flags(Gitlab::Analytics::CYCLE_ANALYTICS_FEATURE_FLAG => true)
render
expect(rendered).to have_content('Cycle Analytics')
expect(rendered).to include(analytics_cycle_analytics_path)
expect(rendered).to match(/<use xlink:href=".+?icons-.+?#repeat">/)
end
end
it 'has `Cycle Analytics` link' do
expect(rendered).to have_content('Cycle Analytics')
expect(rendered).to include(analytics_cycle_analytics_path)
expect(rendered).to match(/<use xlink:href=".+?icons-.+?#repeat">/)
context 'when feature flags are disabled' do
it 'no analytics links are rendered' do
disable_all_analytics_feature_flags
expect(rendered).not_to have_content('Productivity Analytics')
expect(rendered).not_to have_content('Cycle Analytics')
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