diff options
author | James Lopez <james@jameslopez.es> | 2016-11-17 13:22:27 +0100 |
---|---|---|
committer | James Lopez <james@jameslopez.es> | 2016-11-17 13:22:27 +0100 |
commit | ed39d61d746925e49d952bd8169499d3200ae68b (patch) | |
tree | 33128144980f4b62e96309e9ed4c23133422159b /lib/gitlab/cycle_analytics | |
parent | f9de157e70234748cf4285fafda7b3ec13862f5c (diff) | |
download | gitlab-ce-ed39d61d746925e49d952bd8169499d3200ae68b.tar.gz |
refactor events facade so it uses separate classes and refactor query stuff
Diffstat (limited to 'lib/gitlab/cycle_analytics')
16 files changed, 196 insertions, 136 deletions
diff --git a/lib/gitlab/cycle_analytics/base_config.rb b/lib/gitlab/cycle_analytics/base_config.rb deleted file mode 100644 index 06ae9a15a7a..00000000000 --- a/lib/gitlab/cycle_analytics/base_config.rb +++ /dev/null @@ -1,17 +0,0 @@ -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 diff --git a/lib/gitlab/cycle_analytics/base_event.rb b/lib/gitlab/cycle_analytics/base_event.rb new file mode 100644 index 00000000000..254e3621575 --- /dev/null +++ b/lib/gitlab/cycle_analytics/base_event.rb @@ -0,0 +1,27 @@ +module Gitlab + module CycleAnalytics + class BaseEvent + extend MetricsTables + + class << self + attr_reader :stage, :start_time_attrs, :end_time_attrs, :projections + + def order + @order || @start_time_attrs + end + + def query(base_query); end + + def fetch(query) + query.execute(self).map { |event| serialize(event, query) } + end + + private + + def serialize(event, query) + raise NotImplementedError.new("Expected #{self.name} to implement serialize(event)") + end + end + end + end +end diff --git a/lib/gitlab/cycle_analytics/code_config.rb b/lib/gitlab/cycle_analytics/code_event.rb index c27419310db..609b45579b4 100644 --- a/lib/gitlab/cycle_analytics/code_config.rb +++ b/lib/gitlab/cycle_analytics/code_event.rb @@ -1,6 +1,7 @@ module Gitlab module CycleAnalytics - class CodeConfig < BaseConfig + class CodeEvent < BaseEvent + @stage = :code @start_time_attrs = issue_metrics_table[:first_mentioned_in_commit_at] @end_time_attrs = mr_table[:created_at] @@ -13,6 +14,12 @@ module Gitlab mr_table[:author_id]] @order = mr_table[:created_at] + + def self.serialize(event, query) + event['author'] = User.find(event.delete('author_id')) + + AnalyticsMergeRequestSerializer.new(project: query.project).represent(event).as_json + end end end end diff --git a/lib/gitlab/cycle_analytics/review_config.rb b/lib/gitlab/cycle_analytics/event_config.rb index e91dc1ea104..2e1400c41b9 100644 --- a/lib/gitlab/cycle_analytics/review_config.rb +++ b/lib/gitlab/cycle_analytics/event_config.rb @@ -1,6 +1,6 @@ module Gitlab module CycleAnalytics - class ReviewConfig < BaseConfig + class TestEvent < BaseEvent @start_time_attrs = mr_table[:created_at] @end_time_attrs = mr_metrics_table[:merged_at] diff --git a/lib/gitlab/cycle_analytics/events.rb b/lib/gitlab/cycle_analytics/events.rb index 8e6e6b2f4a3..6580c73128c 100644 --- a/lib/gitlab/cycle_analytics/events.rb +++ b/lib/gitlab/cycle_analytics/events.rb @@ -3,73 +3,35 @@ module Gitlab class Events def initialize(project:, options:) @project = project - @fetcher = EventsFetcher.new(project: project, options: options) + @query = EventsQuery.new(project: project, options: options) end def issue_events - @fetcher.fetch(stage: :issue).map { |event| serialize_event(event) } + IssueEvent.fetch(@query) end def plan_events - @fetcher.fetch(stage: :plan).map do |event| - st_commit = first_time_reference_commit(event.delete('commits'), event) - - next unless st_commit - - serialize_commit(event, st_commit) - end + PlanEvent.fetch(@query) end def code_events - @fetcher.fetch(stage: :code).map { |event| serialize_event(event, entity: :merge_request) } + CodeEvent.fetch(@query) end def test_events - @fetcher.fetch(stage: :test).map { |event| serialize_build_event(event) } + TestEvent.fetch(@query) end def review_events - @fetcher.fetch(stage: :review).map { |event| serialize_event(event, entity: :merge_request) } + ReviewEvent.fetch(@query) end def staging_events - @fetcher.fetch(stage: :staging).map { |event| serialize_build_event(event) } + StagingEvent.fetch(@query) end def production_events - @fetcher.fetch(stage: :production).map { |event| serialize_event(event) } - end - - private - - def serialize_event(event, entity: :issue) - event['author'] = User.find(event.delete('author_id')) - - AnalyticsGenericSerializer.new(project: @project, entity: entity).represent(event).as_json - end - - def serialize_build_event(event) - build = ::Ci::Build.find(event['id']) - - AnalyticsBuildSerializer.new.represent(build).as_json - end - - def first_time_reference_commit(commits, event) - YAML.load(commits).find do |commit| - next unless commit[:committed_date] && event['first_mentioned_in_commit_at'] - - commit[:committed_date].to_i == DateTime.parse(event['first_mentioned_in_commit_at'].to_s).to_i - end - end - - def serialize_commit(event, st_commit) - commit = Commit.new(Gitlab::Git::Commit.new(st_commit), @project) - - AnalyticsCommitSerializer.new(project: @project, total_time: event['total_time']).represent(commit).as_json - end - - def interval_in_words(diff) - "#{distance_of_time_in_words(diff.to_f)} ago" + ProductionEvent.fetch(@query) end end end diff --git a/lib/gitlab/cycle_analytics/events_fetcher.rb b/lib/gitlab/cycle_analytics/events_fetcher.rb index 4c1d19774f5..813db46f058 100644 --- a/lib/gitlab/cycle_analytics/events_fetcher.rb +++ b/lib/gitlab/cycle_analytics/events_fetcher.rb @@ -6,9 +6,7 @@ module Gitlab end def fetch(stage:) - @query.execute(stage) do |stage_class, base_query| - stage_class.query(base_query) - end + @query.execute(stage) end end end diff --git a/lib/gitlab/cycle_analytics/events_query.rb b/lib/gitlab/cycle_analytics/events_query.rb index b61320fc561..7ecdc07d17f 100644 --- a/lib/gitlab/cycle_analytics/events_query.rb +++ b/lib/gitlab/cycle_analytics/events_query.rb @@ -1,30 +1,30 @@ module Gitlab module CycleAnalytics class EventsQuery - include MetricsFetcher + attr_reader :project def initialize(project:, options: {}) @project = project @from = options[:from] @branch = options[:branch] + @fetcher = Gitlab::CycleAnalytics::MetricsFetcher.new(project: project, from: @from, branch: @branch) end - def execute(stage, &block) - @stage = stage - query = build_query(&block) + def execute(stage_class) + @stage_class = stage_class ActiveRecord::Base.connection.exec_query(query.to_sql) end private - def build_query - base_query = base_query_for(@stage) - diff_fn = subtract_datetimes_diff(base_query, stage_class.start_time_attrs, stage_class.end_time_attrs) + def query + base_query = @fetcher.base_query_for(@stage_class.stage) + diff_fn = @fetcher.subtract_datetimes_diff(base_query, @stage_class.start_time_attrs, @stage_class.end_time_attrs) - yield(stage_class, base_query) if block_given? + @stage_class.query(base_query) - base_query.project(extract_epoch(diff_fn).as('total_time'), *stage_class.projections).order(stage_class.order.desc) + base_query.project(extract_epoch(diff_fn).as('total_time'), *@stage_class.projections).order(@stage_class.order.desc) end def extract_epoch(arel_attribute) @@ -32,10 +32,6 @@ module Gitlab Arel.sql(%Q{EXTRACT(EPOCH FROM (#{arel_attribute.to_sql}))}) end - - def stage_class - @stage_class ||= "Gitlab::CycleAnalytics::#{@stage.to_s.camelize}Config".constantize - end end end end diff --git a/lib/gitlab/cycle_analytics/issue_config.rb b/lib/gitlab/cycle_analytics/issue_event.rb index 985ac76feb2..9cfcdc9b20e 100644 --- a/lib/gitlab/cycle_analytics/issue_config.rb +++ b/lib/gitlab/cycle_analytics/issue_event.rb @@ -1,6 +1,7 @@ module Gitlab module CycleAnalytics - class IssueConfig < BaseConfig + class IssueEvent < BaseEvent + @stage = :issue @start_time_attrs = issue_table[:created_at] @end_time_attrs = [issue_metrics_table[:first_associated_with_milestone_at], @@ -11,6 +12,12 @@ module Gitlab issue_table[:id], issue_table[:created_at], issue_table[:author_id]] + + def self.serialize(event, query) + event['author'] = User.find(event.delete('author_id')) + + AnalyticsIssueSerializer.new(project: query.project).represent(event).as_json + end end end end diff --git a/lib/gitlab/cycle_analytics/metrics_fetcher.rb b/lib/gitlab/cycle_analytics/metrics_fetcher.rb index 6743cbcc9e0..b71e8735e27 100644 --- a/lib/gitlab/cycle_analytics/metrics_fetcher.rb +++ b/lib/gitlab/cycle_analytics/metrics_fetcher.rb @@ -1,12 +1,18 @@ module Gitlab module CycleAnalytics - module MetricsFetcher + class MetricsFetcher include Gitlab::Database::Median include Gitlab::Database::DateTime + include MetricsTables DEPLOYMENT_METRIC_STAGES = %i[production staging] - private + def initialize(project:, from:, branch:) + @project = project + @project = project + @from = from + @branch = branch + end def calculate_metric(name, start_time_attrs, end_time_attrs) cte_table = Arel::Table.new("cte_table_for_#{name}") @@ -49,38 +55,6 @@ module Gitlab query end - - def mr_metrics_table - MergeRequest::Metrics.arel_table - end - - def mr_table - MergeRequest.arel_table - end - - def mr_diff_table - MergeRequestDiff.arel_table - end - - def mr_closing_issues_table - MergeRequestsClosingIssues.arel_table - end - - def issue_table - Issue.arel_table - end - - def issue_metrics_table - Issue::Metrics.arel_table - end - - def user_table - User.arel_table - end - - def build_table - ::CommitStatus.arel_table - end end end end diff --git a/lib/gitlab/cycle_analytics/metrics_tables.rb b/lib/gitlab/cycle_analytics/metrics_tables.rb new file mode 100644 index 00000000000..9d25ef078e8 --- /dev/null +++ b/lib/gitlab/cycle_analytics/metrics_tables.rb @@ -0,0 +1,37 @@ +module Gitlab + module CycleAnalytics + module MetricsTables + def mr_metrics_table + MergeRequest::Metrics.arel_table + end + + def mr_table + MergeRequest.arel_table + end + + def mr_diff_table + MergeRequestDiff.arel_table + end + + def mr_closing_issues_table + MergeRequestsClosingIssues.arel_table + end + + def issue_table + Issue.arel_table + end + + def issue_metrics_table + Issue::Metrics.arel_table + end + + def user_table + User.arel_table + end + + def build_table + ::CommitStatus.arel_table + end + end + end +end diff --git a/lib/gitlab/cycle_analytics/plan_config.rb b/lib/gitlab/cycle_analytics/plan_config.rb deleted file mode 100644 index 453ee26b4c9..00000000000 --- a/lib/gitlab/cycle_analytics/plan_config.rb +++ /dev/null @@ -1,17 +0,0 @@ -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 diff --git a/lib/gitlab/cycle_analytics/plan_event.rb b/lib/gitlab/cycle_analytics/plan_event.rb new file mode 100644 index 00000000000..b8107b06228 --- /dev/null +++ b/lib/gitlab/cycle_analytics/plan_event.rb @@ -0,0 +1,44 @@ +module Gitlab + module CycleAnalytics + class PlanEvent < BaseEvent + @stage = :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]] + + class << self + def query(base_query) + base_query.join(mr_diff_table).on(mr_diff_table[:merge_request_id].eq(mr_table[:id])) + end + + private + + def serialize(event, query) + st_commit = first_time_reference_commit(event.delete('commits'), event) + + return unless st_commit + + serialize_commit(event, st_commit, query) + end + + def first_time_reference_commit(commits, event) + YAML.load(commits).find do |commit| + next unless commit[:committed_date] && event['first_mentioned_in_commit_at'] + + commit[:committed_date].to_i == DateTime.parse(event['first_mentioned_in_commit_at'].to_s).to_i + end + end + + def serialize_commit(event, st_commit, query) + commit = Commit.new(Gitlab::Git::Commit.new(st_commit), @project) + + AnalyticsCommitSerializer.new(project: query.project, total_time: event['total_time']).represent(commit).as_json + end + end + end + end +end
\ No newline at end of file diff --git a/lib/gitlab/cycle_analytics/production_config.rb b/lib/gitlab/cycle_analytics/production_event.rb index dc9f1d5d059..b0b2d94f7e7 100644 --- a/lib/gitlab/cycle_analytics/production_config.rb +++ b/lib/gitlab/cycle_analytics/production_event.rb @@ -1,6 +1,7 @@ module Gitlab module CycleAnalytics - class ProductionConfig < BaseConfig + class ProductionEvent < BaseEvent + @stage = :production @start_time_attrs = issue_table[:created_at] @end_time_attrs = mr_metrics_table[:first_deployed_to_production_at] @@ -10,6 +11,12 @@ module Gitlab issue_table[:id], issue_table[:created_at], issue_table[:author_id]] + + def self.serialize(event, query) + event['author'] = User.find(event.delete('author_id')) + + AnalyticsIssueSerializer.new(project: query.project).represent(event).as_json + end end end end diff --git a/lib/gitlab/cycle_analytics/review_event.rb b/lib/gitlab/cycle_analytics/review_event.rb new file mode 100644 index 00000000000..dcd138eaa92 --- /dev/null +++ b/lib/gitlab/cycle_analytics/review_event.rb @@ -0,0 +1,21 @@ +module Gitlab + module CycleAnalytics + class ReviewEvent < BaseEvent + @stage = :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]] + + def self.serialize(event, _query) + event['author'] = User.find(event.delete('author_id')) + + AnalyticsMergeRequestSerializer.new(project: query.project).represent(event).as_json + end + end + end +end diff --git a/lib/gitlab/cycle_analytics/staging_config.rb b/lib/gitlab/cycle_analytics/staging_event.rb index f6f471286a0..a8872b50cfd 100644 --- a/lib/gitlab/cycle_analytics/staging_config.rb +++ b/lib/gitlab/cycle_analytics/staging_event.rb @@ -1,6 +1,7 @@ module Gitlab module CycleAnalytics - class StagingConfig < BaseConfig + class StagingEvent < BaseEvent + @stage = :staging @start_time_attrs = mr_metrics_table[:merged_at] @end_time_attrs = mr_metrics_table[:first_deployed_to_production_at] @projections = [build_table[:id]] @@ -9,6 +10,12 @@ module Gitlab def self.query(base_query) base_query.join(build_table).on(mr_metrics_table[:pipeline_id].eq(build_table[:commit_id])) end + + def self.serialize(event, _query) + build = ::Ci::Build.find(event['id']) + + AnalyticsBuildSerializer.new.represent(build).as_json + end end end end diff --git a/lib/gitlab/cycle_analytics/test_config.rb b/lib/gitlab/cycle_analytics/test_event.rb index 6cb80f9a62c..c91d3f47da0 100644 --- a/lib/gitlab/cycle_analytics/test_config.rb +++ b/lib/gitlab/cycle_analytics/test_event.rb @@ -1,6 +1,7 @@ module Gitlab module CycleAnalytics - class TestConfig < BaseConfig + class TestEvent < BaseEvent + @stage = :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]] @@ -9,6 +10,12 @@ module Gitlab def self.query(base_query) base_query.join(build_table).on(mr_metrics_table[:pipeline_id].eq(build_table[:commit_id])) end + + def self.serialize(event, _query) + build = ::Ci::Build.find(event['id']) + + AnalyticsBuildSerializer.new.represent(build).as_json + end end end end |