Commit 1d33ddd2 authored by Michael Kozono's avatar Michael Kozono

Merge branch '33101-add-updated_after-to-deployments-api' into 'master'

Add deployment API updated_at filters

Closes #33101

See merge request gitlab-org/gitlab!20731
parents 34aad02d 5e566d18
# frozen_string_literal: true
class DeploymentsFinder
attr_reader :project, :params
ALLOWED_SORT_VALUES = %w[id iid created_at updated_at ref].freeze
DEFAULT_SORT_VALUE = 'id'.freeze
ALLOWED_SORT_DIRECTIONS = %w[asc desc].freeze
DEFAULT_SORT_DIRECTION = 'asc'.freeze
def initialize(project, params = {})
@project = project
@params = params
end
def execute
items = init_collection
items = by_updated_at(items)
sort(items)
end
private
def init_collection
project.deployments
end
# rubocop: disable CodeReuse/ActiveRecord
def sort(items)
items.order(sort_params)
end
# rubocop: enable CodeReuse/ActiveRecord
def by_updated_at(items)
items = items.updated_before(params[:updated_before]) if params[:updated_before].present?
items = items.updated_after(params[:updated_after]) if params[:updated_after].present?
items
end
def sort_params
order_by = ALLOWED_SORT_VALUES.include?(params[:order_by]) ? params[:order_by] : DEFAULT_SORT_VALUE
order_direction = ALLOWED_SORT_DIRECTIONS.include?(params[:sort]) ? params[:sort] : DEFAULT_SORT_DIRECTION
{ order_by => order_direction }
end
end
......@@ -4,6 +4,7 @@ class Deployment < ApplicationRecord
include AtomicInternalId
include IidRoutes
include AfterCommitQueue
include UpdatedAtFilterable
belongs_to :project, required: true
belongs_to :environment, required: true
......
......@@ -13,6 +13,8 @@ GET /projects/:id/deployments
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
| `order_by`| string | no | Return deployments ordered by `id` or `iid` or `created_at` or `updated_at` or `ref` fields. Default is `id` |
| `sort` | string | no | Return deployments sorted in `asc` or `desc` order. Default is `asc` |
| `updated_after` | datetime | no | Return deployments updated after the specified date |
| `updated_before` | datetime | no | Return deployments updated before the specified date |
```bash
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/deployments"
......
---
title: Add deployment API updated_at filters
merge_request: 20731
author:
type: added
......@@ -17,16 +17,19 @@ module API
end
params do
use :pagination
optional :order_by, type: String, values: %w[id iid created_at updated_at ref], default: 'id', desc: 'Return deployments ordered by `id` or `iid` or `created_at` or `updated_at` or `ref`'
optional :sort, type: String, values: %w[asc desc], default: 'asc', desc: 'Sort by asc (ascending) or desc (descending)'
optional :order_by, type: String, values: DeploymentsFinder::ALLOWED_SORT_VALUES, default: DeploymentsFinder::DEFAULT_SORT_VALUE, desc: 'Return deployments ordered by specified value'
optional :sort, type: String, values: DeploymentsFinder::ALLOWED_SORT_DIRECTIONS, default: DeploymentsFinder::DEFAULT_SORT_DIRECTION, desc: 'Sort by asc (ascending) or desc (descending)'
optional :updated_after, type: DateTime, desc: 'Return deployments updated after the specified date'
optional :updated_before, type: DateTime, desc: 'Return deployments updated before the specified date'
end
# rubocop: disable CodeReuse/ActiveRecord
get ':id/deployments' do
authorize! :read_deployment, user_project
present paginate(user_project.deployments.order(params[:order_by] => params[:sort])), with: Entities::Deployment
deployments = DeploymentsFinder.new(user_project, params).execute
present paginate(deployments), with: Entities::Deployment
end
# rubocop: enable CodeReuse/ActiveRecord
desc 'Gets a specific deployment' do
detail 'This feature was introduced in GitLab 8.11.'
......
# frozen_string_literal: true
require 'spec_helper'
describe DeploymentsFinder do
subject { described_class.new(project, params).execute }
let(:project) { create(:project, :public, :repository) }
let(:params) { {} }
describe "#execute" do
it 'returns all deployments by default' do
deployments = create_list(:deployment, 2, :success, project: project)
is_expected.to match_array(deployments)
end
describe 'filtering' do
context 'when updated_at filters are specified' do
let(:params) { { updated_before: 1.day.ago, updated_after: 3.days.ago } }
let!(:deployment_1) { create(:deployment, :success, project: project, updated_at: 2.days.ago) }
let!(:deployment_2) { create(:deployment, :success, project: project, updated_at: 4.days.ago) }
let!(:deployment_3) { create(:deployment, :success, project: project, updated_at: 1.hour.ago) }
it 'returns deployments with matched updated_at' do
is_expected.to match_array([deployment_1])
end
end
end
describe 'ordering' do
using RSpec::Parameterized::TableSyntax
let(:params) { { order_by: order_by, sort: sort } }
let!(:deployment_1) { create(:deployment, :success, project: project, iid: 11, ref: 'master', created_at: Time.now, updated_at: Time.now) }
let!(:deployment_2) { create(:deployment, :success, project: project, iid: 12, ref: 'feature', created_at: 1.day.ago, updated_at: 2.hours.ago) }
let!(:deployment_3) { create(:deployment, :success, project: project, iid: 8, ref: 'patch', created_at: 2.days.ago, updated_at: 1.hour.ago) }
where(:order_by, :sort, :ordered_deployments) do
'created_at' | 'asc' | [:deployment_3, :deployment_2, :deployment_1]
'created_at' | 'desc' | [:deployment_1, :deployment_2, :deployment_3]
'id' | 'asc' | [:deployment_1, :deployment_2, :deployment_3]
'id' | 'desc' | [:deployment_3, :deployment_2, :deployment_1]
'iid' | 'asc' | [:deployment_3, :deployment_1, :deployment_2]
'iid' | 'desc' | [:deployment_2, :deployment_1, :deployment_3]
'ref' | 'asc' | [:deployment_2, :deployment_1, :deployment_3]
'ref' | 'desc' | [:deployment_3, :deployment_1, :deployment_2]
'updated_at' | 'asc' | [:deployment_2, :deployment_3, :deployment_1]
'updated_at' | 'desc' | [:deployment_1, :deployment_3, :deployment_2]
'invalid' | 'asc' | [:deployment_1, :deployment_2, :deployment_3]
'iid' | 'err' | [:deployment_3, :deployment_1, :deployment_2]
end
with_them do
it 'returns the deployments ordered' do
expect(subject).to eq(ordered_deployments.map { |name| public_send(name) })
end
end
end
end
end
......@@ -31,39 +31,36 @@ describe API::Deployments do
end
describe 'ordering' do
using RSpec::Parameterized::TableSyntax
let(:order_by) { nil }
let(:sort) { nil }
let(:order_by) { 'iid' }
let(:sort) { 'desc' }
subject { get api("/projects/#{project.id}/deployments?order_by=#{order_by}&sort=#{sort}", user) }
before do
subject
end
def expect_deployments(ordered_deployments)
json_response.each_with_index do |deployment_json, index|
expect(deployment_json['id']).to eq(public_send(ordered_deployments[index]).id)
end
expect(json_response.map { |d| d['id'] }).to eq(ordered_deployments.map(&:id))
end
before do
subject
it 'returns ordered deployments' do
expect(json_response.map { |i| i['id'] }).to eq([deployment_2.id, deployment_1.id, deployment_3.id])
end
where(:order_by, :sort, :ordered_deployments) do
'created_at' | 'asc' | [:deployment_3, :deployment_2, :deployment_1]
'created_at' | 'desc' | [:deployment_1, :deployment_2, :deployment_3]
'id' | 'asc' | [:deployment_1, :deployment_2, :deployment_3]
'id' | 'desc' | [:deployment_3, :deployment_2, :deployment_1]
'iid' | 'asc' | [:deployment_3, :deployment_1, :deployment_2]
'iid' | 'desc' | [:deployment_2, :deployment_1, :deployment_3]
'ref' | 'asc' | [:deployment_2, :deployment_1, :deployment_3]
'ref' | 'desc' | [:deployment_3, :deployment_1, :deployment_2]
'updated_at' | 'asc' | [:deployment_2, :deployment_3, :deployment_1]
'updated_at' | 'desc' | [:deployment_1, :deployment_3, :deployment_2]
context 'with invalid order_by' do
let(:order_by) { 'wrong_sorting_value' }
it 'returns error' do
expect(response).to have_gitlab_http_status(400)
end
end
with_them do
it 'returns the deployments ordered' do
expect_deployments(ordered_deployments)
context 'with invalid sorting' do
let(:sort) { 'wrong_sorting_direction' }
it 'returns error' do
expect(response).to have_gitlab_http_status(400)
end
end
end
......
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