Commit 2738e865 authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab master

parents 4724cb4d 72b27b3f
...@@ -49,10 +49,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo ...@@ -49,10 +49,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
push_frontend_feature_flag(:diff_searching_usage_data, @project, default_enabled: :yaml) push_frontend_feature_flag(:diff_searching_usage_data, @project, default_enabled: :yaml)
end end
before_action do
push_frontend_feature_flag(:show_relevant_approval_rule_approvers, @project, default_enabled: :yaml)
end
around_action :allow_gitaly_ref_name_caching, only: [:index, :show, :discussions] around_action :allow_gitaly_ref_name_caching, only: [:index, :show, :discussions]
after_action :log_merge_request_show, only: [:show] after_action :log_merge_request_show, only: [:show]
......
...@@ -41,6 +41,8 @@ module Projects ...@@ -41,6 +41,8 @@ module Projects
true true
rescue StandardError => error rescue StandardError => error
context = Gitlab::ApplicationContext.current.merge(project_id: project.id)
Gitlab::ErrorTracking.track_exception(error, **context)
attempt_rollback(project, error.message) attempt_rollback(project, error.message)
false false
rescue Exception => error # rubocop:disable Lint/RescueException rescue Exception => error # rubocop:disable Lint/RescueException
......
---
name: show_relevant_approval_rule_approvers
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/60339
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/329153
milestone: '13.12'
type: development
group: group::source code
default_enabled: true
...@@ -80,11 +80,6 @@ export default { ...@@ -80,11 +80,6 @@ export default {
default: false, default: false,
}, },
}, },
computed: {
isFeatureEnabled() {
return Boolean(gon.features?.showRelevantApprovalRuleApprovers);
},
},
watch: { watch: {
value(val) { value(val) {
if (val.length > 0) { if (val.length > 0) {
...@@ -140,26 +135,15 @@ export default { ...@@ -140,26 +135,15 @@ export default {
.then((results) => ({ results })); .then((results) => ({ results }));
}, },
fetchGroups(term) { fetchGroups(term) {
if (this.isFeatureEnabled) { const hasTerm = term.trim().length > 0;
const hasTerm = term.trim().length > 0; const DEVELOPER_ACCESS_LEVEL = 30;
const DEVELOPER_ACCESS_LEVEL = 30;
return Api.projectGroups(this.projectId, {
skip_groups: this.skipGroupIds,
...(hasTerm ? { search: term } : {}),
with_shared: true,
shared_visible_only: true,
shared_min_access_level: DEVELOPER_ACCESS_LEVEL,
});
}
// Don't includeAll when search is empty. Otherwise, the user could get a lot of garbage choices.
// https://gitlab.com/gitlab-org/gitlab/issues/11566
const includeAll = term.trim().length > 0;
return Api.groups(term, { return Api.projectGroups(this.projectId, {
skip_groups: this.skipGroupIds, skip_groups: this.skipGroupIds,
all_available: includeAll, ...(hasTerm ? { search: term } : {}),
with_shared: true,
shared_visible_only: true,
shared_min_access_level: DEVELOPER_ACCESS_LEVEL,
}); });
}, },
fetchUsers(term) { fetchUsers(term) {
......
...@@ -3,15 +3,13 @@ ...@@ -3,15 +3,13 @@
module Ci module Ci
module Minutes module Minutes
class Context class Context
delegate :shared_runners_minutes_limit_enabled?, to: :level delegate :shared_runners_minutes_limit_enabled?, to: :namespace
delegate :name, to: :namespace, prefix: true delegate :name, to: :namespace, prefix: true
attr_reader :level attr_reader :namespace
def initialize(project, namespace, tracking_strategy: nil) def initialize(project, namespace, tracking_strategy: nil)
@project = project
@namespace = project&.shared_runners_limit_namespace || namespace @namespace = project&.shared_runners_limit_namespace || namespace
@level = project || namespace
@tracking_strategy = tracking_strategy @tracking_strategy = tracking_strategy
end end
...@@ -21,8 +19,6 @@ module Ci ...@@ -21,8 +19,6 @@ module Ci
private private
attr_reader :project, :namespace
def quota def quota
@quota ||= ::Ci::Minutes::Quota.new(namespace, tracking_strategy: @tracking_strategy) @quota ||= ::Ci::Minutes::Quota.new(namespace, tracking_strategy: @tracking_strategy)
end end
......
...@@ -17,10 +17,10 @@ module Ci ...@@ -17,10 +17,10 @@ module Ci
def show?(current_user, cookies = false) def show?(current_user, cookies = false)
return false unless @stage return false unless @stage
return false unless @context.level return false unless @context.namespace
return false if alert_has_been_dismissed?(cookies) return false if alert_has_been_dismissed?(cookies)
Ability.allowed?(current_user, :read_ci_minutes_quota, @context.level) Ability.allowed?(current_user, :read_ci_minutes_quota, @context.namespace)
end end
def text def text
......
...@@ -298,7 +298,6 @@ module EE ...@@ -298,7 +298,6 @@ module EE
rule { developer }.policy do rule { developer }.policy do
enable :create_wiki enable :create_wiki
enable :admin_merge_request enable :admin_merge_request
enable :read_ci_minutes_quota
enable :read_group_audit_events enable :read_group_audit_events
end end
...@@ -316,6 +315,7 @@ module EE ...@@ -316,6 +315,7 @@ module EE
enable :read_group_compliance_dashboard enable :read_group_compliance_dashboard
enable :read_group_credentials_inventory enable :read_group_credentials_inventory
enable :admin_group_credentials_inventory enable :admin_group_credentials_inventory
enable :read_ci_minutes_quota
end end
rule { (admin | owner) & group_merge_request_approval_settings_enabled }.policy do rule { (admin | owner) & group_merge_request_approval_settings_enabled }.policy do
......
...@@ -183,11 +183,14 @@ module EE ...@@ -183,11 +183,14 @@ module EE
enable :create_vulnerability_feedback enable :create_vulnerability_feedback
enable :destroy_vulnerability_feedback enable :destroy_vulnerability_feedback
enable :update_vulnerability_feedback enable :update_vulnerability_feedback
enable :read_ci_minutes_quota
enable :admin_feature_flags_issue_links enable :admin_feature_flags_issue_links
enable :read_project_audit_events enable :read_project_audit_events
end end
rule { can?(:owner_access) }.policy do
enable :read_ci_minutes_quota
end
rule { can?(:developer_access) & iterations_available }.policy do rule { can?(:developer_access) & iterations_available }.policy do
enable :create_iteration enable :create_iteration
enable :admin_iteration enable :admin_iteration
......
...@@ -13,153 +13,166 @@ RSpec.describe 'CI shared runner limits' do ...@@ -13,153 +13,166 @@ RSpec.describe 'CI shared runner limits' do
let!(:job) { create(:ci_build, pipeline: pipeline) } let!(:job) { create(:ci_build, pipeline: pipeline) }
before do before do
group.add_user(user, membership_level)
sign_in(user) sign_in(user)
end end
context 'when on a project related page' do where(:membership_level, :visible) do
before do :owner | true
group.add_developer(user) :developer | false
end end
where(:case_name, :percent_threshold, :minutes_limit, :minutes_used) do with_them do
'warning level' | 30 | 1000 | 800 context 'when on a project related page' do
'danger level' | 5 | 1000 | 980 where(:membership_level, :visible) do
end :owner | true
:developer | false
end
with_them do before do
context "when there is a notification and minutes still exist", :js do group.add_user(user, membership_level)
let(:message) do end
"#{group.name} namespace has #{percent_threshold}% or less Shared Runner Pipeline minutes remaining. " \
"After it runs out, no new jobs or pipelines in its projects will run."
end
before do where(:case_name, :percent_threshold, :minutes_limit, :minutes_used) do
group.update!(shared_runners_minutes_limit: minutes_limit) 'warning level' | 30 | 1000 | 800
allow_any_instance_of(::Ci::Minutes::Quota).to receive(:total_minutes_used).and_return(minutes_used) 'danger level' | 5 | 1000 | 980
end end
it 'displays a warning message on pipelines page' do with_them do
visit project_pipelines_path(project) context "when there is a notification and minutes still exist", :js do
let(:message) do
"#{group.name} namespace has #{percent_threshold}% or less Shared Runner Pipeline minutes remaining. " \
"After it runs out, no new jobs or pipelines in its projects will run."
end
before do
group.update!(shared_runners_minutes_limit: minutes_limit)
allow_any_instance_of(::Ci::Minutes::Quota).to receive(:total_minutes_used).and_return(minutes_used)
end
it 'displays a warning message on pipelines page' do
visit project_pipelines_path(project)
alerts_according_to_role(visible: visible, message: message)
end
it 'displays a warning message on project homepage' do
visit project_path(project)
expect_quota_exceeded_alert(message) alerts_according_to_role(visible: visible, message: message)
end
it 'displays a warning message on a job page' do
visit project_job_path(project, job)
alerts_according_to_role(visible: visible, message: message)
end
end
end
context 'when limit is exceeded', :js do
let(:group) { create(:group, :with_used_build_minutes_limit) }
let(:message) do
"#{group.name} namespace has exceeded its pipeline minutes quota. " \
"Buy additional pipeline minutes, or no new jobs or pipelines in its projects will run."
end end
it 'displays a warning message on project homepage' do it 'displays a warning message on project homepage' do
visit project_path(project) visit project_path(project)
expect_quota_exceeded_alert(message) alerts_according_to_role(visible: visible, message: message)
end
it 'displays a warning message on pipelines page' do
visit project_pipelines_path(project)
alerts_according_to_role(visible: visible, message: message)
end end
it 'displays a warning message on a job page' do it 'displays a warning message on a job page' do
visit project_job_path(project, job) visit project_job_path(project, job)
expect_quota_exceeded_alert(message) alerts_according_to_role(visible: visible, message: message)
end end
end end
end
context 'when limit is exceeded', :js do context 'when limit not yet exceeded' do
let(:group) { create(:group, :with_used_build_minutes_limit) } let(:group) { create(:group, :with_not_used_build_minutes_limit) }
let(:message) do
"#{group.name} namespace has exceeded its pipeline minutes quota. " \
"Buy additional pipeline minutes, or no new jobs or pipelines in its projects will run."
end
it 'displays a warning message on project homepage' do it 'does not display a warning message on project homepage' do
visit project_path(project) visit project_path(project)
expect_quota_exceeded_alert(message) expect_no_quota_exceeded_alert
end end
it 'displays a warning message on pipelines page' do it 'does not display a warning message on pipelines page' do
visit project_pipelines_path(project) visit project_pipelines_path(project)
expect_quota_exceeded_alert(message) expect_no_quota_exceeded_alert
end end
it 'displays a warning message on a job page' do it 'displays a warning message on a job page' do
visit project_job_path(project, job) visit project_job_path(project, job)
expect_quota_exceeded_alert(message) expect_no_quota_exceeded_alert
end
end end
end end
context 'when limit not yet exceeded' do context 'when on a group related page' do
let(:group) { create(:group, :with_not_used_build_minutes_limit) } where(:case_name, :percent_threshold, :minutes_limit, :minutes_used) do
'warning level' | 30 | 1000 | 800
it 'does not display a warning message on project homepage' do 'danger level' | 5 | 1000 | 980
visit project_path(project)
expect_no_quota_exceeded_alert
end end
it 'does not display a warning message on pipelines page' do with_them do
visit project_pipelines_path(project) context "when there is a notification and minutes still exist", :js do
let(:message) do
"#{group.name} namespace has #{percent_threshold}% or less Shared Runner Pipeline minutes remaining. " \
"After it runs out, no new jobs or pipelines in its projects will run."
end
expect_no_quota_exceeded_alert before do
end group.update!(shared_runners_minutes_limit: minutes_limit)
allow_any_instance_of(::Ci::Minutes::Quota).to receive(:total_minutes_used).and_return(minutes_used)
end
it 'displays a warning message on a job page' do it 'displays a warning message on group information page' do
visit project_job_path(project, job) visit group_path(group)
expect_no_quota_exceeded_alert alerts_according_to_role(visible: visible, message: message)
end
end
end end
end
end
context 'when on a group related page' do context 'when limit is exceeded', :js do
before do let(:group) { create(:group, :with_used_build_minutes_limit) }
group.add_owner(user)
end
where(:case_name, :percent_threshold, :minutes_limit, :minutes_used) do
'warning level' | 30 | 1000 | 800
'danger level' | 5 | 1000 | 980
end
with_them do
context "when there is a notification and minutes still exist", :js do
let(:message) do let(:message) do
"#{group.name} namespace has #{percent_threshold}% or less Shared Runner Pipeline minutes remaining. " \ "#{group.name} namespace has exceeded its pipeline minutes quota. " \
"After it runs out, no new jobs or pipelines in its projects will run." "Buy additional pipeline minutes, or no new jobs or pipelines in its projects will run."
end
before do
group.update!(shared_runners_minutes_limit: minutes_limit)
allow_any_instance_of(::Ci::Minutes::Quota).to receive(:total_minutes_used).and_return(minutes_used)
end end
it 'displays a warning message on group information page' do it 'displays a warning message on group information page' do
visit group_path(group) visit group_path(group)
expect_quota_exceeded_alert(message) alerts_according_to_role(visible: visible, message: message)
end end
end end
end
context 'when limit is exceeded', :js do context 'when limit not yet exceeded' do
let(:group) { create(:group, :with_used_build_minutes_limit) } let(:group) { create(:group, :with_not_used_build_minutes_limit) }
let(:message) do
"#{group.name} namespace has exceeded its pipeline minutes quota. " \
"Buy additional pipeline minutes, or no new jobs or pipelines in its projects will run."
end
it 'displays a warning message on group information page' do it 'does not display a warning message on group information page' do
visit group_path(group) visit group_path(group)
expect_quota_exceeded_alert(message) expect_no_quota_exceeded_alert
end
end end
end end
end
context 'when limit not yet exceeded' do def alerts_according_to_role(visible: false, message: '')
let(:group) { create(:group, :with_not_used_build_minutes_limit) } visible ? expect_quota_exceeded_alert(message) : expect_no_quota_exceeded_alert
it 'does not display a warning message on group information page' do
visit group_path(group)
expect_no_quota_exceeded_alert
end
end
end end
def expect_quota_exceeded_alert(message) def expect_quota_exceeded_alert(message)
......
...@@ -74,30 +74,6 @@ RSpec.describe 'Merge request > User edits MR with approval rules', :js do ...@@ -74,30 +74,6 @@ RSpec.describe 'Merge request > User edits MR with approval rules', :js do
expect(page_rule_names.last).to have_text(rule_name) expect(page_rule_names.last).to have_text(rule_name)
end end
context 'with show_relevant_approval_rule_approvers feature flag disabled' do
before do
stub_feature_flags(show_relevant_approval_rule_approvers: false)
end
context "with public group" do
let(:group) { create(:group, :public) }
before do
group.add_developer create(:user)
click_button 'Approval rules'
click_button "Add approval rule"
end
it "with empty search, does not show public group" do
open_select2 members_selector
wait_for_requests
expect(page).not_to have_selector('.select2-result-label .group-result', text: group.name)
end
end
end
context 'with public group' do context 'with public group' do
let(:group) { create(:group, :public) } let(:group) { create(:group, :public) }
......
...@@ -55,20 +55,21 @@ RSpec.describe 'Merge request > User sets approvers', :js do ...@@ -55,20 +55,21 @@ RSpec.describe 'Merge request > User sets approvers', :js do
end end
context "Group approvers" do context "Group approvers" do
let(:project) { create(:project, :public, :repository, group: group) }
let(:group) { create(:group) }
context 'when creating an MR' do context 'when creating an MR' do
let(:other_user) { create(:user) } let(:other_user) { create(:user) }
before do before do
project.add_developer(user) project.add_developer(user)
project.add_developer(other_user) project.add_developer(other_user)
group.add_developer(other_user)
sign_in(user) sign_in(user)
end end
it 'allows setting groups as approvers' do it 'allows setting groups as approvers' do
group = create :group
group.add_developer(other_user)
visit project_new_merge_request_path(project, merge_request: { target_branch: 'master', source_branch: 'feature' }) visit project_new_merge_request_path(project, merge_request: { target_branch: 'master', source_branch: 'feature' })
open_modal(text: 'Add approval rule') open_modal(text: 'Add approval rule')
...@@ -99,8 +100,6 @@ RSpec.describe 'Merge request > User sets approvers', :js do ...@@ -99,8 +100,6 @@ RSpec.describe 'Merge request > User sets approvers', :js do
it 'allows delete approvers group when it is set in project' do it 'allows delete approvers group when it is set in project' do
approver = create :user approver = create :user
project.add_developer(approver) project.add_developer(approver)
group = create :group
group.add_developer(other_user)
group.add_developer(approver) group.add_developer(approver)
create :approval_project_rule, project: project, users: [approver], groups: [group], approvals_required: 1 create :approval_project_rule, project: project, users: [approver], groups: [group], approvals_required: 1
...@@ -134,42 +133,6 @@ RSpec.describe 'Merge request > User sets approvers', :js do ...@@ -134,42 +133,6 @@ RSpec.describe 'Merge request > User sets approvers', :js do
sign_in(user) sign_in(user)
end end
context 'with show_relevant_approval_rule_approvers feature flag disabled' do
before do
stub_feature_flags(show_relevant_approval_rule_approvers: false)
end
it 'allows setting groups as approvers' do
group = create :group
group.add_developer(other_user)
visit edit_project_merge_request_path(project, merge_request)
open_modal(text: 'Add approval rule')
open_approver_select
expect(find('.select2-results')).not_to have_content(group.name)
close_approver_select
group.add_developer(user) # only display groups that user has access to
open_approver_select
expect(find('.select2-results')).to have_content(group.name)
find('.select2-results .user-result', text: group.name).click
close_approver_select
within('.modal-content') do
click_button 'Add approval rule'
end
click_on("Save changes")
wait_for_all_requests
expect(page).to have_content("Requires 1 approval from eligible users.")
expect(page).to have_selector("img[alt='#{other_user.name}']")
end
end
it 'allows setting groups as approvers when there is possible group approvers' do it 'allows setting groups as approvers when there is possible group approvers' do
group = create :group group = create :group
group_project = create(:project, :public, :repository, namespace: group) group_project = create(:project, :public, :repository, namespace: group)
......
...@@ -6,8 +6,8 @@ RSpec.describe 'Project settings > [EE] Merge Request Approvals', :js do ...@@ -6,8 +6,8 @@ RSpec.describe 'Project settings > [EE] Merge Request Approvals', :js do
include FeatureApprovalHelper include FeatureApprovalHelper
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:group) { create(:group) } let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, namespace: group) }
let_it_be(:group_member) { create(:user) } let_it_be(:group_member) { create(:user) }
let_it_be(:non_member) { create(:user) } let_it_be(:non_member) { create(:user) }
let_it_be(:config_selector) { '.js-approval-rules' } let_it_be(:config_selector) { '.js-approval-rules' }
......
...@@ -73,7 +73,7 @@ describe('Approvals ApproversSelect', () => { ...@@ -73,7 +73,7 @@ describe('Approvals ApproversSelect', () => {
}; };
beforeEach(() => { beforeEach(() => {
jest.spyOn(Api, 'groups').mockResolvedValue(TEST_GROUPS); jest.spyOn(Api, 'projectGroups').mockResolvedValue(TEST_GROUPS);
jest.spyOn(Api, 'projectUsers').mockReturnValue(Promise.resolve(TEST_USERS)); jest.spyOn(Api, 'projectUsers').mockReturnValue(Promise.resolve(TEST_USERS));
}); });
...@@ -123,7 +123,13 @@ describe('Approvals ApproversSelect', () => { ...@@ -123,7 +123,13 @@ describe('Approvals ApproversSelect', () => {
}); });
it('fetches all available groups', () => { it('fetches all available groups', () => {
expect(Api.groups).toHaveBeenCalledWith(term, { skip_groups: [], all_available: true }); expect(Api.projectGroups).toHaveBeenCalledWith(TEST_PROJECT_ID, {
skip_groups: [],
search: term,
with_shared: true,
shared_visible_only: true,
shared_min_access_level: 30,
});
}); });
it('fetches users', () => { it('fetches users', () => {
...@@ -154,9 +160,11 @@ describe('Approvals ApproversSelect', () => { ...@@ -154,9 +160,11 @@ describe('Approvals ApproversSelect', () => {
}); });
it('skips groups and does not fetch all available', () => { it('skips groups and does not fetch all available', () => {
expect(Api.groups).toHaveBeenCalledWith('', { expect(Api.projectGroups).toHaveBeenCalledWith(TEST_PROJECT_ID, {
shared_min_access_level: 30,
shared_visible_only: true,
skip_groups: skipGroupIds, skip_groups: skipGroupIds,
all_available: false, with_shared: true,
}); });
}); });
......
...@@ -9,7 +9,7 @@ RSpec.describe Ci::Minutes::Context do ...@@ -9,7 +9,7 @@ RSpec.describe Ci::Minutes::Context do
describe 'delegation' do describe 'delegation' do
subject { described_class.new(project, group) } subject { described_class.new(project, group) }
it { is_expected.to delegate_method(:shared_runners_minutes_limit_enabled?).to(:level) } it { is_expected.to delegate_method(:shared_runners_minutes_limit_enabled?).to(:namespace) }
it { is_expected.to delegate_method(:name).to(:namespace).with_prefix } it { is_expected.to delegate_method(:name).to(:namespace).with_prefix }
end end
end end
...@@ -189,7 +189,7 @@ RSpec.describe Ci::Minutes::Notification do ...@@ -189,7 +189,7 @@ RSpec.describe Ci::Minutes::Notification do
context 'when at project level' do context 'when at project level' do
context 'when eligible to see notifications' do context 'when eligible to see notifications' do
before do before do
group.add_developer(user) group.add_owner(user)
end end
describe '#show?' do describe '#show?' do
...@@ -217,12 +217,22 @@ RSpec.describe Ci::Minutes::Notification do ...@@ -217,12 +217,22 @@ RSpec.describe Ci::Minutes::Notification do
subject { described_class.new(injected_project, nil) } subject { described_class.new(injected_project, nil) }
end end
end end
context 'when user is not in the correct role' do
before do
group.add_developer user
end
it_behaves_like 'not eligible to see notifications' do
subject { described_class.new(injected_project, nil) }
end
end
end end
context 'when at namespace level' do context 'when at namespace level' do
context 'when eligible to see notifications' do context 'when eligible to see notifications' do
before do before do
group.add_developer(user) group.add_owner(user)
end end
context 'with a project that has runners enabled inside namespace' do context 'with a project that has runners enabled inside namespace' do
...@@ -259,5 +269,15 @@ RSpec.describe Ci::Minutes::Notification do ...@@ -259,5 +269,15 @@ RSpec.describe Ci::Minutes::Notification do
subject { described_class.new(injected_project, nil) } subject { described_class.new(injected_project, nil) }
end end
end end
context 'when user is not in the correct role' do
before do
group.add_developer user
end
it_behaves_like 'not eligible to see notifications' do
subject { described_class.new(injected_project, nil) }
end
end
end end
end end
...@@ -1354,8 +1354,8 @@ RSpec.describe GroupPolicy do ...@@ -1354,8 +1354,8 @@ RSpec.describe GroupPolicy do
where(:role, :admin_mode, :allowed) do where(:role, :admin_mode, :allowed) do
:guest | nil | false :guest | nil | false
:reporter | nil | false :reporter | nil | false
:developer | nil | true :developer | nil | false
:maintainer | nil | true :maintainer | nil | false
:owner | nil | true :owner | nil | true
:admin | true | true :admin | true | true
:admin | false | false :admin | false | false
......
...@@ -1566,8 +1566,8 @@ RSpec.describe ProjectPolicy do ...@@ -1566,8 +1566,8 @@ RSpec.describe ProjectPolicy do
where(:role, :admin_mode, :allowed) do where(:role, :admin_mode, :allowed) do
:guest | nil | false :guest | nil | false
:reporter | nil | false :reporter | nil | false
:developer | nil | true :developer | nil | false
:maintainer | nil | true :maintainer | nil | false
:owner | nil | true :owner | nil | true
:admin | false | false :admin | false | false
:admin | true | true :admin | true | true
......
...@@ -31,6 +31,9 @@ module Gitlab ...@@ -31,6 +31,9 @@ module Gitlab
oids.map { |oid| rugged_find(repo, oid) } oids.map { |oid| rugged_find(repo, oid) }
.compact .compact
.map { |commit| decorate(repo, commit) } .map { |commit| decorate(repo, commit) }
# Match Gitaly's list_commits_by_oid behavior
rescue ::Gitlab::Git::Repository::NoRepository
[]
end end
override :find_commit override :find_commit
......
...@@ -486,6 +486,16 @@ RSpec.describe Gitlab::Git::Commit, :seed_helper do ...@@ -486,6 +486,16 @@ RSpec.describe Gitlab::Git::Commit, :seed_helper do
expect(commits.first.sha).to eq(SeedRepo::Commit::ID) expect(commits.first.sha).to eq(SeedRepo::Commit::ID)
expect(commits.second.sha).to eq(SeedRepo::FirstCommit::ID) expect(commits.second.sha).to eq(SeedRepo::FirstCommit::ID)
end end
context 'when repo does not exist' do
let(:no_repository) { Gitlab::Git::Repository.new('default', '@does-not-exist/project', '', 'bogus/project') }
it 'returns empty commits' do
commits = described_class.batch_by_oid(no_repository, oids)
expect(commits.count).to eq(0)
end
end
end end
context 'when oids is empty' do context 'when oids is empty' do
......
...@@ -78,6 +78,11 @@ RSpec.describe Projects::DestroyService, :aggregate_failures do ...@@ -78,6 +78,11 @@ RSpec.describe Projects::DestroyService, :aggregate_failures do
end.not_to raise_error end.not_to raise_error
end end
it 'reports the error' do
expect(Gitlab::ErrorTracking).to receive(:track_exception).and_call_original
destroy_project(project, user, {})
end
it 'unmarks the project as "pending deletion"' do it 'unmarks the project as "pending deletion"' do
destroy_project(project, user, {}) destroy_project(project, user, {})
......
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