From a957eca6f364b7587175a6ffa647fc9df80abed9 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Wed, 14 Oct 2015 12:15:03 +0200 Subject: Added builds view --- CHANGELOG | 1 + app/assets/javascripts/shortcuts_navigation.coffee | 1 + app/controllers/projects/builds_controller.rb | 25 ++++++++++- app/helpers/gitlab_routing_helper.rb | 4 ++ app/helpers/projects_helper.rb | 4 ++ app/helpers/runners_helper.rb | 13 ++++++ app/models/ability.rb | 2 + app/models/ci/runner.rb | 4 +- app/views/help/_shortcuts.html.haml | 6 +++ app/views/layouts/nav/_project.html.haml | 9 +++- app/views/layouts/nav/_project_settings.html.haml | 2 +- app/views/projects/builds/_build.html.haml | 52 ++++++++++++++++++++++ app/views/projects/builds/index.html.haml | 51 +++++++++++++++++++++ config/routes.rb | 6 ++- spec/features/builds_spec.rb | 49 ++++++++++++++++++++ 15 files changed, 222 insertions(+), 7 deletions(-) create mode 100644 app/views/projects/builds/_build.html.haml create mode 100644 app/views/projects/builds/index.html.haml diff --git a/CHANGELOG b/CHANGELOG index 9e3d21f7e54..8e71c8afb2c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -17,6 +17,7 @@ v 8.1.0 (unreleased) - Fix cases where Markdown did not render links in activity feed (Stan Hu) - Add first and last to pagination (Zeger-Jan van de Weg) - Added Commit Status API + - Added Builds View - Show CI status on commit page - Show CI status on Your projects page and Starred projects page - Remove "Continuous Integration" page from dashboard diff --git a/app/assets/javascripts/shortcuts_navigation.coffee b/app/assets/javascripts/shortcuts_navigation.coffee index 5b6f9e7e3f2..8decaedd87b 100644 --- a/app/assets/javascripts/shortcuts_navigation.coffee +++ b/app/assets/javascripts/shortcuts_navigation.coffee @@ -7,6 +7,7 @@ class @ShortcutsNavigation extends Shortcuts Mousetrap.bind('g e', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-project-activity')) Mousetrap.bind('g f', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-tree')) Mousetrap.bind('g c', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-commits')) + Mousetrap.bind('g b', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-builds')) Mousetrap.bind('g n', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-network')) Mousetrap.bind('g g', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-graphs')) Mousetrap.bind('g i', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-issues')) diff --git a/app/controllers/projects/builds_controller.rb b/app/controllers/projects/builds_controller.rb index 4e4ac6689d3..0bcd9a8a360 100644 --- a/app/controllers/projects/builds_controller.rb +++ b/app/controllers/projects/builds_controller.rb @@ -1,11 +1,32 @@ class Projects::BuildsController < Projects::ApplicationController before_action :ci_project - before_action :build + before_action :build, except: [:index, :cancel_all] - before_action :authorize_admin_project!, except: [:show, :status] + before_action :authorize_admin_project!, except: [:index, :show, :status] layout "project" + def index + @scope = params[:scope] + @all_builds = project.ci_builds.order('created_at DESC').page(params[:page]).per(30) + + @builds = + case @scope + when 'pending' + @all_builds.pending + when 'running' + @all_builds.running + else + @all_builds + end + end + + def cancel_all + @project.ci_builds.running_or_pending.each(&:cancel) + + redirect_to namespace_project_builds_path(project.namespace, project) + end + def show @builds = @ci_project.commits.find_by_sha(@build.sha).builds.order('id DESC') @builds = @builds.where("id not in (?)", @build.id).page(params[:page]).per(20) diff --git a/app/helpers/gitlab_routing_helper.rb b/app/helpers/gitlab_routing_helper.rb index 4d9da6ff837..b0b536d4649 100644 --- a/app/helpers/gitlab_routing_helper.rb +++ b/app/helpers/gitlab_routing_helper.rb @@ -25,6 +25,10 @@ module GitlabRoutingHelper namespace_project_commits_path(project.namespace, project, @ref || project.repository.root_ref) end + def project_builds_path(project, *args) + namespace_project_builds_path(project.namespace, project, *args) + end + def activity_project_path(project, *args) activity_namespace_project_path(project.namespace, project, *args) end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index a0220af4c30..b7965aee875 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -113,6 +113,10 @@ module ProjectsHelper nav_tabs << :merge_requests end + if can?(current_user, :read_build, project) + nav_tabs << :builds + end + if can?(current_user, :admin_project, project) nav_tabs << :settings end diff --git a/app/helpers/runners_helper.rb b/app/helpers/runners_helper.rb index 5d7d06c8490..c13db93ae9c 100644 --- a/app/helpers/runners_helper.rb +++ b/app/helpers/runners_helper.rb @@ -17,4 +17,17 @@ module RunnersHelper class: "fa fa-circle runner-status-#{status}", title: "Runner is #{status}, last contact was #{time_ago_in_words(runner.contacted_at)} ago" end + + def runner_link(runner) + display_name = truncate(runner.display_name, length: 20) + id = "\##{runner.id}" + + if current_user && current_user.admin + link_to ci_admin_runner_path(runner) do + display_name + id + end + else + display_name + id + end + end end diff --git a/app/models/ability.rb b/app/models/ability.rb index 77c121ca5e8..38bc2086683 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -41,6 +41,7 @@ class Ability :read_project_member, :read_merge_request, :read_note, + :read_build, :download_code ] @@ -127,6 +128,7 @@ class Ability :read_project_member, :read_merge_request, :read_note, + :read_build, :create_project, :create_issue, :create_note diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb index 6838ccfaaab..bc5cd137e91 100644 --- a/app/models/ci/runner.rb +++ b/app/models/ci/runner.rb @@ -56,7 +56,7 @@ module Ci end def display_name - return token unless !description.blank? + return short_sha unless !description.blank? description end @@ -78,7 +78,7 @@ module Ci end def short_sha - token[0...10] + token[0...8] end end end diff --git a/app/views/help/_shortcuts.html.haml b/app/views/help/_shortcuts.html.haml index e809d99ba71..67349fcbd78 100644 --- a/app/views/help/_shortcuts.html.haml +++ b/app/views/help/_shortcuts.html.haml @@ -99,6 +99,12 @@ .key c %td Go to commits + %tr + %td.shortcut + .key g + .key b + %td + Go to builds %tr %td.shortcut .key g diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml index e4c285d8023..f52d0ad9c02 100644 --- a/app/views/layouts/nav/_project.html.haml +++ b/app/views/layouts/nav/_project.html.haml @@ -32,12 +32,19 @@ Files - if project_nav_tab? :commits - = nav_link(controller: %w(commit commits compare repositories tags branches builds)) do + = nav_link(controller: %w(commit commits compare repositories tags branches)) do = link_to project_commits_path(@project), title: 'Commits', class: 'shortcuts-commits', data: {placement: 'right'} do = icon('history fw') %span Commits + - if project_nav_tab? :builds + = nav_link(controller: %w(builds)) do + = link_to project_builds_path(@project), title: 'Builds', class: 'shortcuts-builds', data: {placement: 'right'} do + = icon('link fw') + %span + Builds + - if project_nav_tab? :network = nav_link(controller: %w(network)) do = link_to namespace_project_network_path(@project.namespace, @project, current_ref), title: 'Network', class: 'shortcuts-network', data: {placement: 'right'} do diff --git a/app/views/layouts/nav/_project_settings.html.haml b/app/views/layouts/nav/_project_settings.html.haml index 954dbe5d2b9..b12dcd84116 100644 --- a/app/views/layouts/nav/_project_settings.html.haml +++ b/app/views/layouts/nav/_project_settings.html.haml @@ -66,7 +66,7 @@ %span CI Services = nav_link path: 'events#index' do - = link_to ci_project_events_path(@project.gitlab_ci_project) do + = link_to ci_project_events_path(@project.ensure_gitlab_ci_project) do = icon('book fw') %span CI Events diff --git a/app/views/projects/builds/_build.html.haml b/app/views/projects/builds/_build.html.haml new file mode 100644 index 00000000000..10b3ef71202 --- /dev/null +++ b/app/views/projects/builds/_build.html.haml @@ -0,0 +1,52 @@ +%tr.build + %td.status + = ci_status_with_icon(build.status) + + %td.commit_status-link + - if build.target_url + = link_to build.target_url do + %strong Build ##{build.id} + - else + %strong Build ##{build.id} + + %td + = link_to namespace_project_commit_path(@project.namespace, @project, build.sha) do + = build.short_sha + + %td + = link_to namespace_project_commits_path(@project.namespace, @project, build.ref) do + = build.ref + + %td + - if build.runner + = runner_link(build.runner) + - else + .light none + + %td + = build.name + + .pull-right + - if build.tags.any? + - build.tags.each do |tag| + %span.label.label-primary + = tag + - if build.try(:trigger_request) + %span.label.label-info triggered + - if build.try(:allow_failure) + %span.label.label-danger allowed to fail + + %td.duration + - if build.duration + #{duration_in_words(build.finished_at, build.started_at)} + + %td.timestamp + - if build.finished_at + %span #{time_ago_in_words build.finished_at} ago + + %td + .pull-right + - if current_user && can?(current_user, :manage_builds, @project) + - if build.cancel_url + = link_to build.cancel_url, title: 'Cancel' do + %i.fa.fa-remove.cred diff --git a/app/views/projects/builds/index.html.haml b/app/views/projects/builds/index.html.haml new file mode 100644 index 00000000000..2c6cf69c23e --- /dev/null +++ b/app/views/projects/builds/index.html.haml @@ -0,0 +1,51 @@ +- page_title "Builds" +- header_title project_title(@project, "Builds", project_builds_path(@project)) + +%ul.center-top-menu + %li{class: ('active' if @scope.nil?)} + = link_to project_builds_path(@project) do + All builds + %span.badge.js-totalbuilds-count= @all_builds.size + + %li{class: ('active' if @scope == 'pending')} + = link_to project_builds_path(@project, scope: :pending) do + Pending + %span.badge.js-pending-count= @all_builds.pending.size + + %li{class: ('active' if @scope == 'running')} + = link_to project_builds_path(@project, scope: :running) do + Running + %span.badge.js-running-count= @all_builds.running.size + +.gray-content-block + .oneline + List of all builds from this project + + - if @ci_project && current_user && can?(current_user, :manage_builds, @project) + .pull-right + - if @all_builds.running_or_pending.any? + = link_to 'Cancel all', cancel_all_namespace_project_builds_path(@project.namespace, @project), data: { confirm: 'Are you sure?' }, method: :post, class: 'btn btn-danger' + +%ul.content-list + - if @builds.blank? + %li + .nothing-here-block No builds to show + - else + %table.table.builds + %thead + %tr + %th Status + %th Build ID + %th Commit + %th Ref + %th Runner + %th Name + %th Duration + %th Finished at + %th + + - @builds.each do |build| + = render 'projects/builds/build', build: build + + = paginate @builds + diff --git a/config/routes.rb b/config/routes.rb index 8e6fbf6340c..3253d950f27 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -585,7 +585,11 @@ Gitlab::Application.routes.draw do end end - resources :builds, only: [:show] do + resources :builds, only: [:index, :show] do + collection do + post :cancel_all + end + member do get :cancel get :status diff --git a/spec/features/builds_spec.rb b/spec/features/builds_spec.rb index 924047a0d8f..31f8aa83981 100644 --- a/spec/features/builds_spec.rb +++ b/spec/features/builds_spec.rb @@ -9,6 +9,55 @@ describe "Builds" do @gl_project.team << [@user, :master] end + describe "GET /:project/builds" do + context "All builds" do + before do + @build.success + visit namespace_project_builds_path(@gl_project.namespace, @gl_project) + end + + it { expect(page).to have_content 'All builds' } + it { expect(page).to have_content @build.short_sha } + it { expect(page).to have_content @build.ref } + it { expect(page).to have_content @build.name } + it { expect(page).to_not have_content 'Cancel all' } + end + + context "Pending scope" do + before do + @build.success + visit namespace_project_builds_path(@gl_project.namespace, @gl_project, scope: :pending) + end + + it { expect(page).to have_content 'No builds to show' } + it { expect(page).to_not have_content 'Cancel all' } + end + + context "Running scope" do + before do + @build.run! + visit namespace_project_builds_path(@gl_project.namespace, @gl_project, scope: :running) + end + + it { expect(page).to have_content 'Running' } + it { expect(page).to have_content 'Cancel all' } + it { expect(page).to have_content @build.short_sha } + it { expect(page).to have_content @build.ref } + it { expect(page).to have_content @build.name } + end + end + + describe "POST /:project/builds/:id/cancel_all" do + before do + @build.run! + visit cancel_namespace_project_build_path(@gl_project.namespace, @gl_project, @build) + end + + it { expect(page).to have_content 'All builds' } + it { expect(page).to have_content 'canceled' } + it { expect(page).to_not have_content 'Cancel all' } + end + describe "GET /:project/builds/:id" do before do visit namespace_project_build_path(@gl_project.namespace, @gl_project, @build) -- cgit v1.2.1