Commit 0172b7c9 authored by Adam Hegyi's avatar Adam Hegyi Committed by Jan Provaznik

Expose cycle analytics summary via API

This change exposes the summary counts for group level cycle analytics
via a separate endpoint while making sure the old CA implementation is
still working.
parent 51d5357b
# frozen_string_literal: true
module Analytics
module CycleAnalytics
class SummaryController < Analytics::ApplicationController
include CycleAnalyticsParams
check_feature_flag Gitlab::Analytics::CYCLE_ANALYTICS_FEATURE_FLAG
before_action :load_group
before_action :validate_params
def show
return render_403 unless can?(current_user, :read_group_cycle_analytics, @group)
group_level = ::CycleAnalytics::GroupLevel.new(group: @group, options: options(allowed_group_params))
render json: group_level.summary
end
private
def allowed_group_params
params.permit(:created_after, :created_before, project_ids: [])
end
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
end
end
end
......@@ -14,6 +14,7 @@ namespace :analytics do
get :records
end
end
resource :summary, controller: :summary, only: [:show]
end
end
......
......@@ -187,18 +187,7 @@ describe Analytics::CycleAnalytics::StagesController do
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 'date parameter examples'
include_examples 'group permission check on the controller level'
end
......@@ -217,6 +206,8 @@ describe Analytics::CycleAnalytics::StagesController do
expect(response).to be_successful
end
include_examples 'date parameter examples'
include_examples 'group permission check on the controller level'
end
end
......
# frozen_string_literal: true
require 'spec_helper'
describe Analytics::CycleAnalytics::SummaryController do
let_it_be(:user) { create(:user) }
let_it_be(:group, refind: true) { create(:group) }
let(:params) { { group_id: group.full_path, created_after: '2010-01-01', created_before: '2010-01-02' } }
before do
stub_feature_flags(Gitlab::Analytics::CYCLE_ANALYTICS_FEATURE_FLAG => true)
stub_licensed_features(cycle_analytics_for_groups: true)
group.add_reporter(user)
sign_in(user)
end
describe 'GET `show`' do
subject { get :show, params: params }
it 'succeeds' do
subject
expect(response).to be_successful
expect(response).to match_response_schema('analytics/cycle_analytics/summary', dir: 'ee')
end
include_examples 'date parameter examples'
include_examples 'group permission check on the controller level'
end
end
{
"type": "array",
"items": {
"minItems": 2,
"maxItems": 2,
"type": "object",
"required": ["value", "title"],
"properties": {
"value": {
"type": "integer"
},
"title": {
"type": "string"
}
},
"additionalProperties": false
}
}
......@@ -77,3 +77,68 @@ shared_context 'when invalid stage parameters are given' do
expect(response).to match_response_schema('analytics/cycle_analytics/validation_error', dir: 'ee')
end
end
shared_examples 'date parameter examples' do
before do
params[:created_after] = '2019-01-01'
params[:created_before] = '2020-01-01'
end
context 'when valid parameters are given' do
it 'succeeds' do
subject
expect(response).to be_successful
end
end
shared_examples 'example for invalid parameter' do
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
context 'when `created_after` is missing' do
before do
params.delete(:created_after)
end
include_examples 'example for invalid parameter'
end
context 'when `created_after` is invalid' do
before do
params[:created_after] = 'not-a-date'
end
include_examples 'example for invalid parameter'
end
context 'when `created_before` is missing' do
before do
params.delete(:created_before)
end
include_examples 'example for invalid parameter'
end
context 'when `created_after` is invalid' do
before do
params[:created_before] = 'not-a-date'
end
include_examples 'example for invalid parameter'
end
context 'when `created_after` is later than `created_before`' do
before do
params[:created_after] = '2012-01-01'
params[:created_before] = '2010-01-01'
end
include_examples 'example for invalid parameter'
end
end
......@@ -3,18 +3,17 @@
module Gitlab
module CycleAnalytics
class GroupStageSummary
attr_reader :group, :from, :current_user, :options
attr_reader :group, :current_user, :options
def initialize(group, options:)
@group = group
@from = options[:from]
@current_user = options[:current_user]
@options = options
end
def data
[serialize(Summary::Group::Issue.new(group: group, from: from, current_user: current_user, options: options)),
serialize(Summary::Group::Deploy.new(group: group, from: from, options: options))]
[serialize(Summary::Group::Issue.new(group: group, current_user: current_user, options: options)),
serialize(Summary::Group::Deploy.new(group: group, options: options))]
end
private
......
......@@ -5,11 +5,10 @@ module Gitlab
module Summary
module Group
class Base
attr_reader :group, :from, :options
attr_reader :group, :options
def initialize(group:, from:, options:)
def initialize(group:, options:)
@group = group
@from = from
@options = options
end
......
......@@ -20,7 +20,8 @@ module Gitlab
def find_deployments
deployments = Deployment.joins(:project).merge(Project.inside_path(group.full_path))
deployments = deployments.where(projects: { id: options[:projects] }) if options[:projects]
deployments = deployments.where("deployments.created_at > ?", from)
deployments = deployments.where("deployments.created_at > ?", options[:from])
deployments = deployments.where("deployments.created_at < ?", options[:to]) if options[:to]
deployments.success.count
end
end
......
......@@ -5,11 +5,10 @@ module Gitlab
module Summary
module Group
class Issue < Group::Base
attr_reader :group, :from, :current_user, :options
attr_reader :group, :current_user, :options
def initialize(group:, from:, current_user:, options:)
def initialize(group:, current_user:, options:)
@group = group
@from = from
@current_user = current_user
@options = options
end
......@@ -25,10 +24,19 @@ module Gitlab
private
def find_issues
issues = IssuesFinder.new(current_user, group_id: group.id, include_subgroups: true, created_after: from).execute
issues = IssuesFinder.new(current_user, finder_params).execute
issues = issues.where(projects: { id: options[:projects] }) if options[:projects]
issues.count
end
def finder_params
{
group_id: group.id,
include_subgroups: true,
created_after: options[:from],
created_before: options[:to]
}.compact
end
end
end
end
......
......@@ -44,6 +44,14 @@ describe Gitlab::CycleAnalytics::GroupStageSummary do
expect(subject.first[:value]).to eq(2)
end
end
context 'when `from` and `to` parameters are provided' do
subject { described_class.new(group, options: { from: 10.days.ago, to: Time.now, current_user: user }).data }
it 'finds issues from 5 days ago' do
expect(subject.first[:value]).to eq(2)
end
end
end
context 'with other projects' do
......@@ -97,6 +105,14 @@ describe Gitlab::CycleAnalytics::GroupStageSummary do
expect(subject.second[:value]).to eq(2)
end
end
context 'when `from` and `to` parameters are provided' do
subject { described_class.new(group, options: { from: 10.days.ago, to: Time.now, current_user: user }).data }
it 'finds deployments from 5 days ago' do
expect(subject.second[:value]).to eq(2)
end
end
end
context 'with other projects' 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