commit.rb 5.2 KB
Newer Older
D
Douwe Maan 已提交
1 2
# == Schema Information
#
D
Dmitriy Zaporozhets 已提交
3
# Table name: ci_commits
D
Douwe Maan 已提交
4
#
D
Dmitriy Zaporozhets 已提交
5 6 7 8 9 10 11 12 13 14 15 16
#  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
#  gl_project_id :integer
D
Douwe Maan 已提交
17 18 19 20 21
#

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

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

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

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

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

    def to_param
      sha
    end

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

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

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

    def retry
54
      latest_builds.each do |build|
D
Douwe Maan 已提交
55 56 57 58 59 60 61 62 63 64 65
        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 已提交
66
      commit_data.author_name if commit_data
D
Douwe Maan 已提交
67 68 69
    end

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

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

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

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

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

92
    def create_builds(ref, tag, user, trigger_request = nil)
D
Douwe Maan 已提交
93
      return unless config_processor
K
Kamil Trzcinski 已提交
94
      config_processor.stages.any? do |stage|
95
        CreateBuildsService.new.execute(self, stage, ref, tag, user, trigger_request, 'success').present?
K
Kamil Trzcinski 已提交
96 97 98
      end
    end

99
    def create_next_builds(build)
K
Kamil Trzcinski 已提交
100 101
      return unless config_processor

102 103 104
      # don't create other builds if this one is retried
      latest_builds = builds.similar(build).latest
      return unless latest_builds.exists?(build.id)
K
Kamil Trzcinski 已提交
105

106 107 108 109 110 111 112 113 114 115 116
      # get list of stages after this build
      next_stages = config_processor.stages.drop_while { |stage| stage != build.stage }
      next_stages.delete(build.stage)

      # get status for all prior builds
      prior_builds = latest_builds.reject { |other_build| next_stages.include?(other_build.stage) }
      status = Ci::Status.get_status(prior_builds)

      # create builds for next stages based
      next_stages.any? do |stage|
        CreateBuildsService.new.execute(self, stage, build.ref, build.tag, build.user, build.trigger_request, status).present?
K
Kamil Trzcinski 已提交
117
      end
D
Douwe Maan 已提交
118 119
    end

K
Kamil Trzcinski 已提交
120
    def refs
K
Kamil Trzcinski 已提交
121
      statuses.order(:ref).pluck(:ref).uniq
D
Douwe Maan 已提交
122 123
    end

K
Kamil Trzcinski 已提交
124 125
    def latest_statuses
      @latest_statuses ||= statuses.latest.to_a
K
Kamil Trzcinski 已提交
126 127
    end

128 129
    def latest_builds
      @latest_builds ||= builds.latest.to_a
K
Kamil Trzcinski 已提交
130 131
    end

132 133
    def latest_builds_for_ref(ref)
      latest_builds.select { |build| build.ref == ref }
D
Douwe Maan 已提交
134 135
    end

K
Kamil Trzcinski 已提交
136 137
    def retried
      @retried ||= (statuses.order(id: :desc) - statuses.latest)
D
Douwe Maan 已提交
138 139
    end

K
Kamil Trzcinski 已提交
140
    def status
K
Kamil Trzcinski 已提交
141
      if yaml_errors.present?
D
Douwe Maan 已提交
142
        return 'failed'
K
Kamil Trzcinski 已提交
143 144
      end

145
      @status ||= Ci::Status.get_status(latest_statuses)
D
Douwe Maan 已提交
146 147 148
    end

    def pending?
K
Kamil Trzcinski 已提交
149
      status == 'pending'
D
Douwe Maan 已提交
150 151 152
    end

    def running?
K
Kamil Trzcinski 已提交
153
      status == 'running'
D
Douwe Maan 已提交
154 155 156
    end

    def success?
K
Kamil Trzcinski 已提交
157
      status == 'success'
D
Douwe Maan 已提交
158 159 160 161 162 163 164
    end

    def failed?
      status == 'failed'
    end

    def canceled?
K
Kamil Trzcinski 已提交
165
      status == 'canceled'
D
Douwe Maan 已提交
166 167
    end

K
Kamil Trzcinski 已提交
168 169 170
    def duration
      duration_array = latest_statuses.map(&:duration).compact
      duration_array.reduce(:+).to_i
K
Kamil Trzcinski 已提交
171 172
    end

D
Douwe Maan 已提交
173
    def finished_at
K
Kamil Trzcinski 已提交
174
      @finished_at ||= statuses.order('finished_at DESC').first.try(:finished_at)
D
Douwe Maan 已提交
175 176 177 178
    end

    def coverage
      if project.coverage_enabled?
179
        coverage_array = latest_builds.map(&:coverage).compact
D
Douwe Maan 已提交
180 181 182 183 184 185
        if coverage_array.size >= 1
          '%.2f' % (coverage_array.reduce(:+) / coverage_array.size)
        end
      end
    end

K
Kamil Trzcinski 已提交
186
    def matrix_for_ref?(ref)
K
Kamil Trzcinski 已提交
187
      latest_builds_for_ref(ref).size > 1
D
Douwe Maan 已提交
188 189 190
    end

    def config_processor
191
      @config_processor ||= Ci::GitlabCiYamlProcessor.new(ci_yaml_file, gl_project.path_with_namespace)
D
Douwe Maan 已提交
192 193 194 195 196 197 198 199 200
    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 已提交
201
    def ci_yaml_file
202
      gl_project.repository.blob_at(sha, '.gitlab-ci.yml').data
K
Kamil Trzcinski 已提交
203 204 205 206
    rescue
      nil
    end

D
Douwe Maan 已提交
207
    def skip_ci?
K
Kamil Trzcinski 已提交
208
      git_commit_message =~ /(\[ci skip\])/ if git_commit_message
D
Douwe Maan 已提交
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
    end

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

    private

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