Commit 458ea66f authored by Adam Hegyi's avatar Adam Hegyi Committed by Thong Kuah

Separate feature flag for each analytics feature

- Adding Analytics module to keep track of analytics feature flags.
- Check feature flag in analytics controllers.
- Enable Analytics workspace when at least one analytics feature is
enabled
parent a762049d
# Cycle Analytics # Cycle Analytics
> - Introduced prior to GitLab 12.2 at the project level. > - 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 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 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: ...@@ -24,9 +27,6 @@ Cycle Analytics is available:
In the future, multiple groups will be selectable which will effectively make this an In the future, multiple groups will be selectable which will effectively make this an
instance-level feature. instance-level feature.
NOTE: **Note:**
Requires the [analytics workspace](index.md) to be enabled.
- At the project level via **Project > Cycle Analytics**. - At the project level via **Project > Cycle Analytics**.
There are seven stages that are tracked as part of the Cycle Analytics calculations. There are seven stages that are tracked as part of the Cycle Analytics calculations.
......
# Analytics workspace # 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 The Analytics workspace will make it possible to aggregate analytics across
GitLab, so that users can view information across multiple projects and groups GitLab, so that users can view information across multiple projects and groups
in one place. in one place.
To access the centralized analytics workspace: To access the centralized analytics workspace, click on **Analytics** from the top navigation bar.
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.
## Available analytics ## Available analytics
From the centralized analytics workspace, the following analytics are available: 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:** NOTE: **Note:**
Project-level Cycle Analytics are still available at a project's **Project > Cycle Analytics**. 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 ...@@ -4,4 +4,12 @@ class Analytics::ApplicationController < ApplicationController
include RoutableActions include RoutableActions
layout 'analytics' 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 end
# frozen_string_literal: true # frozen_string_literal: true
class Analytics::CycleAnalyticsController < Analytics::ApplicationController class Analytics::CycleAnalyticsController < Analytics::ApplicationController
check_feature_flag Gitlab::Analytics::CYCLE_ANALYTICS_FEATURE_FLAG
end end
# frozen_string_literal: true # frozen_string_literal: true
class Analytics::ProductivityAnalyticsController < Analytics::ApplicationController class Analytics::ProductivityAnalyticsController < Analytics::ApplicationController
check_feature_flag Gitlab::Analytics::PRODUCTIVITY_ANALYTICS_FEATURE_FLAG
before_action :load_group before_action :load_group
before_action :load_project before_action :load_project
before_action :check_feature_availability! before_action :check_feature_availability!
......
...@@ -36,7 +36,7 @@ module EE ...@@ -36,7 +36,7 @@ module EE
override :get_dashboard_nav_links override :get_dashboard_nav_links
def get_dashboard_nav_links def get_dashboard_nav_links
super.tap do |links| super.tap do |links|
links << :analytics if ::Feature.enabled?(:analytics) links << :analytics if ::Gitlab::Analytics.any_features_enabled?
end end
end end
end end
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
= sprite_icon('log', size: 24) = sprite_icon('log', size: 24)
.sidebar-context-title= _('Analytics') .sidebar-context-title= _('Analytics')
%ul.sidebar-top-level-items %ul.sidebar-top-level-items
- if Feature.enabled?(:productivity_analytics) - if Gitlab::Analytics.productivity_analytics_enabled?
= nav_link(controller: :productivity_analytics) do = nav_link(controller: :productivity_analytics) do
= link_to analytics_productivity_analytics_path, class: 'qa-sidebar-productivity-analytics' do = link_to analytics_productivity_analytics_path, class: 'qa-sidebar-productivity-analytics' do
.nav-icon-container .nav-icon-container
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
%strong.fly-out-top-item-name %strong.fly-out-top-item-name
= _('Productivity Analytics') = _('Productivity Analytics')
- if Feature.enabled?(:cycle_analytics) - if Gitlab::Analytics.cycle_analytics_enabled?
= nav_link(controller: :cycle_analytics) do = nav_link(controller: :cycle_analytics) do
= link_to analytics_cycle_analytics_path, class: 'qa-sidebar-cycle-analytics' do = link_to analytics_cycle_analytics_path, class: 'qa-sidebar-cycle-analytics' do
.nav-icon-container .nav-icon-container
...@@ -31,5 +31,4 @@ ...@@ -31,5 +31,4 @@
= link_to analytics_cycle_analytics_path do = link_to analytics_cycle_analytics_path do
%strong.fly-out-top-item-name %strong.fly-out-top-item-name
= _('Cycle Analytics') = _('Cycle Analytics')
= render 'shared/sidebar_toggle_button' = 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 # frozen_string_literal: true
namespace :analytics do namespace :analytics do
constraints(::Constraints::FeatureConstrainer.new(:productivity_analytics)) do root to: 'analytics#index'
root to: redirect('-/analytics/productivity_analytics')
constraints(::Constraints::FeatureConstrainer.new(:productivity_analytics)) do
resource :productivity_analytics, only: :show resource :productivity_analytics, only: :show
end 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 ...@@ -11,9 +11,19 @@ describe Analytics::CycleAnalyticsController do
describe 'GET show' do describe 'GET show' do
it 'renders `show` template' do it 'renders `show` template' do
stub_feature_flags(Gitlab::Analytics::CYCLE_ANALYTICS_FEATURE_FLAG => true)
get :show get :show
expect(response).to render_template :show expect(response).to render_template :show
end 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
end end
...@@ -35,6 +35,15 @@ describe Analytics::ProductivityAnalyticsController do ...@@ -35,6 +35,15 @@ describe Analytics::ProductivityAnalyticsController do
expect(response).to render_template :show expect(response).to render_template :show
end 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 end
describe 'GET show.json' do describe 'GET show.json' do
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
require 'spec_helper' require 'spec_helper'
describe DashboardHelper, type: :helper do describe DashboardHelper, type: :helper do
include AnalyticsHelpers
let(:user) { build(:user) } let(:user) { build(:user) }
before do before do
...@@ -11,9 +13,9 @@ describe DashboardHelper, type: :helper do ...@@ -11,9 +13,9 @@ describe DashboardHelper, type: :helper do
end end
describe '#dashboard_nav_links' do describe '#dashboard_nav_links' do
context 'when analytics is enabled' do context 'when at least one analytics feature is enabled' do
before do before do
stub_feature_flags(analytics: true) enable_only_one_analytics_feature_flag
end end
it 'includes analytics' do it 'includes analytics' do
...@@ -21,9 +23,9 @@ describe DashboardHelper, type: :helper do ...@@ -21,9 +23,9 @@ describe DashboardHelper, type: :helper do
end end
end end
context 'when analytics is disabled' do context 'when all analytics features are disabled' do
before do before do
stub_feature_flags(analytics: false) disable_all_analytics_feature_flags
end end
it 'does not include analytics' do it 'does not include analytics' do
......
...@@ -6,25 +6,7 @@ describe 'Analytics' do ...@@ -6,25 +6,7 @@ describe 'Analytics' do
include RSpec::Rails::RequestExampleGroup include RSpec::Rails::RequestExampleGroup
include Warden::Test::Helpers 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 it 'redirects to sign_in if user is not authenticated' do
expect(get('/-/analytics')).to redirect_to('/users/sign_in') expect(get('/-/analytics')).to redirect_to('/users/sign_in')
end end
it 'returns 404 if user is authenticated' do
login_as(user)
expect(get('/-/analytics')).to eq(404)
end
end
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 @@ ...@@ -3,29 +3,50 @@
require 'spec_helper' require 'spec_helper'
describe 'layouts/nav/sidebar/_analytics' do describe 'layouts/nav/sidebar/_analytics' do
include AnalyticsHelpers
it_behaves_like 'has nav sidebar' it_behaves_like 'has nav sidebar'
context 'top-level items' do context 'top-level items' do
before do context 'when feature flags are enabled' do
it 'has `Analytics` link' do
stub_feature_flags(Gitlab::Analytics::PRODUCTIVITY_ANALYTICS_FEATURE_FLAG => true)
render render
end
it 'has `Analytics` link' do
expect(rendered).to have_content('Analytics') expect(rendered).to have_content('Analytics')
expect(rendered).to include(analytics_root_path) expect(rendered).to include(analytics_root_path)
expect(rendered).to match(/<use xlink:href=".+?icons-.+?#log">/) expect(rendered).to match(/<use xlink:href=".+?icons-.+?#log">/)
end end
it 'has `Productivity Analytics` link' do it 'has `Productivity Analytics` link' do
stub_feature_flags(Gitlab::Analytics::PRODUCTIVITY_ANALYTICS_FEATURE_FLAG => true)
render
expect(rendered).to have_content('Productivity Analytics') expect(rendered).to have_content('Productivity Analytics')
expect(rendered).to include(analytics_productivity_analytics_path) expect(rendered).to include(analytics_productivity_analytics_path)
expect(rendered).to match(/<use xlink:href=".+?icons-.+?#comment">/) expect(rendered).to match(/<use xlink:href=".+?icons-.+?#comment">/)
end end
it 'has `Cycle Analytics` link' do 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 have_content('Cycle Analytics')
expect(rendered).to include(analytics_cycle_analytics_path) expect(rendered).to include(analytics_cycle_analytics_path)
expect(rendered).to match(/<use xlink:href=".+?icons-.+?#repeat">/) expect(rendered).to match(/<use xlink:href=".+?icons-.+?#repeat">/)
end end
end end
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 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