BigW Consortium Gitlab

Commit cf2dcf04 by James Lopez

Refactor all query config stuff into separate classes and added specs

parent cbc9f0cd
module Projects module Projects
module CycleAnalytics module CycleAnalytics
class EventsController < Projects::ApplicationController class EventsController < Projects::ApplicationController
include CycleAnalyticsParams include CycleAnalyticsParams
before_action :authorize_read_cycle_analytics! before_action :authorize_read_cycle_analytics!
...@@ -62,6 +62,6 @@ class EventsController < Projects::ApplicationController ...@@ -62,6 +62,6 @@ class EventsController < Projects::ApplicationController
def authorize_builds! def authorize_builds!
return access_denied! unless current_user.can?(:read_build, project) return access_denied! unless current_user.can?(:read_build, project)
end end
end end
end end
end end
module Gitlab
module CycleAnalytics
class BaseConfig
extend MetricsFetcher
class << self
attr_reader :start_time_attrs, :end_time_attrs, :projections
end
def self.order
@order || @start_time_attrs
end
def self.query(base_query); end
end
end
end
module Gitlab
module CycleAnalytics
class CodeConfig < BaseConfig
@start_time_attrs = issue_metrics_table[:first_mentioned_in_commit_at]
@end_time_attrs = mr_table[:created_at]
@projections = [mr_table[:title],
mr_table[:iid],
mr_table[:id],
mr_table[:created_at],
mr_table[:state],
mr_table[:author_id]]
@order = mr_table[:created_at]
end
end
end
...@@ -8,22 +8,10 @@ module Gitlab ...@@ -8,22 +8,10 @@ module Gitlab
end end
def fetch(stage:) def fetch(stage:)
custom_query = "#{stage}_custom_query".to_sym @query.execute(stage) do |stage_class, base_query|
stage_class.query(base_query)
@query.execute(stage) do |base_query|
public_send(custom_query, base_query) if self.respond_to?(custom_query)
end
end
def plan_custom_query(base_query)
base_query.join(mr_diff_table).on(mr_diff_table[:merge_request_id].eq(mr_table[:id]))
end end
def test_custom_query(base_query)
base_query.join(build_table).on(mr_metrics_table[:pipeline_id].eq(build_table[:commit_id]))
end end
alias_method :staging_custom_query, :test_custom_query
end end
end end
end end
...@@ -11,7 +11,6 @@ module Gitlab ...@@ -11,7 +11,6 @@ module Gitlab
def execute(stage, &block) def execute(stage, &block)
@stage = stage @stage = stage
@config = QueryConfig.get(stage)
query = build_query(&block) query = build_query(&block)
ActiveRecord::Base.connection.exec_query(query.to_sql) ActiveRecord::Base.connection.exec_query(query.to_sql)
...@@ -21,15 +20,11 @@ module Gitlab ...@@ -21,15 +20,11 @@ module Gitlab
def build_query def build_query
base_query = base_query_for(@stage) base_query = base_query_for(@stage)
diff_fn = subtract_datetimes_diff(@config[:base_query], @config[:start_time_attrs], @config[:end_time_attrs]) diff_fn = subtract_datetimes_diff(base_query, stage_class.start_time_attrs, stage_class.end_time_attrs)
yield base_query if block_given? yield(stage_class, base_query) if block_given?
base_query.project(extract_epoch(diff_fn).as('total_time'), *@config[:projections]).order(order.desc) base_query.project(extract_epoch(diff_fn).as('total_time'), *stage_class.projections).order(stage_class.order.desc)
end
def order
@config[:order] || @config[:start_time_attrs]
end end
def extract_epoch(arel_attribute) def extract_epoch(arel_attribute)
...@@ -37,6 +32,10 @@ module Gitlab ...@@ -37,6 +32,10 @@ module Gitlab
Arel.sql(%Q{EXTRACT(EPOCH FROM (#{arel_attribute.to_sql}))}) Arel.sql(%Q{EXTRACT(EPOCH FROM (#{arel_attribute.to_sql}))})
end end
def stage_class
@stage_class ||= "Gitlab::CycleAnalytics::#{@stage.to_s.camelize}Config".constantize
end
end end
end end
end end
module Gitlab
module CycleAnalytics
class IssueConfig < BaseConfig
@start_time_attrs = issue_table[:created_at]
@end_time_attrs = [issue_metrics_table[:first_associated_with_milestone_at],
issue_metrics_table[:first_added_to_board_at]]
@projections = [issue_table[:title],
issue_table[:iid],
issue_table[:id],
issue_table[:created_at],
issue_table[:author_id]]
end
end
end
module Gitlab
module CycleAnalytics
class PlanConfig < BaseConfig
@start_time_attrs = issue_metrics_table[:first_associated_with_milestone_at]
@end_time_attrs = [issue_metrics_table[:first_added_to_board_at],
issue_metrics_table[:first_mentioned_in_commit_at]]
@projections = [mr_diff_table[:st_commits].as('commits'),
issue_metrics_table[:first_mentioned_in_commit_at]]
def self.query(base_query)
base_query.join(mr_diff_table).on(mr_diff_table[:merge_request_id].eq(mr_table[:id]))
end
end
end
end
module Gitlab
module CycleAnalytics
class ProductionConfig < BaseConfig
@start_time_attrs = issue_table[:created_at]
@end_time_attrs = mr_metrics_table[:first_deployed_to_production_at]
@projections = [issue_table[:title],
issue_table[:iid],
issue_table[:id],
issue_table[:created_at],
issue_table[:author_id]]
end
end
end
module Gitlab
module CycleAnalytics
class QueryConfig
include MetricsFetcher
def self.get(*args)
new(*args).get
end
def initialize(stage)
@stage = stage
end
def get
public_send(@stage).freeze if self.respond_to?(@stage)
end
def issue
{
start_time_attrs: issue_table[:created_at],
end_time_attrs: [issue_metrics_table[:first_associated_with_milestone_at],
issue_metrics_table[:first_added_to_board_at]],
projections: [issue_table[:title],
issue_table[:iid],
issue_table[:id],
issue_table[:created_at],
issue_table[:author_id]]
}
end
def plan
{
start_time_attrs: issue_metrics_table[:first_associated_with_milestone_at],
end_time_attrs: [issue_metrics_table[:first_added_to_board_at],
issue_metrics_table[:first_mentioned_in_commit_at]],
projections: [mr_diff_table[:st_commits].as('commits'),
issue_metrics_table[:first_mentioned_in_commit_at]]
}
end
def code
{
start_time_attrs: issue_metrics_table[:first_mentioned_in_commit_at],
end_time_attrs: mr_table[:created_at],
projections: [mr_table[:title],
mr_table[:iid],
mr_table[:id],
mr_table[:created_at],
mr_table[:state],
mr_table[:author_id]],
order: mr_table[:created_at]
}
end
def test
{
start_time_attrs: mr_metrics_table[:latest_build_started_at],
end_time_attrs: mr_metrics_table[:latest_build_finished_at],
projections: [build_table[:id]],
order: build_table[:created_at]
}
end
def review
{
start_time_attrs: mr_table[:created_at],
end_time_attrs: mr_metrics_table[:merged_at],
projections: [mr_table[:title],
mr_table[:iid],
mr_table[:id],
mr_table[:created_at],
mr_table[:state],
mr_table[:author_id]]
}
end
def staging
{
start_time_attrs: mr_metrics_table[:merged_at],
end_time_attrs: mr_metrics_table[:first_deployed_to_production_at],
projections: [build_table[:id]],
order: build_table[:created_at]
}
end
def production
{
start_time_attrs: issue_table[:created_at],
end_time_attrs: mr_metrics_table[:first_deployed_to_production_at],
projections: [issue_table[:title],
issue_table[:iid],
issue_table[:id],
issue_table[:created_at],
issue_table[:author_id]]
}
end
end
end
end
module Gitlab
module CycleAnalytics
class ReviewConfig < BaseConfig
@start_time_attrs = mr_table[:created_at]
@end_time_attrs = mr_metrics_table[:merged_at]
@projections = [mr_table[:title],
mr_table[:iid],
mr_table[:id],
mr_table[:created_at],
mr_table[:state],
mr_table[:author_id]]
end
end
end
module Gitlab
module CycleAnalytics
class StagingConfig < BaseConfig
@start_time_attrs = mr_metrics_table[:merged_at]
@end_time_attrs = mr_metrics_table[:first_deployed_to_production_at]
@projections = [build_table[:id]]
@order = build_table[:created_at]
def self.query(base_query)
base_query.join(build_table).on(mr_metrics_table[:pipeline_id].eq(build_table[:commit_id]))
end
end
end
end
module Gitlab
module CycleAnalytics
class TestConfig < BaseConfig
@start_time_attrs = mr_metrics_table[:latest_build_started_at]
@end_time_attrs = mr_metrics_table[:latest_build_finished_at]
@projections = [build_table[:id]]
@order = build_table[:created_at]
def self.query(base_query)
base_query.join(build_table).on(mr_metrics_table[:pipeline_id].eq(build_table[:commit_id]))
end
end
end
end
require 'spec_helper'
require 'lib/gitlab/cycle_analytics/shared_config_spec'
describe Gitlab::CycleAnalytics::CodeConfig do
it_behaves_like 'default query config'
it 'has the default order' do
expect(described_class.order).not_to eq(described_class.start_time_attrs)
end
end
...@@ -9,6 +9,8 @@ describe Gitlab::CycleAnalytics::Events do ...@@ -9,6 +9,8 @@ describe Gitlab::CycleAnalytics::Events do
subject { described_class.new(project: project, options: { from: from_date }) } subject { described_class.new(project: project, options: { from: from_date }) }
before do before do
allow_any_instance_of(Gitlab::ReferenceExtractor).to receive(:issues).and_return([context])
setup(context) setup(context)
end end
...@@ -317,6 +319,8 @@ describe Gitlab::CycleAnalytics::Events do ...@@ -317,6 +319,8 @@ describe Gitlab::CycleAnalytics::Events do
def setup(context) def setup(context)
milestone = create(:milestone, project: project) milestone = create(:milestone, project: project)
context.update(milestone: milestone) context.update(milestone: milestone)
create_merge_request_closing_issue(context) mr = create_merge_request_closing_issue(context)
ProcessCommitWorker.new.perform(project.id, user.id, mr.commits.last.sha)
end end
end end
require 'spec_helper'
require 'lib/gitlab/cycle_analytics/shared_config_spec'
describe Gitlab::CycleAnalytics::IssueConfig do
it_behaves_like 'default query config'
it 'has the default order' do
expect(described_class.order).to eq(described_class.start_time_attrs)
end
end
require 'spec_helper'
require 'lib/gitlab/cycle_analytics/shared_config_spec'
describe Gitlab::CycleAnalytics::PlanConfig do
it_behaves_like 'default query config'
it 'has the default order' do
expect(described_class.order).to eq(described_class.start_time_attrs)
end
end
require 'spec_helper'
require 'lib/gitlab/cycle_analytics/shared_config_spec'
describe Gitlab::CycleAnalytics::ProductionConfig do
it_behaves_like 'default query config'
it 'has the default order' do
expect(described_class.order).to eq(described_class.start_time_attrs)
end
end
require 'spec_helper'
require 'lib/gitlab/cycle_analytics/shared_config_spec'
describe Gitlab::CycleAnalytics::ReviewConfig do
it_behaves_like 'default query config'
it 'has the default order' do
expect(described_class.order).to eq(described_class.start_time_attrs)
end
end
require 'spec_helper'
shared_examples 'default query config' do
it 'has the start attributes' do
expect(described_class.start_time_attrs).not_to be_nil
end
it 'has the end attributes' do
expect(described_class.end_time_attrs ).not_to be_nil
end
it 'has the projection attributes' do
expect(described_class.projections).not_to be_nil
end
end
require 'spec_helper'
require 'lib/gitlab/cycle_analytics/shared_config_spec'
describe Gitlab::CycleAnalytics::StagingConfig do
it_behaves_like 'default query config'
it 'has the default order' do
expect(described_class.order).not_to eq(described_class.start_time_attrs)
end
end
require 'spec_helper'
require 'lib/gitlab/cycle_analytics/shared_config_spec'
describe Gitlab::CycleAnalytics::TestConfig do
it_behaves_like 'default query config'
it 'has the default order' do
expect(described_class.order).not_to eq(described_class.start_time_attrs)
end
end
...@@ -12,6 +12,8 @@ describe 'cycle analytics events' do ...@@ -12,6 +12,8 @@ describe 'cycle analytics events' do
deploy_master deploy_master
login_as(user) login_as(user)
allow_any_instance_of(Gitlab::ReferenceExtractor).to receive(:issues).and_return([context])
end end
it 'lists the issue events' do it 'lists the issue events' do
...@@ -143,6 +145,6 @@ describe 'cycle analytics events' do ...@@ -143,6 +145,6 @@ describe 'cycle analytics events' do
merge_merge_requests_closing_issue(issue) merge_merge_requests_closing_issue(issue)
Issue::Metrics.update_all(first_mentioned_in_commit_at: mr.commits.last.committed_date) ProcessCommitWorker.new.perform(project.id, user.id, mr.commits.last.sha)
end end
end end
...@@ -2,7 +2,7 @@ require 'spec_helper' ...@@ -2,7 +2,7 @@ require 'spec_helper'
describe AnalyticsGenericEntity do describe AnalyticsGenericEntity do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:entity_hash) { let(:entity_hash) do
{ {
total_time: "172802.724419", total_time: "172802.724419",
title: "Eos voluptatem inventore in sed.", title: "Eos voluptatem inventore in sed.",
...@@ -11,7 +11,7 @@ describe AnalyticsGenericEntity do ...@@ -11,7 +11,7 @@ describe AnalyticsGenericEntity do
created_at: "2016-11-12 15:04:02.948604", created_at: "2016-11-12 15:04:02.948604",
author: user, author: user,
} }
} end
let(:project) { create(:empty_project) } let(:project) { create(:empty_project) }
let(:request) { EntityRequest.new(project: project, entity: :merge_request) } let(:request) { EntityRequest.new(project: project, entity: :merge_request) }
......
...@@ -10,7 +10,7 @@ describe AnalyticsGenericSerializer do ...@@ -10,7 +10,7 @@ describe AnalyticsGenericSerializer do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:json) { serializer.as_json } let(:json) { serializer.as_json }
let(:project) { create(:project) } let(:project) { create(:project) }
let(:resource) { let(:resource) do
{ {
total_time: "172802.724419", total_time: "172802.724419",
title: "Eos voluptatem inventore in sed.", title: "Eos voluptatem inventore in sed.",
...@@ -19,7 +19,7 @@ describe AnalyticsGenericSerializer do ...@@ -19,7 +19,7 @@ describe AnalyticsGenericSerializer do
created_at: "2016-11-12 15:04:02.948604", created_at: "2016-11-12 15:04:02.948604",
author: user, author: user,
} }
} end
context 'when there is a single object provided' do context 'when there is a single object provided' do
it 'it generates payload for single object' do it 'it generates payload for single object' 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