BigW Consortium Gitlab

commit.rb 4.99 KB
Newer Older
1 2
# == Schema Information
#
Dmitriy Zaporozhets committed
3
# Table name: ci_commits
4
#
Dmitriy Zaporozhets committed
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
17 18 19 20 21
#

module Ci
  class Commit < ActiveRecord::Base
    extend Ci::Model
Kamil Trzcinski committed
22

23 24
    belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id
    has_many :statuses, class_name: 'CommitStatus'
25
    has_many :builds, class_name: 'Ci::Build'
26 27
    has_many :trigger_requests, dependent: :destroy, class_name: 'Ci::TriggerRequest'

28
    validates_presence_of :sha
29 30 31 32 33 34 35 36 37 38
    validate :valid_commit_sha

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

    def to_param
      sha
    end

Kamil Trzcinski committed
39 40
    def project_id
      project.id
Kamil Trzcinski committed
41 42
    end

43
    def valid_commit_sha
44
      if self.sha == Gitlab::Git::BLANK_SHA
45 46 47 48 49
        self.errors.add(:sha, " cant be 00000000 (branch removal)")
      end
    end

    def git_author_name
50
      commit_data.author_name if commit_data
51 52 53
    end

    def git_author_email
54
      commit_data.author_email if commit_data
55 56 57
    end

    def git_commit_message
58
      commit_data.message if commit_data
59 60 61 62 63 64 65
    end

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

    def commit_data
66
      @commit ||= project.commit(sha)
67 68 69 70 71
    rescue
      nil
    end

    def stage
Kamil Trzcinski committed
72
      running_or_pending = statuses.latest.running_or_pending.ordered
73
      running_or_pending.first.try(:stage)
74 75
    end

76
    def create_builds(ref, tag, user, trigger_request = nil)
77
      return unless config_processor
Kamil Trzcinski committed
78
      config_processor.stages.any? do |stage|
79
        CreateBuildsService.new.execute(self, stage, ref, tag, user, trigger_request, 'success').present?
Kamil Trzcinski committed
80 81 82
      end
    end

83
    def create_next_builds(build)
Kamil Trzcinski committed
84 85
      return unless config_processor

86 87 88
      # don't create other builds if this one is retried
      latest_builds = builds.similar(build).latest
      return unless latest_builds.exists?(build.id)
Kamil Trzcinski committed
89

90 91 92 93 94 95 96 97 98 99 100
      # 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?
Kamil Trzcinski committed
101
      end
102 103
    end

104
    def refs
Kamil Trzcinski committed
105
      statuses.order(:ref).pluck(:ref).uniq
106 107
    end

Kamil Trzcinski committed
108 109
    def latest_statuses
      @latest_statuses ||= statuses.latest.to_a
110 111
    end

112 113
    def latest_statuses_for_ref(ref)
      latest_statuses.select { |status| status.ref == ref }
114 115
    end

Kamil Trzcinski committed
116 117 118 119 120 121
    def matrix_builds(build = nil)
      matrix_builds = builds.latest.ordered
      matrix_builds = matrix_builds.similar(build) if build
      matrix_builds.to_a
    end

122 123
    def retried
      @retried ||= (statuses.order(id: :desc) - statuses.latest)
124 125
    end

Kamil Trzcinski committed
126
    def status
127
      if yaml_errors.present?
128
        return 'failed'
129 130
      end

131
      @status ||= Ci::Status.get_status(latest_statuses)
132 133 134
    end

    def pending?
135
      status == 'pending'
136 137 138
    end

    def running?
139
      status == 'running'
140 141 142
    end

    def success?
143
      status == 'success'
144 145 146 147 148 149 150
    end

    def failed?
      status == 'failed'
    end

    def canceled?
151
      status == 'canceled'
152 153
    end

154 155 156 157 158 159 160 161
    def active?
      running? || pending?
    end

    def complete?
      canceled? || success? || failed?
    end

Kamil Trzcinski committed
162
    def duration
163
      duration_array = statuses.map(&:duration).compact
Kamil Trzcinski committed
164
      duration_array.reduce(:+).to_i
165 166
    end

167 168 169 170
    def started_at
      @started_at ||= statuses.order('started_at ASC').first.try(:started_at)
    end

171
    def finished_at
172
      @finished_at ||= statuses.order('finished_at DESC').first.try(:finished_at)
173 174 175
    end

    def coverage
176
      coverage_array = latest_statuses.map(&:coverage).compact
177 178
      if coverage_array.size >= 1
        '%.2f' % (coverage_array.reduce(:+) / coverage_array.size)
179 180 181 182
      end
    end

    def config_processor
183
      return nil unless ci_yaml_file
184
      @config_processor ||= Ci::GitlabCiYamlProcessor.new(ci_yaml_file, project.path_with_namespace)
185
    rescue Ci::GitlabCiYamlProcessor::ValidationError, Psych::SyntaxError => e
186 187
      save_yaml_error(e.message)
      nil
188 189
    rescue
      save_yaml_error("Undefined error")
190 191 192
      nil
    end

193
    def ci_yaml_file
194 195 196 197 198
      @ci_yaml_file ||= begin
        blob = project.repository.blob_at(sha, '.gitlab-ci.yml')
        blob.load_all_data!(project.repository)
        blob.data
      end
199 200 201 202
    rescue
      nil
    end

203
    def skip_ci?
204
      git_commit_message =~ /(\[ci skip\])/ if git_commit_message
205 206 207 208 209 210 211 212 213 214 215
    end

    private

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