Commit 22c01303 authored by Adam Hegyi's avatar Adam Hegyi Committed by Douglas Barbosa Alexandre

Expose CA median and records via API

This MR exposes to the frontend the median and the related records
calculated for a given stage.
parent 30b26d73
......@@ -6,6 +6,7 @@ module Analytics
check_feature_flag Gitlab::Analytics::CYCLE_ANALYTICS_FEATURE_FLAG
before_action :load_group
before_action :validate_params, only: %i[median records]
def index
return render_403 unless can?(current_user, :read_group_cycle_analytics, @group)
......@@ -37,8 +38,45 @@ module Analytics
render_stage_service_result(delete_service.execute)
end
def median
return render_403 unless can?(current_user, :read_group_stage, @group)
render json: { value: data_collector.median.seconds }
end
def records
return render_403 unless can?(current_user, :read_group_stage, @group)
render json: data_collector.serialized_records
end
private
def validate_params
if request_params.invalid?
render(
json: { message: 'Invalid parameters', errors: request_params.errors },
status: :unprocessable_entity
)
end
end
def request_params
@request_params ||= Gitlab::Analytics::CycleAnalytics::RequestParams.new(params.permit(:created_before, :created_after))
end
def data_collector
@data_collector ||= Gitlab::Analytics::CycleAnalytics::DataCollector.new(stage: stage, params: {
current_user: current_user,
from: request_params.created_after,
to: request_params.created_before
})
end
def stage
@stage ||= Analytics::CycleAnalytics::StageFinder.new(parent: @group, stage_id: params[:id]).execute
end
def cycle_analytics_configuration(stages)
stage_presenters = stages.map { |s| StagePresenter.new(s) }
......
......@@ -8,7 +8,12 @@ namespace :analytics do
constraints(::Constraints::FeatureConstrainer.new(Gitlab::Analytics::CYCLE_ANALYTICS_FEATURE_FLAG)) do
resource :cycle_analytics, only: :show
namespace :cycle_analytics do
resources :stages, only: [:index, :create, :update, :destroy]
resources :stages, only: [:index, :create, :update, :destroy] do
member do
get :median
get :records
end
end
end
end
......
# frozen_string_literal: true
module Gitlab
module Analytics
module CycleAnalytics
class RequestParams
include ActiveModel::Model
include ActiveModel::Validations
include ActiveModel::Attributes
attribute :created_after, :date
attribute :created_before, :date
validates :created_after, presence: true
validates :created_before, presence: true
validate :validate_created_before
private
def validate_created_before
return if created_after.nil? || created_before.nil?
errors.add(:created_before, :invalid) if created_after > created_before
end
end
end
end
end
......@@ -158,5 +158,53 @@ describe Analytics::CycleAnalytics::StagesController do
expect(response).to have_gitlab_http_status(:forbidden)
end
end
describe 'GET `median`' do
subject { get :median, params: params }
before do
params[:created_after] = '2019-01-01'
params[:created_before] = '2020-01-01'
end
it 'succeeds' do
subject
expect(response).to be_successful
expect(response).to match_response_schema('analytics/cycle_analytics/median', dir: 'ee')
end
context 'when params are invalid' do
before do
params[:created_before] = '2018-01-01'
end
it 'renders `unprocessable_entity`' do
subject
expect(response).to have_gitlab_http_status(:unprocessable_entity)
expect(response).to match_response_schema('analytics/cycle_analytics/validation_error', dir: 'ee')
end
end
include_examples 'group permission check on the controller level'
end
describe 'GET `records`' do
subject { get :records, params: params }
before do
params[:created_after] = '2019-01-01'
params[:created_before] = '2020-01-01'
end
it 'succeeds' do
subject
expect(response).to be_successful
end
include_examples 'group permission check on the controller level'
end
end
end
{
"type": "object",
"properties": {
"value": {
"anyOf": [
{ "type": "integer" },
{ "type": "null" }
]
}
},
"required": ["value"],
"additionalProperties": false
}
......@@ -51,7 +51,7 @@ describe Gitlab::Analytics::CycleAnalytics::DataCollector do
end
it 'loads serialized records' do
items = data_collector.records_fetcher.serialized_records
items = data_collector.serialized_records
expect(items.size).to eq(3)
end
......
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::Analytics::CycleAnalytics::RequestParams do
let(:params) { { created_after: '2018-01-01', created_before: '2019-01-01' } }
subject { described_class.new(params) }
describe 'validations' do
it 'is valid' do
expect(subject).to be_valid
end
context 'when `created_before` is missing' do
before do
params[:created_before] = nil
end
it 'is invalid' do
expect(subject).not_to be_valid
end
end
context 'when `created_before` is earlier than `created_after`' do
before do
params[:created_before] = '2015-01-01'
end
it 'is invalid' do
expect(subject).not_to be_valid
expect(subject.errors.messages[:created_before]).not_to be_empty
end
end
end
it 'casts `created_after` to date' do
expect(subject.created_after).to be_a_kind_of(Date)
end
it 'casts `created_before` to date' do
expect(subject.created_before).to be_a_kind_of(Date)
end
end
......@@ -12,6 +12,8 @@ module Gitlab
class DataCollector
include Gitlab::Utils::StrongMemoize
delegate :serialized_records, to: :records_fetcher
def initialize(stage:, params: {})
@stage = stage
@params = params
......
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