commit.rb 5.4 KB
Newer Older
D
Douwe Maan 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
# == Schema Information
#
# Table name: commits
#
#  id           :integer          not null, primary key
#  project_id   :integer
#  ref          :string(255)
#  sha          :string(255)
#  before_sha   :string(255)
#  push_data    :text
#  created_at   :datetime
#  updated_at   :datetime
#  tag          :boolean          default(FALSE)
#  yaml_errors  :text
#  committed_at :datetime
#

module Ci
  class Commit < ActiveRecord::Base
    extend Ci::Model
K
WIP  
Kamil Trzcinski 已提交
21 22

    belongs_to :gl_project, class_name: '::Project', foreign_key: :gl_project_id
K
Kamil Trzcinski 已提交
23 24
    has_many :statuses, dependent: :destroy, class_name: 'CommitStatus'
    has_many :builds, class_name: 'Ci::Build'
D
Douwe Maan 已提交
25 26
    has_many :trigger_requests, dependent: :destroy, class_name: 'Ci::TriggerRequest'

27 28
    scope :ordered, -> { order('CASE WHEN ci_commits.committed_at IS NULL THEN 0 ELSE 1 END', :committed_at, :id) }

K
Kamil Trzcinski 已提交
29
    validates_presence_of :sha
D
Douwe Maan 已提交
30 31 32 33 34 35 36 37 38 39
    validate :valid_commit_sha

    def self.truncate_sha(sha)
      sha[0...8]
    end

    def to_param
      sha
    end

K
WIP  
Kamil Trzcinski 已提交
40
    def project
41
      @project ||= gl_project.ensure_gitlab_ci_project
K
Kamil Trzcinski 已提交
42 43 44 45
    end

    def project_id
      project.id
K
WIP  
Kamil Trzcinski 已提交
46 47
    end

D
Douwe Maan 已提交
48 49 50 51 52
    def last_build
      builds.order(:id).last
    end

    def retry
53
      latest_builds.each do |build|
D
Douwe Maan 已提交
54 55 56 57 58 59 60 61 62 63 64
        Ci::Build.retry(build)
      end
    end

    def valid_commit_sha
      if self.sha == Ci::Git::BLANK_SHA
        self.errors.add(:sha, " cant be 00000000 (branch removal)")
      end
    end

    def git_author_name
K
Kamil Trzcinski 已提交
65
      commit_data.author_name if commit_data
D
Douwe Maan 已提交
66 67 68
    end

    def git_author_email
K
Kamil Trzcinski 已提交
69
      commit_data.author_email if commit_data
D
Douwe Maan 已提交
70 71 72
    end

    def git_commit_message
K
Kamil Trzcinski 已提交
73
      commit_data.message if commit_data
D
Douwe Maan 已提交
74 75 76 77 78 79 80
    end

    def short_sha
      Ci::Commit.truncate_sha(sha)
    end

    def commit_data
K
Kamil Trzcinski 已提交
81
      @commit ||= gl_project.commit(sha)
D
Douwe Maan 已提交
82 83 84 85 86
    rescue
      nil
    end

    def stage
K
Kamil Trzcinski 已提交
87
      running_or_pending = statuses.latest.running_or_pending.ordered
K
Kamil Trzcinski 已提交
88
      running_or_pending.first.try(:stage)
D
Douwe Maan 已提交
89 90
    end

91
    def create_builds(ref, tag, user, trigger_request = nil)
D
Douwe Maan 已提交
92
      return unless config_processor
K
Kamil Trzcinski 已提交
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
      config_processor.stages.any? do |stage|
        CreateBuildsService.new.execute(self, stage, ref, tag, user, trigger_request).present?
      end
    end

    def create_next_builds(ref, tag, user, trigger_request)
      return unless config_processor

      stages = builds.where(ref: ref, tag: tag, trigger_request: trigger_request).group_by(&:stage)

      config_processor.stages.any? do |stage|
        unless stages.include?(stage)
          CreateBuildsService.new.execute(self, stage, ref, tag, user, trigger_request).present?
        end
      end
D
Douwe Maan 已提交
108 109
    end

K
Kamil Trzcinski 已提交
110
    def refs
K
Kamil Trzcinski 已提交
111
      statuses.order(:ref).pluck(:ref).uniq
D
Douwe Maan 已提交
112 113
    end

K
Kamil Trzcinski 已提交
114 115
    def latest_statuses
      @latest_statuses ||= statuses.latest.to_a
K
Kamil Trzcinski 已提交
116 117
    end

118 119
    def latest_builds
      @latest_builds ||= builds.latest.to_a
