summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKamil Trzcinski <ayufan@ayufan.eu>2016-04-12 19:57:54 +0200
committerKamil Trzcinski <ayufan@ayufan.eu>2016-04-12 20:37:57 +0200
commit8e84acbf2e7e306ba937aaae87cfed35d2632e10 (patch)
tree40a530e78e7b0be13cbd18435bb7105fb9a3eb2c
parent89f0dc713ca07fe935fa9ce2c31d0ca6febb5d6c (diff)
downloadgitlab-ce-8e84acbf2e7e306ba937aaae87cfed35d2632e10.tar.gz
Optimise CI status accessor
-rw-r--r--app/models/ci/commit.rb6
-rw-r--r--app/models/commit_status.rb35
-rw-r--r--app/models/concerns/ci_status.rb1
-rw-r--r--db/migrate/20160412174954_add_ci_commit_indexes.rb7
-rw-r--r--db/migrate/20160412175417_update_ci_commit.rb31
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