Merge branch 'refactor-build-service' into 'master'
Refactor Ci::Commit and Ci::Build to have all builds for same :sha on single page This makes Ci::Commit to have only :sha and simplifies routing to have only :sha in path. The :ref and :push_data is now parameter of Ci::Build. All commit related data (git author, message and .gitlab-ci.yml) is read directly from repository. All code related for creating builds is moved to CreateBuildsService. Status deduction is rewritten to make if more efficient and easier to integrate with Commit Status API. This is partially working, tests are not yet touched. This slightly changes view of Commit: ![Screen_Shot_2015-10-02_at_15.21.47](https://gitlab.com/gitlab-org/gitlab-ce/uploads/ad3f1ccdcc87659ea437d8db6c5b9f94/Screen_Shot_2015-10-02_at_15.21.47.png) @dzaporozhets What do you think? See merge request !1502
This commit is contained in:
commit
3eef0e18e0
55 changed files with 573 additions and 607 deletions
|
@ -18,7 +18,7 @@ module Ci
|
|||
|
||||
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 @@ module Ci
|
|||
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])
|
||||
render json: commit.to_json(only: [:id, :sha], methods: [:status, :coverage])
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
render json: { status: "not_found" }
|
||||
|
@ -22,7 +22,7 @@ module Ci
|
|||
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 @@ module Ci
|
|||
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 @@ module Ci
|
|||
@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
|
||||
|
||||
|
|
|
@ -3,10 +3,6 @@ module BuildsHelper
|
|||
gitlab_ref_link build.project, build.ref
|
||||
end
|
||||
|
||||
def build_compare_link build
|
||||
gitlab_compare_link build.project, build.commit.short_before_sha, build.short_sha
|
||||
end
|
||||
|
||||
def build_commit_link build
|
||||
gitlab_commit_link build.project, build.short_sha
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
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 @@ module Ci
|
|||
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"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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)
|
||||
|
|
|
@ -32,12 +32,14 @@ module Ci
|
|||
belongs_to :commit, class_name: 'Ci::Commit'
|
||||
belongs_to :runner, class_name: 'Ci::Runner'
|
||||
belongs_to :trigger_request, class_name: 'Ci::TriggerRequest'
|
||||
belongs_to :user
|
||||
|
||||
serialize :options
|
||||
|
||||
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,10 @@ module Ci
|
|||
scope :failed, ->() { where(status: "failed") }
|
||||
scope :unstarted, ->() { where(runner_id: nil) }
|
||||
scope :running_or_pending, ->() { where(status:[:running, :pending]) }
|
||||
scope :latest, ->() { where(id: unscope(:select).select('max(id)').group(:name)).order(stage_idx: :asc) }
|
||||
scope :ignore_failures, ->() { where(allow_failure: false) }
|
||||
scope :for_ref, ->(ref) { where(ref: ref) }
|
||||
scope :similar, ->(build) { where(ref: build.ref, tag: build.tag, trigger_request_id: build.trigger_request_id) }
|
||||
|
||||
acts_as_taggable
|
||||
|
||||
|
@ -75,6 +81,8 @@ module Ci
|
|||
|
||||
def retry(build)
|
||||
new_build = Ci::Build.new(status: :pending)
|
||||
new_build.ref = build.ref
|
||||
new_build.tag = build.tag
|
||||
new_build.options = build.options
|
||||
new_build.commands = build.commands
|
||||
new_build.tag_list = build.tag_list
|
||||
|
@ -82,6 +90,7 @@ module Ci
|
|||
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
|
||||
|
@ -117,8 +126,8 @@ module Ci
|
|||
Ci::WebHookService.new.build_end(build)
|
||||
end
|
||||
|
||||
if build.commit.success?
|
||||
build.commit.create_next_builds(build.trigger_request)
|
||||
if build.commit.should_create_next_builds?(build)
|
||||
build.commit.create_next_builds(build.ref, build.tag, build.user, build.trigger_request)
|
||||
end
|
||||
|
||||
project.execute_services(build)
|
||||
|
@ -135,9 +144,13 @@ module Ci
|
|||
state :canceled, value: 'canceled'
|
||||
end
|
||||
|
||||
delegate :sha, :short_sha, :before_sha, :ref, :project,
|
||||
delegate :sha, :short_sha, :project,
|
||||
to: :commit, prefix: false
|
||||
|
||||
def before_sha
|
||||
Gitlab::Git::BLANK_SHA
|
||||
end
|
||||
|
||||
def trace_html
|
||||
html = Ci::Ansi2html::convert(trace) if trace.present?
|
||||
html || ''
|
||||
|
@ -187,6 +200,16 @@ module Ci
|
|||
project.name
|
||||
end
|
||||
|
||||
def project_recipients
|
||||
recipients = project.email_recipients.split(' ')
|
||||
|
||||
if project.email_add_pusher? && user.present? && user.notification_email.present?
|
||||
recipients << user.notification_email
|
||||
end
|
||||
|
||||
recipients.uniq
|
||||
end
|
||||
|
||||
def repo_url
|
||||
project.repo_url_with_auth
|
||||
end
|
||||
|
|
|
@ -23,9 +23,7 @@ module Ci
|
|||
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)
|
||||
|
@ -60,28 +58,16 @@ module Ci
|
|||
end
|
||||
end
|
||||
|
||||
def new_branch?
|
||||
before_sha == Ci::Git::BLANK_SHA
|
||||
end
|
||||
|
||||
def compare?
|
||||
!new_branch?
|
||||
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]
|
||||
end
|
||||
|
||||
def short_before_sha
|
||||
Ci::Commit.truncate_sha(before_sha)
|
||||
commit_data.message if commit_data
|
||||
end
|
||||
|
||||
def short_sha
|
||||
|
@ -89,84 +75,51 @@ module Ci
|
|||
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 }
|
||||
running_or_pending = builds_without_retry.running_or_pending
|
||||
running_or_pending.limit(1).pluck(:stage).first
|
||||
end
|
||||
|
||||
def create_builds_for_stage(stage, trigger_request)
|
||||
def create_builds(ref, tag, user, 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,
|
||||
})
|
||||
config_processor.stages.any? do |stage|
|
||||
CreateBuildsService.new.execute(self, stage, ref, tag, user, trigger_request).present?
|
||||
end
|
||||
end
|
||||
|
||||
def create_next_builds(trigger_request)
|
||||
def create_next_builds(ref, tag, user, trigger_request)
|
||||
return if skip_ci? && trigger_request.blank?
|
||||
return unless config_processor
|
||||
|
||||
stages = builds.where(trigger_request: trigger_request).group_by(&:stage)
|
||||
stages = builds.where(ref: ref, tag: tag, trigger_request: trigger_request).group_by(&:stage)
|
||||
|
||||
config_processor.stages.any? do |stage|
|
||||
!stages.include?(stage) && create_builds_for_stage(stage, trigger_request).present?
|
||||
unless stages.include?(stage)
|
||||
CreateBuildsService.new.execute(self, stage, ref, tag, user, trigger_request).present?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create_builds(trigger_request = nil)
|
||||
return if skip_ci? && trigger_request.blank?
|
||||
return unless config_processor
|
||||
def refs
|
||||
builds.group(:ref).pluck(:ref)
|
||||
end
|
||||
|
||||
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
|
||||
builds.latest
|
||||
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
|
||||
def builds_without_retry_for_ref(ref)
|
||||
builds.for_ref(ref).latest
|
||||
end
|
||||
|
||||
def retried_builds
|
||||
|
@ -225,6 +178,10 @@ module Ci
|
|||
@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 +195,12 @@ module Ci
|
|||
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,16 +210,31 @@ module Ci
|
|||
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!
|
||||
update!(committed_at: DateTime.now)
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
private
|
||||
|
||||
def save_yaml_error(error)
|
||||
|
|
|
@ -28,18 +28,6 @@ module Ci
|
|||
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 @@ class Project < ActiveRecord::Base
|
|||
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
|
||||
|
|
|
@ -11,14 +11,7 @@ module Ci
|
|||
def to_s
|
||||
lines = Array.new
|
||||
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>")
|
||||
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>")
|
||||
end
|
||||
|
||||
lines.push("<a href=\"#{ci_project_commits_url(project, commit.sha)}\">Commit ##{commit.id}</a></br>")
|
||||
lines.push("#{commit.short_sha} #{commit.git_author_name} - #{commit.git_commit_message}</br>")
|
||||
lines.push("#{humanized_status(commit_status)} in #{commit.duration} second(s).")
|
||||
lines.join('')
|
||||
|
|
|
@ -61,7 +61,7 @@ module Ci
|
|||
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)
|
||||
|
|
|
@ -23,15 +23,13 @@ module Ci
|
|||
def attachments
|
||||
fields = []
|
||||
|
||||
if commit.matrix?
|
||||
commit.builds_without_retry.each do |build|
|
||||
next if build.allow_failure?
|
||||
next unless build.failed?
|
||||
fields << {
|
||||
title: build.name,
|
||||
value: "Build <#{ci_project_build_url(project, build)}|\##{build.id}> failed in #{build.duration.to_i} second(s)."
|
||||
}
|
||||
end
|
||||
commit.builds_without_retry.each do |build|
|
||||
next if build.allow_failure?
|
||||
next unless build.failed?
|
||||
fields << {
|
||||
title: build.name,
|
||||
value: "Build <#{ci_project_build_url(project, build)}|\##{build.id}> failed in #{build.duration.to_i} second(s)."
|
||||
}
|
||||
end
|
||||
|
||||
[{
|
||||
|
@ -47,12 +45,7 @@ module Ci
|
|||
|
||||
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}> "
|
||||
else
|
||||
build = commit.builds_without_retry.first
|
||||
out << "Build <#{ci_project_build_url(project, build)}|\##{build.id}> "
|
||||
end
|
||||
out << "Commit <#{ci_project_commits_url(project, commit.sha)}|\##{commit.id}> "
|
||||
out << "(<#{commit_sha_link}|#{commit.short_sha}>) "
|
||||
out << "of <#{commit_ref_link}|#{commit.ref}> "
|
||||
out << "by #{commit.git_author_name} " if commit.git_author_name
|
||||
|
|
|
@ -40,19 +40,10 @@ class GitlabCiService < CiService
|
|||
def execute(data)
|
||||
return unless supported_events.include?(data[:object_kind])
|
||||
|
||||
sha = data[:checkout_sha]
|
||||
|
||||
if sha.present?
|
||||
file = ci_yaml_file(sha)
|
||||
|
||||
if file && file.data
|
||||
data.merge!(ci_yaml_file: file.data)
|
||||
end
|
||||
end
|
||||
|
||||
ci_project = Ci::Project.find_by(gitlab_id: project.id)
|
||||
ci_project = project.gitlab_ci_project
|
||||
if ci_project
|
||||
Ci::CreateCommitService.new.execute(ci_project, data)
|
||||
current_user = User.find_by(id: data[:user_id])
|
||||
Ci::CreateCommitService.new.execute(ci_project, current_user, data)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -63,7 +54,7 @@ class GitlabCiService < CiService
|
|||
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 +71,7 @@ class GitlabCiService < CiService
|
|||
|
||||
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
|
||||
|
||||
|
@ -99,14 +90,4 @@ class GitlabCiService < CiService
|
|||
def fields
|
||||
[]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ci_yaml_file(sha)
|
||||
repository.blob_at(sha, '.gitlab-ci.yml')
|
||||
end
|
||||
|
||||
def repository
|
||||
project.repository
|
||||
end
|
||||
end
|
||||
|
|
|
@ -130,6 +130,7 @@ class User < ActiveRecord::Base
|
|||
has_many :assigned_merge_requests, dependent: :destroy, foreign_key: :assignee_id, class_name: "MergeRequest"
|
||||
has_many :oauth_applications, class_name: 'Doorkeeper::Application', as: :owner, dependent: :destroy
|
||||
has_one :abuse_report, dependent: :destroy
|
||||
has_many :ci_builds, dependent: :nullify, class_name: 'Ci::Build'
|
||||
|
||||
|
||||
#
|
||||
|
|
27
app/services/ci/create_builds_service.rb
Normal file
27
app/services/ci/create_builds_service.rb
Normal file
|
@ -0,0 +1,27 @@
|
|||
module Ci
|
||||
class CreateBuildsService
|
||||
def execute(commit, stage, ref, tag, user, trigger_request)
|
||||
builds_attrs = commit.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(ref: ref, tag: tag, trigger_request: trigger_request, name: build_attrs[:name])
|
||||
build_attrs.slice!(:name,
|
||||
:commands,
|
||||
:tag_list,
|
||||
:options,
|
||||
:allow_failure,
|
||||
:stage,
|
||||
:stage_idx)
|
||||
|
||||
build_attrs.merge!(ref: ref,
|
||||
tag: tag,
|
||||
trigger_request: trigger_request,
|
||||
user: user)
|
||||
|
||||
commit.builds.create!(build_attrs)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,7 +1,6 @@
|
|||
module Ci
|
||||
class CreateCommitService
|
||||
def execute(project, params)
|
||||
before_sha = params[:before]
|
||||
def execute(project, user, params)
|
||||
sha = params[:checkout_sha] || params[:after]
|
||||
origin_ref = params[:ref]
|
||||
|
||||
|
@ -16,33 +15,10 @@ module Ci
|
|||
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/')
|
||||
commit = project.gl_project.ensure_ci_commit(sha)
|
||||
commit.update_committed!
|
||||
commit.create_builds unless commit.builds.any?
|
||||
commit.create_builds(ref, tag, user)
|
||||
|
||||
commit
|
||||
end
|
||||
|
|
|
@ -1,15 +1,20 @@
|
|||
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
|
||||
|
||||
# check if ref is tag
|
||||
tag = project.gl_project.repository.find_tag(ref).present?
|
||||
|
||||
ci_commit = project.gl_project.ensure_ci_commit(commit.sha)
|
||||
|
||||
trigger_request = trigger.trigger_requests.create!(
|
||||
commit: commit,
|
||||
variables: variables
|
||||
variables: variables,
|
||||
commit: ci_commit,
|
||||
)
|
||||
|
||||
if commit.create_builds(trigger_request)
|
||||
if ci_commit.create_builds(ref, tag, nil, trigger_request)
|
||||
trigger_request
|
||||
end
|
||||
end
|
||||
|
|
|
@ -27,9 +27,8 @@ module Ci
|
|||
project_name: project.name,
|
||||
gitlab_url: project.gitlab_url,
|
||||
ref: build.ref,
|
||||
sha: build.sha,
|
||||
before_sha: build.before_sha,
|
||||
push_data: build.commit.push_data
|
||||
sha: build.sha,
|
||||
})
|
||||
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
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#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}
|
||||
|
@ -122,11 +122,6 @@
|
|||
Commit
|
||||
.pull-right
|
||||
%small #{build_commit_link @build}
|
||||
|
||||
- if @build.commit.compare?
|
||||
%p
|
||||
%span.attr-name Compare:
|
||||
#{build_compare_link @build}
|
||||
%p
|
||||
%span.attr-name Branch:
|
||||
#{build_ref_link @build}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -9,22 +9,14 @@
|
|||
.gray-content-block.second-block
|
||||
.row
|
||||
.col-sm-6
|
||||
- if @commit.compare?
|
||||
%p
|
||||
%span.attr-name Compare:
|
||||
#{gitlab_compare_link(@project, @commit.short_before_sha, @commit.short_sha)}
|
||||
- else
|
||||
%p
|
||||
%span.attr-name Commit:
|
||||
#{gitlab_commit_link(@project, @commit.sha)}
|
||||
|
||||
%p
|
||||
%span.attr-name Branch:
|
||||
#{gitlab_ref_link(@project, @commit.ref)}
|
||||
%p
|
||||
%span.attr-name Commit:
|
||||
#{gitlab_commit_link(@project, @commit.sha)}
|
||||
.col-sm-6
|
||||
%p
|
||||
%span.attr-name Author:
|
||||
#{@commit.git_author_name} (#{@commit.git_author_email})
|
||||
- if @commit.git_author_name || @commit.git_author_email
|
||||
%p
|
||||
%span.attr-name Author:
|
||||
#{@commit.git_author_name} (#{@commit.git_author_email})
|
||||
- if @commit.created_at
|
||||
%p
|
||||
%span.attr-name Created at:
|
||||
|
@ -33,7 +25,7 @@
|
|||
- if current_user && can?(current_user, :manage_builds, gl_project)
|
||||
.pull-right
|
||||
- if @commit.builds.running_or_pending.any?
|
||||
= link_to "Cancel", cancel_ci_project_ref_commits_path(@project, @commit.ref, @commit.sha), class: 'btn btn-sm btn-danger'
|
||||
= link_to "Cancel", cancel_ci_project_commits_path(@project, @commit), class: 'btn btn-sm btn-danger'
|
||||
|
||||
|
||||
- if @commit.yaml_errors.present?
|
||||
|
@ -43,34 +35,17 @@
|
|||
- @commit.yaml_errors.split(",").each do |error|
|
||||
%li= error
|
||||
|
||||
- unless @commit.push_data[:ci_yaml_file]
|
||||
- unless @commit.ci_yaml_file
|
||||
.bs-callout.bs-callout-warning
|
||||
\.gitlab-ci.yml not found in this commit
|
||||
|
||||
%h3
|
||||
Builds
|
||||
- if @commit.duration > 0
|
||||
%small.pull-right
|
||||
%i.fa.fa-time
|
||||
#{time_interval_in_words @commit.duration}
|
||||
|
||||
%table.table.builds
|
||||
%thead
|
||||
%tr
|
||||
%th Status
|
||||
%th Build ID
|
||||
%th Stage
|
||||
%th Name
|
||||
%th Duration
|
||||
%th Finished at
|
||||
- if @project.coverage_enabled?
|
||||
%th Coverage
|
||||
%th
|
||||
= render @commit.builds_without_retry_sorted, controls: true
|
||||
|
||||
- if @commit.retried_builds.any?
|
||||
- @commit.refs.each do |ref|
|
||||
%h3
|
||||
Retried builds
|
||||
Builds for #{ref}
|
||||
- if @commit.duration_for_ref(ref) > 0
|
||||
%small.pull-right
|
||||
%i.fa.fa-time
|
||||
#{time_interval_in_words @commit.duration_for_ref(ref)}
|
||||
|
||||
%table.table.builds
|
||||
%thead
|
||||
|
@ -84,4 +59,23 @@
|
|||
- if @project.coverage_enabled?
|
||||
%th Coverage
|
||||
%th
|
||||
= render @commit.retried_builds
|
||||
= render @commit.builds_without_retry.for_ref(ref), controls: true
|
||||
|
||||
- if @commit.retried_builds.any?
|
||||
%h3
|
||||
Retried builds
|
||||
|
||||
%table.table.builds
|
||||
%thead
|
||||
%tr
|
||||
%th Status
|
||||
%th Build ID
|
||||
%th Ref
|
||||
%th Stage
|
||||
%th Name
|
||||
%th Duration
|
||||
%th Finished at
|
||||
- if @project.coverage_enabled?
|
||||
%th Coverage
|
||||
%th
|
||||
= render @commit.retried_builds, ref: true
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
%p
|
||||
Author: #{@build.commit.git_author_name}
|
||||
%p
|
||||
Branch: #{@build.commit.ref}
|
||||
Branch: #{@build.ref}
|
||||
%p
|
||||
Message: #{@build.commit.git_commit_message}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ Build failed for <%= @project.name %>
|
|||
Status: <%= @build.status %>
|
||||
Commit: <%= @build.commit.short_sha %>
|
||||
Author: <%= @build.commit.git_author_name %>
|
||||
Branch: <%= @build.commit.ref %>
|
||||
Branch: <%= @build.ref %>
|
||||
Message: <%= @build.commit.git_commit_message %>
|
||||
|
||||
Url: <%= ci_project_build_url(@build.project, @build) %>
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
%p
|
||||
Author: #{@build.commit.git_author_name}
|
||||
%p
|
||||
Branch: #{@build.commit.ref}
|
||||
Branch: #{@build.ref}
|
||||
%p
|
||||
Message: #{@build.commit.git_commit_message}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ Build successful for <%= @project.name %>
|
|||
Status: <%= @build.status %>
|
||||
Commit: <%= @build.commit.short_sha %>
|
||||
Author: <%= @build.commit.git_author_name %>
|
||||
Branch: <%= @build.commit.ref %>
|
||||
Branch: <%= @build.ref %>
|
||||
Message: <%= @build.commit.git_commit_message %>
|
||||
|
||||
Url: <%= ci_project_build_url(@build.project, @build) %>
|
||||
|
|
|
@ -30,12 +30,10 @@ Gitlab::Application.routes.draw do
|
|||
|
||||
resource :charts, only: [:show]
|
||||
|
||||
resources :refs, constraints: { ref_id: /.*/ }, only: [] do
|
||||
resources :commits, only: [:show] do
|
||||
member do
|
||||
get :status
|
||||
get :cancel
|
||||
end
|
||||
resources :commits, only: [:show] do
|
||||
member do
|
||||
get :status
|
||||
get :cancel
|
||||
end
|
||||
end
|
||||
|
||||
|
|
5
db/migrate/20151002112914_add_stage_idx_to_builds.rb
Normal file
5
db/migrate/20151002112914_add_stage_idx_to_builds.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
class AddStageIdxToBuilds < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :ci_builds, :stage_idx, :integer
|
||||
end
|
||||
end
|
5
db/migrate/20151002121400_add_index_for_builds.rb
Normal file
5
db/migrate/20151002121400_add_index_for_builds.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
class AddIndexForBuilds < ActiveRecord::Migration
|
||||
def up
|
||||
add_index :ci_builds, [:commit_id, :stage_idx, :created_at]
|
||||
end
|
||||
end
|
6
db/migrate/20151002122929_add_ref_and_tag_to_builds.rb
Normal file
6
db/migrate/20151002122929_add_ref_and_tag_to_builds.rb
Normal file
|
@ -0,0 +1,6 @@
|
|||
class AddRefAndTagToBuilds < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :ci_builds, :tag, :boolean
|
||||
add_column :ci_builds, :ref, :string
|
||||
end
|
||||
end
|
|
@ -0,0 +1,6 @@
|
|||
class MigrateRefAndTagToBuild < ActiveRecord::Migration
|
||||
def change
|
||||
execute('UPDATE ci_builds SET ref=(SELECT ref FROM ci_commits WHERE ci_commits.id = ci_builds.commit_id) WHERE ref IS NULL')
|
||||
execute('UPDATE ci_builds SET tag=(SELECT tag FROM ci_commits WHERE ci_commits.id = ci_builds.commit_id) WHERE tag IS NULL')
|
||||
end
|
||||
end
|
5
db/migrate/20151005075649_add_user_id_to_build.rb
Normal file
5
db/migrate/20151005075649_add_user_id_to_build.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
class AddUserIdToBuild < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :ci_builds, :user_id, :integer
|
||||
end
|
||||
end
|
|
@ -11,7 +11,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20150930095736) do
|
||||
ActiveRecord::Schema.define(version: 20151005075649) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
@ -100,8 +100,13 @@ ActiveRecord::Schema.define(version: 20150930095736) do
|
|||
t.boolean "allow_failure", default: false, null: false
|
||||
t.string "stage"
|
||||
t.integer "trigger_request_id"
|
||||
t.integer "stage_idx"
|
||||
t.boolean "tag"
|
||||
t.string "ref"
|
||||
t.integer "user_id"
|
||||
end
|
||||
|
||||
add_index "ci_builds", ["commit_id", "stage_idx", "created_at"], name: "index_ci_builds_on_commit_id_and_stage_idx_and_created_at", using: :btree
|
||||
add_index "ci_builds", ["commit_id"], name: "index_ci_builds_on_commit_id", using: :btree
|
||||
add_index "ci_builds", ["project_id", "commit_id"], name: "index_ci_builds_on_project_id_and_commit_id", using: :btree
|
||||
add_index "ci_builds", ["project_id"], name: "index_ci_builds_on_project_id", using: :btree
|
||||
|
|
|
@ -51,7 +51,7 @@ module Ci
|
|||
required_attributes! [:project_id, :data, :project_token]
|
||||
project = Ci::Project.find(params[:project_id])
|
||||
authenticate_project_token!(project)
|
||||
commit = Ci::CreateCommitService.new.execute(project, params[:data])
|
||||
commit = Ci::CreateCommitService.new.execute(project, current_user, params[:data])
|
||||
|
||||
if commit.persisted?
|
||||
present commit, with: Entities::CommitWithBuilds
|
||||
|
|
|
@ -85,9 +85,10 @@ module Ci
|
|||
|
||||
def build_job(name, job)
|
||||
{
|
||||
stage_idx: stages.index(job[:stage]),
|
||||
stage: job[:stage],
|
||||
script: "#{@before_script.join("\n")}\n#{normalize_script(job[:script])}",
|
||||
tags: job[:tags] || [],
|
||||
commands: "#{@before_script.join("\n")}\n#{normalize_script(job[:script])}",
|
||||
tag_list: job[:tags] || [],
|
||||
name: name,
|
||||
only: job[:only],
|
||||
except: job[:except],
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
|
||||
FactoryGirl.define do
|
||||
factory :ci_build, class: Ci::Build do
|
||||
ref 'master'
|
||||
tag false
|
||||
started_at 'Di 29. Okt 09:51:28 CET 2013'
|
||||
finished_at 'Di 29. Okt 09:53:28 CET 2013'
|
||||
commands 'ls -a'
|
||||
|
@ -43,5 +45,9 @@ FactoryGirl.define do
|
|||
started_at nil
|
||||
finished_at nil
|
||||
end
|
||||
|
||||
factory :ci_build_tag do
|
||||
tag true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -17,60 +17,32 @@
|
|||
|
||||
# Read about factories at https://github.com/thoughtbot/factory_girl
|
||||
FactoryGirl.define do
|
||||
factory :ci_commit, class: Ci::Commit do
|
||||
ref 'master'
|
||||
before_sha '76de212e80737a608d939f648d959671fb0a0142'
|
||||
factory :ci_empty_commit, class: Ci::Commit do
|
||||
sha '97de212e80737a608d939f648d959671fb0a0142'
|
||||
push_data do
|
||||
{
|
||||
ref: 'refs/heads/master',
|
||||
before: '76de212e80737a608d939f648d959671fb0a0142',
|
||||
after: '97de212e80737a608d939f648d959671fb0a0142',
|
||||
user_name: 'Git User',
|
||||
user_email: 'git@example.com',
|
||||
repository: {
|
||||
name: 'test-data',
|
||||
url: 'ssh://git@gitlab.com/test/test-data.git',
|
||||
description: '',
|
||||
homepage: 'http://gitlab.com/test/test-data'
|
||||
},
|
||||
commits: [
|
||||
{
|
||||
id: '97de212e80737a608d939f648d959671fb0a0142',
|
||||
message: 'Test commit message',
|
||||
timestamp: '2014-09-23T13:12:25+02:00',
|
||||
url: 'https://gitlab.com/test/test-data/commit/97de212e80737a608d939f648d959671fb0a0142',
|
||||
author: {
|
||||
name: 'Git User',
|
||||
email: 'git@user.com'
|
||||
}
|
||||
}
|
||||
],
|
||||
total_commits_count: 1,
|
||||
ci_yaml_file: File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml'))
|
||||
}
|
||||
end
|
||||
|
||||
gl_project factory: :empty_project
|
||||
|
||||
factory :ci_commit_without_jobs do
|
||||
after(:create) do |commit, evaluator|
|
||||
commit.push_data[:ci_yaml_file] = YAML.dump({})
|
||||
commit.save
|
||||
after(:build) do |commit|
|
||||
allow(commit).to receive(:ci_yaml_file) { YAML.dump({}) }
|
||||
end
|
||||
end
|
||||
|
||||
factory :ci_commit_with_one_job do
|
||||
after(:create) do |commit, evaluator|
|
||||
commit.push_data[:ci_yaml_file] = YAML.dump({ rspec: { script: "ls" } })
|
||||
commit.save
|
||||
after(:build) do |commit|
|
||||
allow(commit).to receive(:ci_yaml_file) { YAML.dump({ rspec: { script: "ls" } }) }
|
||||
end
|
||||
end
|
||||
|
||||
factory :ci_commit_with_two_jobs do
|
||||
after(:create) do |commit, evaluator|
|
||||
commit.push_data[:ci_yaml_file] = YAML.dump({ rspec: { script: "ls" }, spinach: { script: "ls" } })
|
||||
commit.save
|
||||
after(:build) do |commit|
|
||||
allow(commit).to receive(:ci_yaml_file) { YAML.dump({ rspec: { script: "ls" }, spinach: { script: "ls" } }) }
|
||||
end
|
||||
end
|
||||
|
||||
factory :ci_commit do
|
||||
after(:build) do |commit|
|
||||
allow(commit).to receive(:ci_yaml_file) { File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml')) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,6 +11,10 @@ describe "Commits" do
|
|||
@commit.project.gl_project.team << [@user, :master]
|
||||
end
|
||||
|
||||
before do
|
||||
stub_ci_commit_to_return_yaml_file
|
||||
end
|
||||
|
||||
describe "GET /:project/commits/:sha" do
|
||||
before do
|
||||
visit ci_commit_path(@commit)
|
||||
|
@ -38,8 +42,7 @@ describe "Commits" do
|
|||
end
|
||||
|
||||
it "shows warning" do
|
||||
@commit.push_data[:ci_yaml_file] = nil
|
||||
@commit.save
|
||||
stub_ci_commit_yaml_file(nil)
|
||||
|
||||
visit ci_commit_path(@commit)
|
||||
|
||||
|
|
|
@ -17,11 +17,12 @@ module Ci
|
|||
expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(1)
|
||||
expect(config_processor.builds_for_stage_and_ref(type, "master").first).to eq({
|
||||
stage: "test",
|
||||
stage_idx: 1,
|
||||
except: nil,
|
||||
name: :rspec,
|
||||
only: nil,
|
||||
script: "pwd\nrspec",
|
||||
tags: [],
|
||||
commands: "pwd\nrspec",
|
||||
tag_list: [],
|
||||
options: {},
|
||||
allow_failure: false
|
||||
})
|
||||
|
@ -115,10 +116,11 @@ module Ci
|
|||
expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({
|
||||
except: nil,
|
||||
stage: "test",
|
||||
stage_idx: 1,
|
||||
name: :rspec,
|
||||
only: nil,
|
||||
script: "pwd\nrspec",
|
||||
tags: [],
|
||||
commands: "pwd\nrspec",
|
||||
tag_list: [],
|
||||
options: {
|
||||
image: "ruby:2.1",
|
||||
services: ["mysql"]
|
||||
|
@ -141,10 +143,11 @@ module Ci
|
|||
expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({
|
||||
except: nil,
|
||||
stage: "test",
|
||||
stage_idx: 1,
|
||||
name: :rspec,
|
||||
only: nil,
|
||||
script: "pwd\nrspec",
|
||||
tags: [],
|
||||
commands: "pwd\nrspec",
|
||||
tag_list: [],
|
||||
options: {
|
||||
image: "ruby:2.5",
|
||||
services: ["postgresql"]
|
||||
|
|
|
@ -30,9 +30,12 @@ describe Ci::Build do
|
|||
let(:gl_project) { FactoryGirl.create :empty_project, gitlab_ci_project: project }
|
||||
let(:commit) { FactoryGirl.create :ci_commit, gl_project: gl_project }
|
||||
let(:build) { FactoryGirl.create :ci_build, commit: commit }
|
||||
subject { build }
|
||||
|
||||
it { is_expected.to belong_to(:commit) }
|
||||
it { is_expected.to belong_to(:user) }
|
||||
it { is_expected.to validate_presence_of :status }
|
||||
it { is_expected.to validate_presence_of :ref }
|
||||
|
||||
it { is_expected.to respond_to :success? }
|
||||
it { is_expected.to respond_to :failed? }
|
||||
|
@ -236,12 +239,6 @@ describe Ci::Build do
|
|||
it { is_expected.to eq(options) }
|
||||
end
|
||||
|
||||
describe :ref do
|
||||
subject { build.ref }
|
||||
|
||||
it { is_expected.to eq(commit.ref) }
|
||||
end
|
||||
|
||||
describe :sha do
|
||||
subject { build.sha }
|
||||
|
||||
|
@ -254,12 +251,6 @@ describe Ci::Build do
|
|||
it { is_expected.to eq(commit.short_sha) }
|
||||
end
|
||||
|
||||
describe :before_sha do
|
||||
subject { build.before_sha }
|
||||
|
||||
it { is_expected.to eq(commit.before_sha) }
|
||||
end
|
||||
|
||||
describe :allow_git_fetch do
|
||||
subject { build.allow_git_fetch }
|
||||
|
||||
|
@ -359,4 +350,38 @@ describe Ci::Build do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe :project_recipients do
|
||||
let(:pusher_email) { 'pusher@gitlab.test' }
|
||||
let(:user) { User.new(notification_email: pusher_email) }
|
||||
subject { build.project_recipients }
|
||||
|
||||
before do
|
||||
build.update_attributes(user: user)
|
||||
end
|
||||
|
||||
it 'should return pusher_email as only recipient when no additional recipients are given' do
|
||||
project.update_attributes(email_add_pusher: true,
|
||||
email_recipients: '')
|
||||
is_expected.to eq([pusher_email])
|
||||
end
|
||||
|
||||
it 'should return pusher_email and additional recipients' do
|
||||
project.update_attributes(email_add_pusher: true,
|
||||
email_recipients: 'rec1 rec2')
|
||||
is_expected.to eq(['rec1', 'rec2', pusher_email])
|
||||
end
|
||||
|
||||
it 'should return recipients' do
|
||||
project.update_attributes(email_add_pusher: false,
|
||||
email_recipients: 'rec1 rec2')
|
||||
is_expected.to eq(['rec1', 'rec2'])
|
||||
end
|
||||
|
||||
it 'should return unique recipients only' do
|
||||
project.update_attributes(email_add_pusher: true,
|
||||
email_recipients: "rec1 rec1 #{pusher_email}")
|
||||
is_expected.to eq(['rec1', pusher_email])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -21,15 +21,10 @@ describe Ci::Commit do
|
|||
let(:project) { FactoryGirl.create :ci_project }
|
||||
let(:gl_project) { FactoryGirl.create :empty_project, gitlab_ci_project: project }
|
||||
let(:commit) { FactoryGirl.create :ci_commit, gl_project: gl_project }
|
||||
let(:commit_with_project) { FactoryGirl.create :ci_commit, gl_project: gl_project }
|
||||
let(:config_processor) { Ci::GitlabCiYamlProcessor.new(gitlab_ci_yaml) }
|
||||
|
||||
it { is_expected.to belong_to(:gl_project) }
|
||||
it { is_expected.to have_many(:builds) }
|
||||
it { is_expected.to validate_presence_of :before_sha }
|
||||
it { is_expected.to validate_presence_of :sha }
|
||||
it { is_expected.to validate_presence_of :ref }
|
||||
it { is_expected.to validate_presence_of :push_data }
|
||||
|
||||
it { is_expected.to respond_to :git_author_name }
|
||||
it { is_expected.to respond_to :git_author_email }
|
||||
|
@ -59,53 +54,6 @@ describe Ci::Commit do
|
|||
end
|
||||
end
|
||||
|
||||
describe :project_recipients do
|
||||
|
||||
context 'always sending notification' do
|
||||
it 'should return commit_pusher_email as only recipient when no additional recipients are given' do
|
||||
project = FactoryGirl.create :ci_project,
|
||||
email_add_pusher: true,
|
||||
email_recipients: ''
|
||||
gl_project = FactoryGirl.create :empty_project, gitlab_ci_project: project
|
||||
commit = FactoryGirl.create :ci_commit, gl_project: gl_project
|
||||
expected = 'commit_pusher_email'
|
||||
allow(commit).to receive(:push_data) { { user_email: expected } }
|
||||
expect(commit.project_recipients).to eq([expected])
|
||||
end
|
||||
|
||||
it 'should return commit_pusher_email and additional recipients' do
|
||||
project = FactoryGirl.create :ci_project,
|
||||
email_add_pusher: true,
|
||||
email_recipients: 'rec1 rec2'
|
||||
gl_project = FactoryGirl.create :empty_project, gitlab_ci_project: project
|
||||
commit = FactoryGirl.create :ci_commit, gl_project: gl_project
|
||||
expected = 'commit_pusher_email'
|
||||
allow(commit).to receive(:push_data) { { user_email: expected } }
|
||||
expect(commit.project_recipients).to eq(['rec1', 'rec2', expected])
|
||||
end
|
||||
|
||||
it 'should return recipients' do
|
||||
project = FactoryGirl.create :ci_project,
|
||||
email_add_pusher: false,
|
||||
email_recipients: 'rec1 rec2'
|
||||
gl_project = FactoryGirl.create :empty_project, gitlab_ci_project: project
|
||||
commit = FactoryGirl.create :ci_commit, gl_project: gl_project
|
||||
expect(commit.project_recipients).to eq(['rec1', 'rec2'])
|
||||
end
|
||||
|
||||
it 'should return unique recipients only' do
|
||||
project = FactoryGirl.create :ci_project,
|
||||
email_add_pusher: true,
|
||||
email_recipients: 'rec1 rec1 rec2'
|
||||
gl_project = FactoryGirl.create :empty_project, gitlab_ci_project: project
|
||||
commit = FactoryGirl.create :ci_commit, gl_project: gl_project
|
||||
expected = 'rec2'
|
||||
allow(commit).to receive(:push_data) { { user_email: expected } }
|
||||
expect(commit.project_recipients).to eq(['rec1', 'rec2'])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe :valid_commit_sha do
|
||||
context 'commit.sha can not start with 00000000' do
|
||||
before do
|
||||
|
@ -117,23 +65,6 @@ describe Ci::Commit do
|
|||
end
|
||||
end
|
||||
|
||||
describe :compare? do
|
||||
subject { commit_with_project.compare? }
|
||||
|
||||
context 'if commit.before_sha are not nil' do
|
||||
it { is_expected.to be_truthy }
|
||||
end
|
||||
end
|
||||
|
||||
describe :short_sha do
|
||||
subject { commit.short_before_sha }
|
||||
|
||||
it 'has 8 items' do
|
||||
expect(subject.size).to eq(8)
|
||||
end
|
||||
it { expect(commit.before_sha).to start_with(subject) }
|
||||
end
|
||||
|
||||
describe :short_sha do
|
||||
subject { commit.short_sha }
|
||||
|
||||
|
@ -143,37 +74,86 @@ describe Ci::Commit do
|
|||
it { expect(commit.sha).to start_with(subject) }
|
||||
end
|
||||
|
||||
describe :create_next_builds do
|
||||
describe :stage do
|
||||
subject { commit.stage }
|
||||
|
||||
before do
|
||||
allow(commit).to receive(:config_processor).and_return(config_processor)
|
||||
@second = FactoryGirl.create :ci_build, commit: commit, name: 'deploy', stage: 'deploy', stage_idx: 1, status: :pending
|
||||
@first = FactoryGirl.create :ci_build, commit: commit, name: 'test', stage: 'test', stage_idx: 0, status: :pending
|
||||
end
|
||||
|
||||
it "creates builds for next type" do
|
||||
expect(commit.create_builds).to be_truthy
|
||||
commit.builds.reload
|
||||
expect(commit.builds.size).to eq(2)
|
||||
it 'returns first running stage' do
|
||||
is_expected.to eq('test')
|
||||
end
|
||||
|
||||
expect(commit.create_next_builds(nil)).to be_truthy
|
||||
commit.builds.reload
|
||||
expect(commit.builds.size).to eq(4)
|
||||
context 'first build succeeded' do
|
||||
before do
|
||||
@first.update_attributes(status: :success)
|
||||
end
|
||||
|
||||
expect(commit.create_next_builds(nil)).to be_truthy
|
||||
commit.builds.reload
|
||||
expect(commit.builds.size).to eq(5)
|
||||
it 'returns last running stage' do
|
||||
is_expected.to eq('deploy')
|
||||
end
|
||||
end
|
||||
|
||||
expect(commit.create_next_builds(nil)).to be_falsey
|
||||
context 'all builds succeeded' do
|
||||
before do
|
||||
@first.update_attributes(status: :success)
|
||||
@second.update_attributes(status: :success)
|
||||
end
|
||||
|
||||
it 'returns nil' do
|
||||
is_expected.to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe :create_next_builds do
|
||||
end
|
||||
|
||||
describe :create_builds do
|
||||
before do
|
||||
allow(commit).to receive(:config_processor).and_return(config_processor)
|
||||
let(:commit) { FactoryGirl.create :ci_commit, gl_project: gl_project }
|
||||
|
||||
def create_builds(trigger_request = nil)
|
||||
commit.create_builds('master', false, nil, trigger_request)
|
||||
end
|
||||
|
||||
def create_next_builds(trigger_request = nil)
|
||||
commit.create_next_builds('master', false, nil, trigger_request)
|
||||
end
|
||||
|
||||
it 'creates builds' do
|
||||
expect(commit.create_builds).to be_truthy
|
||||
expect(create_builds).to be_truthy
|
||||
commit.builds.reload
|
||||
expect(commit.builds.size).to eq(2)
|
||||
|
||||
expect(create_next_builds).to be_truthy
|
||||
commit.builds.reload
|
||||
expect(commit.builds.size).to eq(4)
|
||||
|
||||
expect(create_next_builds).to be_truthy
|
||||
commit.builds.reload
|
||||
expect(commit.builds.size).to eq(5)
|
||||
|
||||
expect(create_next_builds).to be_falsey
|
||||
end
|
||||
|
||||
context 'for different ref' do
|
||||
def create_develop_builds
|
||||
commit.create_builds('develop', false, nil, nil)
|
||||
end
|
||||
|
||||
it 'creates builds' do
|
||||
expect(create_builds).to be_truthy
|
||||
commit.builds.reload
|
||||
expect(commit.builds.size).to eq(2)
|
||||
|
||||
expect(create_develop_builds).to be_truthy
|
||||
commit.builds.reload
|
||||
expect(commit.builds.size).to eq(4)
|
||||
expect(commit.refs.size).to eq(2)
|
||||
expect(commit.builds.pluck(:name).uniq.size).to eq(2)
|
||||
end
|
||||
end
|
||||
|
||||
context 'for build triggers' do
|
||||
|
@ -181,40 +161,39 @@ describe Ci::Commit do
|
|||
let(:trigger_request) { FactoryGirl.create :ci_trigger_request, commit: commit, trigger: trigger }
|
||||
|
||||
it 'creates builds' do
|
||||
expect(commit.create_builds(trigger_request)).to be_truthy
|
||||
expect(create_builds(trigger_request)).to be_truthy
|
||||
commit.builds.reload
|
||||
expect(commit.builds.size).to eq(2)
|
||||
end
|
||||
|
||||
it 'rebuilds commit' do
|
||||
expect(commit.create_builds).to be_truthy
|
||||
expect(create_builds).to be_truthy
|
||||
commit.builds.reload
|
||||
expect(commit.builds.size).to eq(2)
|
||||
|
||||
expect(commit.create_builds(trigger_request)).to be_truthy
|
||||
expect(create_builds(trigger_request)).to be_truthy
|
||||
commit.builds.reload
|
||||
expect(commit.builds.size).to eq(4)
|
||||
end
|
||||
|
||||
it 'creates next builds' do
|
||||
expect(commit.create_builds(trigger_request)).to be_truthy
|
||||
expect(create_builds(trigger_request)).to be_truthy
|
||||
commit.builds.reload
|
||||
expect(commit.builds.size).to eq(2)
|
||||
|
||||
expect(commit.create_next_builds(trigger_request)).to be_truthy
|
||||
expect(create_next_builds(trigger_request)).to be_truthy
|
||||
commit.builds.reload
|
||||
expect(commit.builds.size).to eq(4)
|
||||
end
|
||||
|
||||
context 'for [ci skip]' do
|
||||
before do
|
||||
commit.push_data[:commits][0][:message] = 'skip this commit [ci skip]'
|
||||
commit.save
|
||||
allow(commit).to receive(:git_commit_message) { 'message [ci skip]' }
|
||||
end
|
||||
|
||||
it 'rebuilds commit' do
|
||||
expect(commit.status).to eq('skipped')
|
||||
expect(commit.create_builds(trigger_request)).to be_truthy
|
||||
expect(create_builds(trigger_request)).to be_truthy
|
||||
commit.builds.reload
|
||||
expect(commit.builds.size).to eq(2)
|
||||
expect(commit.status).to eq('pending')
|
||||
|
@ -270,4 +249,59 @@ describe Ci::Commit do
|
|||
expect(commit.coverage).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe :should_create_next_builds? do
|
||||
before do
|
||||
@build1 = FactoryGirl.create :ci_build, commit: commit, name: 'build1', ref: 'master', tag: false, status: :success
|
||||
@build2 = FactoryGirl.create :ci_build, commit: commit, name: 'build1', ref: 'develop', tag: false, status: :failed
|
||||
@build3 = FactoryGirl.create :ci_build, commit: commit, name: 'build1', ref: 'master', tag: true, status: :failed
|
||||
@build4 = FactoryGirl.create :ci_build, commit: commit, name: 'build4', ref: 'master', tag: false, status: :success
|
||||
end
|
||||
|
||||
context 'for success' do
|
||||
it 'to create if all succeeded' do
|
||||
expect(commit.should_create_next_builds?(@build4)).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
context 'for failed' do
|
||||
before do
|
||||
@build4.update_attributes(status: :failed)
|
||||
end
|
||||
|
||||
it 'to not create' do
|
||||
expect(commit.should_create_next_builds?(@build4)).to be_falsey
|
||||
end
|
||||
|
||||
context 'and ignore failures for current' do
|
||||
before do
|
||||
@build4.update_attributes(allow_failure: true)
|
||||
end
|
||||
|
||||
it 'to create' do
|
||||
expect(commit.should_create_next_builds?(@build4)).to be_truthy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'for running' do
|
||||
before do
|
||||
@build4.update_attributes(status: :running)
|
||||
end
|
||||
|
||||
it 'to not create' do
|
||||
expect(commit.should_create_next_builds?(@build4)).to be_falsey
|
||||
end
|
||||
end
|
||||
|
||||
context 'for retried' do
|
||||
before do
|
||||
@build5 = FactoryGirl.create :ci_build, commit: commit, name: 'build4', ref: 'master', tag: false, status: :failed
|
||||
end
|
||||
|
||||
it 'to not create' do
|
||||
expect(commit.should_create_next_builds?(@build4)).to be_falsey
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,70 +3,37 @@ require 'spec_helper'
|
|||
describe Ci::HipChatMessage do
|
||||
subject { Ci::HipChatMessage.new(build) }
|
||||
|
||||
context "One build" do
|
||||
let(:commit) { FactoryGirl.create(:ci_commit_with_one_job) }
|
||||
let(:commit) { FactoryGirl.create(:ci_commit_with_two_jobs) }
|
||||
|
||||
let(:build) do
|
||||
commit.create_builds
|
||||
commit.builds.first
|
||||
end
|
||||
let(:build) do
|
||||
commit.builds.first
|
||||
end
|
||||
|
||||
context 'when build succeeds' do
|
||||
it 'returns a successful message' do
|
||||
build.update(status: "success")
|
||||
context 'when all matrix builds succeed' do
|
||||
it 'returns a successful message' do
|
||||
commit.create_builds('master', false, nil)
|
||||
commit.builds.update_all(status: "success")
|
||||
commit.reload
|
||||
|
||||
expect( subject.status_color ).to eq 'green'
|
||||
expect( subject.notify? ).to be_falsey
|
||||
expect( subject.to_s ).to match(/Build '[^']+' #\d+/)
|
||||
expect( subject.to_s ).to match(/Successful in \d+ second\(s\)\./)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when build fails' do
|
||||
it 'returns a failure message' do
|
||||
build.update(status: "failed")
|
||||
|
||||
expect( subject.status_color ).to eq 'red'
|
||||
expect( subject.notify? ).to be_truthy
|
||||
expect( subject.to_s ).to match(/Build '[^']+' #\d+/)
|
||||
expect( subject.to_s ).to match(/Failed in \d+ second\(s\)\./)
|
||||
end
|
||||
expect(subject.status_color).to eq 'green'
|
||||
expect(subject.notify?).to be_falsey
|
||||
expect(subject.to_s).to match(/Commit #\d+/)
|
||||
expect(subject.to_s).to match(/Successful in \d+ second\(s\)\./)
|
||||
end
|
||||
end
|
||||
|
||||
context "Several builds" do
|
||||
let(:commit) { FactoryGirl.create(:ci_commit_with_two_jobs) }
|
||||
context 'when at least one matrix build fails' do
|
||||
it 'returns a failure message' do
|
||||
commit.create_builds('master', false, nil)
|
||||
first_build = commit.builds.first
|
||||
second_build = commit.builds.last
|
||||
first_build.update(status: "success")
|
||||
second_build.update(status: "failed")
|
||||
|
||||
let(:build) do
|
||||
commit.builds.first
|
||||
end
|
||||
|
||||
context 'when all matrix builds succeed' do
|
||||
it 'returns a successful message' do
|
||||
commit.create_builds
|
||||
commit.builds.update_all(status: "success")
|
||||
commit.reload
|
||||
|
||||
expect( subject.status_color ).to eq 'green'
|
||||
expect( subject.notify? ).to be_falsey
|
||||
expect( subject.to_s ).to match(/Commit #\d+/)
|
||||
expect( subject.to_s ).to match(/Successful in \d+ second\(s\)\./)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when at least one matrix build fails' do
|
||||
it 'returns a failure message' do
|
||||
commit.create_builds
|
||||
first_build = commit.builds.first
|
||||
second_build = commit.builds.last
|
||||
first_build.update(status: "success")
|
||||
second_build.update(status: "failed")
|
||||
|
||||
expect( subject.status_color ).to eq 'red'
|
||||
expect( subject.notify? ).to be_truthy
|
||||
expect( subject.to_s ).to match(/Commit #\d+/)
|
||||
expect( subject.to_s ).to match(/Failed in \d+ second\(s\)\./)
|
||||
end
|
||||
expect(subject.status_color).to eq 'red'
|
||||
expect(subject.notify?).to be_truthy
|
||||
expect(subject.to_s).to match(/Commit #\d+/)
|
||||
expect(subject.to_s).to match(/Failed in \d+ second\(s\)\./)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -29,12 +29,13 @@ describe Ci::MailService do
|
|||
|
||||
describe 'Sends email for' do
|
||||
let(:mail) { Ci::MailService.new }
|
||||
let(:user) { User.new(notification_email: 'git@example.com')}
|
||||
|
||||
describe 'failed build' do
|
||||
let(:project) { FactoryGirl.create(:ci_project, email_add_pusher: true) }
|
||||
let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
|
||||
let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
|
||||
let(:build) { FactoryGirl.create(:ci_build, status: :failed, commit: commit) }
|
||||
let(:build) { FactoryGirl.create(:ci_build, status: :failed, commit: commit, user: user) }
|
||||
|
||||
before do
|
||||
allow(mail).to receive_messages(
|
||||
|
@ -57,7 +58,7 @@ describe Ci::MailService do
|
|||
let(:project) { FactoryGirl.create(:ci_project, email_add_pusher: true, email_only_broken_builds: false) }
|
||||
let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
|
||||
let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
|
||||
let(:build) { FactoryGirl.create(:ci_build, status: :success, commit: commit) }
|
||||
let(:build) { FactoryGirl.create(:ci_build, status: :success, commit: commit, user: user) }
|
||||
|
||||
before do
|
||||
allow(mail).to receive_messages(
|
||||
|
@ -85,7 +86,7 @@ describe Ci::MailService do
|
|||
end
|
||||
let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
|
||||
let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
|
||||
let(:build) { FactoryGirl.create(:ci_build, status: :success, commit: commit) }
|
||||
let(:build) { FactoryGirl.create(:ci_build, status: :success, commit: commit, user: user) }
|
||||
|
||||
before do
|
||||
allow(mail).to receive_messages(
|
||||
|
@ -114,7 +115,7 @@ describe Ci::MailService do
|
|||
end
|
||||
let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
|
||||
let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
|
||||
let(:build) { FactoryGirl.create(:ci_build, status: :success, commit: commit) }
|
||||
let(:build) { FactoryGirl.create(:ci_build, status: :success, commit: commit, user: user) }
|
||||
|
||||
before do
|
||||
allow(mail).to receive_messages(
|
||||
|
@ -143,7 +144,7 @@ describe Ci::MailService do
|
|||
end
|
||||
let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
|
||||
let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
|
||||
let(:build) { FactoryGirl.create(:ci_build, status: :success, commit: commit) }
|
||||
let(:build) { FactoryGirl.create(:ci_build, status: :success, commit: commit, user: user) }
|
||||
|
||||
before do
|
||||
allow(mail).to receive_messages(
|
||||
|
@ -166,7 +167,7 @@ describe Ci::MailService do
|
|||
end
|
||||
let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
|
||||
let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
|
||||
let(:build) { FactoryGirl.create(:ci_build, status: :failed, commit: commit) }
|
||||
let(:build) { FactoryGirl.create(:ci_build, status: :failed, commit: commit, user: user) }
|
||||
|
||||
before do
|
||||
allow(mail).to receive_messages(
|
|
@ -3,80 +3,41 @@ require 'spec_helper'
|
|||
describe Ci::SlackMessage do
|
||||
subject { Ci::SlackMessage.new(commit) }
|
||||
|
||||
context "One build" do
|
||||
let(:commit) { FactoryGirl.create(:ci_commit_with_one_job) }
|
||||
let(:commit) { FactoryGirl.create(:ci_commit_with_two_jobs) }
|
||||
|
||||
let(:build) do
|
||||
commit.create_builds
|
||||
commit.builds.first
|
||||
end
|
||||
context 'when all matrix builds succeeded' do
|
||||
let(:color) { 'good' }
|
||||
|
||||
context 'when build succeeded' do
|
||||
let(:color) { 'good' }
|
||||
it 'returns a message with success' do
|
||||
commit.create_builds('master', false, nil)
|
||||
commit.builds.update_all(status: "success")
|
||||
commit.reload
|
||||
|
||||
it 'returns a message with succeeded build' do
|
||||
build.update(status: "success")
|
||||
|
||||
expect(subject.color).to eq(color)
|
||||
expect(subject.fallback).to include('Build')
|
||||
expect(subject.fallback).to include("\##{build.id}")
|
||||
expect(subject.fallback).to include('succeeded')
|
||||
expect(subject.attachments.first[:fields]).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
context 'when build failed' do
|
||||
let(:color) { 'danger' }
|
||||
|
||||
it 'returns a message with failed build' do
|
||||
build.update(status: "failed")
|
||||
|
||||
expect(subject.color).to eq(color)
|
||||
expect(subject.fallback).to include('Build')
|
||||
expect(subject.fallback).to include("\##{build.id}")
|
||||
expect(subject.fallback).to include('failed')
|
||||
expect(subject.attachments.first[:fields]).to be_empty
|
||||
end
|
||||
expect(subject.color).to eq(color)
|
||||
expect(subject.fallback).to include('Commit')
|
||||
expect(subject.fallback).to include("\##{commit.id}")
|
||||
expect(subject.fallback).to include('succeeded')
|
||||
expect(subject.attachments.first[:fields]).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
context "Several builds" do
|
||||
let(:commit) { FactoryGirl.create(:ci_commit_with_two_jobs) }
|
||||
context 'when one of matrix builds failed' do
|
||||
let(:color) { 'danger' }
|
||||
|
||||
context 'when all matrix builds succeeded' do
|
||||
let(:color) { 'good' }
|
||||
it 'returns a message with information about failed build' do
|
||||
commit.create_builds('master', false, nil)
|
||||
first_build = commit.builds.first
|
||||
second_build = commit.builds.last
|
||||
first_build.update(status: "success")
|
||||
second_build.update(status: "failed")
|
||||
|
||||
it 'returns a message with success' do
|
||||
commit.create_builds
|
||||
commit.builds.update_all(status: "success")
|
||||
commit.reload
|
||||
|
||||
expect(subject.color).to eq(color)
|
||||
expect(subject.fallback).to include('Commit')
|
||||
expect(subject.fallback).to include("\##{commit.id}")
|
||||
expect(subject.fallback).to include('succeeded')
|
||||
expect(subject.attachments.first[:fields]).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
context 'when one of matrix builds failed' do
|
||||
let(:color) { 'danger' }
|
||||
|
||||
it 'returns a message with information about failed build' do
|
||||
commit.create_builds
|
||||
first_build = commit.builds.first
|
||||
second_build = commit.builds.last
|
||||
first_build.update(status: "success")
|
||||
second_build.update(status: "failed")
|
||||
|
||||
expect(subject.color).to eq(color)
|
||||
expect(subject.fallback).to include('Commit')
|
||||
expect(subject.fallback).to include("\##{commit.id}")
|
||||
expect(subject.fallback).to include('failed')
|
||||
expect(subject.attachments.first[:fields].size).to eq(1)
|
||||
expect(subject.attachments.first[:fields].first[:title]).to eq(second_build.name)
|
||||
expect(subject.attachments.first[:fields].first[:value]).to include("\##{second_build.id}")
|
||||
end
|
||||
expect(subject.color).to eq(color)
|
||||
expect(subject.fallback).to include('Commit')
|
||||
expect(subject.fallback).to include("\##{commit.id}")
|
||||
expect(subject.fallback).to include('failed')
|
||||
expect(subject.attachments.first[:fields].size).to eq(1)
|
||||
expect(subject.attachments.first[:fields].first[:title]).to eq(second_build.name)
|
||||
expect(subject.attachments.first[:fields].first[:value]).to include("\##{second_build.id}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -39,8 +39,8 @@ describe GitlabCiService do
|
|||
end
|
||||
|
||||
describe :build_page do
|
||||
it { expect(@service.build_page("2ab7834c", 'master')).to eq("http://localhost/ci/projects/#{@ci_project.id}/refs/master/commits/2ab7834c")}
|
||||
it { expect(@service.build_page("issue#2", 'master')).to eq("http://localhost/ci/projects/#{@ci_project.id}/refs/master/commits/issue%232")}
|
||||
it { expect(@service.build_page("2ab7834c", 'master')).to eq("http://localhost/ci/projects/#{@ci_project.id}/commits/2ab7834c")}
|
||||
it { expect(@service.build_page("issue#2", 'master')).to eq("http://localhost/ci/projects/#{@ci_project.id}/commits/issue%232")}
|
||||
end
|
||||
|
||||
describe "execute" do
|
||||
|
@ -48,8 +48,8 @@ describe GitlabCiService do
|
|||
let(:project) { create(:project, name: 'project') }
|
||||
let(:push_sample_data) { Gitlab::PushDataBuilder.build_sample(project, user) }
|
||||
|
||||
it "calls ci_yaml_file" do
|
||||
expect(@service).to receive(:ci_yaml_file).with(push_sample_data[:checkout_sha])
|
||||
it "calls CreateCommitService" do
|
||||
expect_any_instance_of(Ci::CreateCommitService).to receive(:execute).with(@ci_project, user, push_sample_data)
|
||||
|
||||
@service.execute(push_sample_data)
|
||||
end
|
||||
|
|
|
@ -7,6 +7,10 @@ describe Ci::API::API do
|
|||
let(:project) { FactoryGirl.create(:ci_project) }
|
||||
let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
|
||||
|
||||
before do
|
||||
stub_ci_commit_to_return_yaml_file
|
||||
end
|
||||
|
||||
describe "Builds API for runners" do
|
||||
let(:shared_runner) { FactoryGirl.create(:ci_runner, token: "SharedRunner") }
|
||||
let(:shared_project) { FactoryGirl.create(:ci_project, name: "SharedProject") }
|
||||
|
@ -19,7 +23,7 @@ describe Ci::API::API do
|
|||
describe "POST /builds/register" do
|
||||
it "should start a build" do
|
||||
commit = FactoryGirl.create(:ci_commit, gl_project: gl_project)
|
||||
commit.create_builds
|
||||
commit.create_builds('master', false, nil)
|
||||
build = commit.builds.first
|
||||
|
||||
post ci_api("/builds/register"), token: runner.token, info: { platform: :darwin }
|
||||
|
@ -55,7 +59,7 @@ describe Ci::API::API do
|
|||
|
||||
it "returns options" do
|
||||
commit = FactoryGirl.create(:ci_commit, gl_project: gl_project)
|
||||
commit.create_builds
|
||||
commit.create_builds('master', false, nil)
|
||||
|
||||
post ci_api("/builds/register"), token: runner.token, info: { platform: :darwin }
|
||||
|
||||
|
@ -65,7 +69,7 @@ describe Ci::API::API do
|
|||
|
||||
it "returns variables" do
|
||||
commit = FactoryGirl.create(:ci_commit, gl_project: gl_project)
|
||||
commit.create_builds
|
||||
commit.create_builds('master', false, nil)
|
||||
project.variables << Ci::Variable.new(key: "SECRET_KEY", value: "secret_value")
|
||||
|
||||
post ci_api("/builds/register"), token: runner.token, info: { platform: :darwin }
|
||||
|
@ -82,7 +86,7 @@ describe Ci::API::API do
|
|||
commit = FactoryGirl.create(:ci_commit, gl_project: gl_project)
|
||||
|
||||
trigger_request = FactoryGirl.create(:ci_trigger_request_with_variables, commit: commit, trigger: trigger)
|
||||
commit.create_builds(trigger_request)
|
||||
commit.create_builds('master', false, nil, trigger_request)
|
||||
project.variables << Ci::Variable.new(key: "SECRET_KEY", value: "secret_value")
|
||||
|
||||
post ci_api("/builds/register"), token: runner.token, info: { platform: :darwin }
|
||||
|
|
|
@ -44,8 +44,7 @@ describe Ci::API::API, 'Commits' do
|
|||
"email" => "jordi@softcatala.org",
|
||||
}
|
||||
}
|
||||
],
|
||||
ci_yaml_file: gitlab_ci_yaml
|
||||
]
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
@ -5,8 +5,8 @@ describe Ci::API::API do
|
|||
|
||||
describe 'POST /projects/:project_id/refs/:ref/trigger' do
|
||||
let!(:trigger_token) { 'secure token' }
|
||||
let!(:project) { FactoryGirl.create(:ci_project) }
|
||||
let!(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
|
||||
let!(:gl_project) { FactoryGirl.create(:project) }
|
||||
let!(:project) { FactoryGirl.create(:ci_project, gl_project: gl_project) }
|
||||
let!(:project2) { FactoryGirl.create(:ci_project) }
|
||||
let!(:trigger) { FactoryGirl.create(:ci_trigger, project: project, token: trigger_token) }
|
||||
let(:options) do
|
||||
|
@ -15,6 +15,10 @@ describe Ci::API::API do
|
|||
}
|
||||
end
|
||||
|
||||
before do
|
||||
stub_ci_commit_to_return_yaml_file
|
||||
end
|
||||
|
||||
context 'Handles errors' do
|
||||
it 'should return bad request if token is missing' do
|
||||
post ci_api("/projects/#{project.id}/refs/master/trigger")
|
||||
|
@ -33,15 +37,13 @@ describe Ci::API::API do
|
|||
end
|
||||
|
||||
context 'Have a commit' do
|
||||
before do
|
||||
@commit = FactoryGirl.create(:ci_commit, gl_project: gl_project)
|
||||
end
|
||||
let(:commit) { project.commits.last }
|
||||
|
||||
it 'should create builds' do
|
||||
post ci_api("/projects/#{project.id}/refs/master/trigger"), options
|
||||
expect(response.status).to eq(201)
|
||||
@commit.builds.reload
|
||||
expect(@commit.builds.size).to eq(2)
|
||||
commit.builds.reload
|
||||
expect(commit.builds.size).to eq(2)
|
||||
end
|
||||
|
||||
it 'should return bad request with no builds created if there\'s no commit for that ref' do
|
||||
|
@ -70,8 +72,8 @@ describe Ci::API::API do
|
|||
it 'create trigger request with variables' do
|
||||
post ci_api("/projects/#{project.id}/refs/master/trigger"), options.merge(variables: variables)
|
||||
expect(response.status).to eq(201)
|
||||
@commit.builds.reload
|
||||
expect(@commit.builds.first.trigger_request.variables).to eq(variables)
|
||||
commit.builds.reload
|
||||
expect(commit.builds.first.trigger_request.variables).to eq(variables)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,7 +7,7 @@ describe "Commits" do
|
|||
|
||||
describe "GET /:project/refs/:ref_name/commits/:id/status.json" do
|
||||
before do
|
||||
get status_ci_project_ref_commits_path(@commit.project, @commit.ref, @commit.sha), format: :json
|
||||
get status_ci_project_commits_path(@commit.project, @commit.sha), format: :json
|
||||
end
|
||||
|
||||
it { expect(response.status).to eq(200) }
|
||||
|
|
|
@ -4,15 +4,19 @@ module Ci
|
|||
describe CreateCommitService do
|
||||
let(:service) { CreateCommitService.new }
|
||||
let(:project) { FactoryGirl.create(:ci_project) }
|
||||
let(:user) { nil }
|
||||
|
||||
before do
|
||||
stub_ci_commit_to_return_yaml_file
|
||||
end
|
||||
|
||||
describe :execute do
|
||||
context 'valid params' do
|
||||
let(:commit) do
|
||||
service.execute(project,
|
||||
service.execute(project, user,
|
||||
ref: 'refs/heads/master',
|
||||
before: '00000000',
|
||||
after: '31das312',
|
||||
ci_yaml_file: gitlab_ci_yaml,
|
||||
commits: [ { message: "Message" } ]
|
||||
)
|
||||
end
|
||||
|
@ -26,11 +30,10 @@ module Ci
|
|||
|
||||
context "skip tag if there is no build for it" do
|
||||
it "creates commit if there is appropriate job" do
|
||||
result = service.execute(project,
|
||||
result = service.execute(project, user,
|
||||
ref: 'refs/tags/0_1',
|
||||
before: '00000000',
|
||||
after: '31das312',
|
||||
ci_yaml_file: gitlab_ci_yaml,
|
||||
commits: [ { message: "Message" } ]
|
||||
)
|
||||
expect(result).to be_persisted
|
||||
|
@ -38,12 +41,12 @@ module Ci
|
|||
|
||||
it "creates commit if there is no appropriate job but deploy job has right ref setting" do
|
||||
config = YAML.dump({ deploy: { deploy: "ls", only: ["0_1"] } })
|
||||
stub_ci_commit_yaml_file(config)
|
||||
|
||||
result = service.execute(project,
|
||||
result = service.execute(project, user,
|
||||
ref: 'refs/heads/0_1',
|
||||
before: '00000000',
|
||||
after: '31das312',
|
||||
ci_yaml_file: config,
|
||||
commits: [ { message: "Message" } ]
|
||||
)
|
||||
expect(result).to be_persisted
|
||||
|
@ -51,11 +54,11 @@ module Ci
|
|||
end
|
||||
|
||||
it 'fails commits without .gitlab-ci.yml' do
|
||||
result = service.execute(project,
|
||||
stub_ci_commit_yaml_file(nil)
|
||||
result = service.execute(project, user,
|
||||
ref: 'refs/heads/0_1',
|
||||
before: '00000000',
|
||||
after: '31das312',
|
||||
ci_yaml_file: config,
|
||||
commits: [ { message: 'Message' } ]
|
||||
)
|
||||
expect(result).to be_persisted
|
||||
|
@ -64,41 +67,46 @@ module Ci
|
|||
end
|
||||
|
||||
describe :ci_skip? do
|
||||
let(:message) { "some message[ci skip]" }
|
||||
|
||||
before do
|
||||
allow_any_instance_of(Ci::Commit).to receive(:git_commit_message) { message }
|
||||
end
|
||||
|
||||
it "skips builds creation if there is [ci skip] tag in commit message" do
|
||||
commits = [{ message: "some message[ci skip]" }]
|
||||
commit = service.execute(project,
|
||||
commits = [{ message: message }]
|
||||
commit = service.execute(project, user,
|
||||
ref: 'refs/tags/0_1',
|
||||
before: '00000000',
|
||||
after: '31das312',
|
||||
commits: commits,
|
||||
ci_yaml_file: gitlab_ci_yaml
|
||||
commits: commits
|
||||
)
|
||||
expect(commit.builds.any?).to be false
|
||||
expect(commit.status).to eq("skipped")
|
||||
end
|
||||
|
||||
it "does not skips builds creation if there is no [ci skip] tag in commit message" do
|
||||
commits = [{ message: "some message" }]
|
||||
allow_any_instance_of(Ci::Commit).to receive(:git_commit_message) { "some message" }
|
||||
|
||||
commit = service.execute(project,
|
||||
commits = [{ message: "some message" }]
|
||||
commit = service.execute(project, user,
|
||||
ref: 'refs/tags/0_1',
|
||||
before: '00000000',
|
||||
after: '31das312',
|
||||
commits: commits,
|
||||
ci_yaml_file: gitlab_ci_yaml
|
||||
commits: commits
|
||||
)
|
||||
|
||||
expect(commit.builds.first.name).to eq("staging")
|
||||
end
|
||||
|
||||
it "skips builds creation if there is [ci skip] tag in commit message and yaml is invalid" do
|
||||
commits = [{ message: "some message[ci skip]" }]
|
||||
commit = service.execute(project,
|
||||
stub_ci_commit_yaml_file('invalid: file')
|
||||
commits = [{ message: message }]
|
||||
commit = service.execute(project, user,
|
||||
ref: 'refs/tags/0_1',
|
||||
before: '00000000',
|
||||
after: '31das312',
|
||||
commits: commits,
|
||||
ci_yaml_file: "invalid: file"
|
||||
commits: commits
|
||||
)
|
||||
expect(commit.builds.any?).to be false
|
||||
expect(commit.status).to eq("skipped")
|
||||
|
@ -106,35 +114,36 @@ module Ci
|
|||
end
|
||||
|
||||
it "skips build creation if there are already builds" do
|
||||
allow_any_instance_of(Ci::Commit).to receive(:ci_yaml_file) { gitlab_ci_yaml }
|
||||
|
||||
commits = [{ message: "message" }]
|
||||
commit = service.execute(project,
|
||||
commit = service.execute(project, user,
|
||||
ref: 'refs/heads/master',
|
||||
before: '00000000',
|
||||
after: '31das312',
|
||||
commits: commits,
|
||||
ci_yaml_file: gitlab_ci_yaml
|
||||
commits: commits
|
||||
)
|
||||
expect(commit.builds.count(:all)).to eq(2)
|
||||
|
||||
commit = service.execute(project,
|
||||
commit = service.execute(project, user,
|
||||
ref: 'refs/heads/master',
|
||||
before: '00000000',
|
||||
after: '31das312',
|
||||
commits: commits,
|
||||
ci_yaml_file: gitlab_ci_yaml
|
||||
commits: commits
|
||||
)
|
||||
expect(commit.builds.count(:all)).to eq(2)
|
||||
end
|
||||
|
||||
it "creates commit with failed status if yaml is invalid" do
|
||||
stub_ci_commit_yaml_file('invalid: file')
|
||||
|
||||
commits = [{ message: "some message" }]
|
||||
|
||||
commit = service.execute(project,
|
||||
commit = service.execute(project, user,
|
||||
ref: 'refs/tags/0_1',
|
||||
before: '00000000',
|
||||
after: '31das312',
|
||||
commits: commits,
|
||||
ci_yaml_file: "invalid: file"
|
||||
commits: commits
|
||||
)
|
||||
|
||||
expect(commit.status).to eq("failed")
|
||||
|
|
|
@ -2,20 +2,20 @@ require 'spec_helper'
|
|||
|
||||
describe Ci::CreateTriggerRequestService do
|
||||
let(:service) { Ci::CreateTriggerRequestService.new }
|
||||
let(:project) { FactoryGirl.create :ci_project }
|
||||
let(:gl_project) { FactoryGirl.create :empty_project, gitlab_ci_project: project }
|
||||
let(:trigger) { FactoryGirl.create :ci_trigger, project: project }
|
||||
let(:gl_project) { create(:project) }
|
||||
let(:project) { create(:ci_project, gl_project: gl_project) }
|
||||
let(:trigger) { create(:ci_trigger, project: project) }
|
||||
|
||||
before do
|
||||
stub_ci_commit_to_return_yaml_file
|
||||
end
|
||||
|
||||
describe :execute do
|
||||
context 'valid params' do
|
||||
subject { service.execute(project, trigger, 'master') }
|
||||
|
||||
before do
|
||||
@commit = FactoryGirl.create :ci_commit, gl_project: gl_project
|
||||
end
|
||||
|
||||
it { expect(subject).to be_kind_of(Ci::TriggerRequest) }
|
||||
it { expect(subject.commit).to eq(@commit) }
|
||||
it { expect(subject.builds.first).to be_kind_of(Ci::Build) }
|
||||
end
|
||||
|
||||
context 'no commit for ref' do
|
||||
|
@ -28,26 +28,11 @@ describe Ci::CreateTriggerRequestService do
|
|||
subject { service.execute(project, trigger, 'master') }
|
||||
|
||||
before do
|
||||
FactoryGirl.create :ci_commit_without_jobs, gl_project: gl_project
|
||||
stub_ci_commit_yaml_file('{}')
|
||||
FactoryGirl.create :ci_commit, gl_project: gl_project
|
||||
end
|
||||
|
||||
it { expect(subject).to be_nil }
|
||||
end
|
||||
|
||||
context 'for multiple commits' do
|
||||
subject { service.execute(project, trigger, 'master') }
|
||||
|
||||
before do
|
||||
@commit1 = FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, gl_project: gl_project
|
||||
@commit2 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, gl_project: gl_project
|
||||
@commit3 = FactoryGirl.create :ci_commit, committed_at: 3.hour.ago, gl_project: gl_project
|
||||
end
|
||||
|
||||
context 'retries latest one' do
|
||||
it { expect(subject).to be_kind_of(Ci::TriggerRequest) }
|
||||
it { expect(subject).to be_persisted }
|
||||
it { expect(subject.commit).to eq(@commit2) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -43,4 +43,8 @@ RSpec.configure do |config|
|
|||
end
|
||||
end
|
||||
|
||||
FactoryGirl::SyntaxRunner.class_eval do
|
||||
include RSpec::Mocks::ExampleMethods
|
||||
end
|
||||
|
||||
ActiveRecord::Migration.maintain_test_schema!
|
||||
|
|
|
@ -13,6 +13,14 @@ module StubGitlabCalls
|
|||
allow_any_instance_of(Network).to receive(:projects) { project_hash_array }
|
||||
end
|
||||
|
||||
def stub_ci_commit_to_return_yaml_file
|
||||
stub_ci_commit_yaml_file(gitlab_ci_yaml)
|
||||
end
|
||||
|
||||
def stub_ci_commit_yaml_file(ci_yaml)
|
||||
allow_any_instance_of(Ci::Commit).to receive(:ci_yaml_file) { ci_yaml }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def gitlab_url
|
||||
|
|
Loading…
Reference in a new issue