diff --git a/CHANGELOG b/CHANGELOG
index 9e3d21f7e540fa36103ab452a5915ca34f4671dc..8e71c8afb2cb35971fd529bd2c5c2dfcc4be41cc 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 5b6f9e7e3f25e3f75bdba43a28725cf8303ec722..8decaedd87bac29dc05d547dfbfb6ee48d2e341f 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 4e4ac6689d327dafc4b7586651a5456919b9c67d..0bcd9a8a360ca7ebeecce81f7fb7923f4bfd4cd8 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 4d9da6ff837bb2ef86b77b926d8886b67e23967f..b0b536d4649aef959d25a6e9e8e5d330eb18e110 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 a0220af4c30c75cab155583eac8ee7fe8c983b26..b7965aee8750f40bcc964fc3ba8e2dd53cd6e779 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 5d7d06c84903db173ea00ad3945f1f4a758d5b54..c13db93ae9c3c0941db8a0db569f7386c5157349 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 77c121ca5e851bd40b7f10956ad0dda5fa06b80d..38bc208668398a7ddca950f5b346a094bf89964f 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 6838ccfaaab4330e58dced4b462bc249b705f6c4..bc5cd137e91b92377cd8865c68468a76f6c2f5e5 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 e809d99ba71ffb20a69dbe30e9e97f05dc508760..67349fcbd787bf437315ba88e83cb55138c06d47 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 e4c285d802380d51b46445843c91a8843ed58e91..f52d0ad9c024462ae2b00debb23e221d5e8d992d 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 954dbe5d2b9079c39f6fd76c1ee8bf8545e9c6b0..b12dcd841164949cd8e5ee78c301c30e794dbb56 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 0000000000000000000000000000000000000000..10b3ef71202b6aff6c079ac3500eec569cdbcac2
--- /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 0000000000000000000000000000000000000000..2c6cf69c23e98ece6b389295589640c0ca1fb26a
--- /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 8e6fbf6340c0cf39e351de8eaeb4d9e2f7a44cf4..3253d950f277f9139c2d1b4cba088e88b9d10b9c 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 924047a0d8fafd2d49d0a73f7bf6c1af973bfbd6..31f8aa83981c18fd60526deda7b882972d3290fe 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)