Commit 74d5422a authored by Sean McGivern's avatar Sean McGivern

Merge branch '3731-eeu-license' into 'master'

Add epics to EEU license

Closes #3731

See merge request gitlab-org/gitlab-ee!3387
parents 88fd9dcc bbd441bd
- issues = IssuesFinder.new(current_user, group_id: @group.id, state: 'opened').execute - issues = IssuesFinder.new(current_user, group_id: @group.id, state: 'opened').execute
- merge_requests = MergeRequestsFinder.new(current_user, group_id: @group.id, state: 'opened', non_archived: true).execute - merge_requests = MergeRequestsFinder.new(current_user, group_id: @group.id, state: 'opened', non_archived: true).execute
- epics = EpicsFinder.new(current_user, group_id: @group.id).execute
- epics_items = ['epics#show', 'epics#index']
- issues_sub_menu_items = ['groups#issues', 'labels#index', 'milestones#index'] - issues_sub_menu_items = ['groups#issues', 'labels#index', 'milestones#index']
- if @group.feature_available?(:group_issue_boards) - if @group.feature_available?(:group_issue_boards)
- issues_sub_menu_items.push('boards#index', 'boards#show') - issues_sub_menu_items.push('boards#index', 'boards#show')
...@@ -45,20 +43,8 @@ ...@@ -45,20 +43,8 @@
%span %span
Contribution Analytics Contribution Analytics
-# TODO: Add the flag check to only show epics if available
= nav_link(path: epics_items) do = render "layouts/nav/ee/epic_link", group: @group
= link_to group_epics_path(@group) do
.nav-icon-container
= sprite_icon('epic')
%span.nav-item-name
Epics
%span.badge.count= number_with_delimiter(epics.count)
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(path: epics_items, html_options: { class: "fly-out-top-item" } ) do
= link_to group_epics_path(@group) do
%strong.fly-out-top-item-name
#{ _('Epics') }
%span.badge.count.epic_counter.fly-out-badge= number_with_delimiter(epics.count)
= nav_link(path: issues_sub_menu_items) do = nav_link(path: issues_sub_menu_items) do
= link_to issues_group_path(@group) do = link_to issues_group_path(@group) do
......
---
title: Introduce EEU lincese with epics as the first feature
merge_request:
author:
type: added
class Groups::EpicIssuesController < Groups::EpicsController class Groups::EpicIssuesController < Groups::EpicsController
include IssuableLinks include IssuableLinks
before_action :check_epics_available!
skip_before_action :authorize_destroy_issuable! skip_before_action :authorize_destroy_issuable!
before_action :authorize_admin_epic!, only: [:create, :destroy] before_action :authorize_admin_epic!, only: [:create, :destroy]
before_action :authorize_issue_link_association!, only: :destroy before_action :authorize_issue_link_association!, only: :destroy
......
...@@ -2,6 +2,7 @@ class Groups::EpicsController < Groups::ApplicationController ...@@ -2,6 +2,7 @@ class Groups::EpicsController < Groups::ApplicationController
include IssuableActions include IssuableActions
include IssuableCollections include IssuableCollections
before_action :check_epics_available!
before_action :epic, except: :index before_action :epic, except: :index
before_action :set_issuables_index, only: :index before_action :set_issuables_index, only: :index
before_action :authorize_update_issuable!, only: :update before_action :authorize_update_issuable!, only: :update
......
...@@ -52,7 +52,9 @@ class License < ActiveRecord::Base ...@@ -52,7 +52,9 @@ class License < ActiveRecord::Base
commit_committer_check commit_committer_check
].freeze ].freeze
EEU_FEATURES = EEP_FEATURES EEU_FEATURES = EEP_FEATURES + %i[
epics
]
# List all features available for early adopters, # List all features available for early adopters,
# i.e. users that started using GitLab.com before # i.e. users that started using GitLab.com before
......
...@@ -5,6 +5,7 @@ module EE ...@@ -5,6 +5,7 @@ module EE
prepended do prepended do
with_scope :subject with_scope :subject
condition(:ldap_synced) { @subject.ldap_synced? } condition(:ldap_synced) { @subject.ldap_synced? }
condition(:epics_disabled) { !@subject.feature_available?(:epics) }
rule { reporter }.policy do rule { reporter }.policy do
enable :admin_list enable :admin_list
...@@ -46,6 +47,14 @@ module EE ...@@ -46,6 +47,14 @@ module EE
rule { ldap_synced & (admin | owner) }.enable :update_group_member rule { ldap_synced & (admin | owner) }.enable :update_group_member
rule { ldap_synced & (admin | (can_owners_manage_ldap & owner)) }.enable :override_group_member rule { ldap_synced & (admin | (can_owners_manage_ldap & owner)) }.enable :override_group_member
rule { epics_disabled }.policy do
prevent :read_epic
prevent :create_epic
prevent :admin_epic
prevent :update_epic
prevent :destroy_epic
end
end end
end end
end end
...@@ -3,6 +3,8 @@ module EpicIssues ...@@ -3,6 +3,8 @@ module EpicIssues
private private
def issues def issues
return [] unless issuable&.group&.feature_available?(:epics)
issuable.issues(current_user) issuable.issues(current_user)
end end
......
- return unless group.feature_available?(:epics)
- epics = EpicsFinder.new(current_user, group_id: @group.id).execute
- epics_items = ['epics#show', 'epics#index']
= nav_link(path: epics_items) do
= link_to group_epics_path(group) do
.nav-icon-container
= sprite_icon('epic')
%span.nav-item-name
Epics
%span.badge.count= number_with_delimiter(epics.count)
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(path: epics_items, html_options: { class: "fly-out-top-item" } ) do
= link_to group_epics_path(group) do
%strong.fly-out-top-item-name
#{ _('Epics') }
%span.badge.count.epic_counter.fly-out-badge= number_with_delimiter(epics.count)
...@@ -11,6 +11,11 @@ describe Groups::EpicIssuesController do ...@@ -11,6 +11,11 @@ describe Groups::EpicIssuesController do
sign_in(user) sign_in(user)
end end
context 'when epics feature is enabled' do
before do
stub_licensed_features(epics: true)
end
describe 'GET #index' do describe 'GET #index' do
let!(:epic_issues) { create(:epic_issue, epic: epic, issue: issue) } let!(:epic_issues) { create(:epic_issue, epic: epic, issue: issue) }
...@@ -142,4 +147,5 @@ describe Groups::EpicIssuesController do ...@@ -142,4 +147,5 @@ describe Groups::EpicIssuesController do
end end
end end
end end
end
end end
...@@ -9,6 +9,39 @@ describe Groups::EpicsController do ...@@ -9,6 +9,39 @@ describe Groups::EpicsController do
sign_in(user) sign_in(user)
end end
context 'when epics feature is disabled' do
shared_examples '404 status' do
it 'returns 404 status' do
subject
expect(response).to have_gitlab_http_status(404)
end
end
describe 'GET #index' do
subject { get :index, group_id: group }
it_behaves_like '404 status'
end
describe 'GET #show' do
subject { get :show, group_id: group, id: epic.to_param }
it_behaves_like '404 status'
end
describe 'PUT #update' do
subject { put :update, group_id: group, id: epic.to_param }
it_behaves_like '404 status'
end
end
context 'when epics feature is enabled' do
before do
stub_licensed_features(epics: true)
end
describe "GET #index" do describe "GET #index" do
let!(:epic_list) { create_list(:epic, 2, group: group) } let!(:epic_list) { create_list(:epic, 2, group: group) }
...@@ -143,4 +176,5 @@ describe Groups::EpicsController do ...@@ -143,4 +176,5 @@ describe Groups::EpicsController do
expect(controller).to set_flash[:notice].to(/The epic was successfully deleted\./) expect(controller).to set_flash[:notice].to(/The epic was successfully deleted\./)
end end
end end
end
end end
...@@ -7,6 +7,8 @@ feature 'Delete Epic', :js do ...@@ -7,6 +7,8 @@ feature 'Delete Epic', :js do
let!(:epic2) { create(:epic, group: group) } let!(:epic2) { create(:epic, group: group) }
before do before do
stub_licensed_features(epics: true)
sign_in(user) sign_in(user)
end end
......
...@@ -17,6 +17,8 @@ describe 'Epic Issues', :js do ...@@ -17,6 +17,8 @@ describe 'Epic Issues', :js do
end end
def visit_epic def visit_epic
stub_licensed_features(epics: true)
sign_in(user) sign_in(user)
visit group_epic_path(group, epic) visit group_epic_path(group, epic)
wait_for_requests wait_for_requests
......
...@@ -5,6 +5,8 @@ describe 'epics list', :js do ...@@ -5,6 +5,8 @@ describe 'epics list', :js do
let(:user) { create(:user) } let(:user) { create(:user) }
before do before do
stub_licensed_features(epics: true)
sign_in(user) sign_in(user)
end end
......
...@@ -6,6 +6,8 @@ feature 'Update Epic', :js do ...@@ -6,6 +6,8 @@ feature 'Update Epic', :js do
let(:epic) { create(:epic, group: group) } let(:epic) { create(:epic, group: group) }
before do before do
stub_licensed_features(epics: true)
sign_in(user) sign_in(user)
end end
......
...@@ -17,6 +17,21 @@ describe EpicsFinder do ...@@ -17,6 +17,21 @@ describe EpicsFinder do
described_class.new(search_user, params).execute described_class.new(search_user, params).execute
end end
context 'when epics feature is disabled' do
before do
group.add_developer(search_user)
end
it 'raises an exception' do
expect { described_class.new(search_user).execute }.to raise_error { ArgumentError }
end
end
context 'when epics feature is enabled' do
before do
stub_licensed_features(epics: true)
end
context 'without param' do context 'without param' do
it 'raises an error when group_id param is missing' do it 'raises an error when group_id param is missing' do
expect { described_class.new(search_user).execute }.to raise_error { ArgumentError } expect { described_class.new(search_user).execute }.to raise_error { ArgumentError }
...@@ -71,4 +86,5 @@ describe EpicsFinder do ...@@ -71,4 +86,5 @@ describe EpicsFinder do
end end
end end
end end
end
end end
...@@ -9,6 +9,22 @@ describe EpicPolicy do ...@@ -9,6 +9,22 @@ describe EpicPolicy do
described_class.new(user, epic) described_class.new(user, epic)
end end
context 'when epics feature is disabled' do
let(:group) { create(:group, :public) }
it 'no one can read epics' do
group.add_owner(user)
expect(permissions(user, group))
.to be_disallowed(:read_epic, :update_epic, :destroy_epic, :admin_epic, :create_epic)
end
end
context 'when epics feature is enabled' do
before do
stub_licensed_features(epics: true)
end
context 'when an epic is in a private group' do context 'when an epic is in a private group' do
let(:group) { create(:group, :private) } let(:group) { create(:group, :private) }
...@@ -116,4 +132,5 @@ describe EpicPolicy do ...@@ -116,4 +132,5 @@ describe EpicPolicy do
.to be_allowed(:read_epic, :update_epic, :destroy_epic, :admin_epic, :create_epic) .to be_allowed(:read_epic, :update_epic, :destroy_epic, :admin_epic, :create_epic)
end end
end end
end
end end
...@@ -20,6 +20,22 @@ describe GroupPolicy do ...@@ -20,6 +20,22 @@ describe GroupPolicy do
subject { described_class.new(current_user, group) } subject { described_class.new(current_user, group) }
context 'when epics feature is disabled' do
let(:current_user) { owner }
it { is_expected.to be_disallowed(:read_epic, :create_epic, :admin_epic, :destroy_epic) }
end
context 'when epics feature is enabled' do
before do
stub_licensed_features(epics: true)
end
let(:current_user) { owner }
it { is_expected.to be_allowed(:read_epic, :create_epic, :admin_epic, :destroy_epic) }
end
context 'when LDAP sync is not enabled' do context 'when LDAP sync is not enabled' do
context 'owner' do context 'owner' do
let(:current_user) { owner } let(:current_user) { owner }
......
...@@ -37,6 +37,17 @@ describe EpicIssues::CreateService do ...@@ -37,6 +37,17 @@ describe EpicIssues::CreateService do
end end
end end
context 'when epics feature is disabled' do
subject { assign_issue([valid_reference]) }
include_examples 'returns an error'
end
context 'when epics feature is enabled' do
before do
stub_licensed_features(epics: true)
end
context 'when user has permissions to link the issue' do context 'when user has permissions to link the issue' do
before do before do
group.add_developer(user) group.add_developer(user)
...@@ -131,4 +142,5 @@ describe EpicIssues::CreateService do ...@@ -131,4 +142,5 @@ describe EpicIssues::CreateService do
include_examples 'returns an error' include_examples 'returns an error'
end end
end end
end
end end
...@@ -11,6 +11,21 @@ describe EpicIssues::DestroyService do ...@@ -11,6 +11,21 @@ describe EpicIssues::DestroyService do
subject { described_class.new(epic_issue, user).execute } subject { described_class.new(epic_issue, user).execute }
context 'when epics feature is disabled' do
before do
group.add_reporter(user)
end
it 'returns an error' do
is_expected.to eq(message: 'No Issue Link found', status: :error, http_status: 404)
end
end
context 'when epics feature is enabled' do
before do
stub_licensed_features(epics: true)
end
context 'when user has permissions to remove associations' do context 'when user has permissions to remove associations' do
before do before do
group.add_reporter(user) group.add_reporter(user)
...@@ -35,4 +50,5 @@ describe EpicIssues::DestroyService do ...@@ -35,4 +50,5 @@ describe EpicIssues::DestroyService do
end end
end end
end end
end
end end
...@@ -18,7 +18,20 @@ describe EpicIssues::ListService do ...@@ -18,7 +18,20 @@ describe EpicIssues::ListService do
describe '#execute' do describe '#execute' do
subject { described_class.new(epic, user).execute } subject { described_class.new(epic, user).execute }
context 'user can see all issues and destroy their associations' do context 'when epics feature is disabled' do
it 'returns an empty array' do
group.add_developer(user)
expect(subject).to be_empty
end
end
context 'when epics feature is enabled' do
before do
stub_licensed_features(epics: true)
end
context 'owner can see all issues and destroy their associations' do
before do before do
group.add_developer(user) group.add_developer(user)
end end
...@@ -50,7 +63,6 @@ describe EpicIssues::ListService do ...@@ -50,7 +63,6 @@ describe EpicIssues::ListService do
destroy_relation_path: "/groups/#{group.full_path}/-/epics/#{epic.iid}/issues/#{epic_issue3.id}" destroy_relation_path: "/groups/#{group.full_path}/-/epics/#{epic.iid}/issues/#{epic_issue3.id}"
} }
] ]
expect(subject).to match_array(expected_result) expect(subject).to match_array(expected_result)
end end
end end
...@@ -84,4 +96,5 @@ describe EpicIssues::ListService do ...@@ -84,4 +96,5 @@ describe EpicIssues::ListService do
end end
end end
end end
end
end end
...@@ -10,7 +10,7 @@ describe GroupPolicy do ...@@ -10,7 +10,7 @@ describe GroupPolicy do
let(:admin) { create(:admin) } let(:admin) { create(:admin) }
let(:group) { create(:group) } let(:group) { create(:group) }
let(:reporter_permissions) { [:admin_label, :create_epic, :admin_epic] } let(:reporter_permissions) { [:admin_label] }
let(:developer_permissions) { [:admin_milestones] } let(:developer_permissions) { [:admin_milestones] }
...@@ -26,7 +26,6 @@ describe GroupPolicy do ...@@ -26,7 +26,6 @@ describe GroupPolicy do
:admin_namespace, :admin_namespace,
:admin_group_member, :admin_group_member,
:change_visibility_level, :change_visibility_level,
:destroy_epic,
(Gitlab::Database.postgresql? ? :create_subgroup : nil) (Gitlab::Database.postgresql? ? :create_subgroup : nil)
].compact ].compact
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