Skip to content
Snippets Groups Projects
Commit e8d9df83 authored by Shinya Maeda's avatar Shinya Maeda
Browse files

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
parent 591380a3
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -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!
Loading
Loading
@@ -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)
Loading
Loading
Loading
Loading
@@ -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)) }
 
Loading
Loading
@@ -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)
Loading
Loading
---
title: Introduce Internal API for searching environment names
merge_request: 24923
author:
type: added
Loading
Loading
@@ -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
Loading
Loading
Loading
Loading
@@ -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,
Loading
Loading
Loading
Loading
@@ -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
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment