From 1a4ff5d720fa0ec65f925ef381fced3d5f9a040f Mon Sep 17 00:00:00 2001 From: James Lopez <james@jameslopez.es> Date: Thu, 20 Oct 2016 10:08:53 +0200 Subject: [PATCH] Added code events spec and logic. Also fixed SQL issues and refactored the code a bit. --- lib/gitlab/cycle_analytics/events.rb | 11 ++++-- lib/gitlab/cycle_analytics/events_fetcher.rb | 34 ++++++++++++++++--- lib/gitlab/cycle_analytics/metrics_fetcher.rb | 2 +- lib/gitlab/database/date_time.rb | 4 +-- .../lib/gitlab/cycle_analytics/events_spec.rb | 30 +++++++++++++++- 5 files changed, 70 insertions(+), 11 deletions(-) diff --git a/lib/gitlab/cycle_analytics/events.rb b/lib/gitlab/cycle_analytics/events.rb index 51fa4653634..ea8e78d7ab7 100644 --- a/lib/gitlab/cycle_analytics/events.rb +++ b/lib/gitlab/cycle_analytics/events.rb @@ -9,10 +9,10 @@ module Gitlab @fetcher = EventsFetcher.new(project: project, from: from) end - #TODO: backend pagination - specially for commits, etc... + # TODO: backend pagination - specially for commits, etc... def issue_events - #TODO figure out what the frontend needs for displaying the avatar + # TODO figure out what the frontend needs for displaying the avatar @fetcher.fetch_issue_events.each do |event| event['total_time'] = distance_of_time_in_words(event['total_time'].to_f) event['created_at'] = interval_in_words(event['created_at']) @@ -27,6 +27,13 @@ module Gitlab end end + def code_events + @fetcher.fetch_code_events.each do |event| + event['total_time'] = distance_of_time_in_words(event['total_time'].to_f) + event['created_at'] = interval_in_words(event['created_at']) + end + end + private def first_time_reference_commit(commits, event) diff --git a/lib/gitlab/cycle_analytics/events_fetcher.rb b/lib/gitlab/cycle_analytics/events_fetcher.rb index c25bc6c5f32..cb61cda200d 100644 --- a/lib/gitlab/cycle_analytics/events_fetcher.rb +++ b/lib/gitlab/cycle_analytics/events_fetcher.rb @@ -16,18 +16,33 @@ module Gitlab project(extract_epoch(diff_fn).as('total_time'), *issue_projections). order(issue_table[:created_at].desc) - ActiveRecord::Base.connection.execute(query.to_sql).to_a + execute(query) end def fetch_plan_events base_query = base_query_for(:plan) - diff_fn = subtract_datetimes_diff(base_query, issue_table[:created_at], plan_attributes) + diff_fn = subtract_datetimes_diff(base_query, + issue_metrics_table[:first_associated_with_milestone_at], + plan_attributes) query = base_query.join(mr_diff_table).on(mr_diff_table[:merge_request_id].eq(mr_table[:id])). project(extract_epoch(diff_fn).as('total_time'), *plan_projections). - order(issue_table[:created_at].desc) + order(issue_metrics_table[:first_associated_with_milestone_at].desc) - ActiveRecord::Base.connection.execute(query.to_sql).to_a + execute(query) + end + + def fetch_code_events + base_query = base_query_for(:code) + diff_fn = subtract_datetimes_diff(base_query, + issue_metrics_table[:first_mentioned_in_commit_at], + issue_table[:created_at]) + + query = base_query.join(user_table).on(issue_table[:author_id].eq(user_table[:id])). + project(extract_epoch(diff_fn).as('total_time'), *code_projections). + order(mr_table[:created_at].desc) + + execute(query) end private @@ -38,7 +53,8 @@ module Gitlab end def plan_attributes - issue_attributes + [issue_metrics_table[:first_mentioned_in_commit_at]] + [issue_metrics_table[:first_added_to_board_at], + issue_metrics_table[:first_mentioned_in_commit_at]] end def issue_projections @@ -49,6 +65,10 @@ module Gitlab [mr_diff_table[:st_commits].as('commits'), issue_metrics_table[:first_mentioned_in_commit_at]] end + def code_projections + [mr_table[:title], mr_table[:iid], mr_table[:created_at], User.arel_table[:name]] + end + def user_table User.arel_table end @@ -56,6 +76,10 @@ module Gitlab def extract_epoch(arel_attribute) Arel.sql(%Q{EXTRACT(EPOCH FROM (#{arel_attribute.to_sql}))}) end + + def execute(query) + ActiveRecord::Base.connection.execute(query.to_sql).to_a + end end end end diff --git a/lib/gitlab/cycle_analytics/metrics_fetcher.rb b/lib/gitlab/cycle_analytics/metrics_fetcher.rb index 7fcacf652a6..62988fbdec1 100644 --- a/lib/gitlab/cycle_analytics/metrics_fetcher.rb +++ b/lib/gitlab/cycle_analytics/metrics_fetcher.rb @@ -17,7 +17,7 @@ module Gitlab # cycle analytics stage. interval_query = Arel::Nodes::As.new( cte_table, - subtract_datetimes(base_query_for(name), end_time_attrs, start_time_attrs, name.to_s)) + subtract_datetimes(base_query_for(name), start_time_attrs, end_time_attrs, name.to_s)) median_datetime(cte_table, interval_query, name) end diff --git a/lib/gitlab/database/date_time.rb b/lib/gitlab/database/date_time.rb index e2524886de2..38a6fd4276b 100644 --- a/lib/gitlab/database/date_time.rb +++ b/lib/gitlab/database/date_time.rb @@ -7,13 +7,13 @@ module Gitlab # # Note: For MySQL, the interval is returned in seconds. # For PostgreSQL, the interval is returned as an INTERVAL type. - def subtract_datetimes(query_so_far, end_time_attrs, start_time_attrs, as) + def subtract_datetimes(query_so_far, start_time_attrs, end_time_attrs, as) diff_fn = subtract_datetimes_diff(query_so_far, end_time_attrs, start_time_attrs) query_so_far.project(diff_fn.as(as)) end - def subtract_datetimes_diff(query_so_far, end_time_attrs, start_time_attrs) + def subtract_datetimes_diff(query_so_far, start_time_attrs, end_time_attrs) if Gitlab::Database.postgresql? Arel::Nodes::Subtraction.new( Arel::Nodes::NamedFunction.new("COALESCE", Array.wrap(end_time_attrs)), diff --git a/spec/lib/gitlab/cycle_analytics/events_spec.rb b/spec/lib/gitlab/cycle_analytics/events_spec.rb index 4f8ba465d71..4a329737c7e 100644 --- a/spec/lib/gitlab/cycle_analytics/events_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/events_spec.rb @@ -43,7 +43,35 @@ describe Gitlab::CycleAnalytics::Events do end it 'has the total time' do - expect(subject.plan_events.first['total_time']).to eq('2 days') + expect(subject.plan_events.first['total_time']).to eq('less than a minute') + end + end + + describe '#code_events' do + let!(:context) { create(:issue, project: project, created_at: 2.days.ago) } + + before do + create_commit_referencing_issue(context) + end + + it 'has the total time' do + expect(subject.code_events.first['total_time']).to eq('2 days') + end + + it 'has a title' do + expect(subject.code_events.first['title']).to eq('Awesome merge_request') + end + + it 'has an iid' do + expect(subject.code_events.first['iid']).to eq(context.iid.to_s) + end + + it 'has a created_at timestamp' do + expect(subject.code_events.first['created_at']).to end_with('ago') + end + + it "has the author's name" do + expect(subject.code_events.first['name']).to eq(context.author.name) end end -- GitLab