diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-25 03:08:11 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-25 03:08:11 +0300 |
commit | 23bc19cb73aad969c9636b8b935111645e809e54 (patch) | |
tree | 887c9e014f8345f577769db4f75315ca59853b98 /db/fixtures | |
parent | c4db541c1b2c97ab1eda354ea3899489fe5c33e5 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'db/fixtures')
-rw-r--r-- | db/fixtures/development/17_cycle_analytics.rb | 342 |
1 files changed, 153 insertions, 189 deletions
diff --git a/db/fixtures/development/17_cycle_analytics.rb b/db/fixtures/development/17_cycle_analytics.rb index 2bf3c918006..1bdaabad704 100644 --- a/db/fixtures/development/17_cycle_analytics.rb +++ b/db/fixtures/development/17_cycle_analytics.rb @@ -1,240 +1,204 @@ +# frozen_string_literal: true + require './spec/support/sidekiq_middleware' require './spec/support/helpers/test_env' +# 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 + class Gitlab::Seeder::CycleAnalytics - def initialize(project, perf: false) - @project = project - @user = User.admins.first - @issue_count = perf ? 1000 : ENV.fetch('CYCLE_ANALYTICS_ISSUE_COUNT', 5).to_i + 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 end - def seed_metrics! - @issue_count.times do |index| - # Issue - Timecop.travel 5.days.from_now - title = "#{FFaker::Product.brand}-#{FFaker::Product.brand}-#{rand(1000)}" - issue = Issue.create(project: @project, title: title, author: @user) - issue_metrics = issue.metrics - - # Milestones / Labels - Timecop.travel 5.days.from_now - - if index.even? - issue_metrics.first_associated_with_milestone_at = rand(6..12).hours.from_now - else - issue_metrics.first_added_to_board_at = rand(6..12).hours.from_now - end - - # Commit - Timecop.travel 5.days.from_now - issue_metrics.first_mentioned_in_commit_at = rand(6..12).hours.from_now - - # MR - Timecop.travel 5.days.from_now - branch_name = "#{FFaker::Product.brand}-#{FFaker::Product.brand}-#{rand(1000)}" - @project.repository.add_branch(@user, branch_name, 'master') - merge_request = MergeRequest.create(target_project: @project, source_project: @project, source_branch: branch_name, target_branch: 'master', title: branch_name, author: @user) - merge_request_metrics = merge_request.metrics - - # MR closing issues - Timecop.travel 5.days.from_now - MergeRequestsClosingIssues.create!(issue: issue, merge_request: merge_request) - - # Merge - Timecop.travel 5.days.from_now - merge_request_metrics.merged_at = rand(6..12).hours.from_now - - # Start build - Timecop.travel 5.days.from_now - merge_request_metrics.latest_build_started_at = rand(6..12).hours.from_now - - # Finish build - Timecop.travel 5.days.from_now - merge_request_metrics.latest_build_finished_at = rand(6..12).hours.from_now - - # Deploy to production - Timecop.travel 5.days.from_now - merge_request_metrics.first_deployed_to_production_at = rand(6..12).hours.from_now - - issue_metrics.save! - merge_request_metrics.save! - - print '.' - end + 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 = [] end def seed! - Sidekiq::Worker.skipping_transaction_check do - Sidekiq::Testing.inline! do - issues = create_issues - puts '.' - - # Stage 1 - Timecop.travel 5.days.from_now - add_milestones_and_list_labels(issues) - print '.' - - # Stage 2 - Timecop.travel 5.days.from_now - branches = mention_in_commits(issues) - print '.' - - # Stage 3 - Timecop.travel 5.days.from_now - merge_requests = create_merge_requests_closing_issues(issues, branches) - print '.' - - # Stage 4 - Timecop.travel 5.days.from_now - run_builds(merge_requests) - print '.' - - # Stage 5 - Timecop.travel 5.days.from_now - merge_merge_requests(merge_requests) - print '.' - - # Stage 6 / 7 - Timecop.travel 5.days.from_now - deploy_to_production(merge_requests) - print '.' - end - end - - print '.' + 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)}" end private - def create_issues - Array.new(@issue_count) do - issue_params = { - title: "Value Stream Analytics: #{FFaker::Lorem.sentence(6)}", - description: FFaker::Lorem.sentence, - state: 'opened', - assignees: [@project.team.users.sample] - } - - Issues::CreateService.new(@project, @project.team.users.sample, issue_params).execute - end - end - - def add_milestones_and_list_labels(issues) - issues.shuffle.map.with_index do |issue, index| - Timecop.travel 12.hours.from_now + def seed_issue_stage! + issues.each do |issue| + time = within_end_time(issue.created_at + rand(ISSUE_STAGE_MAX_DURATION_IN_HOURS).hours) - if index.even? - issue.update(milestone: @project.milestones.sample) + if issue.id.even? + issue.metrics.update!(first_associated_with_milestone_at: time) else - label_name = "#{FFaker::Product.brand}-#{FFaker::Product.brand}-#{rand(1000)}" - list_label = FactoryBot.create(:label, title: label_name, project: issue.project) - FactoryBot.create(:list, board: FactoryBot.create(:board, project: issue.project), label: list_label) - issue.update(labels: [list_label]) + issue.metrics.update!(first_added_to_board_at: time) end - - issue end end - def mention_in_commits(issues) - issues.map do |issue| - Timecop.travel 12.hours.from_now + 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 - branch_name = filename = "#{FFaker::Product.brand}-#{FFaker::Product.brand}-#{rand(1000)}" + 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 - issue.project.repository.add_branch(@user, branch_name, 'master') + 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) + ) - commit_sha = issue.project.repository.create_file(@user, filename, "content", message: "Commit for #{issue.to_reference}", branch_name: branch_name) - issue.project.repository.commit(commit_sha) + @merge_requests << merge_request - ::Git::BranchPushService.new( - issue.project, - @user, - change: { - oldrev: issue.project.repository.commit("master").sha, - newrev: commit_sha, - ref: 'refs/heads/master' - } - ).execute + MergeRequestsClosingIssues.create!(issue: issue, merge_request: merge_request) + end + end - branch_name + 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 + ) end end - def create_merge_requests_closing_issues(issues, branches) - issues.zip(branches).map do |issue, branch| - Timecop.travel 12.hours.from_now + 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 - opts = { - title: 'Value Stream Analytics merge_request', - description: "Fixes #{issue.to_reference}", - source_branch: branch, - target_branch: 'master' - } + 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 - MergeRequests::CreateService.new(issue.project, @user, opts).execute + 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 end end - def run_builds(merge_requests) - merge_requests.each do |merge_request| - Timecop.travel 12.hours.from_now + 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" + ) - service = Ci::CreatePipelineService.new(merge_request.project, - @user, - ref: "refs/heads/#{merge_request.source_branch}") - pipeline = service.execute(:push, ignore_skip_ci: true, save_on_errors: false) + project.group.add_developer(user) + project.add_developer(user) - pipeline.builds.each(&:enqueue) # make sure all pipelines in pending state - pipeline.builds.each(&:run!) - pipeline.update_legacy_status + @developers << user end end - def merge_merge_requests(merge_requests) - merge_requests.each do |merge_request| - Timecop.travel 12.hours.from_now + 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 - MergeRequests::MergeService.new(merge_request.project, @user).execute(merge_request) - end + def admin + @admin ||= User.admins.first end - def deploy_to_production(merge_requests) - merge_requests.each do |merge_request| - next unless merge_request.head_pipeline + def suffix + @suffix ||= Time.now.to_i + end - Timecop.travel 12.hours.from_now + def start_time + @start_time ||= 25.days.ago + end - job = merge_request.head_pipeline.builds.where.not(environment: nil).last + def end_time + @end_time ||= Time.now + end - job.success! - job.pipeline.update_legacy_status - end + def within_end_time(time) + [time, end_time].min end end Gitlab::Seeder.quiet do - flag = 'SEED_CYCLE_ANALYTICS' - - if ENV[flag] - Project.not_mass_generated.find_each do |project| - # This seed naively assumes that every project has a repository, and every - # repository has a `master` branch, which may be the case for a pristine - # GDK seed, but is almost never true for a GDK that's actually had - # development performed on it. - next unless project.repository_exists? - next unless project.repository.commit('master') - - seeder = Gitlab::Seeder::CycleAnalytics.new(project) - seeder.seed! - end - elsif ENV['CYCLE_ANALYTICS_PERF_TEST'] - seeder = Gitlab::Seeder::CycleAnalytics.new(Project.order(:id).first, perf: true) + 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 seeder.seed! - elsif ENV['CYCLE_ANALYTICS_POPULATE_METRICS_DIRECTLY'] - seeder = Gitlab::Seeder::CycleAnalytics.new(Project.order(:id).first, perf: true) - seeder.seed_metrics! else - puts "Skipped. Use the `#{flag}` environment variable to enable." + puts "Skipped. Use the `#{Gitlab::Seeder::CycleAnalytics::FLAG}` environment variable to enable." end end |