K
Kamil Trzcinski 已提交
120 121
    end

122 123
    def latest_builds_for_ref(ref)
      latest_builds.select { |build| build.ref == ref }
D
Douwe Maan 已提交
124 125
    end

K
Kamil Trzcinski 已提交
126 127
    def retried
      @retried ||= (statuses.order(id: :desc) - statuses.latest)
D
Douwe Maan 已提交
128 129
    end

K
Kamil Trzcinski 已提交
130
    def status
K
Kamil Trzcinski 已提交
131
      if yaml_errors.present?
D
Douwe Maan 已提交
132
        return 'failed'
K
Kamil Trzcinski 已提交
133 134
      end

K
Kamil Trzcinski 已提交
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
      @status ||= begin
        latest = latest_statuses
        latest.reject! { |status| status.try(&:allow_failure?) }

        if latest.none?
          'skipped'
        elsif latest.all?(&:success?)
          'success'
        elsif latest.all?(&:pending?)
          'pending'
        elsif latest.any?(&:running?) || latest.any?(&:pending?)
          'running'
        elsif latest.all?(&:canceled?)
          'canceled'
        else
          'failed'
        end
D
Douwe Maan 已提交
152 153 154 155
      end
    end

    def pending?
K
Kamil Trzcinski 已提交
156
      status == 'pending'
D
Douwe Maan 已提交
157 158 159
    end

    def running?
K
Kamil Trzcinski 已提交
160
      status == 'running'
D
Douwe Maan 已提交
161 162 163
    end

    def success?
K
Kamil Trzcinski 已提交
164
      status == 'success'
D
Douwe Maan 已提交
165 166 167 168 169 170 171
    end

    def failed?
      status == 'failed'
    end

    def canceled?
K
Kamil Trzcinski 已提交
172
      status == 'canceled'
D
Douwe Maan 已提交
173 174
    end

K
Kamil Trzcinski 已提交
175 176 177
    def duration
      duration_array = latest_statuses.map(&:duration).compact
      duration_array.reduce(:+).to_i
K
Kamil Trzcinski 已提交
178 179
    end

D
Douwe Maan 已提交
180
    def finished_at
K
Kamil Trzcinski 已提交
181
      @finished_at ||= statuses.order('finished_at DESC').first.try(:finished_at)
D
Douwe Maan 已提交
182 183 184 185
    end

    def coverage
      if project.coverage_enabled?
186
        coverage_array = latest_builds.map(&:coverage).compact
D
Douwe Maan 已提交
187 188 189 190 191 192
        if coverage_array.size >= 1
          '%.2f' % (coverage_array.reduce(:+) / coverage_array.size)
        end
      end
    end

K
Kamil Trzcinski 已提交
193
    def matrix_for_ref?(ref)
K
Kamil Trzcinski 已提交
194
      latest_builds_for_ref(ref).size > 1
D
Douwe Maan 已提交
195 196 197
    end

    def config_processor
K
Kamil Trzcinski 已提交
198
      @config_processor ||= Ci::GitlabCiYamlProcessor.new(ci_yaml_file)
D
Douwe Maan 已提交
199 200 201 202 203 204 205 206 207
    rescue Ci::GitlabCiYamlProcessor::ValidationError => e
      save_yaml_error(e.message)
      nil
    rescue Exception => e
      logger.error e.message + "\n" + e.backtrace.join("\n")
      save_yaml_error("Undefined yaml error")
      nil
    end

K
Kamil Trzcinski 已提交
208
    def ci_yaml_file
209
      gl_project.repository.blob_at(sha, '.gitlab-ci.yml').data
K
Kamil Trzcinski 已提交
210 211 212 213
    rescue
      nil
    end

D
Douwe Maan 已提交
214
    def skip_ci?
K
Kamil Trzcinski 已提交
215
      git_commit_message =~ /(\[ci skip\])/ if git_commit_message
D
Douwe Maan 已提交
216 217 218 219 220 221
    end

    def update_committed!
      update!(committed_at: DateTime.now)
    end

K
Kamil Trzcinski 已提交
222 223 224 225 226 227 228 229 230 231
    def should_create_next_builds?(build)
      # don't create other builds if this one is retried
      other_builds = builds.similar(build).latest
      return false unless other_builds.include?(build)

      other_builds.all? do |build|
        build.success? || build.ignored?
      end
    end

D
Douwe Maan 已提交
232 233 234 235 236 237 238 239 240
    private

    def save_yaml_error(error)
      return if self.yaml_errors?
      self.yaml_errors = error
      save
    end
  end
end