Commit d17bab44 authored by Mark Chao's avatar Mark Chao

Merge branch 'nfriend-add-group-level-ci-cd-analytics-page' into 'master'

Add new group-level CI/CD Analytics page

See merge request gitlab-org/gitlab!49608
parents 4c149a05 dbdfa17c
---
name: group_ci_cd_analytics_page
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/49608
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/292601
milestone: '13.8'
type: development
group: group::release
default_enabled: false
<script>
export default {
name: 'CiCdAnalyticsApp',
};
</script>
<template>
<div>
<!-- eslint-disable @gitlab/vue-require-i18n-strings -->
<h1 class="gl-font-size-h2">This page is a placeholder</h1>
<p>
If you're seeing this page, it's because you've enabled the
<code>group_ci_cd_analytics_page</code> feature flag.
</p>
<!-- eslint-enable @gitlab/vue-require-i18n-strings -->
</div>
</template>
import Vue from 'vue';
import CiCdAnalyticsApp from './components/app.vue';
export default () => {
const el = document.querySelector('#js-group-ci-cd-analytics-app');
if (!el) return false;
return new Vue({
el,
render: createElement => createElement(CiCdAnalyticsApp),
});
};
import initGroupCiCdAnalyticsApp from 'ee/analytics/group_ci_cd_analytics';
initGroupCiCdAnalyticsApp();
# frozen_string_literal: true
class Groups::Analytics::CiCdAnalyticsController < Groups::Analytics::ApplicationController
layout 'group'
before_action :load_group
before_action -> { check_feature_availability!(:group_ci_cd_analytics) }
before_action -> { authorize_view_by_action!(:view_group_ci_cd_analytics) }
def show
render_404 unless Feature.enabled?(:group_ci_cd_analytics_page, @group)
end
end
......@@ -18,6 +18,7 @@ module EE
override :group_analytics_navbar_links
def group_analytics_navbar_links(group, current_user)
super + [
group_ci_cd_analytics_navbar_link(group, current_user),
group_repository_analytics_navbar_link(group, current_user),
contribution_analytics_navbar_link(group, current_user),
group_insights_navbar_link(group, current_user),
......@@ -115,6 +116,17 @@ module EE
)
end
def group_ci_cd_analytics_navbar_link(group, current_user)
return unless group.feature_available?(:group_ci_cd_analytics)
return unless group_sidebar_link?(:group_ci_cd_analytics)
navbar_sub_item(
title: _('CI / CD'),
path: 'groups/analytics/ci_cd_analytics#show',
link: group_analytics_ci_cd_analytics_path(group)
)
end
def group_repository_analytics_navbar_link(group, current_user)
return unless group.feature_available?(:group_coverage_reports)
return unless group_sidebar_link?(:repository_analytics)
......
......@@ -147,6 +147,10 @@ module EE
links << :iterations
end
if ::Feature.enabled?(:group_ci_cd_analytics_page, @group) && @group.feature_available?(:group_ci_cd_analytics) && can?(current_user, :view_group_ci_cd_analytics, @group)
links << :group_ci_cd_analytics
end
links
end
end
......
......@@ -145,6 +145,7 @@ class License < ApplicationRecord
enforce_pat_expiration
enterprise_templates
environment_alerts
group_ci_cd_analytics
group_level_compliance_dashboard
incident_management
insights
......
......@@ -21,6 +21,10 @@ module EE
@subject.feature_available?(:cycle_analytics_for_groups)
end
condition(:group_ci_cd_analytics_available) do
@subject.feature_available?(:group_ci_cd_analytics)
end
condition(:group_merge_request_analytics_available) do
@subject.feature_available?(:group_merge_request_analytics)
end
......@@ -161,6 +165,10 @@ module EE
enable :read_group_cycle_analytics, :create_group_stage, :read_group_stage, :update_group_stage, :delete_group_stage
end
rule { reporter & group_ci_cd_analytics_available }.policy do
enable :view_group_ci_cd_analytics
end
rule { owner & ~has_parent & prevent_group_forking_available }.policy do
enable :change_prevent_group_forking
end
......
- page_title _("CI / CD Analytics")
#js-group-ci-cd-analytics-app
......@@ -15,6 +15,7 @@ constraints(::Constraints::GroupUrlConstrainer.new) do
resource :contribution_analytics, only: [:show]
namespace :analytics do
resource :ci_cd_analytics, only: :show, path: 'ci_cd'
resource :productivity_analytics, only: :show
resources :coverage_reports, only: :index
resource :merge_request_analytics, only: :show
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Groups::Analytics::CiCdAnalyticsController do
let_it_be(:non_member) { create(:user) }
let_it_be(:guest) { create(:user) }
let_it_be(:reporter) { create(:user) }
let_it_be(:group) { create(:group) }
let(:current_user) { reporter }
before_all do
group.add_guest(guest)
group.add_reporter(reporter)
end
before do
stub_licensed_features(group_ci_cd_analytics: true)
stub_feature_flags(group_ci_cd_analytics_page: true)
sign_in(current_user) if current_user
end
def make_request
get :show, params: { group_id: group.to_param }
end
shared_examples 'returns a 403' do
it do
make_request
expect(response).to have_gitlab_http_status(:forbidden)
end
end
describe 'GET #show' do
it 'renders the #show page' do
make_request
expect(response).to render_template :show
end
context "when the current user doesn't have access" do
context 'when the user is a guest' do
let(:current_user) { guest }
it_behaves_like 'returns a 403'
end
context "when the user doesn't belong to the group" do
let(:current_user) { non_member }
it_behaves_like 'returns a 403'
end
context "when the user is not signed in" do
let(:current_user) { nil }
it 'redirects the user to the login page' do
make_request
expect(response).to redirect_to(new_user_session_path)
end
end
end
context "when the :group_ci_cd_analytics feature isn't licensed" do
before do
stub_licensed_features(group_ci_cd_analytics: false)
end
it_behaves_like 'returns a 403'
end
context "when the :group_ci_cd_analytics_page feature flag is disabled" do
before do
stub_feature_flags(group_ci_cd_analytics_page: false)
end
it 'returns a 404' do
make_request
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
end
import { shallowMount } from '@vue/test-utils';
import CiCdAnalyticsApp from 'ee/analytics/group_ci_cd_analytics/components/app.vue';
describe('ee/analytics/group_ci_cd_analytics/components/app.vue', () => {
let wrapper;
const createComponent = () => {
wrapper = shallowMount(CiCdAnalyticsApp);
};
it('renders without errors', () => {
createComponent();
expect(wrapper).toBeTruthy();
});
});
......@@ -57,16 +57,18 @@ RSpec.describe GroupsHelper do
it 'shows the licensed features when they are available' do
stub_licensed_features(contribution_analytics: true,
group_ci_cd_analytics: true,
epics: true)
expect(helper.group_sidebar_links).to include(:contribution_analytics, :epics)
expect(helper.group_sidebar_links).to include(:contribution_analytics, :group_ci_cd_analytics, :epics)
end
it 'hides the licensed features when they are not available' do
stub_licensed_features(contribution_analytics: false,
group_ci_cd_analytics: false,
epics: false)
expect(helper.group_sidebar_links).not_to include(:contribution_analytics, :epics)
expect(helper.group_sidebar_links).not_to include(:contribution_analytics, :group_ci_cd_analytics, :epics)
end
context 'when contribution analytics is available' do
......@@ -83,6 +85,28 @@ RSpec.describe GroupsHelper do
end
end
end
context 'when the group_ci_cd_analytics_page feature flag is disabled' do
before do
stub_feature_flags(group_ci_cd_analytics_page: false)
end
it 'hides CI / CD Analytics' do
expect(helper.group_sidebar_links).not_to include(:group_ci_cd_analytics)
end
end
context 'when the user does not have permissions to view the CI / CD Analytics page' do
let(:current_user) { create(:user) }
before do
group.add_guest(current_user)
end
it 'hides CI / CD Analytics' do
expect(helper.group_sidebar_links).not_to include(:group_ci_cd_analytics)
end
end
end
describe '#permanent_deletion_date' do
......
......@@ -200,6 +200,36 @@ RSpec.describe GroupPolicy do
it { is_expected.not_to be_allowed(:read_group_activity_analytics) }
end
context 'group CI / CD analytics' do
context 'when group CI / CD analytics is available' do
before do
stub_licensed_features(group_ci_cd_analytics: true)
end
context 'when the user has at least reporter permissions' do
let(:current_user) { reporter }
it { is_expected.to be_allowed(:view_group_ci_cd_analytics) }
end
context 'when the user has less than reporter permissions' do
let(:current_user) { guest }
it { is_expected.not_to be_allowed(:view_group_ci_cd_analytics) }
end
end
context 'when group CI / CD analytics is not available' do
let(:current_user) { reporter }
before do
stub_licensed_features(group_ci_cd_analytics: false)
end
it { is_expected.not_to be_allowed(:view_group_ci_cd_analytics) }
end
end
context 'when group repository analytics is available' do
before do
stub_licensed_features(group_repository_analytics: true)
......
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