diff options
35 files changed, 326 insertions, 238 deletions
diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb index 576fa3cedb2..f9a4aeaa627 100644 --- a/app/controllers/projects/commit_controller.rb +++ b/app/controllers/projects/commit_controller.rb @@ -94,8 +94,8 @@ class Projects::CommitController < Projects::ApplicationController @commit ||= @project.commit(params[:id]) end - def ci_commit - @ci_commit ||= project.ci_commit(commit.sha) + def ci_commits + @ci_commits ||= project.ci_commits.where(sha: commit.sha) end def define_show_vars @@ -108,7 +108,8 @@ class Projects::CommitController < Projects::ApplicationController @diff_refs = [commit.parent || commit, commit] @notes_count = commit.notes.count - @statuses = ci_commit.statuses if ci_commit + @statuses = CommitStatus.where(commit: ci_commits) + @builds = Ci::Build.where(commit: ci_commits) end def assign_revert_commit_vars diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 49064f5d505..ed5a1901056 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -118,6 +118,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController @diffs = @merge_request.compare.diffs(diff_options) if @merge_request.compare @ci_commit = @merge_request.ci_commit + @ci_commits = [@ci_commit].compact @statuses = @ci_commit.statuses if @ci_commit @note_counts = Note.where(commit_id: @commits.map(&:id)). @@ -308,6 +309,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController @merge_request_diff = @merge_request.merge_request_diff @ci_commit = @merge_request.ci_commit + @ci_commits = [@ci_commit].compact @statuses = @ci_commit.statuses if @ci_commit if @merge_request.locked_long_ago? @@ -318,6 +320,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController def define_widget_vars @ci_commit = @merge_request.ci_commit + @ci_commits = [@ci_commit].compact closes_issues end diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/app/controllers/projects/pipelines_controller.rb diff --git a/app/helpers/ci_status_helper.rb b/app/helpers/ci_status_helper.rb index 8b1575d5e0c..fd2179c7af5 100644 --- a/app/helpers/ci_status_helper.rb +++ b/app/helpers/ci_status_helper.rb @@ -1,17 +1,4 @@ module CiStatusHelper - def ci_status_path(ci_commit) - project = ci_commit.project - builds_namespace_project_commit_path(project.namespace, project, ci_commit.sha) - end - - def ci_status_icon(ci_commit) - ci_icon_for_status(ci_commit.status) - end - - def ci_status_label(ci_commit) - ci_label_for_status(ci_commit.status) - end - def ci_status_with_icon(status, target = nil) content = ci_icon_for_status(status) + ' '.html_safe + ci_label_for_status(status) klass = "ci-status ci-#{status}" @@ -47,10 +34,10 @@ module CiStatusHelper end def render_ci_status(ci_commit, tooltip_placement: 'auto left') - link_to ci_status_icon(ci_commit), - ci_status_path(ci_commit), + link_to ci_icon_for_status(ci_commit.status), + project_ci_commit_path(ci_commit.project, ci_commit), class: "ci-status-link ci-status-icon-#{ci_commit.status.dasherize}", - title: "Build #{ci_status_label(ci_commit)}", + title: "Build #{ci_label_for_status(ci_commit.status)}", data: { toggle: 'tooltip', placement: tooltip_placement } end diff --git a/app/helpers/gitlab_routing_helper.rb b/app/helpers/gitlab_routing_helper.rb index f3fddef01cb..f1af8e163cd 100644 --- a/app/helpers/gitlab_routing_helper.rb +++ b/app/helpers/gitlab_routing_helper.rb @@ -25,10 +25,22 @@ module GitlabRoutingHelper namespace_project_commits_path(project.namespace, project, @ref || project.repository.root_ref) end + def project_pipelines_path(project, *args) + namespace_project_pipelines_path(project.namespace, project, *args) + end + def project_builds_path(project, *args) namespace_project_builds_path(project.namespace, project, *args) end + def project_commit_path(project, commit) + builds_namespace_project_commit_path(project.namespace, project, commit.id) + end + + def project_ci_commit_path(project, ci_commit) + builds_namespace_project_commit_path(project.namespace, project, ci_commit.sha) + end + def activity_project_path(project, *args) activity_namespace_project_path(project.namespace, project, *args) end diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 7d33838044b..15fc714b538 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -50,7 +50,6 @@ module Ci scope :unstarted, ->() { where(runner_id: nil) } scope :ignore_failures, ->() { where(allow_failure: false) } - scope :similar, ->(build) { where(ref: build.ref, tag: build.tag, trigger_request_id: build.trigger_request_id) } mount_uploader :artifacts_file, ArtifactUploader mount_uploader :artifacts_metadata, ArtifactUploader @@ -62,6 +61,8 @@ module Ci before_destroy { project } + after_create :execute_hooks + class << self def columns_without_lazy (column_names - LAZY_ATTRIBUTES).map do |column_name| @@ -126,12 +127,16 @@ module Ci end def retried? - !self.commit.latest_statuses_for_ref(self.ref).include?(self) + !self.commit.latest.include?(self) + end + + def retry + Ci::Build.retry(self) end def depends_on_builds # Get builds of the same type - latest_builds = self.commit.builds.similar(self).latest + latest_builds = self.commit.builds.latest # Return builds from previous stages latest_builds.where('stage_idx < ?', stage_idx) diff --git a/app/models/ci/commit.rb b/app/models/ci/commit.rb index f4cf7034b14..70fe63877cb 100644 --- a/app/models/ci/commit.rb +++ b/app/models/ci/commit.rb @@ -19,6 +19,7 @@ module Ci class Commit < ActiveRecord::Base extend Ci::Model + include CiStatus belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id has_many :statuses, class_name: 'CommitStatus' @@ -28,12 +29,18 @@ module Ci validates_presence_of :sha validate :valid_commit_sha + # Make sure that status is saved + before_save :status + before_save :started_at + before_save :finished_at + before_save :duration + def self.truncate_sha(sha) sha[0...8] end - def to_param - sha + def stages + statuses.group(:stage).order(:stage_idx).pluck(:stage) end def project_id @@ -68,15 +75,26 @@ module Ci nil end - def stage - running_or_pending = statuses.latest.running_or_pending.ordered - running_or_pending.first.try(:stage) + def branch? + !tag? + end + + def retryable? + builds.latest.any? do |build| + build.failed? || build.retryable? + end + end + + def invalidate + status = nil + started_at = nil + finished_at = nil end - def create_builds(ref, tag, user, trigger_request = nil) + def create_builds(user, trigger_request = nil) return unless config_processor config_processor.stages.any? do |stage| - CreateBuildsService.new.execute(self, stage, ref, tag, user, trigger_request, 'success').present? + CreateBuildsService.new(self).execute(stage, user, 'success', trigger_request).present? end end @@ -84,7 +102,7 @@ module Ci return unless config_processor # don't create other builds if this one is retried - latest_builds = builds.similar(build).latest + latest_builds = builds.latest return unless latest_builds.exists?(build.id) # get list of stages after this build @@ -97,26 +115,12 @@ module Ci # create builds for next stages based next_stages.any? do |stage| - CreateBuildsService.new.execute(self, stage, build.ref, build.tag, build.user, build.trigger_request, status).present? + CreateBuildsService.new(self).execute(stage, build.user, status, build.trigger_request).present? end end - def refs - statuses.order(:ref).pluck(:ref).uniq - end - - def latest_statuses - @latest_statuses ||= statuses.latest.to_a - end - - def latest_statuses_for_ref(ref) - latest_statuses.select { |status| status.ref == ref } - end - - def matrix_builds(build = nil) - matrix_builds = builds.latest.ordered - matrix_builds = matrix_builds.similar(build) if build - matrix_builds.to_a + def latest + statuses.latest end def retried @@ -124,56 +128,23 @@ module Ci end def status - if yaml_errors.present? - return 'failed' - end - - @status ||= Ci::Status.get_status(latest_statuses) - end - - def pending? - status == 'pending' - end - - def running? - status == 'running' - end - - def success? - status == 'success' - end - - def failed? - status == 'failed' - end - - def canceled? - status == 'canceled' - end - - def active? - running? || pending? - end - - def complete? - canceled? || success? || failed? + read_attribute(:status) || update_status end def duration - duration_array = statuses.map(&:duration).compact - duration_array.reduce(:+).to_i + read_attribute(:duration) || update_duration end def started_at - @started_at ||= statuses.order('started_at ASC').first.try(:started_at) + read_attribute(:started_at) || update_started_at end def finished_at - @finished_at ||= statuses.order('finished_at DESC').first.try(:finished_at) + read_attribute(:finished_at) || update_finished_at end def coverage - coverage_array = latest_statuses.map(&:coverage).compact + coverage_array = latest.map(&:coverage).compact if coverage_array.size >= 1 '%.2f' % (coverage_array.reduce(:+) / coverage_array.size) end @@ -191,6 +162,7 @@ module Ci end def ci_yaml_file + return nil if defined?(@ci_yaml_file) @ci_yaml_file ||= begin blob = project.repository.blob_at(sha, '.gitlab-ci.yml') blob.load_all_data!(project.repository) @@ -206,6 +178,32 @@ module Ci private + def update_status + status = + if yaml_errors.present? + 'failed' + else + latest.status + end + end + + def update_started_at + started_at = + statuses.order(:id).first.try(:started_at) + end + + def update_finished_at + finished_at = + statuses.order(id: :desc).first.try(:finished_at) + end + + def update_duration + duration = begin + duration_array = latest.map(&:duration).compact + duration_array.reduce(:+).to_i + end + end + def save_yaml_error(error) return if self.yaml_errors? self.yaml_errors = error diff --git a/app/models/commit.rb b/app/models/commit.rb index d09876a07d9..a898f7ba337 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -209,12 +209,13 @@ class Commit @raw.short_id(7) end - def ci_commit - project.ci_commit(sha) + def ci_commits + @ci_commits ||= project.ci_commits.where(sha: sha) end def status - ci_commit.try(:status) || :not_found + return @status if defined?(@status) + @status ||= ci_commits.status end def revert_branch_name diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb index 3377a85a55a..da7d6ea6b94 100644 --- a/app/models/commit_status.rb +++ b/app/models/commit_status.rb @@ -33,6 +33,8 @@ # class CommitStatus < ActiveRecord::Base + include CiStatus + self.table_name = 'ci_builds' belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id @@ -40,21 +42,13 @@ class CommitStatus < ActiveRecord::Base belongs_to :user validates :commit, presence: true - validates :status, inclusion: { in: %w(pending running failed success canceled) } validates_presence_of :name alias_attribute :author, :user - scope :running, -> { where(status: 'running') } - scope :pending, -> { where(status: 'pending') } - scope :success, -> { where(status: 'success') } - scope :failed, -> { where(status: 'failed') } - scope :running_or_pending, -> { where(status: [:running, :pending]) } - scope :finished, -> { where(status: [:success, :failed, :canceled]) } - scope :latest, -> { where(id: unscope(:select).select('max(id)').group(:name, :ref)) } + scope :latest, -> { where(id: unscope(:select).select('max(id)').group(:name)) } scope :ordered, -> { order(:ref, :stage_idx, :name) } - scope :for_ref, ->(ref) { where(ref: ref) } AVAILABLE_STATUSES = ['pending', 'running', 'success', 'failed', 'canceled'] @@ -87,31 +81,13 @@ class CommitStatus < ActiveRecord::Base MergeRequests::MergeWhenBuildSucceedsService.new(commit_status.commit.project, nil).trigger(commit_status) end - state :pending, value: 'pending' - state :running, value: 'running' - state :failed, value: 'failed' - state :success, value: 'success' - state :canceled, value: 'canceled' - end - - delegate :sha, :short_sha, to: :commit, prefix: false - - # TODO: this should be removed with all references - def before_sha - Gitlab::Git::BLANK_SHA - end - - def started? - !pending? && !canceled? && started_at - end - - def active? - running? || pending? + after_transition any => any do |commit_status| + commit_status.commit.invalidate + commit_status.save + end end - def complete? - canceled? || success? || failed? - end + delegate :before_sha, :sha, :short_sha, to: :commit, prefix: false def ignored? allow_failure? && (failed? || canceled?) diff --git a/app/models/concerns/ci_status.rb b/app/models/concerns/ci_status.rb new file mode 100644 index 00000000000..9fe20bc9d73 --- /dev/null +++ b/app/models/concerns/ci_status.rb @@ -0,0 +1,58 @@ +module CiStatus + extend ActiveSupport::Concern + + module ClassMethods + def status + objs = all.to_a + if objs.none? + nil + elsif objs.all? { |status| status.success? || status.try(:ignored?) } + 'success' + elsif objs.all?(&:pending?) + 'pending' + elsif objs.any?(&:running?) || all.any?(&:pending?) + 'running' + elsif objs.all?(&:canceled?) + 'canceled' + else + 'failed' + end + end + + def duration + duration_array = all.map(&:duration).compact + duration_array.reduce(:+).to_i + end + end + + included do + validates :status, inclusion: { in: %w(pending running failed success canceled) } + + state_machine :status, initial: :pending do + state :pending, value: 'pending' + state :running, value: 'running' + state :failed, value: 'failed' + state :success, value: 'success' + state :canceled, value: 'canceled' + end + + scope :running, -> { where(status: 'running') } + scope :pending, -> { where(status: 'pending') } + scope :success, -> { where(status: 'success') } + scope :failed, -> { where(status: 'failed') } + scope :running_or_pending, -> { where(status: [:running, :pending]) } + scope :finished, -> { where(status: [:success, :failed, :canceled]) } + end + + def started? + !pending? && !canceled? && started_at + end + + def active? + running? || pending? + end + + def complete? + canceled? || success? || failed? + end +end
\ No newline at end of file diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index bf185cb5dd8..33869e215c9 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -589,7 +589,7 @@ class MergeRequest < ActiveRecord::Base end def ci_commit - @ci_commit ||= source_project.ci_commit(last_commit.id) if last_commit && source_project + @ci_commit ||= source_project.ci_commit(last_commit.id, source_branch) if last_commit && source_project end def diff_refs diff --git a/app/models/project.rb b/app/models/project.rb index 3e1f04b4158..b9d589a4594 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -919,12 +919,12 @@ class Project < ActiveRecord::Base !namespace.share_with_group_lock end - def ci_commit(sha) - ci_commits.find_by(sha: sha) + def ci_commit(sha, ref) + ci_commits.find_by(sha: sha, ref: ref) end - def ensure_ci_commit(sha) - ci_commit(sha) || ci_commits.create(sha: sha) + def ensure_ci_commit(sha, ref) + ci_commit(sha, ref) || ci_commits.create(sha: sha, ref: ref) end def enable_ci diff --git a/app/services/ci/create_builds_service.rb b/app/services/ci/create_builds_service.rb index 2cd51a7610f..3b6e045d698 100644 --- a/app/services/ci/create_builds_service.rb +++ b/app/services/ci/create_builds_service.rb @@ -1,7 +1,11 @@ module Ci class CreateBuildsService - def execute(commit, stage, ref, tag, user, trigger_request, status) - builds_attrs = commit.config_processor.builds_for_stage_and_ref(stage, ref, tag, trigger_request) + def initialize(commit) + @commit = commit + end + + def execute(stage, user, status, trigger_request = nil) + builds_attrs = config_processor.builds_for_stage_and_ref(stage, @commit.ref, @commit.tag, trigger_request) # check when to create next build builds_attrs = builds_attrs.select do |build_attrs| @@ -17,7 +21,8 @@ module Ci 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]) + unless commit.builds.find_by(ref: @commit.ref, tag: @commit.tag, + trigger_request: trigger_request, name: build_attrs[:name]) build_attrs.slice!(:name, :commands, :tag_list, @@ -26,17 +31,21 @@ module Ci :stage, :stage_idx) - build_attrs.merge!(ref: ref, - tag: tag, + build_attrs.merge!(ref: @commit.ref, + tag: @commit.tag, trigger_request: trigger_request, user: user, - project: commit.project) + project: @commit.project) - build = commit.builds.create!(build_attrs) - build.execute_hooks - build + @commit.builds.create!(build_attrs) end end end + + private + + def config_processor + @config_processor ||= @commit.config_processor + end end end diff --git a/app/services/ci/create_trigger_request_service.rb b/app/services/ci/create_trigger_request_service.rb index b3dfc707221..d3745c770ea 100644 --- a/app/services/ci/create_trigger_request_service.rb +++ b/app/services/ci/create_trigger_request_service.rb @@ -7,7 +7,7 @@ module Ci # check if ref is tag tag = project.repository.find_tag(ref).present? - ci_commit = project.ensure_ci_commit(commit.sha) + ci_commit = project.ci_commits.create(commit.sha, ref) trigger_request = trigger.trigger_requests.create!( variables: variables, diff --git a/app/services/create_commit_builds_service.rb b/app/services/create_commit_builds_service.rb index 69d5c42a877..e7e1134ce4b 100644 --- a/app/services/create_commit_builds_service.rb +++ b/app/services/create_commit_builds_service.rb @@ -2,6 +2,7 @@ class CreateCommitBuildsService def execute(project, user, params) return false unless project.builds_enabled? + before_sha = params[:checkout_sha] || params[:before] sha = params[:checkout_sha] || params[:after] origin_ref = params[:ref] @@ -10,15 +11,16 @@ class CreateCommitBuildsService end ref = Gitlab::Git.ref_name(origin_ref) + tag = Gitlab::Git.tag_ref?(origin_ref) # Skip branch removal if sha == Gitlab::Git::BLANK_SHA return false end - commit = project.ci_commit(sha) + commit = project.ci_commit(sha, ref) unless commit - commit = project.ci_commits.new(sha: sha) + commit = project.ci_commits.new(sha: sha, ref: ref, before_sha: before_sha, tag: tag) # Skip creating ci_commit when no gitlab-ci.yml is found unless commit.ci_yaml_file @@ -32,8 +34,7 @@ class CreateCommitBuildsService # Skip creating builds for commits that have [ci skip] unless commit.skip_ci? # Create builds for commit - tag = Gitlab::Git.tag_ref?(origin_ref) - commit.create_builds(ref, tag, user) + commit.create_builds(user) end commit diff --git a/app/views/admin/runners/show.html.haml b/app/views/admin/runners/show.html.haml index 8700b4820cd..50d00051409 100644 --- a/app/views/admin/runners/show.html.haml +++ b/app/views/admin/runners/show.html.haml @@ -117,7 +117,7 @@ %td.build-link - if project - = link_to ci_status_path(build.commit) do + = link_to builds_namespace_project_commit_path(project.namespace, project, build.sha) do %strong #{build.commit.short_sha} %td.timestamp diff --git a/app/views/projects/_last_commit.html.haml b/app/views/projects/_last_commit.html.haml index 386d72e7787..6eccbaa4bfa 100644 --- a/app/views/projects/_last_commit.html.haml +++ b/app/views/projects/_last_commit.html.haml @@ -1,9 +1,8 @@ .project-last-commit - - ci_commit = project.ci_commit(commit.sha) - - if ci_commit - = link_to ci_status_path(ci_commit), class: "ci-status ci-#{ci_commit.status}" do - = ci_status_icon(ci_commit) - = ci_status_label(ci_commit) + - if commit.status + = link_to project_commit_path(commit.project, commit), class: "ci-status ci-#{commit.status}" do + = ci_icon_for_status(commit.status) + = ci_label_for_status(commit.status) = link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit_short_id" = link_to_gfm commit.title, namespace_project_commit_path(project.namespace, project, commit), class: "commit-row-message" diff --git a/app/views/projects/builds/show.html.haml b/app/views/projects/builds/show.html.haml index b02aee3db21..41b1ca9f9e8 100644 --- a/app/views/projects/builds/show.html.haml +++ b/app/views/projects/builds/show.html.haml @@ -4,7 +4,7 @@ .build-page .gray-content-block.top-block Build ##{@build.id} for commit - %strong.monospace= link_to @build.commit.short_sha, ci_status_path(@build.commit) + %strong.monospace= link_to @build.commit.short_sha, builds_namespace_project_commit_path(@project.namespace, @project, @build.sha) from = link_to @build.ref, namespace_project_commits_path(@project.namespace, @project, @build.ref) - merge_request = @build.merge_request @@ -13,7 +13,7 @@ = link_to "merge request ##{merge_request.iid}", merge_request_path(merge_request) #up-build-trace - - builds = @build.commit.matrix_builds(@build) + - builds = @build.commit.builds.latest.to_a - if builds.size > 1 %ul.nav-links.no-top.no-bottom - builds.each do |build| @@ -173,7 +173,7 @@ Commit .pull-right %small - = link_to @build.commit.short_sha, ci_status_path(@build.commit), class: "monospace" + = link_to @build.commit.short_sha, builds_namespace_project_commit_path(@project.namespace, @project, @build.sha), class: "monospace" %p %span.attr-name Branch: = link_to @build.ref, namespace_project_commits_path(@project.namespace, @project, @build.ref) @@ -196,7 +196,7 @@ .build-widget %h4.title #{pluralize(@builds.count(:id), "other build")} for = succeed ":" do - = link_to @build.commit.short_sha, ci_status_path(@build.commit), class: "monospace" + = link_to @build.commit.short_sha, builds_namespace_project_commit_path(@project.namespace, @project, build.sha), class: "monospace" %table.table.builds - @builds.each_with_index do |build, i| %tr.build diff --git a/app/views/projects/ci/builds/_build.html.haml b/app/views/projects/ci/builds/_build.html.haml index 2cf9115e4dd..218d396b898 100644 --- a/app/views/projects/ci/builds/_build.html.haml +++ b/app/views/projects/ci/builds/_build.html.haml @@ -19,11 +19,12 @@ %td = link_to build.short_sha, namespace_project_commit_path(build.project.namespace, build.project, build.sha), class: "monospace" - %td - - if build.ref - = link_to build.ref, namespace_project_commits_path(build.project.namespace, build.project, build.ref) - - else - .light none + - if !defined?(ref) || ref + %td + - if build.ref + = link_to build.ref, namespace_project_commits_path(build.project.namespace, build.project, build.ref) + - else + .light none - if defined?(runner) && runner %td @@ -48,6 +49,8 @@ %span.label.label-info triggered - if build.try(:allow_failure) %span.label.label-danger allowed to fail + - if defined?(retried) && retried + %span.label.label-warning retried %td.duration - if build.duration diff --git a/app/views/projects/ci/commits/_commit.html.haml b/app/views/projects/ci/commits/_commit.html.haml new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/app/views/projects/ci/commits/_commit.html.haml diff --git a/app/views/projects/ci_commits/_header_title.html.haml b/app/views/projects/ci_commits/_header_title.html.haml new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/app/views/projects/ci_commits/_header_title.html.haml diff --git a/app/views/projects/ci_commits/index.html.haml b/app/views/projects/ci_commits/index.html.haml new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/app/views/projects/ci_commits/index.html.haml diff --git a/app/views/projects/ci_commits/new.html.haml b/app/views/projects/ci_commits/new.html.haml new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/app/views/projects/ci_commits/new.html.haml diff --git a/app/views/projects/commit/_builds.html.haml b/app/views/projects/commit/_builds.html.haml index 003b7c18d0e..5c9a319edeb 100644 --- a/app/views/projects/commit/_builds.html.haml +++ b/app/views/projects/commit/_builds.html.haml @@ -1,67 +1,2 @@ -.gray-content-block.middle-block - .pull-right - - if can?(current_user, :update_build, @ci_commit.project) - - if @ci_commit.builds.latest.failed.any?(&:retryable?) - = link_to "Retry failed", retry_builds_namespace_project_commit_path(@ci_commit.project.namespace, @ci_commit.project, @ci_commit.sha), class: 'btn btn-grouped btn-primary', method: :post - - - if @ci_commit.builds.running_or_pending.any? - = link_to "Cancel running", cancel_builds_namespace_project_commit_path(@ci_commit.project.namespace, @ci_commit.project, @ci_commit.sha), data: { confirm: 'Are you sure?' }, class: 'btn btn-grouped btn-danger', method: :post - - .oneline - = pluralize @statuses.count(:id), "build" - - if defined?(link_to_commit) && link_to_commit - for commit - = link_to @ci_commit.short_sha, namespace_project_commit_path(@ci_commit.project.namespace, @ci_commit.project, @ci_commit.sha), class: "monospace" - - if @ci_commit.duration > 0 - in - = time_interval_in_words @ci_commit.duration - -- if @ci_commit.yaml_errors.present? - .bs-callout.bs-callout-danger - %h4 Found errors in your .gitlab-ci.yml: - %ul - - @ci_commit.yaml_errors.split(",").each do |error| - %li= error - You can also test your .gitlab-ci.yml in the #{link_to "Lint", ci_lint_path} - -- if @ci_commit.project.builds_enabled? && !@ci_commit.ci_yaml_file - .bs-callout.bs-callout-warning - \.gitlab-ci.yml not found in this commit - -.table-holder - %table.table.builds - %thead - %tr - %th Status - %th Build ID - %th Ref - %th Stage - %th Name - %th Duration - %th Finished at - - if @ci_commit.project.build_coverage_enabled? - %th Coverage - %th - - @ci_commit.refs.each do |ref| - - builds = @ci_commit.statuses.for_ref(ref).latest.ordered - = render builds, coverage: @ci_commit.project.build_coverage_enabled?, stage: true, allow_retry: true - -- if @ci_commit.retried.any? - .gray-content-block.second-block - Retried builds - - .table-holder - %table.table.builds - %thead - %tr - %th Status - %th Build ID - %th Ref - %th Stage - %th Name - %th Duration - %th Finished at - - if @ci_commit.project.build_coverage_enabled? - %th Coverage - %th - = render @ci_commit.retried, coverage: @ci_commit.project.build_coverage_enabled?, stage: true +- @ci_commits.each do |ci_commit| + = render "ci_commit", ci_commit: ci_commit diff --git a/app/views/projects/commit/_ci_commit.html.haml b/app/views/projects/commit/_ci_commit.html.haml new file mode 100644 index 00000000000..06520e40bd9 --- /dev/null +++ b/app/views/projects/commit/_ci_commit.html.haml @@ -0,0 +1,69 @@ +.gray-content-block.middle-block + .pull-right + - if can?(current_user, :update_build, @project) + - if ci_commit.builds.latest.failed.any?(&:retryable?) + = link_to "Retry failed", retry_builds_namespace_project_commit_path(@project.namespace, @project, @commit.id), class: 'btn btn-grouped btn-primary', method: :post + + - if ci_commit.builds.running_or_pending.any? + = link_to "Cancel running", cancel_builds_namespace_project_commit_path(@project.namespace, @project, @commit.id), data: { confirm: 'Are you sure?' }, class: 'btn btn-grouped btn-danger', method: :post + + .oneline + = pluralize ci_commit.statuses.count(:id), "build" + - if ci_commit.ref + for + %span.label.label-info + = ci_commit.ref + - if defined?(link_to_commit) && link_to_commit + for commit + = link_to @commit.short_id, namespace_project_commit_path(@project.namespace, @project, @commit.id), class: "monospace" + - if ci_commit.duration > 0 + in + = time_interval_in_words ci_commit.duration + +- if ci_commit.yaml_errors.present? + .bs-callout.bs-callout-danger + %h4 Found errors in your .gitlab-ci.yml: + %ul + - ci_commit.yaml_errors.split(",").each do |error| + %li= error + You can also test your .gitlab-ci.yml in the #{link_to "Lint", ci_lint_path} + +- if @project.builds_enabled? && !ci_commit.ci_yaml_file + .bs-callout.bs-callout-warning + \.gitlab-ci.yml not found in this commit + +.table-holder + %table.table.builds + %thead + %tr + %th Status + %th Build ID + %th Stage + %th Name + %th Duration + %th Finished at + - if @project.build_coverage_enabled? + %th Coverage + %th + - builds = ci_commit.statuses.latest.ordered + = render builds, coverage: @project.build_coverage_enabled?, stage: true, ref: false, allow_retry: true + +- if ci_commit.retried.any? + .gray-content-block.second-block + Retried builds + + .table-holder + %table.table.builds + %thead + %tr + %th Status + %th Build ID + %th Ref + %th Stage + %th Name + %th Duration + %th Finished at + - if @project.build_coverage_enabled? + %th Coverage + %th + = render ci_commit.retried, coverage: @project.build_coverage_enabled?, stage: true, ref: false diff --git a/app/views/projects/commit/_commit_box.html.haml b/app/views/projects/commit/_commit_box.html.haml index 71995fcc487..0908e830f83 100644 --- a/app/views/projects/commit/_commit_box.html.haml +++ b/app/views/projects/commit/_commit_box.html.haml @@ -42,12 +42,12 @@ - @commit.parents.each do |parent| = link_to parent.short_id, namespace_project_commit_path(@project.namespace, @project, parent), class: "monospace" -- if @ci_commit +- if @commit.status .pull-right - = link_to ci_status_path(@ci_commit), class: "ci-status ci-#{@ci_commit.status}" do - = ci_status_icon(@ci_commit) + = link_to builds_namespace_project_commit_path(@project.namespace, @project, @commit.id), class: "ci-status ci-#{@commit.status}" do + = ci_icon_for_status(@commit.status) build: - = ci_status_label(@ci_commit) + = ci_label_for_status(@commit.status) .commit-info-row.branches %i.fa.fa-spinner.fa-spin diff --git a/app/views/projects/commit/show.html.haml b/app/views/projects/commit/show.html.haml index 21e186120c3..096f7058bd4 100644 --- a/app/views/projects/commit/show.html.haml +++ b/app/views/projects/commit/show.html.haml @@ -5,7 +5,7 @@ .prepend-top-default = render "commit_box" -- if @ci_commit +- if @commit.status = render "ci_menu" - else %div.block-connector diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml index 7f2903589a9..fa34f7b7d61 100644 --- a/app/views/projects/commits/_commit.html.haml +++ b/app/views/projects/commits/_commit.html.haml @@ -4,9 +4,8 @@ - notes = commit.notes - note_count = notes.user.count -- ci_commit = project.ci_commit(commit.sha) - cache_key = [project.path_with_namespace, commit.id, current_application_settings, note_count] -- cache_key.push(ci_commit.status) if ci_commit +- cache_key.push(commit.status) if commit.status = cache(cache_key) do %li.commit.js-toggle-container{ id: "commit-#{commit.short_id}" } @@ -17,8 +16,8 @@ %a.text-expander.js-toggle-button ... .pull-right - - if ci_commit - = render_ci_status(ci_commit) + - if commit.status + = render_ci_status(commit) = clipboard_button(clipboard_text: commit.id) = link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit_short_id" diff --git a/app/views/projects/issues/_related_branches.html.haml b/app/views/projects/issues/_related_branches.html.haml index b10cd03515f..bdfa0c7009e 100644 --- a/app/views/projects/issues/_related_branches.html.haml +++ b/app/views/projects/issues/_related_branches.html.haml @@ -5,7 +5,7 @@ - @related_branches.each do |branch| %li - sha = @project.repository.find_branch(branch).target - - ci_commit = @project.ci_commit(sha) if sha + - ci_commit = @project.ci_commit(sha, branch) if sha - if ci_commit %span.related-branch-ci-status = render_ci_status(ci_commit) diff --git a/app/views/shared/projects/_project.html.haml b/app/views/shared/projects/_project.html.haml index 53ff8959bc8..53261fcace7 100644 --- a/app/views/shared/projects/_project.html.haml +++ b/app/views/shared/projects/_project.html.haml @@ -6,9 +6,8 @@ - css_class = '' unless local_assigns[:css_class] - show_last_commit_as_description = false unless local_assigns[:show_last_commit_as_description] == true && project.commit - css_class += " no-description" if project.description.blank? && !show_last_commit_as_description -- ci_commit = project.ci_commit(project.commit.sha) if ci && !project.empty_repo? && project.commit - cache_key = [project.namespace, project, controller.controller_name, controller.action_name, current_application_settings, 'v2.3'] -- cache_key.push(ci_commit.status) if ci_commit +- cache_key.push(project.commit.status) if project.commit.status %li.project-row{ class: css_class } = cache(cache_key) do @@ -16,9 +15,9 @@ - if project.main_language %span = project.main_language - - if ci_commit + - if project.commit.status %span - = render_ci_status(ci_commit) + = render_ci_status(project.commit) - if forks %span = icon('code-fork') diff --git a/db/migrate/20160331153918_add_fields_to_ci_commit.rb b/db/migrate/20160331153918_add_fields_to_ci_commit.rb new file mode 100644 index 00000000000..03eb9ba4e53 --- /dev/null +++ b/db/migrate/20160331153918_add_fields_to_ci_commit.rb @@ -0,0 +1,7 @@ +class AddFieldsToCiCommit < ActiveRecord::Migration + def change + add_column :ci_commits, :status, :string + add_column :ci_commits, :started_at, :timestamp + add_column :ci_commits, :finished_at, :timestamp + end +end diff --git a/db/migrate/20160331204039_add_action_to_ci_commit.rb b/db/migrate/20160331204039_add_action_to_ci_commit.rb new file mode 100644 index 00000000000..e9f8eb624d6 --- /dev/null +++ b/db/migrate/20160331204039_add_action_to_ci_commit.rb @@ -0,0 +1,5 @@ +class AddActionToCiCommit < ActiveRecord::Migration + def change + add_column :ci_commits, :action, :string + end +end diff --git a/db/migrate/20160411122626_add_duration_to_ci_commit.rb b/db/migrate/20160411122626_add_duration_to_ci_commit.rb new file mode 100644 index 00000000000..7def7a48cde --- /dev/null +++ b/db/migrate/20160411122626_add_duration_to_ci_commit.rb @@ -0,0 +1,5 @@ +class AddDurationToCiCommit < ActiveRecord::Migration + def change + add_column :ci_commits, :duration, :integer + end +end diff --git a/db/schema.rb b/db/schema.rb index ec235c19131..72d63913387 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: 20160331223143) do +ActiveRecord::Schema.define(version: 20160411122626) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -141,6 +141,7 @@ ActiveRecord::Schema.define(version: 20160331223143) do t.text "artifacts_metadata" t.integer "erased_by_id" t.datetime "erased_at" + t.string "plugin" 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 @@ -168,6 +169,11 @@ ActiveRecord::Schema.define(version: 20160331223143) do t.text "yaml_errors" t.datetime "committed_at" t.integer "gl_project_id" + t.string "status" + t.datetime "started_at" + t.datetime "finished_at" + t.string "action" + t.integer "duration" end add_index "ci_commits", ["gl_project_id"], name: "index_ci_commits_on_gl_project_id", using: :btree @@ -306,11 +312,20 @@ ActiveRecord::Schema.define(version: 20160331223143) do add_index "ci_tags", ["name"], name: "index_ci_tags_on_name", unique: true, using: :btree create_table "ci_trigger_requests", force: :cascade do |t| - t.integer "trigger_id", null: false + t.integer "trigger_id" t.text "variables" t.datetime "created_at" t.datetime "updated_at" t.integer "commit_id" + t.string "sha" + t.string "before_sha" + t.string "ref" + t.string "action" + t.string "status" + t.datetime "started_at" + t.datetime "finished_at" + t.integer "project_id" + t.string "origin_ref" end create_table "ci_triggers", force: :cascade do |t| @@ -731,6 +746,7 @@ ActiveRecord::Schema.define(version: 20160331223143) do t.boolean "public_builds", default: true, null: false t.string "main_language" t.integer "pushes_since_gc", default: 0 + t.boolean "images_enabled" end add_index "projects", ["builds_enabled", "shared_runners_enabled"], name: "index_projects_on_builds_enabled_and_shared_runners_enabled", using: :btree diff --git a/lib/api/commit_statuses.rb b/lib/api/commit_statuses.rb index 8e74e177ea0..e7d76764ff5 100644 --- a/lib/api/commit_statuses.rb +++ b/lib/api/commit_statuses.rb @@ -21,7 +21,7 @@ module API authorize!(:read_commit_status, user_project) not_found!('Commit') unless user_project.commit(params[:sha]) - ci_commit = user_project.ci_commit(params[:sha]) + ci_commit = user_project.ci_commit(params[:sha], params[:ref]) return [] unless ci_commit statuses = ci_commit.statuses |