diff options
author | Kamil Trzcinski <ayufan@ayufan.eu> | 2016-04-12 19:57:54 +0200 |
---|---|---|
committer | Kamil Trzcinski <ayufan@ayufan.eu> | 2016-04-12 20:37:57 +0200 |
commit | 8e84acbf2e7e306ba937aaae87cfed35d2632e10 (patch) | |
tree | 40a530e78e7b0be13cbd18435bb7105fb9a3eb2c | |
parent | 89f0dc713ca07fe935fa9ce2c31d0ca6febb5d6c (diff) | |
download | gitlab-ce-8e84acbf2e7e306ba937aaae87cfed35d2632e10.tar.gz |
Optimise CI status accessor
-rw-r--r-- | app/models/ci/commit.rb | 6 | ||||
-rw-r--r-- | app/models/commit_status.rb | 35 | ||||
-rw-r--r-- | app/models/concerns/ci_status.rb | 1 | ||||
-rw-r--r-- | db/migrate/20160412174954_add_ci_commit_indexes.rb | 7 | ||||
-rw-r--r-- | db/migrate/20160412175417_update_ci_commit.rb | 31 |
5 files changed, 79 insertions, 1 deletions
diff --git a/app/models/ci/commit.rb b/app/models/ci/commit.rb index 94951ced1fd..8865bd76bd2 100644 --- a/app/models/ci/commit.rb +++ b/app/models/ci/commit.rb @@ -44,8 +44,12 @@ module Ci sha[0...8] end + def self.stages + CommitStatus.where(commit: all).stages + end + def stages - statuses.group(:stage).order(:stage_idx).pluck(:stage) + statuses.stages end def project_id diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb index e8a331e720c..8a7b1f00cde 100644 --- a/app/models/commit_status.rb +++ b/app/models/commit_status.rb @@ -49,6 +49,7 @@ class CommitStatus < ActiveRecord::Base scope :latest, -> { where(id: unscope(:select).select('max(id)').group(:name, :commit_id)) } scope :ordered, -> { order(:ref, :stage_idx, :name) } + scope :ignored, -> { where(allow_failure: true, status: [:failed, :canceled]) } AVAILABLE_STATUSES = ['pending', 'running', 'success', 'failed', 'canceled'] @@ -84,6 +85,40 @@ class CommitStatus < ActiveRecord::Base delegate :before_sha, :sha, :short_sha, to: :commit, prefix: false + def self.stages + order_by = 'max(stage_idx)' + group('stage').order(order_by).pluck(:stage, order_by).map(&:first).compact + end + + def self.status_sql + builds = all.select('count(id)').to_sql + success = all.success.select('count(id)').to_sql + ignored = all.failed.where(allow_failure: true).select('count(id)').to_sql if all.try(:ignored) + ignored ||= '0' + pending = all.pending.select('count(id)').to_sql + running = all.running.select('count(id)').to_sql + canceled = all.canceled.select('count(id)').to_sql + + deduce_status = "(CASE + WHEN (#{builds})=0 THEN 'skipped' + WHEN (#{builds})=(#{success})+(#{ignored}) THEN 'success' + WHEN (#{builds})=(#{pending}) THEN 'pending' + WHEN (#{builds})=(#{canceled}) THEN 'canceled' + WHEN (#{running})+(#{pending})>0 THEN 'running' + ELSE 'failed' + END)" + + deduce_status + end + + def self.status + pluck(self.status_sql).first + end + + def self.stages_status + Hash[group(:stage).pluck(:stage, self.status_sql)] + end + def ignored? allow_failure? && (failed? || canceled?) end diff --git a/app/models/concerns/ci_status.rb b/app/models/concerns/ci_status.rb index 6450b6dd202..88b890376cf 100644 --- a/app/models/concerns/ci_status.rb +++ b/app/models/concerns/ci_status.rb @@ -43,6 +43,7 @@ module CiStatus scope :pending, -> { where(status: 'pending') } scope :success, -> { where(status: 'success') } scope :failed, -> { where(status: 'failed') } + scope :canceled, -> { where(status: 'canceled') } scope :running_or_pending, -> { where(status: [:running, :pending]) } scope :finished, -> { where(status: [:success, :failed, :canceled]) } end diff --git a/db/migrate/20160412174954_add_ci_commit_indexes.rb b/db/migrate/20160412174954_add_ci_commit_indexes.rb new file mode 100644 index 00000000000..49fbb3e9bdc --- /dev/null +++ b/db/migrate/20160412174954_add_ci_commit_indexes.rb @@ -0,0 +1,7 @@ +class AddCiCommitIndexes < ActiveRecord::Migration + def change + add_index :ci_commits, [:gl_project_id, :sha] + add_index :ci_commits, [:gl_project_id, :status] + add_index :ci_commits, [:status] + end +end diff --git a/db/migrate/20160412175417_update_ci_commit.rb b/db/migrate/20160412175417_update_ci_commit.rb new file mode 100644 index 00000000000..ebe1d143b1f --- /dev/null +++ b/db/migrate/20160412175417_update_ci_commit.rb @@ -0,0 +1,31 @@ +class UpdateCiCommit < ActiveRecord::Migration + def change + execute("UPDATE ci_commits SET status=#{status}, ref=#{ref}, tag=#{tag} WHERE status IS NULL") + end + + def status + builds = '(SELECT COUNT(*) FROM ci_builds WHERE ci_builds.commit_id=ci_commits.id)' + success = "(SELECT COUNT(*) FROM ci_builds WHERE ci_builds.commit_id=ci_commits.id AND status='success')" + ignored = "(SELECT COUNT(*) FROM ci_builds WHERE ci_builds.commit_id=ci_commits.id AND (status='failed' OR status='canceled') AND allow_failure)" + pending = "(SELECT COUNT(*) FROM ci_builds WHERE ci_builds.commit_id=ci_commits.id AND status='pending')" + running = "(SELECT COUNT(*) FROM ci_builds WHERE ci_builds.commit_id=ci_commits.id AND status='running')" + canceled = "(SELECT COUNT(*) FROM ci_builds WHERE ci_builds.commit_id=ci_commits.id AND status='canceled')" + + "(CASE + WHEN #{builds}=0 THEN 'skipped' + WHEN #{builds}=#{success}+#{ignored} THEN 'success' + WHEN #{builds}=#{pending} THEN 'pending' + WHEN #{builds}=#{canceled} THEN 'canceled' + WHEN #{running}+#{pending}>0 THEN 'running' + ELSE 'failed' + END)" + end + + def ref + '(SELECT ref FROM ci_builds WHERE ci_builds.commit_id=ci_commits.id ORDER BY id DESC LIMIT 1)' + end + + def tag + '(SELECT tag FROM ci_builds WHERE ci_builds.commit_id=ci_commits.id ORDER BY id DESC LIMIT 1)' + end +end |