diff --git a/app/controllers/ci/builds_controller.rb b/app/controllers/ci/builds_controller.rb index 80ee866679266013bc5098fe9e9dba0e82632ed6..bf87f81439a24b4d121d82fb737550e43159c0d8 100644 --- a/app/controllers/ci/builds_controller.rb +++ b/app/controllers/ci/builds_controller.rb @@ -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 diff --git a/app/controllers/ci/commits_controller.rb b/app/controllers/ci/commits_controller.rb index 7a0a500fbe6f4f5455e3076350b16cec1d175cab..887e92f84cfa3c5ce884a235a579c988f1a4bb08 100644 --- a/app/controllers/ci/commits_controller.rb +++ b/app/controllers/ci/commits_controller.rb @@ -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 diff --git a/app/controllers/ci/projects_controller.rb b/app/controllers/ci/projects_controller.rb index e8788955eba72b812f83a946d5bf5b771fce5edc..20e6c2c2ba7736b23b637032a2f5ee435d66abcf 100644 --- a/app/controllers/ci/projects_controller.rb +++ b/app/controllers/ci/projects_controller.rb @@ -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 diff --git a/app/helpers/builds_helper.rb b/app/helpers/builds_helper.rb index b6658e52d092c2ae4a6c628e065bd7dafbd69af5..626f4e2f4c0edae34f0839b9c7df24194281ecb2 100644 --- a/app/helpers/builds_helper.rb +++ b/app/helpers/builds_helper.rb @@ -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 diff --git a/app/helpers/ci/commits_helper.rb b/app/helpers/ci/commits_helper.rb index 9069aed5b4d3f044d270521115a76784a4e45097..a0df4c3d72d35d599387cb908a1a48c284cb1dab 100644 --- a/app/helpers/ci/commits_helper.rb +++ b/app/helpers/ci/commits_helper.rb @@ -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) diff --git a/app/helpers/ci/gitlab_helper.rb b/app/helpers/ci/gitlab_helper.rb index 13e4d0fd9c3b984056ce1a636d33f0dac684b976..baddbc806f2d386d31ec6e85605ba7af0136a2c4 100644 --- a/app/helpers/ci/gitlab_helper.rb +++ b/app/helpers/ci/gitlab_helper.rb @@ -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" diff --git a/app/helpers/ci_status_helper.rb b/app/helpers/ci_status_helper.rb index 3a88ed7107ee509ab519ae453939690c2db63277..794bdc2530ea2f1c11af7edf7137db2d90a28ae8 100644 --- a/app/helpers/ci_status_helper.rb +++ b/app/helpers/ci_status_helper.rb @@ -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) diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 645ad68e1b3d1183cba31fcbd9a615f36d2375a5..f35224916ed20e728593d92c1acc30d382796bb0 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -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 diff --git a/app/models/ci/commit.rb b/app/models/ci/commit.rb index 6d048779cde78099b8a420e5e57acb51d18c5d26..46370034f9a30933988b20c0f441051a4b6dcd80 100644 --- a/app/models/ci/commit.rb +++ b/app/models/ci/commit.rb @@ -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) diff --git a/app/models/ci/project_status.rb b/app/models/ci/project_status.rb index 6d5cafe81a2f1a44a04f88274c73c7207206b5f5..b66f1212f239da967a16480ac2fe9b5d428edbc9 100644 --- a/app/models/ci/project_status.rb +++ b/app/models/ci/project_status.rb @@ -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 diff --git a/app/models/project.rb b/app/models/project.rb index b90a82da9f231059a78f7e8a2f4dab54d05f816c..bb47b9abb03907a356cc86ad3d199bb0e364e510 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -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 diff --git a/app/models/project_services/ci/hip_chat_message.rb b/app/models/project_services/ci/hip_chat_message.rb index 25c72033eacafd948e84dbb77ccfdc0306fa24eb..0bf448d47f27f27c37c8b17ddab8dc2e8498f8cd 100644 --- a/app/models/project_services/ci/hip_chat_message.rb +++ b/app/models/project_services/ci/hip_chat_message.rb @@ -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('') diff --git a/app/models/project_services/ci/mail_service.rb b/app/models/project_services/ci/mail_service.rb index 1bd2f33612b5cb196618c2a909e3e0b1c1ae080a..11a2743f9693a6b41ed3aed7bb33e19e2c8201d0 100644 --- a/app/models/project_services/ci/mail_service.rb +++ b/app/models/project_services/ci/mail_service.rb @@ -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) diff --git a/app/models/project_services/ci/slack_message.rb b/app/models/project_services/ci/slack_message.rb index 757b1961143f846f8bedc453ac8dad58814caf1f..a89c01517b73e5b2be4d2962c46457627a62674b 100644 --- a/app/models/project_services/ci/slack_message.rb +++ b/app/models/project_services/ci/slack_message.rb @@ -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 diff --git a/app/models/project_services/gitlab_ci_service.rb b/app/models/project_services/gitlab_ci_service.rb index 6d2cf79b691ce0baed3351bb5bd765597911b677..b63a75cf3afb1a0d61f25bba43d7c197dba20320 100644 --- a/app/models/project_services/gitlab_ci_service.rb +++ b/app/models/project_services/gitlab_ci_service.rb @@ -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 diff --git a/app/models/user.rb b/app/models/user.rb index 1069f8e36640212372f9237ea8d1918b0cf767ff..c7e3992b6a166fece09544fd9a3934c57f702503 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -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' # diff --git a/app/services/ci/create_builds_service.rb b/app/services/ci/create_builds_service.rb new file mode 100644 index 0000000000000000000000000000000000000000..c420f3268fd322444d173c0abb26882800ba573e --- /dev/null +++ b/app/services/ci/create_builds_service.rb @@ -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 diff --git a/app/services/ci/create_commit_service.rb b/app/services/ci/create_commit_service.rb index 0a1abf89a95b14786bd03e10d6715fdf0f9de65a..fc1ae5774d561b6c96b8cd3f4f3bceaec2bfd997 100644 --- a/app/services/ci/create_commit_service.rb +++ b/app/services/ci/create_commit_service.rb @@ -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 diff --git a/app/services/ci/create_trigger_request_service.rb b/app/services/ci/create_trigger_request_service.rb index 9bad09f2f54b35fd4ff1d6b3684621040d4f2e7b..4b86cb0a1f54edb4a6a5f7e235c0c2e728cece39 100644 --- a/app/services/ci/create_trigger_request_service.rb +++ b/app/services/ci/create_trigger_request_service.rb @@ -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 diff --git a/app/services/ci/web_hook_service.rb b/app/services/ci/web_hook_service.rb index 87984b20fa16c747bb27fffd0e1b1a8c80ece883..92e6df442b4f3f9ee929077a254c81684ed3571c 100644 --- a/app/services/ci/web_hook_service.rb +++ b/app/services/ci/web_hook_service.rb @@ -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 diff --git a/app/views/ci/builds/_build.html.haml b/app/views/ci/builds/_build.html.haml index 515b862e992c11f95d7ea07a2e71691234d95fa1..8ccc0dff2fbf49ae110a42f250ae3d2530ad13cb 100644 --- a/app/views/ci/builds/_build.html.haml +++ b/app/views/ci/builds/_build.html.haml @@ -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 diff --git a/app/views/ci/builds/show.html.haml b/app/views/ci/builds/show.html.haml index 839dbf5c55444f7772dea4340c118db4e4f1e95f..c42d11bf05deaa85d25ca212126f5815ef0f84e8 100644 --- a/app/views/ci/builds/show.html.haml +++ b/app/views/ci/builds/show.html.haml @@ -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} diff --git a/app/views/ci/commits/_commit.html.haml b/app/views/ci/commits/_commit.html.haml index 1eacfca944fce44254928c5d5a87b5fa558ad83e..f8a1fa508517c35dec3896f31030d2a0e9e2180c 100644 --- a/app/views/ci/commits/_commit.html.haml +++ b/app/views/ci/commits/_commit.html.haml @@ -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 diff --git a/app/views/ci/commits/show.html.haml b/app/views/ci/commits/show.html.haml index 8f38aa84676a6c39b0ef05aa2418de2d19958648..7217671fe95351b33cef489d2d58e13644c7113a 100644 --- a/app/views/ci/commits/show.html.haml +++ b/app/views/ci/commits/show.html.haml @@ -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,30 +35,31 @@ - @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} +- @commit.refs.each do |ref| + %h3 + 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 - %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 + %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.for_ref(ref), controls: true - if @commit.retried_builds.any? %h3 @@ -77,6 +70,7 @@ %tr %th Status %th Build ID + %th Ref %th Stage %th Name %th Duration @@ -84,4 +78,4 @@ - if @project.coverage_enabled? %th Coverage %th - = render @commit.retried_builds + = render @commit.retried_builds, ref: true diff --git a/app/views/ci/notify/build_fail_email.html.haml b/app/views/ci/notify/build_fail_email.html.haml index d818e8b6756aaca8c8100ce8752d48c053c76b00..4ebdfa1b6c088d884f62efef3dcc7422facb4478 100644 --- a/app/views/ci/notify/build_fail_email.html.haml +++ b/app/views/ci/notify/build_fail_email.html.haml @@ -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} diff --git a/app/views/ci/notify/build_fail_email.text.erb b/app/views/ci/notify/build_fail_email.text.erb index 1add215a1c8ab5c0ffda424632ebd2ec6f48ed0c..177827f9a3c1c2aa16874f6a840c598aa6c1a685 100644 --- a/app/views/ci/notify/build_fail_email.text.erb +++ b/app/views/ci/notify/build_fail_email.text.erb @@ -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) %> diff --git a/app/views/ci/notify/build_success_email.html.haml b/app/views/ci/notify/build_success_email.html.haml index a20dcaee24e4f0d7f437e047d0188907741bdc01..7cc43300e883e4a45986a526db88af6b9c1a6922 100644 --- a/app/views/ci/notify/build_success_email.html.haml +++ b/app/views/ci/notify/build_success_email.html.haml @@ -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} diff --git a/app/views/ci/notify/build_success_email.text.erb b/app/views/ci/notify/build_success_email.text.erb index 7ebd17e7270495bc56b06f3d2c2c99692dfc3af0..4d55c39b0fb7c6e5e5c3481949cf85de57125ec0 100644 --- a/app/views/ci/notify/build_success_email.text.erb +++ b/app/views/ci/notify/build_success_email.text.erb @@ -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) %> diff --git a/config/routes.rb b/config/routes.rb index 7bda7ade817307cbf810daec5d89787fc1b55e13..a21889631ed7a2d09b62ab9d4fdcda9b1a35ab64 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -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 diff --git a/db/migrate/20151002112914_add_stage_idx_to_builds.rb b/db/migrate/20151002112914_add_stage_idx_to_builds.rb new file mode 100644 index 0000000000000000000000000000000000000000..68a745ffef49d6c1839964560013d6d274ff9434 --- /dev/null +++ b/db/migrate/20151002112914_add_stage_idx_to_builds.rb @@ -0,0 +1,5 @@ +class AddStageIdxToBuilds < ActiveRecord::Migration + def change + add_column :ci_builds, :stage_idx, :integer + end +end diff --git a/db/migrate/20151002121400_add_index_for_builds.rb b/db/migrate/20151002121400_add_index_for_builds.rb new file mode 100644 index 0000000000000000000000000000000000000000..4ffc1363910dab6f9e4443d06d2b1146d5f18136 --- /dev/null +++ b/db/migrate/20151002121400_add_index_for_builds.rb @@ -0,0 +1,5 @@ +class AddIndexForBuilds < ActiveRecord::Migration + def up + add_index :ci_builds, [:commit_id, :stage_idx, :created_at] + end +end diff --git a/db/migrate/20151002122929_add_ref_and_tag_to_builds.rb b/db/migrate/20151002122929_add_ref_and_tag_to_builds.rb new file mode 100644 index 0000000000000000000000000000000000000000..e3d2ac1cea5cc43e34d52e07a1a055b5dbc20693 --- /dev/null +++ b/db/migrate/20151002122929_add_ref_and_tag_to_builds.rb @@ -0,0 +1,6 @@ +class AddRefAndTagToBuilds < ActiveRecord::Migration + def change + add_column :ci_builds, :tag, :boolean + add_column :ci_builds, :ref, :string + end +end diff --git a/db/migrate/20151002122943_migrate_ref_and_tag_to_build.rb b/db/migrate/20151002122943_migrate_ref_and_tag_to_build.rb new file mode 100644 index 0000000000000000000000000000000000000000..01d7b3f6773822dcbae7116c76d0c3ff90acceb6 --- /dev/null +++ b/db/migrate/20151002122943_migrate_ref_and_tag_to_build.rb @@ -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 diff --git a/db/migrate/20151005075649_add_user_id_to_build.rb b/db/migrate/20151005075649_add_user_id_to_build.rb new file mode 100644 index 0000000000000000000000000000000000000000..0f4b92b8b79f3d587772627bf6cfea01c7125518 --- /dev/null +++ b/db/migrate/20151005075649_add_user_id_to_build.rb @@ -0,0 +1,5 @@ +class AddUserIdToBuild < ActiveRecord::Migration + def change + add_column :ci_builds, :user_id, :integer + end +end diff --git a/db/schema.rb b/db/schema.rb index 72609da93f14f05490b821504bb97bedab8b3dd2..0e8d54fb267b027e6af0f0cf091e7605602e465a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -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 diff --git a/lib/ci/api/commits.rb b/lib/ci/api/commits.rb index bac463a59096e1797c5ba627cbe1406a6be5b47c..a60769d83059f431585697a4137c2d721febb227 100644 --- a/lib/ci/api/commits.rb +++ b/lib/ci/api/commits.rb @@ -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 diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index e625e790df8f06175a5f7c42ebef95e80bb8dae4..c47951bc5d190e108e89bfc8b95e4afb851cbf00 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -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], diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb index 99da5a187769d86792457f154c7523bdcd2ff58d..21b582afba4648b177e0699ff21248a81b67ba6b 100644 --- a/spec/factories/ci/builds.rb +++ b/spec/factories/ci/builds.rb @@ -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 diff --git a/spec/factories/ci/commits.rb b/spec/factories/ci/commits.rb index 9c7a0e9cbe028097e590ae70178db1116bcef4fe..79e000b7ccb1c164e519f93d70904303a3ff3c51 100644 --- a/spec/factories/ci/commits.rb +++ b/spec/factories/ci/commits.rb @@ -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 diff --git a/spec/features/ci/commits_spec.rb b/spec/features/ci/commits_spec.rb index 657a9dabe9e19b10665282aac13d63b79b9e3d39..b4236e1e589626bdf4cf95da32abcaff359c6627 100644 --- a/spec/features/ci/commits_spec.rb +++ b/spec/features/ci/commits_spec.rb @@ -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) diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index 49482ac2b12c2fb5e8a7d7e24c17996af589e761..aba957da4881694b6795736bfc163b1b682b6786 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -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"] diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index ca070a14975516f85bda039bc3cf2034bb15057d..da56f6e31ae11673498d682be19e8903c8881735 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -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 diff --git a/spec/models/ci/commit_spec.rb b/spec/models/ci/commit_spec.rb index c04bbcbadc7ff43e1f0233bad7fd496c6ecf117b..acff1ddf0fcf274a1fef5112d3a2275d1dfb0f54 100644 --- a/spec/models/ci/commit_spec.rb +++ b/spec/models/ci/commit_spec.rb @@ -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,63 +65,95 @@ 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 } + subject { commit.short_sha } it 'has 8 items' do expect(subject.size).to eq(8) end - it { expect(commit.before_sha).to start_with(subject) } + it { expect(commit.sha).to start_with(subject) } end - describe :short_sha do - subject { commit.short_sha } + describe :stage do + subject { commit.stage } - it 'has 8 items' do - expect(subject.size).to eq(8) + before do + @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 'returns first running stage' do + is_expected.to eq('test') + end + + context 'first build succeeded' do + before do + @first.update_attributes(status: :success) + end + + it 'returns last running stage' do + is_expected.to eq('deploy') + end + end + + 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 - it { expect(commit.sha).to start_with(subject) } end describe :create_next_builds do - before do - allow(commit).to receive(:config_processor).and_return(config_processor) + end + + describe :create_builds do + 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 for next type" do - expect(commit.create_builds).to be_truthy + it 'creates builds' do + expect(create_builds).to be_truthy commit.builds.reload expect(commit.builds.size).to eq(2) - expect(commit.create_next_builds(nil)).to be_truthy + expect(create_next_builds).to be_truthy commit.builds.reload expect(commit.builds.size).to eq(4) - expect(commit.create_next_builds(nil)).to be_truthy + expect(create_next_builds).to be_truthy commit.builds.reload expect(commit.builds.size).to eq(5) - expect(commit.create_next_builds(nil)).to be_falsey + expect(create_next_builds).to be_falsey end - end - describe :create_builds do - before do - allow(commit).to receive(:config_processor).and_return(config_processor) - end + context 'for different ref' do + def create_develop_builds + commit.create_builds('develop', false, nil, nil) + end - it 'creates builds' do - expect(commit.create_builds).to be_truthy - commit.builds.reload - expect(commit.builds.size).to eq(2) + 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 diff --git a/spec/models/ci/project_services/hip_chat_message_spec.rb b/spec/models/ci/project_services/hip_chat_message_spec.rb index 1903c036924104b013dbb9b33ffc8dad243defea..e23d6ae2c2844ae7e090011910096f32ba5aa44b 100644 --- a/spec/models/ci/project_services/hip_chat_message_spec.rb +++ b/spec/models/ci/project_services/hip_chat_message_spec.rb @@ -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 - - context 'when build succeeds' do - it 'returns a successful message' do - build.update(status: "success") - - 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 - end + let(:build) do + commit.builds.first end - context "Several builds" do - let(:commit) { FactoryGirl.create(:ci_commit_with_two_jobs) } - - 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 + 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(/Commit #\d+/) - expect( subject.to_s ).to match(/Successful 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 '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 + 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") + + 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 diff --git a/spec/models/ci/mail_service_spec.rb b/spec/models/ci/project_services/mail_service_spec.rb similarity index 95% rename from spec/models/ci/mail_service_spec.rb rename to spec/models/ci/project_services/mail_service_spec.rb index 0d9f85959bafbfad1d0a6c944b9d39159cfb4e8e..04e870dce7f5d36778f61afb7736fc9825153789 100644 --- a/spec/models/ci/mail_service_spec.rb +++ b/spec/models/ci/project_services/mail_service_spec.rb @@ -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( diff --git a/spec/models/ci/project_services/slack_message_spec.rb b/spec/models/ci/project_services/slack_message_spec.rb index 7b541802d7d7693b0aa547b128e1242c57acf435..8adda6c86ccc84950f35290142b0e59dae010e43 100644 --- a/spec/models/ci/project_services/slack_message_spec.rb +++ b/spec/models/ci/project_services/slack_message_spec.rb @@ -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 build succeeded' do - let(:color) { 'good' } + context 'when all matrix builds succeeded' do + let(:color) { 'good' } - it 'returns a message with succeeded build' do - build.update(status: "success") + it 'returns a message with success' do + commit.create_builds('master', false, nil) + commit.builds.update_all(status: "success") + commit.reload - 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 all matrix builds succeeded' do - let(:color) { 'good' } - - 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 + context 'when one of matrix builds failed' do + let(:color) { 'danger' } + + 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") + + 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 diff --git a/spec/models/project_services/gitlab_ci_service_spec.rb b/spec/models/project_services/gitlab_ci_service_spec.rb index 683a403a9071c56048f724410334d8e890da6bd7..c0b8a144c3add3279e20367f181a29cab2847599 100644 --- a/spec/models/project_services/gitlab_ci_service_spec.rb +++ b/spec/models/project_services/gitlab_ci_service_spec.rb @@ -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 diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb index bad250fbf484b86d7c490d02b9fc644b122865a7..54c1d0199f6a88b57026a882ee6b42df3259f166 100644 --- a/spec/requests/ci/api/builds_spec.rb +++ b/spec/requests/ci/api/builds_spec.rb @@ -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 } diff --git a/spec/requests/ci/api/commits_spec.rb b/spec/requests/ci/api/commits_spec.rb index a41c321a30043f5001efe4effd31fb2dbb51484d..6049135fd104f799c8757e81824dfc185a7c5495 100644 --- a/spec/requests/ci/api/commits_spec.rb +++ b/spec/requests/ci/api/commits_spec.rb @@ -44,8 +44,7 @@ describe Ci::API::API, 'Commits' do "email" => "jordi@softcatala.org", } } - ], - ci_yaml_file: gitlab_ci_yaml + ] } end diff --git a/spec/requests/ci/api/triggers_spec.rb b/spec/requests/ci/api/triggers_spec.rb index bbe98e7dacdb947a0c4c09bf211ce153ba6aed65..93617fc4b3f2dc9eee0b9656a3d53f1aab77b7e3 100644 --- a/spec/requests/ci/api/triggers_spec.rb +++ b/spec/requests/ci/api/triggers_spec.rb @@ -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 diff --git a/spec/requests/ci/commits_spec.rb b/spec/requests/ci/commits_spec.rb index 3ab8c915dfd9b739e532ab92539d9c666392e1d6..f43a3982d718ec2759e1700e79cebf74b9c22178 100644 --- a/spec/requests/ci/commits_spec.rb +++ b/spec/requests/ci/commits_spec.rb @@ -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) } diff --git a/spec/services/ci/create_commit_service_spec.rb b/spec/services/ci/create_commit_service_spec.rb index 84ab0a615dd603882b22a37ac6e3fefe643131c0..e3a8fe9681b6c87a84c1ff7732deae4d8f9be062 100644 --- a/spec/services/ci/create_commit_service_spec.rb +++ b/spec/services/ci/create_commit_service_spec.rb @@ -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") diff --git a/spec/services/ci/create_trigger_request_service_spec.rb b/spec/services/ci/create_trigger_request_service_spec.rb index 525a24cc20048870271926d7589d048d60996c6a..fcafae386448090f89f881b6b5dd5d7508847855 100644 --- a/spec/services/ci/create_trigger_request_service_spec.rb +++ b/spec/services/ci/create_trigger_request_service_spec.rb @@ -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 diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 05bb32baa903e2468517d9e5e2ac9357933c0d3d..2be13bb3e6a0dd95d1c8962724b12e18517011e0 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -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! diff --git a/spec/support/stub_gitlab_calls.rb b/spec/support/stub_gitlab_calls.rb index 5e6744afda120a338235015e1f88f8a693e2237b..5b3eb1bfc5f26f9ea7a1140fc439e716014f1068 100644 --- a/spec/support/stub_gitlab_calls.rb +++ b/spec/support/stub_gitlab_calls.rb @@ -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