Commit 546a3c65 authored by Kamil Trzcinski's avatar Kamil Trzcinski
Browse files

Refactor commit and build

parent 32f957b9203c
......@@ -18,7 +18,7 @@ def show
if commit
# Redirect to commit page
redirect_to ci_project_ref_commit_path(@project, @build.commit.ref, @build.commit.sha)
redirect_to ci_project_commit_path(@project, @build.commit)
return
end
end
......
......@@ -13,7 +13,7 @@ def show
end
def status
commit = Ci::Project.find(params[:project_id]).commits.find_by_sha_and_ref!(params[:id], params[:ref_id])
commit = Ci::Project.find(params[:project_id]).commits.find_by_sha!(params[:id], params[:ref_id])
render json: commit.to_json(only: [:id, :sha], methods: [:status, :coverage])
rescue ActiveRecord::RecordNotFound
render json: { status: "not_found" }
......@@ -22,7 +22,7 @@ def status
def cancel
commit.builds.running_or_pending.each(&:cancel)
redirect_to ci_project_ref_commits_path(project, commit.ref, commit.sha)
redirect_to ci_project_commits_path(project, commit.sha)
end
private
......@@ -32,7 +32,7 @@ def project
end
def commit
@commit ||= Ci::Project.find(params[:project_id]).commits.find_by_sha_and_ref!(params[:id], params[:ref_id])
@commit ||= Ci::Project.find(params[:project_id]).commits.find_by_sha!(params[:id])
end
end
end
......@@ -19,7 +19,8 @@ def show
@ref = params[:ref]
@commits = @project.commits.reverse_order
@commits = @commits.where(ref: @ref) if @ref
# TODO: this is broken
# @commits = @commits.where(ref: @ref) if @ref
@commits = @commits.page(params[:page]).per(20)
end
......
module Ci
module CommitsHelper
def ci_commit_path(commit)
ci_project_ref_commits_path(commit.project, commit.ref, commit.sha)
ci_project_commits_path(commit.project, commit)
end
def commit_link(commit)
......
......@@ -26,7 +26,7 @@ def gitlab_commit_link project, sha
def yaml_web_editor_link(project)
commits = project.commits
if commits.any? && commits.last.push_data[:ci_yaml_file]
if commits.any? && commits.last.ci_yaml_file
"#{project.gitlab_url}/edit/master/.gitlab-ci.yml"
else
"#{project.gitlab_url}/new/master"
......
module CiStatusHelper
def ci_status_path(ci_commit)
ci_project_ref_commits_path(ci_commit.project, ci_commit.ref, ci_commit)
ci_project_commits_path(ci_commit.project, ci_commit)
end
def ci_status_icon(ci_commit)
......
......@@ -34,10 +34,12 @@ class Build < ActiveRecord::Base
belongs_to :trigger_request, class_name: 'Ci::TriggerRequest'
serialize :options
serialize :push_data
validates :commit, presence: true
validates :status, presence: true
validates :coverage, numericality: true, allow_blank: true
validates_presence_of :ref
scope :running, ->() { where(status: "running") }
scope :pending, ->() { where(status: "pending") }
......@@ -45,6 +47,9 @@ class Build < ActiveRecord::Base
scope :failed, ->() { where(status: "failed") }
scope :unstarted, ->() { where(runner_id: nil) }
scope :running_or_pending, ->() { where(status:[:running, :pending]) }
scope :latest, ->() { group(:name).order(stage_idx: :asc, created_at: :desc) }
scope :ignore_failures, ->() { where(allow_failure: false) }
scope :for_ref, ->(ref) { where(ref: ref) }
acts_as_taggable
......@@ -82,6 +87,7 @@ def retry(build)
new_build.name = build.name
new_build.allow_failure = build.allow_failure
new_build.stage = build.stage
new_build.stage_idx = build.stage_idx
new_build.trigger_request = build.trigger_request
new_build.save
new_build
......@@ -187,6 +193,16 @@ def project_name
project.name
end
def project_recipients
recipients = project.email_recipients.split(' ')
if project.email_add_pusher? && push_data[:user_email].present?
recipients << push_data[:user_email]
end
recipients.uniq
end
def repo_url
project.repo_url_with_auth
end
......
......@@ -23,9 +23,7 @@ class Commit < ActiveRecord::Base
has_many :builds, dependent: :destroy, class_name: 'Ci::Build'
has_many :trigger_requests, dependent: :destroy, class_name: 'Ci::TriggerRequest'
serialize :push_data
validates_presence_of :ref, :sha, :before_sha, :push_data
validates_presence_of :sha
validate :valid_commit_sha
def self.truncate_sha(sha)
......@@ -69,15 +67,15 @@ def compare?
end
def git_author_name
commit_data[:author][:name] if commit_data && commit_data[:author]
commit_data.author_name if commit_data
end
def git_author_email
commit_data[:author][:email] if commit_data && commit_data[:author]
commit_data.author_email if commit_data
end
def git_commit_message
commit_data[:message] if commit_data && commit_data[:message]
commit_data.message if commit_data
end
def short_before_sha
......@@ -89,84 +87,31 @@ def short_sha
end
def commit_data
push_data[:commits].find do |commit|
commit[:id] == sha
end
@commit ||= gl_project.commit(sha)
rescue
nil
end
def project_recipients
recipients = project.email_recipients.split(' ')
if project.email_add_pusher? && push_data[:user_email].present?
recipients << push_data[:user_email]
end
recipients.uniq
end
def stage
return unless config_processor
stages = builds_without_retry.select(&:active?).map(&:stage)
config_processor.stages.find { |stage| stages.include? stage }
builds_without_retry.group(:stage_idx).select(:stage).last
end
def create_builds_for_stage(stage, trigger_request)
def create_builds(ref, tag, push_data, trigger_request = nil)
return if skip_ci? && trigger_request.blank?
return unless config_processor
builds_attrs = config_processor.builds_for_stage_and_ref(stage, ref, tag)
builds_attrs.map do |build_attrs|
builds.create!({
name: build_attrs[:name],
commands: build_attrs[:script],
tag_list: build_attrs[:tags],
options: build_attrs[:options],
allow_failure: build_attrs[:allow_failure],
stage: build_attrs[:stage],
trigger_request: trigger_request,
})
end
CreateBuildsService.new.execute(self, config_processor, ref, tag, push_data, trigger_request)
end
def create_next_builds(trigger_request)
return if skip_ci? && trigger_request.blank?
return unless config_processor
stages = builds.where(trigger_request: trigger_request).group_by(&:stage)
config_processor.stages.any? do |stage|
!stages.include?(stage) && create_builds_for_stage(stage, trigger_request).present?
end
def refs
builds.group(:ref).pluck(:ref)
end
def create_builds(trigger_request = nil)
return if skip_ci? && trigger_request.blank?
return unless config_processor
config_processor.stages.any? do |stage|
create_builds_for_stage(stage, trigger_request).present?
end
def last_ref
builds.latest.first.try(:ref)
end
def builds_without_retry
@builds_without_retry ||=
begin
grouped_builds = builds.group_by(&:name)
grouped_builds.map do |name, builds|
builds.sort_by(&:id).last
end
end
end
def builds_without_retry_sorted
return builds_without_retry unless config_processor
stages = config_processor.stages
builds_without_retry.sort_by do |build|
[stages.index(build.stage) || -1, build.name || ""]
end
builds.latest
end
def retried_builds
......@@ -180,35 +125,32 @@ def status
return 'failed'
elsif builds.none?
return 'skipped'
elsif success?
'success'
elsif pending?
'pending'
elsif running?
'running'
elsif canceled?
'canceled'
end
statuses = builds_without_retry.ignore_failures.pluck(:status)
if statuses.all? { |status| status == 'success' }
return 'success'
elsif statuses.all? { |status| status == 'pending' }
return 'pending'
elsif statuses.include?('running') || statuses.include?('pending')
return 'running'
elsif statuses.all? { |status| status == 'canceled' }
return 'canceled'
else
'failed'
return 'failed'
end
end
def pending?
builds_without_retry.all? do |build|
build.pending?
end
status == 'pending'
end
def running?
builds_without_retry.any? do |build|
build.running? || build.pending?
end
status == 'running'
end
def success?
builds_without_retry.all? do |build|
build.success? || build.ignored?
end
status == 'success'
end
def failed?
......@@ -216,15 +158,17 @@ def failed?
end
def canceled?
builds_without_retry.all? do |build|
build.canceled?
end
status == 'canceled'
end
def duration
@duration ||= builds_without_retry.select(&:duration).sum(&:duration).to_i
end
def duration_for_ref(ref)
builds_without_retry.for_ref(ref).select(&:duration).sum(&:duration).to_i
end
def finished_at
@finished_at ||= builds.order('finished_at DESC').first.try(:finished_at)
end
......@@ -238,12 +182,12 @@ def coverage
end
end
def matrix?
builds_without_retry.size > 1
def matrix_for_ref?(ref)
builds_without_retry.for_ref(ref).pluck(:id).size > 1
end
def config_processor
@config_processor ||= Ci::GitlabCiYamlProcessor.new(push_data[:ci_yaml_file])
@config_processor ||= Ci::GitlabCiYamlProcessor.new(ci_yaml_file)
rescue Ci::GitlabCiYamlProcessor::ValidationError => e
save_yaml_error(e.message)
nil
......@@ -253,10 +197,15 @@ def config_processor
nil
end
def ci_yaml_file
gl_project.repository.blob_at(sha, '.gitlab-ci.yml')
rescue
nil
end
def skip_ci?
return false if builds.any?
commits = push_data[:commits]
commits.present? && commits.last[:message] =~ /(\[ci skip\])/
git_commit_message =~ /(\[ci skip\])/ if git_commit_message
end
def update_committed!
......
......@@ -28,18 +28,6 @@ def human_status
status
end
# only check for toggling build status within same ref.
def last_commit_changed_status?
ref = last_commit.ref
last_commits = commits.where(ref: ref).last(2)
if last_commits.size < 2
false
else
last_commits[0].status != last_commits[1].status
end
end
def last_commit_for_ref(ref)
commits.where(ref: ref).last
end
......
......@@ -744,7 +744,11 @@ def create_wiki
end
def ci_commit(sha)
gitlab_ci_project.commits.find_by(sha: sha) if gitlab_ci?
ci_commits.find_by(sha: sha)
end
def ensure_ci_commit(sha)
ci_commit(sha) || ci_commits.create(sha: sha)
end
def ensure_gitlab_ci_project
......
......@@ -13,7 +13,7 @@ def to_s
lines.push("<a href=\"#{ci_project_url(project)}\">#{project.name}</a> - ")
if commit.matrix?
lines.push("<a href=\"#{ci_project_ref_commits_url(project, commit.ref, commit.sha)}\">Commit ##{commit.id}</a></br>")
lines.push("<a href=\"#{ci_project_commits_url(project, commit.sha)}\">Commit ##{commit.id}</a></br>")
else
first_build = commit.builds_without_retry.first
lines.push("<a href=\"#{ci_project_build_url(project, first_build)}\">Build '#{first_build.name}' ##{first_build.id}</a></br>")
......
......@@ -61,7 +61,7 @@ def can_execute?(build)
end
def execute(build)
build.commit.project_recipients.each do |recipient|
build.project_recipients.each do |recipient|
case build.status.to_sym
when :success
mailer.build_success_email(build.id, recipient)
......
......@@ -48,7 +48,7 @@ def attachments
def attachment_message
out = "<#{ci_project_url(project)}|#{project_name}>: "
if commit.matrix?
out << "Commit <#{ci_project_ref_commits_url(project, commit.ref, commit.sha)}|\##{commit.id}> "
out << "Commit <#{ci_project_commits_url(project, commit.sha)}|\##{commit.id}> "
else
build = commit.builds_without_retry.first
out << "Build <#{ci_project_build_url(project, build)}|\##{build.id}> "
......
......@@ -63,7 +63,7 @@ def token
end
def get_ci_commit(sha, ref)
Ci::Project.find(project.gitlab_ci_project).commits.find_by_sha_and_ref!(sha, ref)
Ci::Project.find(project.gitlab_ci_project).commits.find_by_sha!(sha)
end
def commit_status(sha, ref)
......@@ -80,7 +80,7 @@ def commit_coverage(sha, ref)
def build_page(sha, ref)
if project.gitlab_ci_project.present?
ci_project_ref_commits_url(project.gitlab_ci_project, ref, sha)
ci_project_commits_url(project.gitlab_ci_project, sha)
end
end
......
module Ci
class CreateBuildsService
def execute(commit, ref, tag, push_data, config_processor, trigger_request)
config_processor.stages.any? do |stage|
builds_attrs = config_processor.builds_for_stage_and_ref(stage, ref, tag)
builds_attrs.map do |build_attrs|
# don't create the same build twice
unless commit.builds.find_by_name_and_trigger_request(name: build_attrs[:name], ref: ref, tag: tag, trigger_request: trigger_request)
commit.builds.create!({
name: build_attrs[:name],
commands: build_attrs[:script],
tag_list: build_attrs[:tags],
options: build_attrs[:options],
allow_failure: build_attrs[:allow_failure],
stage: build_attrs[:stage],
stage_idx: build_attrs[:stage_idx],
trigger_request: trigger_request,
ref: ref,
tag: tag,
push_data: push_data,
})
end
end
end
end
end
end
......@@ -16,33 +16,22 @@ def execute(project, params)
return false
end
commit = project.commits.find_by_sha_and_ref(sha, ref)
# Create commit if not exists yet
unless commit
data = {
ref: ref,
sha: sha,
tag: origin_ref.start_with?('refs/tags/'),
before_sha: before_sha,
push_data: {
before: before_sha,
after: sha,
ref: ref,
user_name: params[:user_name],
user_email: params[:user_email],
repository: params[:repository],
commits: params[:commits],
total_commits_count: params[:total_commits_count],
ci_yaml_file: params[:ci_yaml_file]
}
}
commit = project.commits.create(data)
end
tag = origin_ref.start_with?('refs/tags/')
push_data = {
before: before_sha,
after: sha,
ref: ref,
user_name: params[:user_name],
user_email: params[:user_email],
repository: params[:repository],
commits: params[:commits],
total_commits_count: params[:total_commits_count],
ci_yaml_file: params[:ci_yaml_file]
}
commit = project.gl_project.ensure_ci_commit(sha)
commit.update_committed!
commit.create_builds unless commit.builds.any?
commit.create_builds(ref, tag, push_data)
commit
end
......
module Ci
class CreateTriggerRequestService
def execute(project, trigger, ref, variables = nil)
commit = project.commits.where(ref: ref).last
commit = project.gl_project.commit(ref)
return unless commit
ci_commit = project.gl_project.ensure_ci_commit(commit.sha)
trigger_request = trigger.trigger_requests.create!(
commit: commit,
variables: variables
)
if commit.create_builds(trigger_request)
if ci_commit.create_builds(ref, tag, nil, trigger_request)
trigger_request
end
end
......
......@@ -6,6 +6,10 @@
= link_to ci_project_build_path(build.project, build) do
%strong Build ##{build.id}
- if defined?(ref)
%td
= build.ref
%td
= build.stage
......
#up-build-trace
- if @commit.matrix?
- if @commit.matrix_for_ref?(@build.ref)
%ul.center-top-menu
- @commit.builds_without_retry_sorted.each do |build|
- @commit.builds_without_retry.for_ref(build.ref).each do |build|
%li{class: ('active' if build == @build) }
= link_to ci_project_build_url(@project, build) do
= ci_icon_for_status(build.status)
......@@ -12,7 +12,7 @@
= build.id
- unless @commit.builds_without_retry.include?(@build)
- unless @commit.builds_without_retry.for_ref(@build.ref).include?(@build)
%li.active
%a
Build ##{@build.id}
......
......@@ -7,7 +7,7 @@
%td.build-link
= link_to ci_project_ref_commits_path(commit.project, commit.ref, commit.sha) do
= link_to ci_project_commits_path(commit.project, commit.sha) do
%strong #{commit.short_sha}
%td.build-message
......@@ -16,7 +16,7 @@
%td.build-branch
- unless @ref
%span
= link_to truncate(commit.ref, length: 25), ci_project_path(@project, ref: commit.ref)
= link_to truncate(commit.last_ref, length: 25), ci_project_path(@project, ref: commit.last_ref)
%td.duration
- if commit.duration > 0
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment