Inroduce Internal API for searching environment names
Add changelog Rename word to query User hash for limit Do not allow control limit Rename pluck names and add more specs
This commit is contained in:
parent
591380a3f1
commit
e8d9df83a6
6 changed files with 177 additions and 0 deletions
|
@ -158,6 +158,16 @@ class Projects::EnvironmentsController < Projects::ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def search
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
environment_names = search_environment_names
|
||||
|
||||
render json: environment_names, status: environment_names.any? ? :ok : :no_content
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def verify_api_request!
|
||||
|
@ -181,6 +191,12 @@ class Projects::EnvironmentsController < Projects::ApplicationController
|
|||
@environment ||= project.environments.find(params[:id])
|
||||
end
|
||||
|
||||
def search_environment_names
|
||||
return [] unless params[:query]
|
||||
|
||||
project.environments.for_name_like(params[:query]).pluck_names
|
||||
end
|
||||
|
||||
def serialize_environments(request, response, nested = false)
|
||||
EnvironmentSerializer
|
||||
.new(project: @project, current_user: @current_user)
|
||||
|
|
|
@ -50,6 +50,14 @@ class Environment < ActiveRecord::Base
|
|||
end
|
||||
scope :in_review_folder, -> { where(environment_type: "review") }
|
||||
scope :for_name, -> (name) { where(name: name) }
|
||||
|
||||
##
|
||||
# Search environments which have names like the given query.
|
||||
# Do not set a large limit unless you've confirmed that it works on gitlab.com scale.
|
||||
scope :for_name_like, -> (query, limit: 5) do
|
||||
where('name LIKE ?', "#{sanitize_sql_like(query)}%").limit(limit)
|
||||
end
|
||||
|
||||
scope :for_project, -> (project) { where(project_id: project) }
|
||||
scope :with_deployment, -> (sha) { where('EXISTS (?)', Deployment.select(1).where('deployments.environment_id = environments.id').where(sha: sha)) }
|
||||
|
||||
|
@ -70,6 +78,10 @@ class Environment < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
def self.pluck_names
|
||||
pluck(:name)
|
||||
end
|
||||
|
||||
def predefined_variables
|
||||
Gitlab::Ci::Variables::Collection.new
|
||||
.append(key: 'CI_ENVIRONMENT_NAME', value: name)
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Introduce Internal API for searching environment names
|
||||
merge_request: 24923
|
||||
author:
|
||||
type: added
|
|
@ -224,6 +224,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
|
|||
collection do
|
||||
get :metrics, action: :metrics_redirect
|
||||
get :folder, path: 'folders/*id', constraints: { format: /(html|json)/ }
|
||||
get :search
|
||||
end
|
||||
|
||||
resources :deployments, only: [:index] do
|
||||
|
|
|
@ -422,6 +422,79 @@ describe Projects::EnvironmentsController do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'GET #search' do
|
||||
before do
|
||||
create(:environment, name: 'staging', project: project)
|
||||
create(:environment, name: 'review/patch-1', project: project)
|
||||
create(:environment, name: 'review/patch-2', project: project)
|
||||
end
|
||||
|
||||
let(:query) { 'pro' }
|
||||
|
||||
it 'responds with status code 200' do
|
||||
get :search, params: environment_params(format: :json, query: query)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
end
|
||||
|
||||
it 'returns matched results' do
|
||||
get :search, params: environment_params(format: :json, query: query)
|
||||
|
||||
expect(json_response).to contain_exactly('production')
|
||||
end
|
||||
|
||||
context 'when query is review' do
|
||||
let(:query) { 'review' }
|
||||
|
||||
it 'returns matched results' do
|
||||
get :search, params: environment_params(format: :json, query: query)
|
||||
|
||||
expect(json_response).to contain_exactly('review/patch-1', 'review/patch-2')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when query is empty' do
|
||||
let(:query) { '' }
|
||||
|
||||
it 'returns matched results' do
|
||||
get :search, params: environment_params(format: :json, query: query)
|
||||
|
||||
expect(json_response)
|
||||
.to contain_exactly('production', 'staging', 'review/patch-1', 'review/patch-2')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when query is review/patch-3' do
|
||||
let(:query) { 'review/patch-3' }
|
||||
|
||||
it 'responds with status code 204' do
|
||||
get :search, params: environment_params(format: :json, query: query)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:no_content)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when query is partially matched in the middle of environment name' do
|
||||
let(:query) { 'patch' }
|
||||
|
||||
it 'responds with status code 204' do
|
||||
get :search, params: environment_params(format: :json, query: query)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:no_content)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when query contains a wildcard character' do
|
||||
let(:query) { 'review%' }
|
||||
|
||||
it 'prevents wildcard injection' do
|
||||
get :search, params: environment_params(format: :json, query: query)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:no_content)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def environment_params(opts = {})
|
||||
opts.reverse_merge(namespace_id: project.namespace,
|
||||
project_id: project,
|
||||
|
|
|
@ -41,6 +41,76 @@ describe Environment do
|
|||
end
|
||||
end
|
||||
|
||||
describe '.for_name_like' do
|
||||
subject { project.environments.for_name_like(query, limit: limit) }
|
||||
|
||||
let!(:environment) { create(:environment, name: 'production', project: project) }
|
||||
let(:query) { 'pro' }
|
||||
let(:limit) { 5 }
|
||||
|
||||
it 'returns a found name' do
|
||||
is_expected.to include(environment)
|
||||
end
|
||||
|
||||
context 'when query is production' do
|
||||
let(:query) { 'production' }
|
||||
|
||||
it 'returns a found name' do
|
||||
is_expected.to include(environment)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when query is productionA' do
|
||||
let(:query) { 'productionA' }
|
||||
|
||||
it 'returns empty array' do
|
||||
is_expected.to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
context 'when query is empty' do
|
||||
let(:query) { '' }
|
||||
|
||||
it 'returns a found name' do
|
||||
is_expected.to include(environment)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when query is nil' do
|
||||
let(:query) { }
|
||||
|
||||
it 'raises an error' do
|
||||
expect { subject }.to raise_error(NoMethodError)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when query is partially matched in the middle of environment name' do
|
||||
let(:query) { 'duction' }
|
||||
|
||||
it 'returns empty array' do
|
||||
is_expected.to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
context 'when query contains a wildcard character' do
|
||||
let(:query) { 'produc%' }
|
||||
|
||||
it 'prevents wildcard injection' do
|
||||
is_expected.to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.pluck_names' do
|
||||
subject { described_class.pluck_names }
|
||||
|
||||
let!(:environment) { create(:environment, name: 'production', project: project) }
|
||||
|
||||
it 'plucks names' do
|
||||
is_expected.to eq(%w[production])
|
||||
end
|
||||
end
|
||||
|
||||
describe '#expire_etag_cache' do
|
||||
let(:store) { Gitlab::EtagCaching::Store.new }
|
||||
|
||||
|
|
Loading…
Reference in a new issue