summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGosia Ksionek <mksionek@gitlab.com>2019-06-17 13:17:18 +0000
committerJames Lopez <james@gitlab.com>2019-06-17 13:17:18 +0000
commit976b8b5391199f18a099021639e206f8acc52008 (patch)
tree64b0947ff325b54fe841cd5f10619628ecd6de80
parentea1aa785733d654ac11b239b121ba2acbc183406 (diff)
downloadgitlab-ce-976b8b5391199f18a099021639e206f8acc52008.tar.gz
Fix plan stage query
Fix plan stage query and the way it is displayed
-rw-r--r--app/assets/javascripts/cycle_analytics/components/stage_plan_component.vue59
-rw-r--r--app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js3
-rw-r--r--changelogs/unreleased/30138-display-cycle-analytics-issue-logic-fixes.yml5
-rw-r--r--lib/gitlab/cycle_analytics/builds_event_helper.rb36
-rw-r--r--lib/gitlab/cycle_analytics/code_event_fetcher.rb2
-rw-r--r--lib/gitlab/cycle_analytics/code_helper.rb11
-rw-r--r--lib/gitlab/cycle_analytics/code_stage.rb2
-rw-r--r--lib/gitlab/cycle_analytics/issue_event_fetcher.rb2
-rw-r--r--lib/gitlab/cycle_analytics/issue_helper.rb17
-rw-r--r--lib/gitlab/cycle_analytics/issue_stage.rb2
-rw-r--r--lib/gitlab/cycle_analytics/plan_event_fetcher.rb54
-rw-r--r--lib/gitlab/cycle_analytics/plan_helper.rb18
-rw-r--r--lib/gitlab/cycle_analytics/plan_stage.rb4
-rw-r--r--lib/gitlab/cycle_analytics/production_event_fetcher.rb23
-rw-r--r--lib/gitlab/cycle_analytics/review_event_fetcher.rb2
-rw-r--r--lib/gitlab/cycle_analytics/review_helper.rb11
-rw-r--r--lib/gitlab/cycle_analytics/review_stage.rb2
-rw-r--r--lib/gitlab/cycle_analytics/staging_event_fetcher.rb30
-rw-r--r--lib/gitlab/cycle_analytics/staging_stage.rb1
-rw-r--r--lib/gitlab/cycle_analytics/test_event_fetcher.rb4
-rw-r--r--lib/gitlab/cycle_analytics/test_helper.rb21
-rw-r--r--lib/gitlab/cycle_analytics/test_stage.rb10
-rw-r--r--locale/gitlab.pot9
-rw-r--r--spec/features/cycle_analytics_spec.rb2
-rw-r--r--spec/lib/gitlab/cycle_analytics/code_stage_spec.rb36
-rw-r--r--spec/lib/gitlab/cycle_analytics/events_spec.rb31
-rw-r--r--spec/lib/gitlab/cycle_analytics/issue_stage_spec.rb31
-rw-r--r--spec/lib/gitlab/cycle_analytics/plan_stage_spec.rb31
-rw-r--r--spec/lib/gitlab/cycle_analytics/review_stage_spec.rb37
-rw-r--r--spec/lib/gitlab/cycle_analytics/shared_stage_spec.rb2
-rw-r--r--spec/lib/gitlab/cycle_analytics/staging_stage_spec.rb41
-rw-r--r--spec/requests/projects/cycle_analytics_events_spec.rb4
32 files changed, 379 insertions, 164 deletions
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_plan_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_plan_component.vue
deleted file mode 100644
index 6c256fa6736..00000000000
--- a/app/assets/javascripts/cycle_analytics/components/stage_plan_component.vue
+++ /dev/null
@@ -1,59 +0,0 @@
-<script>
-import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
-import iconCommit from '../svg/icon_commit.svg';
-import limitWarning from './limit_warning_component.vue';
-import totalTime from './total_time_component.vue';
-
-export default {
- components: {
- userAvatarImage,
- totalTime,
- limitWarning,
- },
- props: {
- items: {
- type: Array,
- default: () => [],
- },
- stage: {
- type: Object,
- default: () => ({}),
- },
- },
- computed: {
- iconCommit() {
- return iconCommit;
- },
- },
-};
-</script>
-<template>
- <div>
- <div class="events-description">
- {{ stage.description }}
- <limit-warning :count="items.length" />
- </div>
- <ul class="stage-event-list">
- <li v-for="(commit, i) in items" :key="i" class="stage-event-item">
- <div class="item-details item-conmmit-component">
- <!-- FIXME: Pass an alt attribute here for accessibility -->
- <user-avatar-image :img-src="commit.author.avatarUrl" />
- <h5 class="item-title commit-title">
- <a :href="commit.commitUrl"> {{ commit.title }} </a>
- </h5>
- <span>
- {{ s__('FirstPushedBy|First') }} <span class="commit-icon" v-html="iconCommit"> </span>
- <a :href="commit.commitUrl" class="commit-hash-link commit-sha">{{
- commit.shortSha
- }}</a>
- {{ s__('FirstPushedBy|pushed by') }}
- <a :href="commit.author.webUrl" class="commit-author-link">
- {{ commit.author.name }}
- </a>
- </span>
- </div>
- <div class="item-time"><total-time :time="commit.totalTime" /></div>
- </li>
- </ul>
- </div>
-</template>
diff --git a/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js b/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js
index 3f0a9f2602c..b56e08175cc 100644
--- a/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js
+++ b/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js
@@ -5,7 +5,6 @@ import Flash from '../flash';
import Translate from '../vue_shared/translate';
import banner from './components/banner.vue';
import stageCodeComponent from './components/stage_code_component.vue';
-import stagePlanComponent from './components/stage_plan_component.vue';
import stageComponent from './components/stage_component.vue';
import stageReviewComponent from './components/stage_review_component.vue';
import stageStagingComponent from './components/stage_staging_component.vue';
@@ -26,7 +25,7 @@ export default () => {
components: {
banner,
'stage-issue-component': stageComponent,
- 'stage-plan-component': stagePlanComponent,
+ 'stage-plan-component': stageComponent,
'stage-code-component': stageCodeComponent,
'stage-test-component': stageTestComponent,
'stage-review-component': stageReviewComponent,
diff --git a/changelogs/unreleased/30138-display-cycle-analytics-issue-logic-fixes.yml b/changelogs/unreleased/30138-display-cycle-analytics-issue-logic-fixes.yml
new file mode 100644
index 00000000000..574995f20fa
--- /dev/null
+++ b/changelogs/unreleased/30138-display-cycle-analytics-issue-logic-fixes.yml
@@ -0,0 +1,5 @@
+---
+title: Change logic behind cycle analytics
+merge_request: 29018
+author:
+type: changed
diff --git a/lib/gitlab/cycle_analytics/builds_event_helper.rb b/lib/gitlab/cycle_analytics/builds_event_helper.rb
new file mode 100644
index 00000000000..0d6f32fdc6f
--- /dev/null
+++ b/lib/gitlab/cycle_analytics/builds_event_helper.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module CycleAnalytics
+ module BuildsEventHelper
+ def initialize(*args)
+ @projections = [build_table[:id]]
+ @order = build_table[:created_at]
+
+ super(*args)
+ end
+
+ def fetch
+ Updater.update!(event_result, from: 'id', to: 'build', klass: ::Ci::Build)
+
+ super
+ end
+
+ def events_query
+ base_query.join(build_table).on(mr_metrics_table[:pipeline_id].eq(build_table[:commit_id]))
+
+ super
+ end
+
+ private
+
+ def allowed_ids
+ nil
+ end
+
+ def serialize(event)
+ AnalyticsBuildSerializer.new.represent(event['build'])
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/cycle_analytics/code_event_fetcher.rb b/lib/gitlab/cycle_analytics/code_event_fetcher.rb
index 591db3c35e6..6c348f1862d 100644
--- a/lib/gitlab/cycle_analytics/code_event_fetcher.rb
+++ b/lib/gitlab/cycle_analytics/code_event_fetcher.rb
@@ -3,6 +3,8 @@
module Gitlab
module CycleAnalytics
class CodeEventFetcher < BaseEventFetcher
+ include CodeHelper
+
def initialize(*args)
@projections = [mr_table[:title],
mr_table[:iid],
diff --git a/lib/gitlab/cycle_analytics/code_helper.rb b/lib/gitlab/cycle_analytics/code_helper.rb
new file mode 100644
index 00000000000..8f28bdd2502
--- /dev/null
+++ b/lib/gitlab/cycle_analytics/code_helper.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module CycleAnalytics
+ module CodeHelper
+ def stage_query(project_ids)
+ super(project_ids).where(mr_table[:created_at].gteq(issue_metrics_table[:first_mentioned_in_commit_at]))
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/cycle_analytics/code_stage.rb b/lib/gitlab/cycle_analytics/code_stage.rb
index 2e5f9ef5a40..89a6430221c 100644
--- a/lib/gitlab/cycle_analytics/code_stage.rb
+++ b/lib/gitlab/cycle_analytics/code_stage.rb
@@ -3,6 +3,8 @@
module Gitlab
module CycleAnalytics
class CodeStage < BaseStage
+ include CodeHelper
+
def start_time_attrs
@start_time_attrs ||= issue_metrics_table[:first_mentioned_in_commit_at]
end
diff --git a/lib/gitlab/cycle_analytics/issue_event_fetcher.rb b/lib/gitlab/cycle_analytics/issue_event_fetcher.rb
index 30c6ead8968..8a870f2e2a3 100644
--- a/lib/gitlab/cycle_analytics/issue_event_fetcher.rb
+++ b/lib/gitlab/cycle_analytics/issue_event_fetcher.rb
@@ -3,6 +3,8 @@
module Gitlab
module CycleAnalytics
class IssueEventFetcher < BaseEventFetcher
+ include IssueHelper
+
def initialize(*args)
@projections = [issue_table[:title],
issue_table[:iid],
diff --git a/lib/gitlab/cycle_analytics/issue_helper.rb b/lib/gitlab/cycle_analytics/issue_helper.rb
new file mode 100644
index 00000000000..c9266341378
--- /dev/null
+++ b/lib/gitlab/cycle_analytics/issue_helper.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module CycleAnalytics
+ module IssueHelper
+ def stage_query(project_ids)
+ query = issue_table.join(issue_metrics_table).on(issue_table[:id].eq(issue_metrics_table[:issue_id]))
+ .project(issue_table[:project_id].as("project_id"))
+ .where(issue_table[:project_id].in(project_ids))
+ .where(issue_table[:created_at].gteq(@options[:from])) # rubocop:disable Gitlab/ModuleWithInstanceVariables
+ .where(issue_metrics_table[:first_added_to_board_at].not_eq(nil).or(issue_metrics_table[:first_associated_with_milestone_at].not_eq(nil)))
+
+ query
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/cycle_analytics/issue_stage.rb b/lib/gitlab/cycle_analytics/issue_stage.rb
index 4eae2da512c..738cb3eba03 100644
--- a/lib/gitlab/cycle_analytics/issue_stage.rb
+++ b/lib/gitlab/cycle_analytics/issue_stage.rb
@@ -3,6 +3,8 @@
module Gitlab
module CycleAnalytics
class IssueStage < BaseStage
+ include IssueHelper
+
def start_time_attrs
@start_time_attrs ||= issue_table[:created_at]
end
diff --git a/lib/gitlab/cycle_analytics/plan_event_fetcher.rb b/lib/gitlab/cycle_analytics/plan_event_fetcher.rb
index aeca9d00156..d924f956dcd 100644
--- a/lib/gitlab/cycle_analytics/plan_event_fetcher.rb
+++ b/lib/gitlab/cycle_analytics/plan_event_fetcher.rb
@@ -3,60 +3,26 @@
module Gitlab
module CycleAnalytics
class PlanEventFetcher < BaseEventFetcher
+ include PlanHelper
+
def initialize(*args)
- @projections = [mr_diff_table[:id],
- issue_metrics_table[:first_mentioned_in_commit_at]]
+ @projections = [issue_table[:title],
+ issue_table[:iid],
+ issue_table[:id],
+ issue_table[:created_at],
+ issue_table[:author_id]]
super(*args)
end
- def events_query
- base_query
- .join(mr_diff_table)
- .on(mr_diff_table[:merge_request_id].eq(mr_table[:id]))
-
- super
- end
-
private
- def allowed_ids
- nil
- end
-
- def merge_request_diff_commits
- @merge_request_diff_commits ||=
- MergeRequestDiffCommit
- .where(merge_request_diff_id: event_result.map { |event| event['id'] })
- .group_by(&:merge_request_diff_id)
- end
-
def serialize(event)
- commit = first_time_reference_commit(event)
-
- return unless commit
-
- serialize_commit(event, commit, query)
- end
-
- def first_time_reference_commit(event)
- return unless event && merge_request_diff_commits
-
- commits = merge_request_diff_commits[event['id'].to_i]
-
- return if commits.blank?
-
- 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
+ AnalyticsIssueSerializer.new(project: @project).represent(event)
end
- def serialize_commit(event, commit, query)
- commit = Commit.from_hash(commit.to_hash, @project)
-
- AnalyticsCommitSerializer.new(project: @project, total_time: event['total_time']).represent(commit)
+ def allowed_ids_finder_class
+ IssuesFinder
end
end
end
diff --git a/lib/gitlab/cycle_analytics/plan_helper.rb b/lib/gitlab/cycle_analytics/plan_helper.rb
new file mode 100644
index 00000000000..30fc2ce6d40
--- /dev/null
+++ b/lib/gitlab/cycle_analytics/plan_helper.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module CycleAnalytics
+ module PlanHelper
+ def stage_query(project_ids)
+ query = issue_table.join(issue_metrics_table).on(issue_table[:id].eq(issue_metrics_table[:issue_id]))
+ .project(issue_table[:project_id].as("project_id"))
+ .where(issue_table[:project_id].in(project_ids))
+ .where(issue_table[:created_at].gteq(@options[:from])) # rubocop:disable Gitlab/ModuleWithInstanceVariables
+ .where(issue_metrics_table[:first_added_to_board_at].not_eq(nil).or(issue_metrics_table[:first_associated_with_milestone_at].not_eq(nil)))
+ .where(issue_metrics_table[:first_mentioned_in_commit_at].not_eq(nil))
+
+ query
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/cycle_analytics/plan_stage.rb b/lib/gitlab/cycle_analytics/plan_stage.rb
index 513e4575be0..0b27d114f52 100644
--- a/lib/gitlab/cycle_analytics/plan_stage.rb
+++ b/lib/gitlab/cycle_analytics/plan_stage.rb
@@ -3,6 +3,8 @@
module Gitlab
module CycleAnalytics
class PlanStage < BaseStage
+ include PlanHelper
+
def start_time_attrs
@start_time_attrs ||= [issue_metrics_table[:first_associated_with_milestone_at],
issue_metrics_table[:first_added_to_board_at]]
@@ -21,7 +23,7 @@ module Gitlab
end
def legend
- _("Related Commits")
+ _("Related Issues")
end
def description
diff --git a/lib/gitlab/cycle_analytics/production_event_fetcher.rb b/lib/gitlab/cycle_analytics/production_event_fetcher.rb
index 6681cb42c90..6bcbe0412a9 100644
--- a/lib/gitlab/cycle_analytics/production_event_fetcher.rb
+++ b/lib/gitlab/cycle_analytics/production_event_fetcher.rb
@@ -2,7 +2,28 @@
module Gitlab
module CycleAnalytics
- class ProductionEventFetcher < IssueEventFetcher
+ class ProductionEventFetcher < BaseEventFetcher
+ include ProductionHelper
+
+ def initialize(*args)
+ @projections = [issue_table[:title],
+ issue_table[:iid],
+ issue_table[:id],
+ issue_table[:created_at],
+ issue_table[:author_id]]
+
+ super(*args)
+ end
+
+ private
+
+ def serialize(event)
+ AnalyticsIssueSerializer.new(project: @project).represent(event)
+ end
+
+ def allowed_ids_finder_class
+ IssuesFinder
+ end
end
end
end
diff --git a/lib/gitlab/cycle_analytics/review_event_fetcher.rb b/lib/gitlab/cycle_analytics/review_event_fetcher.rb
index de100295281..b6354b5ffad 100644
--- a/lib/gitlab/cycle_analytics/review_event_fetcher.rb
+++ b/lib/gitlab/cycle_analytics/review_event_fetcher.rb
@@ -3,6 +3,8 @@
module Gitlab
module CycleAnalytics
class ReviewEventFetcher < BaseEventFetcher
+ include ReviewHelper
+
def initialize(*args)
@projections = [mr_table[:title],
mr_table[:iid],
diff --git a/lib/gitlab/cycle_analytics/review_helper.rb b/lib/gitlab/cycle_analytics/review_helper.rb
new file mode 100644
index 00000000000..c53249652b5
--- /dev/null
+++ b/lib/gitlab/cycle_analytics/review_helper.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module CycleAnalytics
+ module ReviewHelper
+ def stage_query(project_ids)
+ super(project_ids).where(mr_metrics_table[:merged_at].not_eq(nil))
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/cycle_analytics/review_stage.rb b/lib/gitlab/cycle_analytics/review_stage.rb
index 294b656bc55..e9df8cd5a05 100644
--- a/lib/gitlab/cycle_analytics/review_stage.rb
+++ b/lib/gitlab/cycle_analytics/review_stage.rb
@@ -3,6 +3,8 @@
module Gitlab
module CycleAnalytics
class ReviewStage < BaseStage
+ include ReviewHelper
+
def start_time_attrs
@start_time_attrs ||= mr_table[:created_at]
end
diff --git a/lib/gitlab/cycle_analytics/staging_event_fetcher.rb b/lib/gitlab/cycle_analytics/staging_event_fetcher.rb
index 70ce82383b3..1454a1a33eb 100644
--- a/lib/gitlab/cycle_analytics/staging_event_fetcher.rb
+++ b/lib/gitlab/cycle_analytics/staging_event_fetcher.rb
@@ -3,34 +3,8 @@
module Gitlab
module CycleAnalytics
class StagingEventFetcher < BaseEventFetcher
- def initialize(*args)
- @projections = [build_table[:id]]
- @order = build_table[:created_at]
-
- super(*args)
- end
-
- def fetch
- Updater.update!(event_result, from: 'id', to: 'build', klass: ::Ci::Build)
-
- super
- end
-
- def events_query
- base_query.join(build_table).on(mr_metrics_table[:pipeline_id].eq(build_table[:commit_id]))
-
- super
- end
-
- private
-
- def allowed_ids
- nil
- end
-
- def serialize(event)
- AnalyticsBuildSerializer.new.represent(event['build'])
- end
+ include ProductionHelper
+ include BuildsEventHelper
end
end
end
diff --git a/lib/gitlab/cycle_analytics/staging_stage.rb b/lib/gitlab/cycle_analytics/staging_stage.rb
index dbc2414ff66..e03627c6cd1 100644
--- a/lib/gitlab/cycle_analytics/staging_stage.rb
+++ b/lib/gitlab/cycle_analytics/staging_stage.rb
@@ -4,6 +4,7 @@ module Gitlab
module CycleAnalytics
class StagingStage < BaseStage
include ProductionHelper
+
def start_time_attrs
@start_time_attrs ||= mr_metrics_table[:merged_at]
end
diff --git a/lib/gitlab/cycle_analytics/test_event_fetcher.rb b/lib/gitlab/cycle_analytics/test_event_fetcher.rb
index 4d5ea5b7c34..2fa44b1b364 100644
--- a/lib/gitlab/cycle_analytics/test_event_fetcher.rb
+++ b/lib/gitlab/cycle_analytics/test_event_fetcher.rb
@@ -2,7 +2,9 @@
module Gitlab
module CycleAnalytics
- class TestEventFetcher < StagingEventFetcher
+ class TestEventFetcher < BaseEventFetcher
+ include TestHelper
+ include BuildsEventHelper
end
end
end
diff --git a/lib/gitlab/cycle_analytics/test_helper.rb b/lib/gitlab/cycle_analytics/test_helper.rb
new file mode 100644
index 00000000000..32fca7fa898
--- /dev/null
+++ b/lib/gitlab/cycle_analytics/test_helper.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module CycleAnalytics
+ module TestHelper
+ def stage_query(project_ids)
+ if branch
+ super(project_ids).where(build_table[:ref].eq(branch))
+ else
+ super(project_ids)
+ end
+ end
+
+ private
+
+ def branch
+ @branch ||= @options[:branch] # rubocop:disable Gitlab/ModuleWithInstanceVariables
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/cycle_analytics/test_stage.rb b/lib/gitlab/cycle_analytics/test_stage.rb
index c31b664148b..4787a906c07 100644
--- a/lib/gitlab/cycle_analytics/test_stage.rb
+++ b/lib/gitlab/cycle_analytics/test_stage.rb
@@ -3,6 +3,8 @@
module Gitlab
module CycleAnalytics
class TestStage < BaseStage
+ include TestHelper
+
def start_time_attrs
@start_time_attrs ||= mr_metrics_table[:latest_build_started_at]
end
@@ -26,14 +28,6 @@ module Gitlab
def description
_("Total test time for all commits/merges")
end
-
- def stage_query(project_ids)
- if @options[:branch]
- super(project_ids).where(build_table[:ref].eq(@options[:branch]))
- else
- super(project_ids)
- end
- end
end
end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 53a1d1c5466..186c4cb2dba 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -4500,12 +4500,6 @@ msgstr ""
msgid "First day of the week"
msgstr ""
-msgid "FirstPushedBy|First"
-msgstr ""
-
-msgid "FirstPushedBy|pushed by"
-msgstr ""
-
msgid "FlowdockService|Flowdock Git source token"
msgstr ""
@@ -8313,9 +8307,6 @@ msgstr ""
msgid "Registry"
msgstr ""
-msgid "Related Commits"
-msgstr ""
-
msgid "Related Deployed Jobs"
msgstr ""
diff --git a/spec/features/cycle_analytics_spec.rb b/spec/features/cycle_analytics_spec.rb
index 48edc764a8e..4108a0f370d 100644
--- a/spec/features/cycle_analytics_spec.rb
+++ b/spec/features/cycle_analytics_spec.rb
@@ -58,7 +58,7 @@ describe 'Cycle Analytics', :js do
expect_issue_to_be_present
click_stage('Plan')
- expect(find('.stage-events')).to have_content(mr.commits.last.title)
+ expect_issue_to_be_present
click_stage('Code')
expect_merge_request_to_be_present
diff --git a/spec/lib/gitlab/cycle_analytics/code_stage_spec.rb b/spec/lib/gitlab/cycle_analytics/code_stage_spec.rb
index e8fc67acf05..c738cc49c1f 100644
--- a/spec/lib/gitlab/cycle_analytics/code_stage_spec.rb
+++ b/spec/lib/gitlab/cycle_analytics/code_stage_spec.rb
@@ -4,5 +4,41 @@ require 'lib/gitlab/cycle_analytics/shared_stage_spec'
describe Gitlab::CycleAnalytics::CodeStage do
let(:stage_name) { :code }
+ let(:project) { create(:project) }
+ let!(:issue_1) { create(:issue, project: project, created_at: 90.minutes.ago) }
+ let!(:issue_2) { create(:issue, project: project, created_at: 60.minutes.ago) }
+ let!(:issue_3) { create(:issue, project: project, created_at: 60.minutes.ago) }
+ let!(:mr_1) { create(:merge_request, source_project: project, created_at: 15.minutes.ago) }
+ let!(:mr_2) { create(:merge_request, source_project: project, created_at: 10.minutes.ago, source_branch: 'A') }
+ let!(:mr_3) { create(:merge_request, source_project: project, created_at: 10.minutes.ago, source_branch: 'B') }
+ let(:stage) { described_class.new(project: project, options: { from: 2.days.ago, current_user: project.creator }) }
+
+ before do
+ issue_1.metrics.update!(first_associated_with_milestone_at: 60.minutes.ago, first_mentioned_in_commit_at: 45.minutes.ago)
+ issue_2.metrics.update!(first_added_to_board_at: 60.minutes.ago, first_mentioned_in_commit_at: 40.minutes.ago)
+ issue_3.metrics.update!(first_added_to_board_at: 60.minutes.ago, first_mentioned_in_commit_at: 40.minutes.ago)
+ create(:merge_requests_closing_issues, merge_request: mr_1, issue: issue_1)
+ create(:merge_requests_closing_issues, merge_request: mr_2, issue: issue_2)
+ end
+
it_behaves_like 'base stage'
+
+ describe '#median' do
+ around do |example|
+ Timecop.freeze { example.run }
+ end
+
+ it 'counts median from issues with metrics' do
+ expect(stage.median).to eq(ISSUES_MEDIAN)
+ end
+ end
+
+ describe '#events' do
+ it 'exposes merge requests that closes issues' do
+ result = stage.events
+
+ expect(result.count).to eq(2)
+ expect(result.map { |event| event[:title] }).to contain_exactly(mr_1.title, mr_2.title)
+ end
+ end
end
diff --git a/spec/lib/gitlab/cycle_analytics/events_spec.rb b/spec/lib/gitlab/cycle_analytics/events_spec.rb
index 397dd4e5d2c..f8b103c0fab 100644
--- a/spec/lib/gitlab/cycle_analytics/events_spec.rb
+++ b/spec/lib/gitlab/cycle_analytics/events_spec.rb
@@ -53,20 +53,28 @@ describe 'cycle analytics events' do
describe '#plan_events' do
let(:stage) { :plan }
- it 'has a title' do
- expect(events.first[:title]).not_to be_nil
+ before do
+ create_commit_referencing_issue(context)
end
- it 'has a sha short ID' do
- expect(events.first[:short_sha]).not_to be_nil
+ it 'has the total time' do
+ expect(events.first[:total_time]).not_to be_empty
+ end
+
+ it 'has a title' do
+ expect(events.first[:title]).to eq(context.title)
end
it 'has the URL' do
- expect(events.first[:commit_url]).not_to be_nil
+ expect(events.first[:url]).not_to be_nil
end
- it 'has the total time' do
- expect(events.first[:total_time]).not_to be_empty
+ it 'has an iid' do
+ expect(events.first[:iid]).to eq(context.iid.to_s)
+ end
+
+ it 'has a created_at timestamp' do
+ expect(events.first[:created_at]).to end_with('ago')
end
it "has the author's URL" do
@@ -78,12 +86,13 @@ describe 'cycle analytics events' do
end
it "has the author's name" do
- expect(events.first[:author][:name]).not_to be_nil
+ expect(events.first[:author][:name]).to eq(context.author.name)
end
end
describe '#code_events' do
let(:stage) { :code }
+ let!(:merge_request) { MergeRequest.first }
before do
create_commit_referencing_issue(context)
@@ -122,6 +131,7 @@ describe 'cycle analytics events' do
let(:stage) { :test }
let(:merge_request) { MergeRequest.first }
+ let!(:context) { create(:issue, project: project, created_at: 2.days.ago) }
let!(:pipeline) do
create(:ci_pipeline,
@@ -137,6 +147,7 @@ describe 'cycle analytics events' do
pipeline.run!
pipeline.succeed!
+ merge_merge_requests_closing_issue(user, project, context)
end
it 'has the name' do
@@ -180,6 +191,10 @@ describe 'cycle analytics events' do
let(:stage) { :review }
let!(:context) { create(:issue, project: project, created_at: 2.days.ago) }
+ before do
+ merge_merge_requests_closing_issue(user, project, context)
+ end
+
it 'has the total time' do
expect(events.first[:total_time]).not_to be_empty
end
diff --git a/spec/lib/gitlab/cycle_analytics/issue_stage_spec.rb b/spec/lib/gitlab/cycle_analytics/issue_stage_spec.rb
index 3127f01989d..3b6af9cbaed 100644
--- a/spec/lib/gitlab/cycle_analytics/issue_stage_spec.rb
+++ b/spec/lib/gitlab/cycle_analytics/issue_stage_spec.rb
@@ -3,6 +3,37 @@ require 'lib/gitlab/cycle_analytics/shared_stage_spec'
describe Gitlab::CycleAnalytics::IssueStage do
let(:stage_name) { :issue }
+ let(:project) { create(:project) }
+ let!(:issue_1) { create(:issue, project: project, created_at: 90.minutes.ago) }
+ let!(:issue_2) { create(:issue, project: project, created_at: 60.minutes.ago) }
+ let!(:issue_3) { create(:issue, project: project, created_at: 30.minutes.ago) }
+ let!(:issue_without_milestone) { create(:issue, project: project, created_at: 1.minute.ago) }
+ let(:stage) { described_class.new(project: project, options: { from: 2.days.ago, current_user: project.creator }) }
+
+ before do
+ issue_1.metrics.update!(first_associated_with_milestone_at: 60.minutes.ago )
+ issue_2.metrics.update!(first_added_to_board_at: 30.minutes.ago)
+ issue_3.metrics.update!(first_added_to_board_at: 15.minutes.ago)
+ end
it_behaves_like 'base stage'
+
+ describe '#median' do
+ around do |example|
+ Timecop.freeze { example.run }
+ end
+
+ it 'counts median from issues with metrics' do
+ expect(stage.median).to eq(ISSUES_MEDIAN)
+ end
+ end
+
+ describe '#events' do
+ it 'exposes issues with metrics' do
+ result = stage.events
+
+ expect(result.count).to eq(3)
+ expect(result.map { |event| event[:title] }).to contain_exactly(issue_1.title, issue_2.title, issue_3.title)
+ end
+ end
end
diff --git a/spec/lib/gitlab/cycle_analytics/plan_stage_spec.rb b/spec/lib/gitlab/cycle_analytics/plan_stage_spec.rb
index 4c715921ad6..506a8160412 100644
--- a/spec/lib/gitlab/cycle_analytics/plan_stage_spec.rb
+++ b/spec/lib/gitlab/cycle_analytics/plan_stage_spec.rb
@@ -3,6 +3,37 @@ require 'lib/gitlab/cycle_analytics/shared_stage_spec'
describe Gitlab::CycleAnalytics::PlanStage do
let(:stage_name) { :plan }
+ let(:project) { create(:project) }
+ let!(:issue_1) { create(:issue, project: project, created_at: 90.minutes.ago) }
+ let!(:issue_2) { create(:issue, project: project, created_at: 60.minutes.ago) }
+ let!(:issue_3) { create(:issue, project: project, created_at: 30.minutes.ago) }
+ let!(:issue_without_milestone) { create(:issue, project: project, created_at: 1.minute.ago) }
+ let(:stage) { described_class.new(project: project, options: { from: 2.days.ago, current_user: project.creator }) }
+
+ before do
+ issue_1.metrics.update!(first_associated_with_milestone_at: 60.minutes.ago, first_mentioned_in_commit_at: 10.minutes.ago)
+ issue_2.metrics.update!(first_added_to_board_at: 30.minutes.ago, first_mentioned_in_commit_at: 20.minutes.ago)
+ issue_3.metrics.update!(first_added_to_board_at: 15.minutes.ago)
+ end
it_behaves_like 'base stage'
+
+ describe '#median' do
+ around do |example|
+ Timecop.freeze { example.run }
+ end
+
+ it 'counts median from issues with metrics' do
+ expect(stage.median).to eq(ISSUES_MEDIAN)
+ end
+ end
+
+ describe '#events' do
+ it 'exposes issues with metrics' do
+ result = stage.events
+
+ expect(result.count).to eq(2)
+ expect(result.map { |event| event[:title] }).to contain_exactly(issue_1.title, issue_2.title)
+ end
+ end
end
diff --git a/spec/lib/gitlab/cycle_analytics/review_stage_spec.rb b/spec/lib/gitlab/cycle_analytics/review_stage_spec.rb
index 1412c8dfa08..f072a9644e8 100644
--- a/spec/lib/gitlab/cycle_analytics/review_stage_spec.rb
+++ b/spec/lib/gitlab/cycle_analytics/review_stage_spec.rb
@@ -3,6 +3,43 @@ require 'lib/gitlab/cycle_analytics/shared_stage_spec'
describe Gitlab::CycleAnalytics::ReviewStage do
let(:stage_name) { :review }
+ let(:project) { create(:project) }
+ let!(:issue_1) { create(:issue, project: project, created_at: 90.minutes.ago) }
+ let!(:issue_2) { create(:issue, project: project, created_at: 60.minutes.ago) }
+ let!(:issue_3) { create(:issue, project: project, created_at: 60.minutes.ago) }
+ let!(:mr_1) { create(:merge_request, :closed, source_project: project, created_at: 60.minutes.ago) }
+ let!(:mr_2) { create(:merge_request, :closed, source_project: project, created_at: 40.minutes.ago, source_branch: 'A') }
+ let!(:mr_3) { create(:merge_request, source_project: project, created_at: 10.minutes.ago, source_branch: 'B') }
+ let!(:mr_4) { create(:merge_request, source_project: project, created_at: 10.minutes.ago, source_branch: 'C') }
+ let(:stage) { described_class.new(project: project, options: { from: 2.days.ago, current_user: project.creator }) }
+
+ before do
+ mr_1.metrics.update!(merged_at: 30.minutes.ago)
+ mr_2.metrics.update!(merged_at: 10.minutes.ago)
+
+ create(:merge_requests_closing_issues, merge_request: mr_1, issue: issue_1)
+ create(:merge_requests_closing_issues, merge_request: mr_2, issue: issue_2)
+ create(:merge_requests_closing_issues, merge_request: mr_3, issue: issue_3)
+ end
it_behaves_like 'base stage'
+
+ describe '#median' do
+ around do |example|
+ Timecop.freeze { example.run }
+ end
+
+ it 'counts median from issues with metrics' do
+ expect(stage.median).to eq(ISSUES_MEDIAN)
+ end
+ end
+
+ describe '#events' do
+ it 'exposes merge requests that close issues' do
+ result = stage.events
+
+ expect(result.count).to eq(2)
+ expect(result.map { |event| event[:title] }).to contain_exactly(mr_1.title, mr_2.title)
+ end
+ end
end
diff --git a/spec/lib/gitlab/cycle_analytics/shared_stage_spec.rb b/spec/lib/gitlab/cycle_analytics/shared_stage_spec.rb
index 08425acbfc8..1a4b572cc11 100644
--- a/spec/lib/gitlab/cycle_analytics/shared_stage_spec.rb
+++ b/spec/lib/gitlab/cycle_analytics/shared_stage_spec.rb
@@ -1,6 +1,8 @@
require 'spec_helper'
shared_examples 'base stage' do
+ ISSUES_MEDIAN = 30.minutes.to_i
+
let(:stage) { described_class.new(project: double, options: {}) }
before do
diff --git a/spec/lib/gitlab/cycle_analytics/staging_stage_spec.rb b/spec/lib/gitlab/cycle_analytics/staging_stage_spec.rb
index 8154b3ac701..17d5fbb9733 100644
--- a/spec/lib/gitlab/cycle_analytics/staging_stage_spec.rb
+++ b/spec/lib/gitlab/cycle_analytics/staging_stage_spec.rb
@@ -4,5 +4,46 @@ require 'lib/gitlab/cycle_analytics/shared_stage_spec'
describe Gitlab::CycleAnalytics::StagingStage do
let(:stage_name) { :staging }
+ let(:project) { create(:project) }
+ let!(:issue_1) { create(:issue, project: project, created_at: 90.minutes.ago) }
+ let!(:issue_2) { create(:issue, project: project, created_at: 60.minutes.ago) }
+ let!(:issue_3) { create(:issue, project: project, created_at: 60.minutes.ago) }
+ let!(:mr_1) { create(:merge_request, :closed, source_project: project, created_at: 60.minutes.ago) }
+ let!(:mr_2) { create(:merge_request, :closed, source_project: project, created_at: 40.minutes.ago, source_branch: 'A') }
+ let!(:mr_3) { create(:merge_request, source_project: project, created_at: 10.minutes.ago, source_branch: 'B') }
+ let(:build_1) { create(:ci_build, project: project) }
+ let(:build_2) { create(:ci_build, project: project) }
+
+ let(:stage) { described_class.new(project: project, options: { from: 2.days.ago, current_user: project.creator }) }
+
+ before do
+ mr_1.metrics.update!(merged_at: 80.minutes.ago, first_deployed_to_production_at: 50.minutes.ago, pipeline_id: build_1.commit_id)
+ mr_2.metrics.update!(merged_at: 60.minutes.ago, first_deployed_to_production_at: 30.minutes.ago, pipeline_id: build_2.commit_id)
+ mr_3.metrics.update!(merged_at: 10.minutes.ago, first_deployed_to_production_at: 3.days.ago, pipeline_id: create(:ci_build, project: project).commit_id)
+
+ create(:merge_requests_closing_issues, merge_request: mr_1, issue: issue_1)
+ create(:merge_requests_closing_issues, merge_request: mr_2, issue: issue_2)
+ create(:merge_requests_closing_issues, merge_request: mr_3, issue: issue_3)
+ end
+
it_behaves_like 'base stage'
+
+ describe '#median' do
+ around do |example|
+ Timecop.freeze { example.run }
+ end
+
+ it 'counts median from issues with metrics' do
+ expect(stage.median).to eq(ISSUES_MEDIAN)
+ end
+ end
+
+ describe '#events' do
+ it 'exposes builds connected to merge request' do
+ result = stage.events
+
+ expect(result.count).to eq(2)
+ expect(result.map { |event| event[:name] }).to contain_exactly(build_1.name, build_2.name)
+ end
+ end
end
diff --git a/spec/requests/projects/cycle_analytics_events_spec.rb b/spec/requests/projects/cycle_analytics_events_spec.rb
index 49412b628b3..25390f8a23e 100644
--- a/spec/requests/projects/cycle_analytics_events_spec.rb
+++ b/spec/requests/projects/cycle_analytics_events_spec.rb
@@ -32,10 +32,10 @@ describe 'cycle analytics events' do
it 'lists the plan events' do
get project_cycle_analytics_plan_path(project, format: :json)
- first_mr_short_sha = project.merge_requests.sort_by_attribute(:created_asc).first.commits.first.short_id
+ first_issue_iid = project.issues.sort_by_attribute(:created_desc).pluck(:iid).first.to_s
expect(json_response['events']).not_to be_empty
- expect(json_response['events'].first['short_sha']).to eq(first_mr_short_sha)
+ expect(json_response['events'].first['iid']).to eq(first_issue_iid)
end
it 'lists the code events' do