summaryrefslogtreecommitdiff
path: root/db/post_migrate/20170630111158_migrate_stages_statuses.rb
blob: c0a5294720d400be79765089d98071309f253c13 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
class MigrateStagesStatuses < ActiveRecord::Migration
  include Gitlab::Database::MigrationHelpers

  DOWNTIME = false

  disable_ddl_transaction!

  STATUSES = { created: 0, pending: 1, running: 2, success: 3,
               failed: 4, canceled: 5, skipped: 6, manual: 7 }

  class Build < ActiveRecord::Base
    self.table_name = 'ci_builds'

    scope :latest, -> { where(retried: [false, nil]) }
    scope :created, -> { where(status: 'created') }
    scope :running, -> { where(status: 'running') }
    scope :pending, -> { where(status: 'pending') }
    scope :success, -> { where(status: 'success') }
    scope :failed, -> { where(status: 'failed')  }
    scope :canceled, -> { where(status: 'canceled')  }
    scope :skipped, -> { where(status: 'skipped')  }
    scope :manual, -> { where(status: 'manual')  }

    scope :failed_but_allowed, -> do
      where(allow_failure: true, status: [:failed, :canceled])
    end

    scope :exclude_ignored, -> do
      where("allow_failure = ? OR status IN (?)",
        false, %w[created pending running success skipped])
    end

    def self.status_sql
      scope_relevant = latest.exclude_ignored
      scope_warnings = latest.failed_but_allowed

      builds = scope_relevant.select('count(*)').to_sql
      created = scope_relevant.created.select('count(*)').to_sql
      success = scope_relevant.success.select('count(*)').to_sql
      manual = scope_relevant.manual.select('count(*)').to_sql
      pending = scope_relevant.pending.select('count(*)').to_sql
      running = scope_relevant.running.select('count(*)').to_sql
      skipped = scope_relevant.skipped.select('count(*)').to_sql
      canceled = scope_relevant.canceled.select('count(*)').to_sql
      warnings = scope_warnings.select('count(*) > 0').to_sql

      <<-SQL.strip_heredoc
        (CASE
          WHEN (#{builds}) = (#{skipped}) AND (#{warnings}) THEN #{STATUSES[:success]}
          WHEN (#{builds}) = (#{skipped}) THEN #{STATUSES[:skipped]}
          WHEN (#{builds}) = (#{success}) THEN #{STATUSES[:success]}
          WHEN (#{builds}) = (#{created}) THEN #{STATUSES[:created]}
          WHEN (#{builds}) = (#{success}) + (#{skipped}) THEN #{STATUSES[:success]}
          WHEN (#{builds}) = (#{success}) + (#{skipped}) + (#{canceled}) THEN #{STATUSES[:canceled]}
          WHEN (#{builds}) = (#{created}) + (#{skipped}) + (#{pending}) THEN #{STATUSES[:pending]}
          WHEN (#{running}) + (#{pending}) > 0 THEN #{STATUSES[:running]}
          WHEN (#{manual}) > 0 THEN #{STATUSES[:manual]}
          WHEN (#{created}) > 0 THEN #{STATUSES[:running]}
          ELSE #{STATUSES[:failed]}
        END)
      SQL
    end
  end

  def up
    disable_statement_timeout

    status_sql = Build
      .where('ci_builds.commit_id = ci_stages.pipeline_id')
      .where('ci_builds.stage = ci_stages.name')
      .status_sql

    update_column_in_batches(:ci_stages, :status, Arel.sql("(#{status_sql})")) do |table, query|
      query.where(table[:status].eq(nil))
    end
  end

  def down
    disable_statement_timeout

    execute <<-SQL.strip_heredoc
      UPDATE ci_stages SET status = null
    SQL
  end
end