Commit 3e93b6c4 authored by Mayra Cabrera's avatar Mayra Cabrera

Merge branch '460-protected-branches-api-search' into 'master'

Add search support for protected branches API

See merge request gitlab-org/gitlab!24137
parents 6e1b9e51 263ba45c
# frozen_string_literal: true
# ProtectedBranchesFinder
#
# Used to filter protected branches by set of params
#
# Arguments:
# project - which project to scope to
# params:
# search: string
class ProtectedBranchesFinder
LIMIT = 100
attr_accessor :project, :params
def initialize(project, params = {})
@project = project
@params = params
end
def execute
protected_branches = project.limited_protected_branches(LIMIT)
protected_branches = by_name(protected_branches)
protected_branches
end
private
def by_name(protected_branches)
return protected_branches unless params[:search].present?
protected_branches.by_name(params[:search])
end
end
......@@ -2304,6 +2304,10 @@ class Project < ApplicationRecord
ci_config_path.blank? || ci_config_path == Gitlab::FileDetector::PATTERNS[:gitlab_ci]
end
def limited_protected_branches(limit)
protected_branches.limit(limit)
end
private
def closest_namespace_setting(name)
......
......@@ -2,6 +2,7 @@
class ProtectedBranch < ApplicationRecord
include ProtectedRef
include Gitlab::SQL::Pattern
scope :requiring_code_owner_approval,
-> { where(code_owner_approval_required: true) }
......@@ -45,6 +46,12 @@ class ProtectedBranch < ApplicationRecord
# NOOP
#
end
def self.by_name(query)
return none if query.blank?
where(fuzzy_arel_match(:name, query.downcase))
end
end
ProtectedBranch.prepend_if_ee('EE::ProtectedBranch')
---
title: Add search support for protected branches API
merge_request: 24137
author:
type: added
......@@ -19,10 +19,15 @@ module API
end
params do
use :pagination
optional :search, type: String, desc: 'Search for a protected branch by name'
end
# rubocop: disable CodeReuse/ActiveRecord
get ':id/protected_branches' do
protected_branches = user_project.protected_branches.preload(:push_access_levels, :merge_access_levels)
protected_branches =
ProtectedBranchesFinder
.new(user_project, params)
.execute
.preload(:push_access_levels, :merge_access_levels)
present paginate(protected_branches), with: Entities::ProtectedBranch, project: user_project
end
......
# frozen_string_literal: true
require 'spec_helper'
describe ProtectedBranchesFinder do
let(:project) { create(:project) }
let!(:protected_branch) { create(:protected_branch, project: project) }
let!(:another_protected_branch) { create(:protected_branch, project: project) }
let!(:other_protected_branch) { create(:protected_branch) }
let(:params) { {} }
describe '#execute' do
subject { described_class.new(project, params).execute }
it 'returns all protected branches of project by default' do
expect(subject).to match_array([protected_branch, another_protected_branch])
end
context 'when search param is present' do
let(:params) { { search: protected_branch.name } }
it 'filters by search param' do
expect(subject).to eq([protected_branch])
end
end
context 'when there are more protected branches than the limit' do
before do
stub_const("#{described_class}::LIMIT", 1)
end
it 'returns limited protected branches of project' do
expect(subject).to eq([another_protected_branch])
end
end
end
end
......@@ -5507,6 +5507,18 @@ describe Project do
end
end
describe '#limited_protected_branches' do
let(:project) { create(:project) }
let!(:protected_branch) { create(:protected_branch, project: project) }
let!(:another_protected_branch) { create(:protected_branch, project: project) }
subject { project.limited_protected_branches(1) }
it 'returns limited number of protected branches based on specified limit' do
expect(subject).to eq([another_protected_branch])
end
end
def rugged_config
rugged_repo(project.repository).config
end
......
......@@ -220,4 +220,32 @@ describe ProtectedBranch do
end
end
end
describe '.by_name' do
let!(:protected_branch) { create(:protected_branch, name: 'master') }
let!(:another_protected_branch) { create(:protected_branch, name: 'stable') }
it 'returns protected branches with a matching name' do
expect(described_class.by_name(protected_branch.name))
.to eq([protected_branch])
end
it 'returns protected branches with a partially matching name' do
expect(described_class.by_name(protected_branch.name[0..2]))
.to eq([protected_branch])
end
it 'returns protected branches with a matching name regardless of the casing' do
expect(described_class.by_name(protected_branch.name.upcase))
.to eq([protected_branch])
end
it 'returns nothing when nothing matches' do
expect(described_class.by_name('unknown')).to be_empty
end
it 'return nothing when query is blank' do
expect(described_class.by_name('')).to be_empty
end
end
end
......@@ -12,18 +12,18 @@ describe API::ProtectedBranches do
end
describe "GET /projects/:id/protected_branches" do
let(:params) { {} }
let(:route) { "/projects/#{project.id}/protected_branches" }
shared_examples_for 'protected branches' do
it 'returns the protected branches' do
get api(route, user), params: { per_page: 100 }
get api(route, user), params: params.merge(per_page: 100)
expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
protected_branch_names = json_response.map { |x| x['name'] }
expected_branch_names = project.protected_branches.map { |x| x['name'] }
expect(protected_branch_names).to match_array(expected_branch_names)
end
end
......@@ -33,7 +33,19 @@ describe API::ProtectedBranches do
project.add_maintainer(user)
end
it_behaves_like 'protected branches'
context 'when search param is not present' do
it_behaves_like 'protected branches' do
let(:expected_branch_names) { project.protected_branches.map { |x| x['name'] } }
end
end
context 'when search param is present' do
it_behaves_like 'protected branches' do
let(:another_protected_branch) { create(:protected_branch, project: project, name: 'stable') }
let(:params) { { search: another_protected_branch.name } }
let(:expected_branch_names) { [another_protected_branch.name] }
end
end
end
context 'when authenticated as a guest' do
......
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