Commit 3fc64000 authored by Phil Hughes's avatar Phil Hughes

Merge branch '9908-hide-approver-ui-in-free' into 'master'

Fix Approval UI showing up for free plan

Closes #9908

See merge request gitlab-org/gitlab-ee!9819
parents 72be917b 1ca1c452
...@@ -112,7 +112,7 @@ export default { ...@@ -112,7 +112,7 @@ export default {
return enableSquashBeforeMerge && commitsCount > 1; return enableSquashBeforeMerge && commitsCount > 1;
}, },
isApprovalNeeded() { isApprovalNeeded() {
return this.mr.approvalsRequired ? !this.mr.isApproved : false; return this.mr.hasApprovalsAvailable ? !this.mr.isApproved : false;
}, },
shouldShowMergeControls() { shouldShowMergeControls() {
return this.mr.isMergeAllowed || this.shouldShowMergeWhenPipelineSucceedsText; return this.mr.isMergeAllowed || this.shouldShowMergeWhenPipelineSucceedsText;
......
...@@ -59,7 +59,10 @@ export default { ...@@ -59,7 +59,10 @@ export default {
</script> </script>
<template> <template>
<mr-widget-container> <mr-widget-container>
<div v-if="mr.approvalsRequired" class="media media-section js-mr-approvals align-items-center"> <div
v-if="mr.hasApprovalsAvailable"
class="media media-section js-mr-approvals align-items-center"
>
<mr-widget-icon name="approval" /> <mr-widget-icon name="approval" />
<div v-show="fetchingApprovals" class="mr-approvals-loading-state media-body"> <div v-show="fetchingApprovals" class="mr-approvals-loading-state media-body">
<span class="approvals-loading-text"> {{ $options.FETCH_LOADING }} </span> <span class="approvals-loading-text"> {{ $options.FETCH_LOADING }} </span>
......
...@@ -32,7 +32,7 @@ export default { ...@@ -32,7 +32,7 @@ export default {
}, },
computed: { computed: {
shouldRenderApprovals() { shouldRenderApprovals() {
return this.mr.approvalsRequired && this.mr.state !== 'nothingToMerge'; return this.mr.hasApprovalsAvailable && this.mr.state !== 'nothingToMerge';
}, },
shouldRenderCodeQuality() { shouldRenderCodeQuality() {
const { codeclimate } = this.mr; const { codeclimate } = this.mr;
......
...@@ -44,8 +44,10 @@ export default class MergeRequestStore extends CEMergeRequestStore { ...@@ -44,8 +44,10 @@ export default class MergeRequestStore extends CEMergeRequestStore {
this.isApproved = this.isApproved || false; this.isApproved = this.isApproved || false;
this.approvals = this.approvals || null; this.approvals = this.approvals || null;
this.approvalRules = this.approvalRules || []; this.approvalRules = this.approvalRules || [];
this.hasApprovalsAvailable = Boolean(
data.has_approvals_available || this.hasApprovalsAvailable,
);
this.approvalsPath = data.approvals_path || this.approvalsPath; this.approvalsPath = data.approvals_path || this.approvalsPath;
this.approvalsRequired = data.approvalsRequired || Boolean(this.approvalsPath);
this.apiApprovalsPath = data.api_approvals_path || this.apiApprovalsPath; this.apiApprovalsPath = data.api_approvals_path || this.apiApprovalsPath;
this.apiApprovalSettingsPath = data.api_approval_settings_path || this.apiApprovalSettingsPath; this.apiApprovalSettingsPath = data.api_approval_settings_path || this.apiApprovalSettingsPath;
this.apiApprovePath = data.api_approve_path || this.apiApprovePath; this.apiApprovePath = data.api_approve_path || this.apiApprovePath;
...@@ -60,7 +62,7 @@ export default class MergeRequestStore extends CEMergeRequestStore { ...@@ -60,7 +62,7 @@ export default class MergeRequestStore extends CEMergeRequestStore {
this.preventMerge = !this.isApproved; this.preventMerge = !this.isApproved;
} else { } else {
this.isApproved = !this.approvalsLeft || false; this.isApproved = !this.approvalsLeft || false;
this.preventMerge = this.approvalsRequired && this.approvalsLeft; this.preventMerge = this.hasApprovalsAvailable && this.approvalsLeft;
} }
} }
......
...@@ -10,7 +10,7 @@ class ApprovalState ...@@ -10,7 +10,7 @@ class ApprovalState
attr_reader :merge_request, :project attr_reader :merge_request, :project
def_delegators :@merge_request, :merge_status, :approved_by_users, :approvals def_delegators :@merge_request, :merge_status, :approved_by_users, :approvals, :approval_feature_available?
alias_method :approved_approvers, :approved_by_users alias_method :approved_approvers, :approved_by_users
def initialize(merge_request) def initialize(merge_request)
...@@ -31,6 +31,8 @@ class ApprovalState ...@@ -31,6 +31,8 @@ class ApprovalState
def wrapped_approval_rules def wrapped_approval_rules
strong_memoize(:wrapped_approval_rules) do strong_memoize(:wrapped_approval_rules) do
next [] unless approval_feature_available?
result = use_fallback? ? [fallback_rule] : regular_rules result = use_fallback? ? [fallback_rule] : regular_rules
result += code_owner_rules result += code_owner_rules
result result
......
...@@ -7,6 +7,16 @@ module Approvable ...@@ -7,6 +7,16 @@ module Approvable
# such as approver_groups and target_project in presenters # such as approver_groups and target_project in presenters
include ::VisibleApprovable include ::VisibleApprovable
def approval_feature_available?
strong_memoize(:approval_feature_available) do
if project
project.feature_available?(:merge_request_approvers)
else
false
end
end
end
def approval_state def approval_state
@approval_state ||= ApprovalState.new(self) @approval_state ||= ApprovalState.new(self)
end end
...@@ -40,7 +50,7 @@ module Approvable ...@@ -40,7 +50,7 @@ module Approvable
end end
def approvals_before_merge def approvals_before_merge
return nil unless project&.feature_available?(:merge_request_approvers) return nil unless approval_feature_available?
super super
end end
......
...@@ -5,11 +5,6 @@ ...@@ -5,11 +5,6 @@
module VisibleApprovable module VisibleApprovable
include ::Gitlab::Utils::StrongMemoize include ::Gitlab::Utils::StrongMemoize
def requires_approve?
# keep until UI changes implemented
true
end
# Users in the list of approvers who have not already approved this MR. # Users in the list of approvers who have not already approved this MR.
# #
def approvers_left def approvers_left
......
...@@ -6,31 +6,31 @@ module EE ...@@ -6,31 +6,31 @@ module EE
prepend VisibleApprovableForRule prepend VisibleApprovableForRule
def approvals_path def approvals_path
if requires_approve? if approval_feature_available?
approvals_project_merge_request_path(project, merge_request) approvals_project_merge_request_path(project, merge_request)
end end
end end
def api_approvals_path def api_approvals_path
if requires_approve? if approval_feature_available?
api_v4_projects_merge_requests_approvals_path(id: project.id, merge_request_iid: merge_request.iid) api_v4_projects_merge_requests_approvals_path(id: project.id, merge_request_iid: merge_request.iid)
end end
end end
def api_approval_settings_path def api_approval_settings_path
if requires_approve? if approval_feature_available?
api_v4_projects_merge_requests_approval_settings_path(id: project.id, merge_request_iid: merge_request.iid) api_v4_projects_merge_requests_approval_settings_path(id: project.id, merge_request_iid: merge_request.iid)
end end
end end
def api_approve_path def api_approve_path
if requires_approve? if approval_feature_available?
api_v4_projects_merge_requests_approve_path(id: project.id, merge_request_iid: merge_request.iid) api_v4_projects_merge_requests_approve_path(id: project.id, merge_request_iid: merge_request.iid)
end end
end end
def api_unapprove_path def api_unapprove_path
if requires_approve? if approval_feature_available?
api_v4_projects_merge_requests_unapprove_path(id: project.id, merge_request_iid: merge_request.iid) api_v4_projects_merge_requests_unapprove_path(id: project.id, merge_request_iid: merge_request.iid)
end end
end end
......
...@@ -122,6 +122,9 @@ module EE ...@@ -122,6 +122,9 @@ module EE
expose :can_push_to_source_branch do |merge_request| expose :can_push_to_source_branch do |merge_request|
presenter(merge_request).can_push_to_source_branch? presenter(merge_request).can_push_to_source_branch?
end end
expose :has_approvals_available do |merge_request|
merge_request.approval_feature_available?
end
expose :rebase_path do |merge_request| expose :rebase_path do |merge_request|
presenter(merge_request).rebase_path presenter(merge_request).rebase_path
end end
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
- form = local_assigns.fetch(:form) - form = local_assigns.fetch(:form)
- return unless issuable.is_a?(MergeRequest) - return unless issuable.is_a?(MergeRequest)
- return unless presenter.requires_approve? - return unless issuable.approval_feature_available?
- can_update_approvers = can?(current_user, :update_approvers, issuable) - can_update_approvers = can?(current_user, :update_approvers, issuable)
......
---
title: Fix approval-related UI showing up in free plan
merge_request: 9819
author:
type: fixed
...@@ -389,6 +389,10 @@ module EE ...@@ -389,6 +389,10 @@ module EE
approval_state.has_non_fallback_rules? approval_state.has_non_fallback_rules?
end end
expose :merge_request_approvers_available do |approval_state|
approval_state.project.feature_available?(:merge_request_approvers)
end
expose :multiple_approval_rules_available do |approval_state| expose :multiple_approval_rules_available do |approval_state|
approval_state.project.multiple_approval_rules_available? approval_state.project.multiple_approval_rules_available?
end end
......
...@@ -720,7 +720,7 @@ describe('ee merge request widget options', () => { ...@@ -720,7 +720,7 @@ describe('ee merge request widget options', () => {
vm = mountComponent(Component, { vm = mountComponent(Component, {
mrData: { mrData: {
...mockData, ...mockData,
approvalsRequired: false, has_approvals_available: false,
}, },
}); });
vm.mr.state = 'readyToMerge'; vm.mr.state = 'readyToMerge';
...@@ -732,7 +732,7 @@ describe('ee merge request widget options', () => { ...@@ -732,7 +732,7 @@ describe('ee merge request widget options', () => {
vm = mountComponent(Component, { vm = mountComponent(Component, {
mrData: { mrData: {
...mockData, ...mockData,
approvalsRequired: true, has_approvals_available: true,
}, },
}); });
vm.mr.state = 'nothingToMerge'; vm.mr.state = 'nothingToMerge';
...@@ -744,7 +744,7 @@ describe('ee merge request widget options', () => { ...@@ -744,7 +744,7 @@ describe('ee merge request widget options', () => {
vm = mountComponent(Component, { vm = mountComponent(Component, {
mrData: { mrData: {
...mockData, ...mockData,
approvalsRequired: true, has_approvals_available: true,
}, },
}); });
vm.mr.state = 'readyToMerge'; vm.mr.state = 'readyToMerge';
......
...@@ -9,6 +9,24 @@ describe Approvable do ...@@ -9,6 +9,24 @@ describe Approvable do
stub_feature_flags(approval_rules: false) stub_feature_flags(approval_rules: false)
end end
describe '#approval_feature_available?' do
let(:project) { create(:project) }
let(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
subject { merge_request.approval_feature_available? }
it 'is false when feature is disabled' do
allow(project).to receive(:feature_available?).with(:merge_request_approvers).and_return(false)
is_expected.to be false
end
it 'is true when feature is enabled' do
allow(project).to receive(:feature_available?).with(:merge_request_approvers).and_return(true)
is_expected.to be true
end
end
describe '#approvers_overwritten?' do describe '#approvers_overwritten?' do
subject { merge_request.approvers_overwritten? } subject { merge_request.approvers_overwritten? }
......
...@@ -17,6 +17,10 @@ describe ApprovalState do ...@@ -17,6 +17,10 @@ describe ApprovalState do
end end
end end
def disable_feature
allow(subject).to receive(:approval_feature_available?).and_return(false)
end
let(:merge_request) { create(:merge_request) } let(:merge_request) { create(:merge_request) }
let(:project) { merge_request.target_project } let(:project) { merge_request.target_project }
let(:approver1) { create(:user) } let(:approver1) { create(:user) }
...@@ -108,6 +112,14 @@ describe ApprovalState do ...@@ -108,6 +112,14 @@ describe ApprovalState do
expect(subject.wrapped_approval_rules).to all(be_an(ApprovalWrappedRule)) expect(subject.wrapped_approval_rules).to all(be_an(ApprovalWrappedRule))
expect(subject.wrapped_approval_rules.size).to eq(2) expect(subject.wrapped_approval_rules.size).to eq(2)
end end
context 'when approval feature is unavailable' do
it 'returns empty array' do
disable_feature
expect(subject.wrapped_approval_rules).to eq([])
end
end
end end
describe '#approval_needed?' do describe '#approval_needed?' do
...@@ -150,6 +162,14 @@ describe ApprovalState do ...@@ -150,6 +162,14 @@ describe ApprovalState do
expect(subject.approval_needed?).to eq(false) expect(subject.approval_needed?).to eq(false)
end end
end end
context 'when approval feature is unavailable' do
it 'returns false' do
disable_feature
expect(subject.approval_needed?).to eq(false)
end
end
end end
describe '#approved?' do describe '#approved?' do
...@@ -216,6 +236,15 @@ describe ApprovalState do ...@@ -216,6 +236,15 @@ describe ApprovalState do
it_behaves_like 'when rules are present' it_behaves_like 'when rules are present'
end end
context 'when approval feature is unavailable' do
it 'returns true' do
disable_feature
create_rule(users: [create(:user)], approvals_required: 1)
expect(subject.approved?).to eq(true)
end
end
end end
describe '#any_approver_allowed?' do describe '#any_approver_allowed?' do
...@@ -261,6 +290,14 @@ describe ApprovalState do ...@@ -261,6 +290,14 @@ describe ApprovalState do
it 'sums approvals_left from rules' do it 'sums approvals_left from rules' do
expect(subject.approvals_left).to eq(12) expect(subject.approvals_left).to eq(12)
end end
context 'when approval feature is unavailable' do
it 'returns 0' do
disable_feature
expect(subject.approvals_left).to eq(0)
end
end
end end
describe '#approval_rules_left' do describe '#approval_rules_left' do
...@@ -268,12 +305,21 @@ describe ApprovalState do ...@@ -268,12 +305,21 @@ describe ApprovalState do
create_rule(approvals_required: 1, users: [create(:user)]) create_rule(approvals_required: 1, users: [create(:user)])
end end
it 'counts approval_rules left' do before do
create_unapproved_rule 2.times { create_unapproved_rule }
create_unapproved_rule end
it 'counts approval_rules left' do
expect(subject.approval_rules_left.size).to eq(2) expect(subject.approval_rules_left.size).to eq(2)
end end
context 'when approval feature is unavailable' do
it 'returns empty array' do
disable_feature
expect(subject.approval_rules_left).to eq([])
end
end
end end
describe '#approvers' do describe '#approvers' do
......
...@@ -9,12 +9,6 @@ describe VisibleApprovable do ...@@ -9,12 +9,6 @@ describe VisibleApprovable do
stub_feature_flags(approval_rules: false) stub_feature_flags(approval_rules: false)
end end
describe '#requires_approve' do
subject { resource.requires_approve? }
it { is_expected.to be true }
end
describe '#approvers_left' do describe '#approvers_left' do
let!(:private_group) { create(:group_with_members, :private) } let!(:private_group) { create(:group_with_members, :private) }
let!(:public_group) { create(:group_with_members) } let!(:public_group) { create(:group_with_members) }
......
...@@ -15,7 +15,6 @@ describe 'shared/issuable/_approvals.html.haml' do ...@@ -15,7 +15,6 @@ describe 'shared/issuable/_approvals.html.haml' do
allow(view).to receive(:current_user).and_return(user) allow(view).to receive(:current_user).and_return(user)
allow(form).to receive(:label) allow(form).to receive(:label)
allow(form).to receive(:number_field) allow(form).to receive(:number_field)
allow(merge_request).to receive(:requires_approve?).and_return(true)
allow(MergeRequestApproverPresenter).to receive(:new).and_return(approver_presenter) allow(MergeRequestApproverPresenter).to receive(:new).and_return(approver_presenter)
assign(:project, project) assign(:project, project)
end end
......
...@@ -128,6 +128,7 @@ ...@@ -128,6 +128,7 @@
"conflicts_docs_path": { "type": ["string", "null"] }, "conflicts_docs_path": { "type": ["string", "null"] },
// EE-specific // EE-specific
"has_approvals_available": { "type": ["boolean"] },
"approvals_before_merge": { "type": ["integer", "null"] }, "approvals_before_merge": { "type": ["integer", "null"] },
"approved": { "type": "boolean" }, "approved": { "type": "boolean" },
"approvals_path": { "type": ["string", "null"] }, "approvals_path": { "type": ["string", "null"] },
......
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