Calculate CI/CD statuses in Ruby instead of SQL

Currently we calculate CI status using SQL with implementation like:

    def status_sql
      builds = all.select('count(*)').to_sql
      success = all.success.select('count(*)').to_sql
      ignored = all.ignored.select('count(*)').to_sql if all.respond_to?(:ignored)
      ignored ||= '0'
      pending = all.pending.select('count(*)').to_sql
      running = all.running.select('count(*)').to_sql
      canceled = all.canceled.select('count(*)').to_sql
      skipped = all.skipped.select('count(*)').to_sql

      deduce_status = "(CASE
        WHEN (#{builds})=0 THEN NULL
        WHEN (#{builds})=(#{success})+(#{ignored}) THEN 'success'
        WHEN (#{builds})=(#{pending}) THEN 'pending'
        WHEN (#{builds})=(#{canceled})+(#{success})+(#{ignored}) THEN 'canceled'
        WHEN (#{builds})=(#{skipped}) THEN 'skipped'
        WHEN (#{running})+(#{pending})>0 THEN 'running'
        ELSE 'failed'
      END)"

      deduce_status
    end

    def status
      all.pluck(self.status_sql).first
    end

We do this because of performance reasons, this is much faster than code we had before.

Instead of doing this that way we cold load entire collection of statuses into the memory, and calculate status in Ruby, what could be

  • more maintainable
  • more testable
  • similar in performance
  • easier to change

This is also required to resolve a ~"technical debt" issue https://gitlab.com/gitlab-org/gitlab-ce/issues/23257

Edited by Grzegorz Bizon