Read about our upcoming Code of Conduct on this issue

17_cycle_analytics.rb 5.52 KB
Newer Older
1
2
# frozen_string_literal: true

3
require './spec/support/sidekiq_middleware'
4
require './spec/support/helpers/test_env'
5

6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Usage:
#
# Simple invocation always creates a new project:
#
# FILTER=cycle_analytics SEED_CYCLE_ANALYTICS=1 bundle exec rake db:seed_fu
#
# Create more issues/MRs:
#
# CYCLE_ANALYTICS_ISSUE_COUNT=100 FILTER=cycle_analytics SEED_CYCLE_ANALYTICS=1 bundle exec rake db:seed_fu
#
# Run for an existing project
#
# CYCLE_ANALYTICS_SEED_PROJECT_ID=10 FILTER=cycle_analytics SEED_CYCLE_ANALYTICS=1 bundle exec rake db:seed_fu

20
class Gitlab::Seeder::CycleAnalytics
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
  attr_reader :project, :issues, :merge_requests, :developers

  FLAG = 'SEED_CYCLE_ANALYTICS'
  PERF_TEST = 'CYCLE_ANALYTICS_PERF_TEST'

  ISSUE_STAGE_MAX_DURATION_IN_HOURS = 72
  PLAN_STAGE_MAX_DURATION_IN_HOURS = 48
  CODE_STAGE_MAX_DURATION_IN_HOURS = 72
  TEST_STAGE_MAX_DURATION_IN_HOURS = 5
  REVIEW_STAGE_MAX_DURATION_IN_HOURS = 72
  DEPLOYMENT_MAX_DURATION_IN_HOURS = 48

  def self.seeder_base_on_env(project)
    if ENV[FLAG]
      self.new(project: project)
    elsif ENV[PERF_TEST]
      self.new(project: project, perf: true)
    end
39
40
  end

41
42
43
44
45
46
  def initialize(project: nil, perf: false)
    @project = project || create_new_vsm_project
    @issue_count = perf ? 1000 : ENV.fetch('CYCLE_ANALYTICS_ISSUE_COUNT', 5).to_i
    @issues = []
    @merge_requests = []
    @developers = []
47
48
  end

49
  def seed!
50
51
52
53
54
55
56
57
58
59
60
61
    create_developers!
    create_issues!

    seed_issue_stage!
    seed_plan_stage!
    seed_code_stage!
    seed_test_stage!
    seed_review_stage!
    seed_staging_stage!

    puts "Successfully seeded '#{project.full_path}' for Value Stream Management!"
    puts "URL: #{Rails.application.routes.url_helpers.project_url(project)}"
62
63
64
65
  end

  private

66
67
68
  def seed_issue_stage!
    issues.each do |issue|
      time = within_end_time(issue.created_at + rand(ISSUE_STAGE_MAX_DURATION_IN_HOURS).hours)
69

70
71
      if issue.id.even?
        issue.metrics.update!(first_associated_with_milestone_at: time)
72
      else
73
        issue.metrics.update!(first_added_to_board_at: time)
74
75
76
77
      end
    end
  end

78
79
80
  def seed_plan_stage!
    issues.each do |issue|
      plan_stage_start = issue.metrics.first_associated_with_milestone_at || issue.metrics.first_added_to_board_at
81

82
83
84
85
      first_mentioned_in_commit_at = within_end_time(plan_stage_start + rand(PLAN_STAGE_MAX_DURATION_IN_HOURS).hours)
      issue.metrics.update!(first_mentioned_in_commit_at: first_mentioned_in_commit_at)
    end
  end
86

87
88
89
90
91
92
93
94
95
96
97
  def seed_code_stage!
    issues.each do |issue|
      merge_request = FactoryBot.create(
        :merge_request,
        target_project: project,
        source_project: project,
        source_branch: "#{issue.iid}-feature-branch",
        target_branch: 'master',
        author: developers.sample,
        created_at: within_end_time(issue.metrics.first_mentioned_in_commit_at + rand(CODE_STAGE_MAX_DURATION_IN_HOURS).hours)
      )
98

99
      @merge_requests << merge_request
100

101
102
103
      MergeRequestsClosingIssues.create!(issue: issue, merge_request: merge_request)
    end
  end
104

105
106
107
108
109
110
111
112
113
114
  def seed_test_stage!
    merge_requests.each do |merge_request|
      pipeline = FactoryBot.create(:ci_pipeline, :success, project: project)
      build = FactoryBot.create(:ci_build, pipeline: pipeline, project: project, user: developers.sample)

      merge_request.metrics.update!(
        latest_build_started_at: merge_request.created_at,
        latest_build_finished_at: within_end_time(merge_request.created_at + TEST_STAGE_MAX_DURATION_IN_HOURS.hours),
        pipeline_id: build.commit_id
      )
115
116
117
    end
  end

118
119
120
121
122
  def seed_review_stage!
    merge_requests.each do |merge_request|
      merge_request.metrics.update!(merged_at: within_end_time(merge_request.created_at + REVIEW_STAGE_MAX_DURATION_IN_HOURS.hours))
    end
  end
123

124
125
126
127
128
  def seed_staging_stage!
    merge_requests.each do |merge_request|
      merge_request.metrics.update!(first_deployed_to_production_at: within_end_time(merge_request.metrics.merged_at + DEPLOYMENT_MAX_DURATION_IN_HOURS.hours))
    end
  end
129

130
131
132
133
134
135
  def create_issues!
    @issue_count.times do
      Timecop.travel start_time + rand(5).days do
        title = "#{FFaker::Product.brand}-#{suffix}"
        @issues << Issue.create!(project: project, title: title, author: developers.sample)
      end
136
137
138
    end
  end

139
140
141
142
143
144
145
146
  def create_developers!
    5.times do |i|
      user = FactoryBot.create(
        :user,
        name: "VSM User#{i}",
        username: "vsm-user-#{i}-#{suffix}",
        email: "vsm-user-#{i}@#{suffix}.com"
      )
147

148
149
      project.group.add_developer(user)
      project.add_developer(user)
150

151
      @developers << user
152
153
154
    end
  end

155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
  def create_new_vsm_project
    project = FactoryBot.create(
      :project,
      name: "Value Stream Management Project #{suffix}",
      path: "vsmp-#{suffix}",
      creator: admin,
      namespace: FactoryBot.create(
        :group,
        name: "Value Stream Management Group (#{suffix})",
        path: "vsmg-#{suffix}"
      )
    )

    project.create_repository
    project
  end
171

172
173
  def admin
    @admin ||= User.admins.first
174
175
  end

176
177
178
  def suffix
    @suffix ||= Time.now.to_i
  end
179

180
181
182
  def start_time
    @start_time ||= 25.days.ago
  end
183

184
185
186
  def end_time
    @end_time ||= Time.now
  end
187

188
189
  def within_end_time(time)
    [time, end_time].min
190
191
192
193
  end
end

Gitlab::Seeder.quiet do
194
195
196
197
198
199
  project_id = ENV['CYCLE_ANALYTICS_SEED_PROJECT_ID']
  project = Project.find(project_id) if project_id

  seeder = Gitlab::Seeder::CycleAnalytics.seeder_base_on_env(project)

  if seeder
200
    seeder.seed!
Timothy Andrew's avatar
Timothy Andrew committed
201
  else
202
    puts "Skipped. Use the `#{Gitlab::Seeder::CycleAnalytics::FLAG}` environment variable to enable."
203
204
  end
end