diff options
Diffstat (limited to 'app')
-rw-r--r-- | app/controllers/projects/builds_controller.rb | 28 | ||||
-rw-r--r-- | app/controllers/projects/ci_commits_controller.rb | 63 | ||||
-rw-r--r-- | app/controllers/projects/commit_controller.rb | 5 | ||||
-rw-r--r-- | app/models/ability.rb | 7 | ||||
-rw-r--r-- | app/models/ci/build.rb | 4 | ||||
-rw-r--r-- | app/models/ci/commit.rb | 12 | ||||
-rw-r--r-- | app/models/commit_status.rb | 2 | ||||
-rw-r--r-- | app/models/concerns/ci_status.rb | 11 | ||||
-rw-r--r-- | app/views/layouts/nav/_project.html.haml | 9 | ||||
-rw-r--r-- | app/views/projects/ci/commits/_commit.html.haml | 148 | ||||
-rw-r--r-- | app/views/projects/ci_commits/_header_title.html.haml | 2 | ||||
-rw-r--r-- | app/views/projects/ci_commits/index.html.haml | 36 | ||||
-rw-r--r-- | app/views/projects/ci_commits/new.html.haml | 25 | ||||
-rw-r--r-- | app/views/projects/ci_commits/show.html.haml | 216 |
14 files changed, 216 insertions, 352 deletions
diff --git a/app/controllers/projects/builds_controller.rb b/app/controllers/projects/builds_controller.rb index f159e169f6d..269c0d3c21f 100644 --- a/app/controllers/projects/builds_controller.rb +++ b/app/controllers/projects/builds_controller.rb @@ -20,6 +20,30 @@ class Projects::BuildsController < Projects::ApplicationController @builds = @builds.page(params[:page]).per(30) end + def commits + @scope = params[:scope] + @all_commits = project.ci_commits + @commits = @all_commits.order(id: :desc) + @commits = + case @scope + when 'latest' + @commits + when 'branches' + refs = project.repository.branches.map(&:name) + ids = @all_commits.where(ref: refs).group(:ref).select('max(id)') + @commits.where(id: ids) + when 'tags' + refs = project.repository.tags.map(&:name) + ids = @all_commits.where(ref: refs).group(:ref).select('max(id)') + @commits.where(id: ids) + else + @commits + end + @commits = @commits.page(params[:page]).per(30) + end + + private + def cancel_all @project.builds.running_or_pending.each(&:cancel) redirect_to namespace_project_builds_path(project.namespace, project) @@ -68,6 +92,10 @@ class Projects::BuildsController < Projects::ApplicationController @build ||= project.builds.unscoped.find_by!(id: params[:id]) end + def ci_commit + @ci_commit ||= project.ci_commits.find_by!(id: params[:id]) + end + def build_path(build) namespace_project_build_path(build.project.namespace, build.project, build) end diff --git a/app/controllers/projects/ci_commits_controller.rb b/app/controllers/projects/ci_commits_controller.rb index e4797833b06..a36e3085e8a 100644 --- a/app/controllers/projects/ci_commits_controller.rb +++ b/app/controllers/projects/ci_commits_controller.rb @@ -1,6 +1,8 @@ class Projects::CiCommitsController < Projects::ApplicationController - before_action :ci_commit, except: [:index] - before_action :authorize_read_build! + before_action :ci_commit, except: [:index, :new, :create] + before_action :authorize_read_pipeline! + before_action :authorize_create_pipeline!, only: [:new, :create] + before_action :authorize_update_pipeline!, only: [:retry, :cancel] layout 'project' def index @@ -11,6 +13,8 @@ class Projects::CiCommitsController < Projects::ApplicationController case @scope when 'latest' @commits + when 'running' + @commits.running_or_pending when 'branches' refs = project.repository.branches.map(&:name) ids = @all_commits.where(ref: refs).group(:ref).select('max(id)') @@ -25,6 +29,47 @@ class Projects::CiCommitsController < Projects::ApplicationController @commits = @commits.page(params[:page]).per(30) end + def new + end + + def create + ref_names = project.repository.ref_names + unless ref_names.include?(params[:ref]) + @error = 'Reference not found' + render action: 'new' + return + end + + commit = project.commit(params[:ref]) + unless commit + @error = 'Commit not found' + render action: 'new' + return + end + + ci_commit = project.ci_commit(commit.id, params[:ref]) + if ci_commit + @error = 'Pipeline already created' + render action: 'new' + return + end + + # Skip creating ci_commit when no gitlab-ci.yml is found + commit = project.ci_commits.new(sha: commit.id, ref: params[:ref], before_sha: Gitlab::Git::BLANK_SHA) + unless commit.config_processor + @error = commit.yaml_errors || 'Missing .gitlab-ci.yml file' + render action: 'new' + return + end + + Ci::Commit.transaction do + commit.save! + commit.create_builds(params[:ref], false, current_user) + end + + redirect_to builds_namespace_project_commit_path(project.namespace, project, commit.id) + end + def show @commit = @ci_commit.commit @builds = @ci_commit.builds @@ -35,6 +80,20 @@ class Projects::CiCommitsController < Projects::ApplicationController end end + def retry + ci_commit.builds.latest.failed.select(&:retryable?).each(&:retry) + + redirect_back_or_default default: namespace_project_ci_commits_path(project.namespace, project) + end + + def cancel + ci_commit.builds.running_or_pending.each(&:cancel) + + redirect_back_or_default default: namespace_project_ci_commits_path(project.namespace, project) + end + + def retry_builds + end private def ci_commit diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb index ef20281e82f..623856f282f 100644 --- a/app/controllers/projects/commit_controller.rb +++ b/app/controllers/projects/commit_controller.rb @@ -96,6 +96,11 @@ class Projects::CommitController < Projects::ApplicationController def ci_commits @ci_commits ||= project.ci_commits.where(sha: commit.sha) + if params[:commit_id] + @ci_commits.where(id: params[:commit_id].to_i) + else + @ci_commits + end end def define_show_vars diff --git a/app/models/ability.rb b/app/models/ability.rb index c0bf6def7c5..ec5ac54c277 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -195,6 +195,7 @@ class Ability :admin_label, :read_commit_status, :read_build, + :read_pipeline, ] end @@ -206,6 +207,8 @@ class Ability :update_commit_status, :create_build, :update_build, + :create_pipeline, + :update_pipeline, :create_merge_request, :create_wiki, :push_code @@ -234,7 +237,8 @@ class Ability :admin_wiki, :admin_project, :admin_commit_status, - :admin_build + :admin_build, + :admin_pipeline ] end @@ -277,6 +281,7 @@ class Ability unless project.builds_enabled rules += named_abilities('build') + rules += named_abilities('pipeline') end rules diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index c99aeff6f1c..d497cf67cbc 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -129,6 +129,10 @@ module Ci !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.latest diff --git a/app/models/ci/commit.rb b/app/models/ci/commit.rb index cd9ce0a283d..45309614115 100644 --- a/app/models/ci/commit.rb +++ b/app/models/ci/commit.rb @@ -67,6 +67,12 @@ module Ci .pluck(:stage, :stage_idx).map(&:first) end + def stages + statuses + .group(:stage, :stage_idx).order(:stage_idx) + .pluck(:stage, :stage_idx).map(&:first) + end + def to_param sha end @@ -115,6 +121,12 @@ module Ci Gitlab::Git::branch_ref?(origin_ref) end + def retryable? + builds.latest.any? do |build| + build.failed? || build.retryable? + end + end + def create_builds(ref, tag, user, trigger_request = nil) return unless config_processor config_processor.stages.any? do |stage| diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb index 3a059f01d49..88cb7e21d66 100644 --- a/app/models/commit_status.rb +++ b/app/models/commit_status.rb @@ -53,7 +53,7 @@ class CommitStatus < ActiveRecord::Base 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) } diff --git a/app/models/concerns/ci_status.rb b/app/models/concerns/ci_status.rb index 494db025048..f7a9af1507d 100644 --- a/app/models/concerns/ci_status.rb +++ b/app/models/concerns/ci_status.rb @@ -3,15 +3,16 @@ module CiStatus module ClassMethods def status - if all.none? + objs = all.to_a + if objs.none? nil - elsif all.all? { |status| status.success? || status.ignored? } + elsif objs.all? { |status| status.success? || status.ignored? } 'success' - elsif all.all?(&:pending?) + elsif objs.all?(&:pending?) 'pending' - elsif all.any?(&:running?) || all.any?(&:pending?) + elsif objs.any?(&:running?) || all.any?(&:pending?) 'running' - elsif all.all?(&:canceled?) + elsif objs.all?(&:canceled?) 'canceled' else 'failed' diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml index 862a3e087f1..6fb2add7458 100644 --- a/app/views/layouts/nav/_project.html.haml +++ b/app/views/layouts/nav/_project.html.haml @@ -25,19 +25,18 @@ - if project_nav_tab? :builds = nav_link(controller: %w(ci_commits)) do - = link_to project_ci_commits_path(@project), title: 'CI', class: 'shortcuts-ci' do - = icon('cubes fw') + = link_to project_ci_commits_path(@project), title: 'Pipelines', class: 'shortcuts-builds' do + = icon('ship fw') %span - CI + Pipelines %span.count.ci_counter= number_with_delimiter(@project.ci_commits.running_or_pending.count(:all)) - - if project_nav_tab? :builds = nav_link(controller: %w(builds)) do = link_to project_builds_path(@project), title: 'Builds', class: 'shortcuts-builds' do = icon('cubes fw') %span Builds - %span.count.builds_counter= number_with_delimiter(@project.builds.running_or_pending.count(:all)) + %span.count.ci_counter= number_with_delimiter(@project.builds.running_or_pending.count(:all)) - if project_nav_tab? :graphs = nav_link(controller: %w(graphs)) do diff --git a/app/views/projects/ci/commits/_commit.html.haml b/app/views/projects/ci/commits/_commit.html.haml index 671c5abcbed..8219e7bf701 100644 --- a/app/views/projects/ci/commits/_commit.html.haml +++ b/app/views/projects/ci/commits/_commit.html.haml @@ -1,22 +1,14 @@ +- status = commit.status %tr.commit %td.commit-link - - if can?(current_user, :read_commit, commit) - = link_to namespace_project_commit_url(commit.project.namespace, commit.project, commit) do - %strong ##{commit.id} - - else + = link_to namespace_project_commit_url(@project.namespace, @project, commit), class: "ci-status ci-#{status}" do + = ci_icon_for_status(status) %strong ##{commit.id} - %td.status - %div - - if can?(current_user, :read_commit, commit) - = ci_status_with_icon(commit.status, namespace_project_commit_url(commit.project.namespace, commit.project, commit)) - - else - = ci_status_with_icon(commit.status) - %td %div - if commit.ref - = link_to commit.ref, namespace_project_commits_path(commit.project.namespace, commit.project, commit.ref) + = link_to commit.ref, namespace_project_commits_path(@project.namespace, @project, commit.ref) - if commit.tag? %span.label.label-primary tag @@ -35,107 +27,43 @@ %p Cant find HEAD commit for this branch + - stages.each do |stage| + %td + - status = commit.statuses.latest.where(stage: stage).status + - if status + = ci_status_with_icon(status) + - else + = ci_status_with_icon('missing') + %td - %div - Duration: - - - if commit.started_at && commit.finished_at + - if commit.started_at && commit.finished_at + %p #{duration_in_words(commit.finished_at, commit.started_at)} - - else - \- + - if commit.finished_at %p - Finished: - - - if commit.finished_at - #{time_ago_with_tooltip(commit.finished_at)} - - else - \- + #{time_ago_with_tooltip(commit.finished_at)} %td.content - .controls.hidden-xs - = link_to project_builds_path(commit.project), class: 'btn btn-grouped btn-xs' do - = icon('cubes fw') - Details + .controls.hidden-xs.pull-right + - artifacts = commit.builds.latest.select { |status| status.artifacts? } + - if artifacts.present? + .dropdown.inline + %button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'} + = icon('download') + %b.caret + %ul.dropdown-menu.dropdown-menu-align-right + - artifacts.each do |build| + %li + = link_to download_namespace_project_build_artifacts_path(@project.namespace, @project, build), rel: 'nofollow' do + %i.fa.fa-download + %span #{build.name} + - - @project = commit.project - - ref = 'master' - %span.btn-group.btn-grouped - %a.btn.btn-default.dropdown-toggle{ 'data-toggle' => 'dropdown' } - %span.caret - %span.sr-only - Select Archive Format - %ul.col-xs-10.dropdown-menu.dropdown-menu-align-right{ role: 'menu' } - %li - = link_to archive_namespace_project_repository_path(@project.namespace, @project, ref: ref, format: 'zip'), rel: 'nofollow' do - %i.fa.fa-download - %span Download zip - %li - = link_to archive_namespace_project_repository_path(@project.namespace, @project, ref: ref, format: 'tar.gz'), rel: 'nofollow' do - %i.fa.fa-download - %span Download tar.gz - %li - = link_to archive_namespace_project_repository_path(@project.namespace, @project, ref: ref, format: 'tar.bz2'), rel: 'nofollow' do - %i.fa.fa-download - %span Download tar.bz2 - %li - = link_to archive_namespace_project_repository_path(@project.namespace, @project, ref: ref, format: 'tar'), rel: 'nofollow' do - %i.fa.fa-download - %span Download tar --#%tr.commit --# %td.status --# - if can?(current_user, :read_commit, commit) --# = ci_status_with_icon(commit.status, namespace_project_commit_url(commit.project.namespace, commit.project, commit)) --# - else --# = ci_status_with_icon(commit.status) --# --# %td.commit-link --# - if can?(current_user, :read_commit, commit) --# = link_to namespace_project_commit_url(commit.project.namespace, commit.project, commit) do --# %strong ##{commit.id} --# - else --# %strong ##{commit.id} --# --# - if defined?(commit_sha) && commit_sha --# %td --# = link_to commit.short_sha, namespace_project_commit_path(commit.project.namespace, commit.project, commit.sha), class: "monospace" --# --# %td --# - if commit.ref --# = link_to commit.ref, namespace_project_commits_path(commit.project.namespace, commit.project, commit.ref) --# - else --# .light none --# --# %td --# = commit.git_commit_message --# --# %td.duration --# - if commit.started_at && commit.finished_at --# #{duration_in_words(commit.finished_at, commit.started_at)} --# --# %td.timestamp --# - if commit.finished_at --# %span #{time_ago_with_tooltip(commit.finished_at)} --# --# - if defined?(coverage) && coverage --# %td.coverage --# - if commit.try(:coverage) --# #{commit.coverage}% --# --# %td --# .pull-right --# - if can?(current_user, :read_commit, commit) && commit.artifacts? --# = link_to download_namespace_project_commit_artifacts_path(commit.project.namespace, commit.project, commit), title: 'Download artifacts' do --# %i.fa.fa-download --# - if can?(current_user, :update_commit, commit) --# - if commit.active? --# = link_to cancel_namespace_project_commit_path(commit.project.namespace, commit.project, commit, return_to: request.original_url), method: :post, title: 'Cancel' do --# %i.fa.fa-remove.cred --# - elsif defined?(allow_retry) && allow_retry && commit.retryable? --# = link_to retry_namespace_project_commit_path(commit.project.namespace, commit.project, commit, return_to: request.original_url), method: :post, title: 'Retry' do --# %i.fa.fa-repeat --# --#- if commit.yaml_errors.present? --# %tr --# %td{colspan: 7} --# .light --# = commit.yaml_errors
\ No newline at end of file + - if can?(current_user, :update_pipeline, @project) + - if commit.retryable? + = link_to retry_namespace_project_ci_commit_path(@project.namespace, @project, commit.id), class: 'btn has-tooltip', title: "Retry", method: :post do + = icon("repeat") + + - if commit.active? + = link_to cancel_namespace_project_ci_commit_path(@project.namespace, @project, commit.id), class: 'btn btn-remove has-tooltip', title: "Cancel", method: :post do + = icon("remove cred") diff --git a/app/views/projects/ci_commits/_header_title.html.haml b/app/views/projects/ci_commits/_header_title.html.haml index c04fc6be9f1..27c125ca40f 100644 --- a/app/views/projects/ci_commits/_header_title.html.haml +++ b/app/views/projects/ci_commits/_header_title.html.haml @@ -1 +1 @@ -- header_title project_title(@project, "CI", project_ci_commits_path(@project)) +- header_title project_title(@project, "Pipelines", project_ci_commits_path(@project)) diff --git a/app/views/projects/ci_commits/index.html.haml b/app/views/projects/ci_commits/index.html.haml index 7955e5e9abf..0347c220382 100644 --- a/app/views/projects/ci_commits/index.html.haml +++ b/app/views/projects/ci_commits/index.html.haml @@ -1,11 +1,11 @@ -- page_title "CI Changes" +- page_title "Pipelines" = render "header_title" .top-area %ul.nav-links - %li{class: ('active' if @scope.nil? || @scope == 'latest')} - = link_to project_ci_commits_path(@project, scope: :latest) do - Latest + %li{class: ('active' if @scope.nil?)} + = link_to project_ci_commits_path(@project) do + All %span.badge.js-totalbuilds-count = number_with_delimiter(@all_commits.count(:id)) @@ -21,31 +21,45 @@ %span.badge.js-running-count = number_with_delimiter(@all_commits.running_or_pending.count(:id)) - %li{class: ('active' if @scope == 'failed')} - = link_to project_ci_commits_path(@project, scope: :failed) do + %li{class: ('active' if @scope == 'running')} + = link_to project_ci_commits_path(@project, scope: :running) do Failed %span.badge.js-running-count - = number_with_delimiter(@all_commits.finished.count(:id)) + = number_with_delimiter(@all_commits.running_or_pending.count(:id)) .nav-controls + - if can? current_user, :create_pipeline, @project + = link_to new_namespace_project_ci_commit_path(@project.namespace, @project), class: 'btn btn-create' do + = icon('plus') + New + - if can?(current_user, :update_build, @project) - unless @repository.gitlab_ci_yml - = link_to 'Get started with Builds', help_page_path('ci/quick_start', 'README'), class: 'btn btn-info' + = link_to 'Get started with Pipelines', help_page_path('ci/quick_start', 'README'), class: 'btn btn-info' = link_to ci_lint_path, class: 'btn btn-default' do = icon('wrench') %span CI Lint .gray-content-block - #{(@scope || 'running').capitalize} changes on this project + Pipelines for #{(@scope || 'changes')} on this project %ul.content-list + - stages = @commits.stages - if @commits.blank? %li - .nothing-here-block No commits to show + .nothing-here-block No pipelines to show - else .table-holder %table.table.builds - = render @commits, commit_sha: true, stage: true, allow_retry: true + %tbody + %th Pipeline ID + %th Commit + - @commits.stages.each do |stage| + %th + = stage.titleize + %th + %th + = render @commits.includes(:statuses).includes(:builds), commit_sha: true, stage: true, allow_retry: true, stages: stages = paginate @commits, theme: 'gitlab' 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..e9a22bbb157 --- /dev/null +++ b/app/views/projects/ci_commits/new.html.haml @@ -0,0 +1,25 @@ +- page_title "New Pipeline" += render "header_title" + +- if @error + .alert.alert-danger + %button{ type: "button", class: "close", "data-dismiss" => "alert"} × + = @error +%h3.page-title + New Pipeline +%hr + += form_tag namespace_project_ci_commits_path, method: :post, id: "new-pipeline-form", class: "form-horizontal js-create-branch-form js-requires-input" do + .form-group + = label_tag :ref, 'Create for', class: 'control-label' + .col-sm-10 + = text_field_tag :ref, params[:ref] || @project.default_branch, required: true, tabindex: 2, class: 'form-control' + .help-block Existing branch name, tag + .form-actions + = button_tag 'Create pipeline', class: 'btn btn-create', tabindex: 3 + = link_to 'Cancel', namespace_project_ci_commits_path(@project.namespace, @project), class: 'btn btn-cancel' + +:javascript + var availableRefs = #{@project.repository.ref_names.to_json}; + + new NewBranchForm($('.js-create-branch-form'), availableRefs) diff --git a/app/views/projects/ci_commits/show.html.haml b/app/views/projects/ci_commits/show.html.haml deleted file mode 100644 index b02aee3db21..00000000000 --- a/app/views/projects/ci_commits/show.html.haml +++ /dev/null @@ -1,216 +0,0 @@ -- page_title "#{@build.name} (##{@build.id})", "Builds" -= render "header_title" - -.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) - from - = link_to @build.ref, namespace_project_commits_path(@project.namespace, @project, @build.ref) - - merge_request = @build.merge_request - - if merge_request - via - = link_to "merge request ##{merge_request.iid}", merge_request_path(merge_request) - - #up-build-trace - - builds = @build.commit.matrix_builds(@build) - - if builds.size > 1 - %ul.nav-links.no-top.no-bottom - - builds.each do |build| - %li{class: ('active' if build == @build) } - = link_to namespace_project_build_path(@project.namespace, @project, build) do - = ci_icon_for_status(build.status) - %span - - if build.name - = build.name - - else - = build.id - - - if @build.retried? - %li.active - %a - Build ##{@build.id} - · - %i.fa.fa-warning - This build was retried. - - .gray-content-block.middle-block - .build-head - .clearfix - = ci_status_with_icon(@build.status) - - if @build.duration - %span - %i.fa.fa-time - #{duration_in_words(@build.finished_at, @build.started_at)} - .pull-right - #{time_ago_with_tooltip(@build.finished_at) if @build.finished_at} - - - if @build.stuck? - - unless @build.any_runners_online? - .bs-callout.bs-callout-warning - %p - - if no_runners_for_project?(@build.project) - This build is stuck, because the project doesn't have any runners online assigned to it. - - elsif @build.tags.any? - This build is stuck, because you don't have any active runners online with any of these tags assigned to them: - - @build.tags.each do |tag| - %span.label.label-primary - = tag - - else - This build is stuck, because you don't have any active runners that can run this build. - - %br - Go to - = link_to namespace_project_runners_path(@build.project.namespace, @build.project) do - Runners page - - .row.prepend-top-default - .col-md-9 - .clearfix - - if @build.active? - .autoscroll-container - %button.btn.btn-success.btn-sm#autoscroll-button{:type => "button", :data => {:state => 'disabled'}} enable autoscroll - .clearfix - #js-build-scroll.scroll-controls - = link_to '#up-build-trace', class: 'btn' do - %i.fa.fa-angle-up - = link_to '#down-build-trace', class: 'btn' do - %i.fa.fa-angle-down - - - if @build.erased? - .erased.alert.alert-warning - - erased_by = "by #{link_to @build.erased_by.name, user_path(@build.erased_by)}" if @build.erased_by - Build has been erased #{erased_by.html_safe} #{time_ago_with_tooltip(@build.erased_at)} - - else - %pre.trace#build-trace - %code.bash - = preserve do - = raw @build.trace_html - - %div#down-build-trace - - .col-md-3 - - if @build.coverage - .build-widget - %h4.title - Test coverage - %h1 #{@build.coverage}% - - - if can?(current_user, :read_build, @project) && @build.artifacts? - .build-widget.artifacts - %h4.title Build artifacts - .center - .btn-group{ role: :group } - = link_to download_namespace_project_build_artifacts_path(@project.namespace, @project, @build), class: 'btn btn-sm btn-primary' do - = icon('download') - Download - - - if @build.artifacts_metadata? - = link_to browse_namespace_project_build_artifacts_path(@project.namespace, @project, @build), class: 'btn btn-sm btn-primary' do - = icon('folder-open') - Browse - - .build-widget - %h4.title - Build ##{@build.id} - - if can?(current_user, :update_build, @project) - .center - .btn-group{ role: :group } - - if @build.active? - = link_to "Cancel", cancel_namespace_project_build_path(@project.namespace, @project, @build), class: 'btn btn-sm btn-danger', method: :post - - elsif @build.retryable? - = link_to "Retry", retry_namespace_project_build_path(@project.namespace, @project, @build), class: 'btn btn-sm btn-primary', method: :post - - - if @build.erasable? - = link_to erase_namespace_project_build_path(@project.namespace, @project, @build), - class: 'btn btn-sm btn-warning', method: :post, - data: { confirm: 'Are you sure you want to erase this build?' } do - = icon('eraser') - Erase - - .clearfix - - if @build.duration - %p - %span.attr-name Duration: - #{duration_in_words(@build.finished_at, @build.started_at)} - %p - %span.attr-name Created: - #{time_ago_with_tooltip(@build.created_at)} - - if @build.finished_at - %p - %span.attr-name Finished: - #{time_ago_with_tooltip(@build.finished_at)} - - if @build.erased_at - %p - %span.attr-name Erased: - #{time_ago_with_tooltip(@build.erased_at)} - %p - %span.attr-name Runner: - - if @build.runner && current_user && current_user.admin - = link_to "##{@build.runner.id}", admin_runner_path(@build.runner.id) - - elsif @build.runner - \##{@build.runner.id} - - - if @build.trigger_request - .build-widget - %h4.title - Trigger - - %p - %span.attr-name Token: - #{@build.trigger_request.trigger.short_token} - - - if @build.trigger_request.variables - %p - %span.attr-name Variables: - - %code - - @build.trigger_request.variables.each do |key, value| - #{key}=#{value} - - .build-widget - %h4.title - Commit - .pull-right - %small - = link_to @build.commit.short_sha, ci_status_path(@build.commit), class: "monospace" - %p - %span.attr-name Branch: - = link_to @build.ref, namespace_project_commits_path(@project.namespace, @project, @build.ref) - %p - %span.attr-name Author: - #{@build.commit.git_author_name} - %p - %span.attr-name Message: - #{@build.commit.git_commit_message} - - - if @build.tags.any? - .build-widget - %h4.title - Tags - - @build.tag_list.each do |tag| - %span.label.label-primary - = tag - - - if @builds.present? - .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" - %table.table.builds - - @builds.each_with_index do |build, i| - %tr.build - %td - = ci_icon_for_status(build.status) - %td - = link_to namespace_project_build_path(@project.namespace, @project, build) do - - if build.name - = build.name - - else - %span ##{build.id} - - %td.status= build.status - - - :javascript - new CiBuild("#{namespace_project_build_url(@project.namespace, @project, @build)}", "#{@build.status}") |