diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 1dc49ca336d56fedc87927a5334753b72e2ceb2e..85730e1b6870a7b00a19eba678570f32853723a9 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -115,6 +115,11 @@ bundler:audit:
   script:
     - "bundle exec bundle-audit check --update --ignore OSVDB-115941"
 
+db-migrate-reset:
+  stage: test
+  script:
+    - RAILS_ENV=test bundle exec rake db:migrate:reset
+
 # Ruby 2.2 jobs
 
 spec:feature:ruby22:
diff --git a/.scss-lint.yml b/.scss-lint.yml
index 835a4a88c44d2d3078f0f40130c7ea63391dd012..9bfc18b96983b32c9286b7d793d9c32fe09cb79a 100644
--- a/.scss-lint.yml
+++ b/.scss-lint.yml
@@ -65,7 +65,7 @@ linters:
   
   # Reports when you have an empty rule set.
   EmptyRule:
-    enabled: false
+    enabled: true
   
   # Reports when you have an @extend directive.
   ExtendDirective:
diff --git a/CHANGELOG b/CHANGELOG
index 89572b9e1565279ef0210bbc8941167e87562882..fbc3ee194cbfdb8a8859c30bc96595baa056693f 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,8 +1,18 @@
 Please view this file on the master branch, on stable branches it's out of date.
 
 v 8.8.0 (unreleased)
-
-v 8.7.0 (unreleased)
+  - Remove future dates from contribution calendar graph.
+
+v 8.7.1 (unreleased)
+  - Fix .gitlab-ci.yml parsing issue when hidde job is a template without script definition. !3849
+  - Fix license detection to detect all license files, not only known licenses. !3878
+  - Use the `can?` helper instead of `current_user.can?`. !3882
+  - Prevent users from deleting Webhooks via API they do not own
+  - Fix Error 500 due to stale cache when projects are renamed or transferred
+
+v 8.7.0
+  - Gitlab::GitAccess and Gitlab::GitAccessWiki are now instrumented
+  - Fix vulnerability that made it possible to gain access to private labels and milestones
   - The number of InfluxDB points stored per UDP packet can now be configured
   - Fix error when cross-project label reference used with non-existent project
   - Transactions for /internal/allowed now have an "action" tag set
@@ -53,7 +63,7 @@ v 8.7.0 (unreleased)
   - Add links to CI setup documentation from project settings and builds pages
   - Display project members page to all members
   - Handle nil descriptions in Slack issue messages (Stan Hu)
-  - Add automated repository integrity checks
+  - Add automated repository integrity checks (OFF by default)
   - API: Expose open_issues_count, closed_issues_count, open_merge_requests_count for labels (Robert Schilling)
   - API: Ability to star and unstar a project (Robert Schilling)
   - Add default scope to projects to exclude projects pending deletion
@@ -80,6 +90,7 @@ v 8.7.0 (unreleased)
   - Remove "Congratulations!" tweet button on newly-created project. (Connor Shea)
   - Fix admin/projects when using visibility levels on search (PotHix)
   - Build status notifications
+  - Update email confirmation interface
   - API: Expose user location (Robert Schilling)
   - API: Do not leak group existence via return code (Robert Schilling)
   - ClosingIssueExtractor regex now also works with colons. e.g. "Fixes: #1234" !3591
@@ -107,6 +118,7 @@ v 8.7.0 (unreleased)
   - Updated print style for issues
   - Use GitHub Issue/PR number as iid to keep references
   - Import GitHub labels
+  - Add option to filter by "Owned projects" on dashboard page
   - Import GitHub milestones
   - Fix emoji catgories in the emoji picker
   - Execute system web hooks on push to the project
diff --git a/Gemfile b/Gemfile
index 67cc3f34b8c7d3077c894bab5fe85d09858286be..2aa5f8b1ce3187d340a1af26f8417675ec9f0e36 100644
--- a/Gemfile
+++ b/Gemfile
@@ -178,7 +178,7 @@ gem 'ruby-fogbugz', '~> 0.2.1'
 gem 'd3_rails', '~> 3.5.0'
 
 #cal-heatmap
-gem 'cal-heatmap-rails', '~> 3.5.0'
+gem 'cal-heatmap-rails', '~> 3.6.0'
 
 # underscore-rails
 gem "underscore-rails", "~> 1.8.0"
diff --git a/Gemfile.lock b/Gemfile.lock
index b00d7b35c845612f05bc5f2c3bd8e1ee66839b1a..add056b169fd4ee4d10cdb410c031641c312d178 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -103,7 +103,7 @@ GEM
       bundler (~> 1.2)
       thor (~> 0.18)
     byebug (8.2.1)
-    cal-heatmap-rails (3.5.1)
+    cal-heatmap-rails (3.6.0)
     capybara (2.6.2)
       addressable
       mime-types (>= 1.16)
@@ -134,7 +134,7 @@ GEM
       execjs
     coffee-script-source (1.10.0)
     colorize (0.7.7)
-    concurrent-ruby (1.0.0)
+    concurrent-ruby (1.0.1)
     connection_pool (2.2.0)
     coveralls (0.8.13)
       json (~> 1.8)
@@ -629,7 +629,7 @@ GEM
     recaptcha (1.0.2)
       json
     redcarpet (3.3.3)
-    redis (3.2.2)
+    redis (3.3.0)
     redis-actionpack (4.0.1)
       actionpack (~> 4)
       redis-rack (~> 1.5.0)
@@ -736,10 +736,9 @@ GEM
       rack
     shoulda-matchers (2.8.0)
       activesupport (>= 3.0.0)
-    sidekiq (4.0.1)
+    sidekiq (4.1.1)
       concurrent-ruby (~> 1.0)
       connection_pool (~> 2.2, >= 2.2.0)
-      json (~> 1.0)
       redis (~> 3.2, >= 3.2.1)
     sidekiq-cron (0.4.0)
       redis-namespace (>= 1.5.2)
@@ -905,7 +904,7 @@ DEPENDENCIES
   bullet
   bundler-audit
   byebug
-  cal-heatmap-rails (~> 3.5.0)
+  cal-heatmap-rails (~> 3.6.0)
   capybara (~> 2.6.2)
   capybara-screenshot (~> 1.0.0)
   carrierwave (~> 0.10.0)
diff --git a/app/assets/javascripts/commits.js.coffee b/app/assets/javascripts/commits.js.coffee
index ffd3627b1b073d53b6361c33c31c58684f8ad736..0acb4c1955ecc484a9c5a3c5d5dd0f98b0e3c5b5 100644
--- a/app/assets/javascripts/commits.js.coffee
+++ b/app/assets/javascripts/commits.js.coffee
@@ -1,7 +1,7 @@
 class @CommitsList
   @timer = null
 
-  @init: (ref, limit) ->
+  @init: (limit) ->
     $("body").on "click", ".day-commits-table li.commit", (event) ->
       if event.target.nodeName != "A"
         location.href = $(this).attr("url")
diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee
index e5204f9dee970ab7c60ba3f8c500173e2fae3fc0..29466e9f2edfb4079373b89d808c789d4cac8d90 100644
--- a/app/assets/javascripts/gl_dropdown.js.coffee
+++ b/app/assets/javascripts/gl_dropdown.js.coffee
@@ -221,6 +221,9 @@ class GitLabDropdown
 
     menu.toggleClass PAGE_TWO_CLASS
 
+    # Focus first visible input on active page
+    @dropdown.find('[class^="dropdown-page-"]:visible :text:visible:first').focus()
+
   parseData: (data) ->
     @renderedData = data
 
@@ -240,7 +243,8 @@ class GitLabDropdown
   shouldPropagate: (e) =>
     if @options.multiSelect
       $target = $(e.target)
-      if not $target.hasClass('dropdown-menu-close') and not $target.hasClass('dropdown-menu-close-icon')
+
+      if not $target.hasClass('dropdown-menu-close') and not $target.hasClass('dropdown-menu-close-icon') and not $target.data('is-link')
         e.stopPropagation()
         return false
       else
@@ -375,7 +379,6 @@ class GitLabDropdown
       selectedObject = @renderedData[selectedIndex]
     value = if @options.id then @options.id(selectedObject, el) else selectedObject.id
     field = @dropdown.parent().find("input[name='#{fieldName}'][value='#{value}']")
-
     if el.hasClass(ACTIVE_CLASS)
       el.removeClass(ACTIVE_CLASS)
       field.remove()
diff --git a/app/assets/javascripts/labels_select.js.coffee b/app/assets/javascripts/labels_select.js.coffee
index 021ade73d445b5102439012395fa739801d5fffb..85517b18c5ac4cdda67263b00db9b06bcfe39f14 100644
--- a/app/assets/javascripts/labels_select.js.coffee
+++ b/app/assets/javascripts/labels_select.js.coffee
@@ -19,23 +19,19 @@ class @LabelsSelect
       $form = $dropdown.closest('form')
       $sidebarCollapsedValue = $block.find('.sidebar-collapsed-icon span')
       $value = $block.find('.value')
-      $loading = $block.find('.block-loading').fadeOut()
-
-      if newLabelField.length
-        $newLabelCreateButton = $('.js-new-label-btn')
-        $colorPreview = $('.js-dropdown-label-color-preview')
-        $newLabelError = $dropdown.parent().find('.js-label-error')
-        $newLabelError.hide()
+      $newLabelError = $('.js-label-error')
+      $colorPreview = $('.js-dropdown-label-color-preview')
+      $newLabelCreateButton = $('.js-new-label-btn')
 
-        # Suggested colors in the dropdown to chose from pre-chosen colors
-        $('.suggest-colors-dropdown a').on 'click', (e) ->
+      $newLabelError.hide()
+      $loading = $block.find('.block-loading').fadeOut()
 
       issueURLSplit = issueUpdateURL.split('/') if issueUpdateURL?
       if issueUpdateURL
         labelHTMLTemplate = _.template(
             '<% _.each(labels, function(label){ %>
             <a href="<%= ["",issueURLSplit[1], issueURLSplit[2],""].join("/") %>issues?label_name=<%= _.escape(label.title) %>">
-            <span class="label has-tooltip color-label" title="<%= _.escape(label.description) %>" style="background-color: <%= label.color %>;">
+            <span class="label has-tooltip color-label" title="<%= _.escape(label.description) %>" style="background-color: <%= label.color %>; color: <%= label.text_color %>;">
             <%= _.escape(label.title) %>
             </span>
             </a>
@@ -43,7 +39,9 @@ class @LabelsSelect
         )
         labelNoneHTMLTemplate = _.template('<div class="light">None</div>')
 
-      if newLabelField.length and $dropdown.hasClass 'js-extra-options'
+      if newLabelField.length
+
+        # Suggested colors in the dropdown to chose from pre-chosen colors
         $('.suggest-colors-dropdown a').on "click", (e) ->
           e.preventDefault()
           e.stopPropagation()
@@ -82,26 +80,25 @@ class @LabelsSelect
         enableLabelCreateButton = ->
           if newLabelField.val() isnt '' and newColorField.val() isnt ''
             $newLabelError.hide()
-            $('.js-new-label-btn').disable()
-
-            # Create new label with API
-            Api.newLabel projectId, {
-              name: newLabelField.val()
-              color: newColorField.val()
-            }, (label) ->
-              $('.js-new-label-btn').enable()
-
-              if label.message?
-                $newLabelError
-                  .text label.message
-                  .show()
-              else
-                $('.dropdown-menu-back', $dropdown.parent()).trigger 'click'
-
             $newLabelCreateButton.enable()
           else
             $newLabelCreateButton.disable()
 
+        saveLabel = ->
+          # Create new label with API
+          Api.newLabel projectId, {
+            name: newLabelField.val()
+            color: newColorField.val()
+          }, (label) ->
+            $newLabelCreateButton.enable()
+
+            if label.message?
+              $newLabelError
+                .text label.message
+                .show()
+            else
+              $('.dropdown-menu-back', $dropdown.parent()).trigger 'click'
+
         newLabelField.on 'keyup change', enableLabelCreateButton
 
         newColorField.on 'keyup change', enableLabelCreateButton
@@ -112,24 +109,7 @@ class @LabelsSelect
           .on 'click', (e) ->
             e.preventDefault()
             e.stopPropagation()
-
-            if newLabelField.val() isnt '' and newColorField.val() isnt ''
-              $newLabelError.hide()
-              $('.js-new-label-btn').disable()
-
-              # Create new label with API
-              Api.newLabel projectId, {
-                name: newLabelField.val()
-                color: newColorField.val()
-              }, (label) ->
-                $('.js-new-label-btn').enable()
-
-                if label.message?
-                  $newLabelError
-                    .text label.message
-                    .show()
-                else
-                  $('.dropdown-menu-back', $dropdown.parent()).trigger 'click'
+            saveLabel()
 
       saveLabelData = ->
         selected = $dropdown
@@ -243,7 +223,7 @@ class @LabelsSelect
         fieldName: $dropdown.data('field-name')
         id: (label) ->
           if $dropdown.hasClass("js-filter-submit") and not label.isAny?
-            label.title
+            _.escape label.title
           else
             label.id
 
diff --git a/app/assets/javascripts/merge_request_tabs.js.coffee b/app/assets/javascripts/merge_request_tabs.js.coffee
index e8613cab72b039196fd4fb09f44a0cff40d49e08..372732d0aac27ab6fed5ec47bf8cd75af3993843 100644
--- a/app/assets/javascripts/merge_request_tabs.js.coffee
+++ b/app/assets/javascripts/merge_request_tabs.js.coffee
@@ -87,8 +87,8 @@ class @MergeRequestTabs
     if window.location.hash
       navBarHeight = $('.navbar-gitlab').outerHeight()
 
-      $el = $("#{container} #{window.location.hash}")
-      $.scrollTo("#{container} #{window.location.hash}", offset: -navBarHeight) if $el.length
+      $el = $("#{container} #{window.location.hash}:not(.match)")
+      $.scrollTo("#{container} #{window.location.hash}:not(.match)", offset: -navBarHeight) if $el.length
 
   # Activate a tab based on the current action
   activateTab: (action) ->
@@ -176,12 +176,12 @@ class @MergeRequestTabs
 
     if locationHash isnt ''
       hashClassString = ".#{locationHash.replace('#', '')}"
-      $diffLine = $(locationHash)
+      $diffLine = $("#{locationHash}:not(.match)", $('#diffs'))
 
-      if $diffLine.is ':not(tr)'
-        $diffLine = $("td#{locationHash}, td#{hashClassString}")
+      if not $diffLine.is 'tr'
+        $diffLine = $('#diffs').find("td#{locationHash}, td#{hashClassString}")
       else
-        $diffLine = $('td', $diffLine)
+        $diffLine = $diffLine.find('td')
 
       if $diffLine.length
         $diffLine.addClass 'hll'
diff --git a/app/assets/javascripts/todos.js.coffee b/app/assets/javascripts/todos.js.coffee
index 10e698d6a54ee702466cbb31fd7a2ae39f226989..10bef96f43d53f13b2c3b31573910a4f76226e8a 100644
--- a/app/assets/javascripts/todos.js.coffee
+++ b/app/assets/javascripts/todos.js.coffee
@@ -102,7 +102,8 @@ class @Todos
     todoLink = $(this).data('url')
     return unless todoLink
 
-    if e.metaKey
+    # Allow Meta-Click or Mouse3-click to open in a new tab
+    if e.metaKey or e.which is 2
       e.preventDefault()
       window.open(todoLink,'_blank')
     else
diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss
index e8c0172680db63f9cf982898a42286008c026b58..18a74fe21a0cc6609d6dc6084c2043ecc494eb51 100644
--- a/app/assets/stylesheets/framework/buttons.scss
+++ b/app/assets/stylesheets/framework/buttons.scss
@@ -144,6 +144,10 @@
   }
 }
 
+.btn-lg {
+  padding: 12px 20px;
+}
+
 .btn-transparent {
   color: $btn-transparent-color;
   background-color: transparent;
diff --git a/app/assets/stylesheets/framework/calendar.scss b/app/assets/stylesheets/framework/calendar.scss
index 0b3af592d4aec64493f66549aca4876a42e25ca2..11f39d583bd1755fd27268806a4012d70f0c6b50 100644
--- a/app/assets/stylesheets/framework/calendar.scss
+++ b/app/assets/stylesheets/framework/calendar.scss
@@ -54,6 +54,10 @@
     fill: #254e77 !important;
   }
 
+  .future {
+    visibility: hidden;
+  }
+
   .domain-background {
     fill: none;
     shape-rendering: crispedges;
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index fd395041c3dcb34ec4baaf4a696b5f825424842b..239eaf15cc1088f00d898f42006a06b293130b12 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -320,7 +320,7 @@
   }
 }
 
-.dropdown-input-field {
+.dropdown-input-field, .default-dropdown-input {
   width: 100%;
   padding: 0 7px;
   color: $dropdown-input-color;
diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss
index 789df42fb66afc5b3051a96edb2b9d5deeecfa2a..61d9954c6c87dfafba5664431fe1c516004f9e31 100644
--- a/app/assets/stylesheets/framework/files.scss
+++ b/app/assets/stylesheets/framework/files.scss
@@ -38,12 +38,14 @@
 
     .filename {
       &.old {
+        display: inline-block;
         span.idiff {
           background-color: #f8cbcb;
         }
       }
 
       &.new {
+        display: inline-block;
         span.idiff {
           background-color: #a6f3a6;
         }
@@ -82,10 +84,6 @@
       }
     }
 
-    &.blob_file {
-
-    }
-
     &.blob-no-preview {
       background: #eee;
       text-shadow: 0 1px 2px #fff;
@@ -129,6 +127,11 @@
       td.line-numbers {
         float: none;
         border-left: 1px solid #ddd;
+
+        i {
+          float: none;
+          margin-right: 0;
+        }
       }
       td.lines {
         padding: 0;
diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss
index b2fab387e1791b4101218e8ee3cb26b6aae6cc2a..eae5f062ddad42e57d52d201f1e1de594eb81302 100644
--- a/app/assets/stylesheets/framework/selects.scss
+++ b/app/assets/stylesheets/framework/selects.scss
@@ -121,9 +121,6 @@
   }
 }
 
-.select2-container-multi .select2-choices .select2-search-choice {
-}
-
 .select2-drop-active {
   margin-top: 6px;
   font-size: 14px;
diff --git a/app/assets/stylesheets/highlight/monokai.scss b/app/assets/stylesheets/highlight/monokai.scss
index 28253d4ccb4c756b45b0aee6db9e7c32539fd052..80a509a7c1ac9fa3b949bf8269228d7aa4bc7b9a 100644
--- a/app/assets/stylesheets/highlight/monokai.scss
+++ b/app/assets/stylesheets/highlight/monokai.scss
@@ -111,8 +111,6 @@
   .vg { color: #f8f8f2 } /* Name.Variable.Global */
   .vi { color: #f8f8f2 } /* Name.Variable.Instance */
   .il { color: #ae81ff } /* Literal.Number.Integer.Long */
-
-  .gh { } /* Generic Heading & Diff Header */
   .gu { color: #75715e; } /* Generic.Subheading & Diff Unified/Comment? */
   .gd { color: #f92672; } /* Generic.Deleted & Diff Deleted */
   .gi { color: #a6e22e; } /* Generic.Inserted & Diff Inserted */
diff --git a/app/assets/stylesheets/pages/confirmation.scss b/app/assets/stylesheets/pages/confirmation.scss
new file mode 100644
index 0000000000000000000000000000000000000000..125f495d6d4577e4d3ee03f3f14d4e833beeb10d
--- /dev/null
+++ b/app/assets/stylesheets/pages/confirmation.scss
@@ -0,0 +1,18 @@
+.well-confirmation {
+  margin-bottom: 20px;
+  border-bottom: 1px solid #eee;
+
+  > h1 {
+    font-weight: 400;
+  }
+
+  .lead {
+    margin-bottom: 20px;
+  }
+}
+
+.confirmation-content {
+  a {
+    color: $md-link-color;
+  }
+}
diff --git a/app/assets/stylesheets/pages/graph.scss b/app/assets/stylesheets/pages/graph.scss
index 4e5c4ed84b65322cf9aed2005f26a1498a4453e0..f7f9a9bb7700be56f292f89a8e2d1d85334035af 100644
--- a/app/assets/stylesheets/pages/graph.scss
+++ b/app/assets/stylesheets/pages/graph.scss
@@ -18,9 +18,6 @@
 }
 
 .graphs {
-  .graph-author-commits-count {
-  }
-
   .graph-author-email {
     float: right;
     color: #777;
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 1d6190c8f18621ccde71c5bf5621f983c6fdcf6f..1cf3023ecc976c4f2553a27c553a3c57daabecb3 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -249,6 +249,10 @@
       background: $gray-dark;
       border: 1px solid $border-gray-dark;
     }
+
+    &.btn-primary {
+      @extend .btn-primary
+    }
   }
 
   a:not(.issuable-pager) {
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index 82f78e8d7966af0c19d694950c72a527f7dd1950..d54abe9bc0202937db6fca576e5f8c81f8ea7d63 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -183,6 +183,9 @@ ul.notes {
     }
   }
 
+  .author_link {
+    color: $gl-gray;
+  }
 }
 
 .note-headline-light,
diff --git a/app/controllers/concerns/filter_projects.rb b/app/controllers/concerns/filter_projects.rb
index f63b703d101250db6096e2964c44bfb606c59ead..586f97c5eb47bebf955ebf01693d9be19bacb3a1 100644
--- a/app/controllers/concerns/filter_projects.rb
+++ b/app/controllers/concerns/filter_projects.rb
@@ -10,6 +10,8 @@ module FilterProjects
   def filter_projects(projects)
     projects = projects.search(params[:filter_projects]) if params[:filter_projects].present?
     projects = projects.non_archived if params[:archived].blank?
+    projects = projects.personal(current_user) if params[:personal].present? && current_user
+
     projects
   end
 end
diff --git a/app/controllers/confirmations_controller.rb b/app/controllers/confirmations_controller.rb
index af1faca93f6cb969fe7a7206df92d6f2dc53075b..7b66ad3f92c5e72042afbb8a18273cf8fae429d2 100644
--- a/app/controllers/confirmations_controller.rb
+++ b/app/controllers/confirmations_controller.rb
@@ -1,7 +1,16 @@
 class ConfirmationsController < Devise::ConfirmationsController
 
+  def almost_there
+    flash[:notice] = nil
+    render layout: "devise_empty"
+  end
+
   protected
 
+  def after_resending_confirmation_instructions_path_for(resource)
+    users_almost_there_path
+  end
+
   def after_confirmation_path_for(resource_name, resource)
     if signed_in?(resource_name)
       after_sign_in_path_for(resource)
diff --git a/app/controllers/projects/application_controller.rb b/app/controllers/projects/application_controller.rb
index 74150ad606bac43bc2c6fdfafd68830e66d54926..be872a93feee0c8251485422590d159ba421db8d 100644
--- a/app/controllers/projects/application_controller.rb
+++ b/app/controllers/projects/application_controller.rb
@@ -83,8 +83,7 @@ class Projects::ApplicationController < ApplicationController
   end
 
   def apply_diff_view_cookie!
-    view = params[:view] || cookies[:diff_view]
-    cookies.permanent[:diff_view] = params[:view] = view if view
+    cookies.permanent[:diff_view] = params.delete(:view) if params[:view].present?
   end
 
   def builds_enabled
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index b96ab91c17db96aa00c8c746a93238341ba1378b..7d4fc361ce2aa1c43d7e95021ab1c49268eeb7fa 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -101,7 +101,6 @@ class Projects::IssuesController < Projects::ApplicationController
     end
 
     respond_to do |format|
-      format.js
       format.html do
         if @issue.valid?
           redirect_to issue_path(@issue)
@@ -110,7 +109,7 @@ class Projects::IssuesController < Projects::ApplicationController
         end
       end
       format.json do
-        render json: @issue.to_json(include: [:milestone, :labels, assignee: { methods: :avatar_url }])
+        render json: @issue.to_json(include: { milestone: {}, assignee: { methods: :avatar_url }, labels: { methods: :text_color } })
       end
     end
   end
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 81003c34f594b279f0881b756ec4c506c1f95aca..9c147b3689ebac7d906140cdc443164a23a369a9 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -149,13 +149,12 @@ class Projects::MergeRequestsController < Projects::ApplicationController
 
     if @merge_request.valid?
       respond_to do |format|
-        format.js
         format.html do
           redirect_to([@merge_request.target_project.namespace.becomes(Namespace),
                        @merge_request.target_project, @merge_request])
         end
         format.json do
-          render json: @merge_request.to_json(include: [:milestone, :labels, assignee: { methods: :avatar_url }])
+          render json: @merge_request.to_json(include: { milestone: {}, assignee: { methods: :avatar_url }, labels: { methods: :text_color } })
         end
       end
     else
diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb
index c48175a4c5ab25fb73277740ccab91e9e2df1bef..059b88e22538895a0760dd72090d4f107bc0e5a2 100644
--- a/app/controllers/registrations_controller.rb
+++ b/app/controllers/registrations_controller.rb
@@ -31,11 +31,11 @@ class RegistrationsController < Devise::RegistrationsController
   end
 
   def after_sign_up_path_for(_resource)
-    new_user_session_path
+    users_almost_there_path
   end
 
   def after_inactive_sign_up_path_for(_resource)
-    new_user_session_path
+    users_almost_there_path
   end
 
   private
diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index 93aa30b325571113191a117550ed8af0df113cd2..f00f3f709e99c7e9d4fd792209f2aba989d20d8f 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -278,9 +278,7 @@ class IssuableFinder
       end
     end
 
-    # When filtering by multiple labels we may end up duplicating issues (if one
-    # has multiple labels). This ensures we only return unique issues.
-    items.distinct
+    items
   end
 
   def by_due_date(items)
diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb
index 6a3ec83b8c0195ae30f93d507dab9c923d8b3755..97466d532f4bde6056f83c32b39047f159e6772a 100644
--- a/app/helpers/diff_helper.rb
+++ b/app/helpers/diff_helper.rb
@@ -9,7 +9,13 @@ module DiffHelper
   end
 
   def diff_view
-    params[:view] == 'parallel' ? 'parallel' : 'inline'
+    diff_views = %w(inline parallel)
+
+    if diff_views.include?(cookies[:diff_view])
+      cookies[:diff_view]
+    else
+      diff_views.first
+    end
   end
 
   def diff_hard_limit_enabled?
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index ab85694da3f36b7c8c09fcb3b8790e86177dd1f1..3d5e61d2c18706cc51718d2412450edf20b99f1d 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -123,6 +123,18 @@ module ProjectsHelper
     end
   end
 
+  def license_short_name(project)
+    no_license_key = project.repository.license_key.nil? ||
+      # Back-compat if cache contains 'no-license', can be removed in a few weeks
+      project.repository.license_key == 'no-license'
+
+    return 'LICENSE' if no_license_key
+
+    license = Licensee::License.new(project.repository.license_key)
+
+    license.nickname || license.name
+  end
+
   private
 
   def get_project_nav_tabs(project, current_user)
@@ -320,14 +332,6 @@ module ProjectsHelper
     @ref || @repository.try(:root_ref)
   end
 
-  def license_short_name(project)
-    license = Licensee::License.new(project.repository.license_key)
-
-    license.nickname || license.name
-  end
-
-  private
-
   def filename_path(project, filename)
     if project && blob = project.repository.send(filename)
       namespace_project_blob_path(
diff --git a/app/models/project.rb b/app/models/project.rb
index 7aa21b19e674f19d999840e9366079ad712a8840..0420c6a61aee219421f6ce166cf8b7b9bad1cd8a 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -820,13 +820,11 @@ class Project < ActiveRecord::Base
     wiki = Repository.new("#{old_path}.wiki", self)
 
     if repo.exists?
-      repo.expire_cache
-      repo.expire_emptiness_caches
+      repo.before_delete
     end
 
     if wiki.exists?
-      wiki.expire_cache
-      wiki.expire_emptiness_caches
+      wiki.before_delete
     end
   end
 
diff --git a/app/models/repository.rb b/app/models/repository.rb
index da751591103d4b17acb909072d2249df513f18a0..61c8dce6060f3baf3a469a615e4522e9a1f026a3 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -466,8 +466,8 @@ class Repository
     return nil if !exists? || empty?
 
     cache.fetch(:license_blob) do
-      if licensee_project.license
-        blob_at_branch(root_ref, licensee_project.matched_file.filename)
+      tree(:head).blobs.find do |file|
+        file.name =~ /\A(licen[sc]e|copying)(\..+|\z)/i
       end
     end
   end
@@ -476,7 +476,7 @@ class Repository
     return nil if !exists? || empty?
 
     cache.fetch(:license_key) do
-      licensee_project.license.try(:key) || 'no-license'
+      Licensee.license(path).try(:key)
     end
   end
 
@@ -959,8 +959,4 @@ class Repository
   def cache
     @cache ||= RepositoryCache.new(path_with_namespace)
   end
-
-  def licensee_project
-    @licensee_project ||= Licensee.project(path)
-  end
 end
diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb
index 18f76d3f650d1e8bfc60101edc5dbcc74d52669e..2b16089df1bef1957bbe1ab37ec27a390489b765 100644
--- a/app/services/issuable_base_service.rb
+++ b/app/services/issuable_base_service.rb
@@ -37,8 +37,9 @@ class IssuableBaseService < BaseService
   end
 
   def filter_params(issuable_ability_name = :issue)
-    params[:assignee_id]  = "" if params[:assignee_id] == IssuableFinder::NONE
-    params[:milestone_id] = "" if params[:milestone_id] == IssuableFinder::NONE
+    filter_assignee
+    filter_milestone
+    filter_labels
 
     ability = :"admin_#{issuable_ability_name}"
 
@@ -49,6 +50,29 @@ class IssuableBaseService < BaseService
     end
   end
 
+  def filter_assignee
+    if params[:assignee_id] == IssuableFinder::NONE
+      params[:assignee_id] = ''
+    end
+  end
+
+  def filter_milestone
+    milestone_id = params[:milestone_id]
+    return unless milestone_id
+
+    if milestone_id == IssuableFinder::NONE ||
+        project.milestones.find_by(id: milestone_id).nil?
+      params[:milestone_id] = ''
+    end
+  end
+
+  def filter_labels
+    return if params[:label_ids].to_a.empty?
+
+    params[:label_ids] =
+      project.labels.where(id: params[:label_ids]).pluck(:id)
+  end
+
   def update(issuable)
     change_state(issuable)
     filter_params
diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb
index 79a27f4af7e5a939392261c753b2204505367f94..111b3ec05eabfbcd947dad433ddb88f2ae904e08 100644
--- a/app/services/projects/transfer_service.rb
+++ b/app/services/projects/transfer_service.rb
@@ -34,6 +34,8 @@ module Projects
           raise TransferError.new("Project with same path in target namespace already exists")
         end
 
+        project.expire_caches_before_rename(old_path)
+
         # Apply new namespace id and visibility level
         project.namespace = new_namespace
         project.visibility_level = new_namespace.visibility_level unless project.visibility_level_allowed_by_group?
diff --git a/app/views/devise/confirmations/almost_there.haml b/app/views/devise/confirmations/almost_there.haml
new file mode 100644
index 0000000000000000000000000000000000000000..3c3830a3f103a233456f5107d0bdb745c4bf04c5
--- /dev/null
+++ b/app/views/devise/confirmations/almost_there.haml
@@ -0,0 +1,10 @@
+.well-confirmation.text-center
+  %h1.prepend-top-0
+    Almost there...
+  %p.lead
+    Please check your email to confirm your account
+%p.confirmation-content.text-center
+  No confirmation email received? Please check your spam folder or
+.append-bottom-20.prepend-top-20.text-center
+  %a.btn.btn-lg.btn-success{ href: new_user_confirmation_path }
+    Request new confirmation email
diff --git a/app/views/layouts/devise_empty.html.haml b/app/views/layouts/devise_empty.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..7c061dd531fd0cf4ea4125b08843cfae40d25027
--- /dev/null
+++ b/app/views/layouts/devise_empty.html.haml
@@ -0,0 +1,17 @@
+!!! 5
+%html{ lang: "en"}
+  = render "layouts/head"
+  %body.ui_charcoal.login-page.application.navless
+    = render "layouts/header/empty"
+    = render "layouts/broadcast"
+    .container.navless-container
+      .content
+        = render "layouts/flash"
+        = yield
+
+    %hr
+    .container
+      .footer-links
+        = link_to "Explore", explore_root_path
+        = link_to "Help", help_path
+        = link_to "About GitLab", "https://about.gitlab.com/"
diff --git a/app/views/projects/blob/diff.html.haml b/app/views/projects/blob/diff.html.haml
index 38e62c81fed95fe850fe616dfd7a897e9dc09b0e..5926d181ba3c13129d327df5459f9bb14e59b8c1 100644
--- a/app/views/projects/blob/diff.html.haml
+++ b/app/views/projects/blob/diff.html.haml
@@ -1,17 +1,17 @@
 - if @lines.present?
   - if @form.unfold? && @form.since != 1 && !@form.bottom?
-    %tr.line_holder{ id: @form.since }
+    %tr.line_holder
       = render "projects/diffs/match_line", { line: @match_line,
         line_old: @form.since, line_new: @form.since, bottom: false, new_file: false }
 
   - @lines.each_with_index do |line, index|
     - line_new = index + @form.since
     - line_old = line_new - @form.offset
-    %tr.line_holder
+    %tr.line_holder{ id: line_old }
       %td.old_line.diff-line-num{ data: { linenumber: line_old } }
-        = link_to raw(line_old), "#"
+        = link_to raw(line_old), "##{line_old}"
       %td.new_line.diff-line-num{ data: { linenumber: line_old } }
-        = link_to raw(line_new) , "#"
+        = link_to raw(line_new) , "##{line_old}"
       %td.line_content.noteable_line==#{' ' * @form.indent}#{line}
 
   - if @form.unfold? && @form.bottom? && @form.to < @blob.loc
diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml
index c52cf25d40ab2abf785d3166618467535d85ee4e..bcdb09208aa4e3215dc1b0ddaa08a6506f35cf34 100644
--- a/app/views/projects/commits/show.html.haml
+++ b/app/views/projects/commits/show.html.haml
@@ -39,4 +39,4 @@
 = spinner
 
 :javascript
-  CommitsList.init("#{@ref}", #{@limit});
+  CommitsList.init(#{@limit});
diff --git a/app/views/projects/issues/update.js.haml b/app/views/projects/issues/update.js.haml
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml
index 8d05060f5638e21f5f045e300b71658fad4c1591..290753d57c6edacdbaed8f5d5f8e0112649e3f41 100644
--- a/app/views/projects/merge_requests/_show.html.haml
+++ b/app/views/projects/merge_requests/_show.html.haml
@@ -3,7 +3,7 @@
 - page_card_attributes @merge_request.card_attributes
 - header_title project_title(@project, "Merge Requests", namespace_project_merge_requests_path(@project.namespace, @project))
 
-- if params[:view] == 'parallel'
+- if diff_view == 'parallel'
   - fluid_layout true
 
 .merge-request{'data-url' => merge_request_path(@merge_request)}
diff --git a/app/views/projects/merge_requests/invalid.html.haml b/app/views/projects/merge_requests/invalid.html.haml
index 8ac653427c937732fb650fb2d6297d4b443f2ef5..f5bf16ef3adb1efce0b655b0f0a8391d58001782 100644
--- a/app/views/projects/merge_requests/invalid.html.haml
+++ b/app/views/projects/merge_requests/invalid.html.haml
@@ -1,4 +1,4 @@
-- page_title "#{@merge_request.title} (#{merge_request.to_reference}", "Merge Requests"
+- page_title "#{@merge_request.title} (#{@merge_request.to_reference}", "Merge Requests"
 = render "header_title"
 
 .merge-request
diff --git a/app/views/projects/merge_requests/update.js.haml b/app/views/projects/merge_requests/update.js.haml
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/app/views/projects/project_members/_shared_group_members.html.haml b/app/views/projects/project_members/_shared_group_members.html.haml
index 62888e41935c428023dfb98388d698777e14a1bd..ae13f8428f0e1a89a9d1d8165b1b9d21ce528dfd 100644
--- a/app/views/projects/project_members/_shared_group_members.html.haml
+++ b/app/views/projects/project_members/_shared_group_members.html.haml
@@ -8,7 +8,7 @@
       group, members with
       %strong #{group_links.human_access}
       role (#{shared_group_users_count})
-      - if current_user.can?(:admin_group, shared_group)
+      - if can?(current_user, :admin_group, shared_group)
         .panel-head-actions
           = link_to group_group_members_path(shared_group), class: 'btn btn-sm' do
             %i.fa.fa-pencil-square-o
diff --git a/app/views/shared/issuable/_label_dropdown.html.haml b/app/views/shared/issuable/_label_dropdown.html.haml
index 3eaa45258f0ea591d5a0906553802d44016e9438..61fd1e9c335d7262658f73abdd857d968303cd57 100644
--- a/app/views/shared/issuable/_label_dropdown.html.haml
+++ b/app/views/shared/issuable/_label_dropdown.html.haml
@@ -8,39 +8,7 @@
       = h(multi_label_name(params[:label_name], "Label"))
     = icon('chevron-down')
   .dropdown-menu.dropdown-select.dropdown-menu-paging.dropdown-menu-labels.dropdown-menu-selectable
-    .dropdown-page-one
-      = dropdown_title("Filter by label")
-      = dropdown_filter("Search labels")
-      = dropdown_content
-      - if @project
-        = dropdown_footer do
-          %ul.dropdown-footer-list
-            - if can? current_user, :admin_label, @project
-              %li
-                %a.dropdown-toggle-page{href: "#"}
-                  Create new
-            %li
-              = link_to namespace_project_labels_path(@project.namespace, @project) do
-                - if can? current_user, :admin_label, @project
-                  Manage labels
-                - else
-                  View labels
+    = render partial: "shared/issuable/label_page_default", locals: { title: "Filter by label" }
     - if can? current_user, :admin_label, @project and @project
-      .dropdown-page-two.dropdown-new-label
-        = dropdown_title("Create new label", back: true)
-        = dropdown_content do
-          .dropdown-labels-error.js-label-error
-          %input#new_label_name.dropdown-input-field{type: "text", placeholder: "Name new label"}
-          .suggest-colors.suggest-colors-dropdown
-            - suggested_colors.each do |color|
-              = link_to '#', style: "background-color: #{color}", data: { color: color } do
-                &nbsp
-          .dropdown-label-color-input
-            .dropdown-label-color-preview.js-dropdown-label-color-preview
-            %input#new_label_color.dropdown-input-field{ type: "text" }
-          .clearfix
-            %button.btn.btn-primary.pull-left.js-new-label-btn{type: "button"}
-              Create
-            %button.btn.btn-default.pull-right.js-cancel-label-btn{type: "button"}
-              Cancel
+      = render partial: "shared/issuable/label_page_create"
     = dropdown_loading
diff --git a/app/views/shared/issuable/_label_page_create.html.haml b/app/views/shared/issuable/_label_page_create.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..3bc57d3d2acc691fbca348d6c833f4041c26b191
--- /dev/null
+++ b/app/views/shared/issuable/_label_page_create.html.haml
@@ -0,0 +1,17 @@
+.dropdown-page-two.dropdown-new-label
+  = dropdown_title("Create new label", back: true)
+  = dropdown_content do
+    .dropdown-labels-error.js-label-error
+    %input#new_label_name.default-dropdown-input{ type: "text", placeholder: "Name new label" }
+    .suggest-colors.suggest-colors-dropdown
+      - suggested_colors.each do |color|
+        = link_to '#', style: "background-color: #{color}", data: { color: color } do
+          &nbsp
+    .dropdown-label-color-input
+      .dropdown-label-color-preview.js-dropdown-label-color-preview
+      %input#new_label_color.default-dropdown-input{ type: "text" }
+    .clearfix
+      %button.btn.btn-primary.pull-left.js-new-label-btn{ type: "button" }
+        Create
+      %button.btn.btn-default.pull-right.js-cancel-label-btn{ type: "button" }
+        Cancel
diff --git a/app/views/shared/issuable/_label_page_default.html.haml b/app/views/shared/issuable/_label_page_default.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..7f4867417f78f76a519eff03dec1a5a2957f70e2
--- /dev/null
+++ b/app/views/shared/issuable/_label_page_default.html.haml
@@ -0,0 +1,20 @@
+- title = local_assigns.fetch(:title, 'Assign labels')
+- filter_placeholder = local_assigns.fetch(:filter_placeholder, 'Search labels')
+.dropdown-page-one
+  = dropdown_title(title)
+  = dropdown_filter(filter_placeholder)
+  = dropdown_content
+  - if @project
+    = dropdown_footer do
+      %ul.dropdown-footer-list
+        - if can? current_user, :admin_label, @project
+          %li
+            %a.dropdown-toggle-page{href: "#"}
+              Create new
+        %li
+          = link_to namespace_project_labels_path(@project.namespace, @project), :"data-is-link" => true do
+            - if can? current_user, :admin_label, @project
+              Manage labels
+            - else
+              View labels
+  = dropdown_loading
\ No newline at end of file
diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml
index a50b4b9669340df1b8d844a3c0fcfab4a30f4c96..04b834ba5d1af5fcbf6f0ad3308c11e0fc548522 100644
--- a/app/views/shared/issuable/_sidebar.html.haml
+++ b/app/views/shared/issuable/_sidebar.html.haml
@@ -20,7 +20,7 @@
           %a.btn.btn-default.issuable-pager.disabled{href: '#'}
             Next
 
-    = form_for [@project.namespace.becomes(Namespace), @project, issuable], remote: true, html: {class: 'issuable-context-form inline-update js-issuable-update'} do |f|
+    = form_for [@project.namespace.becomes(Namespace), @project, issuable], remote: true, format: :json, html: {class: 'issuable-context-form inline-update js-issuable-update'} do |f|
       .block.assignee
         .sidebar-collapsed-icon.sidebar-collapsed-user{data: {toggle: "tooltip", placement: "left", container: "body"}, title: (issuable.assignee.to_reference if issuable.assignee)}
           - if issuable.assignee
@@ -129,24 +129,9 @@
                   Label
                 = icon('chevron-down')
               .dropdown-menu.dropdown-select.dropdown-menu-paging.dropdown-menu-labels.dropdown-menu-selectable
-                .dropdown-page-one
-                  = dropdown_title("Assign labels")
-                  = dropdown_filter("Search labels")
-                  = dropdown_content
-                  - if @project
-                    = dropdown_footer do
-                      %ul.dropdown-footer-list
-                        - if can? current_user, :admin_label, @project
-                          %li
-                            %a.dropdown-toggle-page{href: "#"}
-                              Create new
-                        %li
-                          = link_to namespace_project_labels_path(@project.namespace, @project) do
-                            - if can? current_user, :admin_label, @project
-                              Manage labels
-                            - else
-                              View labels
-                  = dropdown_loading
+                = render partial: "shared/issuable/label_page_default"
+                - if can? current_user, :admin_label, @project and @project
+                  = render partial: "shared/issuable/label_page_create"
 
       = render "shared/issuable/participants", participants: issuable.participants(current_user)
       - if current_user
diff --git a/app/views/shared/projects/_dropdown.html.haml b/app/views/shared/projects/_dropdown.html.haml
index e7e04621ff4437d59de82b5e4fe27915c2c7e5a5..1169bed038284f282938672dc0b01a3e0ac0b109 100644
--- a/app/views/shared/projects/_dropdown.html.haml
+++ b/app/views/shared/projects/_dropdown.html.haml
@@ -1,4 +1,5 @@
 - @sort ||= sort_value_recently_updated
+- personal = params[:personal]
 - archived = params[:archived]
 .dropdown.inline
   %button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
@@ -10,7 +11,7 @@
       Sort by
     - projects_sort_options_hash.each do |value, title|
       %li
-        = link_to filter_projects_path(sort: value, archived: archived), class: ("is-active" if @sort == value) do
+        = link_to filter_projects_path(sort: value, archived: archived, personal: personal), class: ("is-active" if @sort == value) do
           = title
 
     %li.divider
@@ -20,3 +21,11 @@
     %li
       = link_to filter_projects_path(sort: @sort, archived: true), class: ("is-active" if params[:archived].present?) do
         Show archived projects
+    - if current_user
+      %li.divider
+      %li
+        = link_to filter_projects_path(sort: @sort, personal: nil), class: ("is-active" unless personal) do
+          Owned by anyone
+      %li
+        = link_to filter_projects_path(sort: @sort, personal: true), class: ("is-active" if personal) do
+          Owned by me
diff --git a/bin/rails b/bin/rails
index 5191e6927af7238928ada521f47e6c3457371baf..0138d79b751b9668a1036329a9ef29a213836162 100755
--- a/bin/rails
+++ b/bin/rails
@@ -1,4 +1,9 @@
 #!/usr/bin/env ruby
+begin
+  load File.expand_path('../spring', __FILE__)
+rescue LoadError => e
+  raise unless e.message.include?('spring')
+end
 APP_PATH = File.expand_path('../../config/application', __FILE__)
 require_relative '../config/boot'
 require 'rails/commands'
diff --git a/bin/rake b/bin/rake
index 17240489f64832c9ce080088e27780d3dc3ee29a..d87d5f578104597c1d1b951b55942e37f8af1277 100755
--- a/bin/rake
+++ b/bin/rake
@@ -1,4 +1,9 @@
 #!/usr/bin/env ruby
+begin
+  load File.expand_path('../spring', __FILE__)
+rescue LoadError => e
+  raise unless e.message.include?('spring')
+end
 require_relative '../config/boot'
 require 'rake'
 Rake.application.run
diff --git a/bin/rspec b/bin/rspec
index 20060ebd79c0ec217596c425ddc66ea58b4a02d1..6e6709219af4b84b143079e7d7b6493080c743f9 100755
--- a/bin/rspec
+++ b/bin/rspec
@@ -1,7 +1,8 @@
 #!/usr/bin/env ruby
 begin
-  load File.expand_path("../spring", __FILE__)
-rescue LoadError
+  load File.expand_path('../spring', __FILE__)
+rescue LoadError => e
+  raise unless e.message.include?('spring')
 end
 require 'bundler/setup'
 load Gem.bin_path('rspec-core', 'rspec')
diff --git a/bin/spinach b/bin/spinach
index a080e286cfe025ec2c80934395e9020c1c1f9812..474050e29d11879520382b50833e37e1b68be46f 100755
--- a/bin/spinach
+++ b/bin/spinach
@@ -1,7 +1,8 @@
 #!/usr/bin/env ruby
 begin
-  load File.expand_path("../spring", __FILE__)
-rescue LoadError
+  load File.expand_path('../spring', __FILE__)
+rescue LoadError => e
+  raise unless e.message.include?('spring')
 end
 require 'bundler/setup'
 load Gem.bin_path('spinach', 'spinach')
diff --git a/bin/spring b/bin/spring
index 7b45d374fcd980449a9a849a136a124622dd91ce..7fe232c3aae5996a1d6ca1f69d10e636630f5c5c 100755
--- a/bin/spring
+++ b/bin/spring
@@ -4,12 +4,12 @@
 # It gets overwritten when you run the `spring binstub` command.
 
 unless defined?(Spring)
-  require "rubygems"
-  require "bundler"
+  require 'rubygems'
+  require 'bundler'
 
-  if match = Bundler.default_lockfile.read.match(/^GEM$.*?^    (?:  )*spring \((.*?)\)$.*?^$/m)
-    Gem.paths = { "GEM_PATH" => [Bundler.bundle_path.to_s, *Gem.path].uniq }
-    gem "spring", match[1]
-    require "spring/binstub"
+  if (match = Bundler.default_lockfile.read.match(/^GEM$.*?^    (?:  )*spring \((.*?)\)$.*?^$/m))
+    Gem.paths = { 'GEM_PATH' => [Bundler.bundle_path.to_s, *Gem.path].uniq.join(Gem.path_separator) }
+    gem 'spring', match[1]
+    require 'spring/binstub'
   end
 end
diff --git a/bin/teaspoon b/bin/teaspoon
new file mode 100755
index 0000000000000000000000000000000000000000..7c3b8dfc4ed8849db5a793163d62266139a0997d
--- /dev/null
+++ b/bin/teaspoon
@@ -0,0 +1,8 @@
+#!/usr/bin/env ruby
+begin
+  load File.expand_path('../spring', __FILE__)
+rescue LoadError => e
+  raise unless e.message.include?('spring')
+end
+require 'bundler/setup'
+load Gem.bin_path('teaspoon', 'teaspoon')
diff --git a/config/initializers/metrics.rb b/config/initializers/metrics.rb
index 22fe51a45343554bd6efc0ebaa6b6444a463fb29..283936d0efc7937b4848fb7e024b3d08320a4006 100644
--- a/config/initializers/metrics.rb
+++ b/config/initializers/metrics.rb
@@ -107,6 +107,10 @@ if Gitlab::Metrics.enabled?
       config.instrument_methods(const)
       config.instrument_instance_methods(const)
     end
+
+    # Instrument the classes used for checking if somebody has push access.
+    config.instrument_instance_methods(Gitlab::GitAccess)
+    config.instrument_instance_methods(Gitlab::GitAccessWiki)
   end
 
   GC::Profiler.enable
diff --git a/config/routes.rb b/config/routes.rb
index df6116b6eaf33562f231974086f5e6027cc23e70..9f667dca63839de1318124d912cacc1405a7a005 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -424,6 +424,7 @@ Rails.application.routes.draw do
 
   devise_scope :user do
     get '/users/auth/:provider/omniauth_error' => 'omniauth_callbacks#omniauth_error', as: :omniauth_error
+    get '/users/almost_there' => 'confirmations#almost_there'
   end
 
   root to: "root#index"
diff --git a/db/migrate/20160421130527_disable_repository_checks.rb b/db/migrate/20160421130527_disable_repository_checks.rb
new file mode 100644
index 0000000000000000000000000000000000000000..808a4b93c7c596adf0bd8b84c8752f268d36d7b9
--- /dev/null
+++ b/db/migrate/20160421130527_disable_repository_checks.rb
@@ -0,0 +1,11 @@
+class DisableRepositoryChecks < ActiveRecord::Migration
+  def up
+    change_column_default :application_settings, :repository_checks_enabled, false 
+    execute 'UPDATE application_settings SET repository_checks_enabled = false'
+  end
+
+  def down
+    change_column_default :application_settings, :repository_checks_enabled, true    
+    execute 'UPDATE application_settings SET repository_checks_enabled = true'
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index a743e6824235c7d94e8e34e19b912983969115cf..42457d923534680ba5c7832a8f83820d9a85fb81 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: 20160419120017) do
+ActiveRecord::Schema.define(version: 20160421130527) do
 
   # These are extensions that must be enabled in order to support this database
   enable_extension "plpgsql"
@@ -77,7 +77,7 @@ ActiveRecord::Schema.define(version: 20160419120017) do
     t.string   "akismet_api_key"
     t.boolean  "email_author_in_body",              default: false
     t.integer  "default_group_visibility"
-    t.boolean  "repository_checks_enabled",         default: true
+    t.boolean  "repository_checks_enabled",         default: false
     t.integer  "metrics_packet_size",               default: 1
     t.text     "shared_runners_text"
   end
diff --git a/doc/README.md b/doc/README.md
index e6ac47948278380637e6e18bf965fc1029a86cc9..e358da1c4245ccd8c6fe17eb942fb9ceda41007f 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -41,6 +41,8 @@
 - [Git LFS configuration](workflow/lfs/lfs_administration.md)
 - [Housekeeping](administration/housekeeping.md) Keep your Git repository tidy and fast.
 - [GitLab Performance Monitoring](monitoring/performance/introduction.md) Configure GitLab and InfluxDB for measuring performance metrics
+- [Sidekiq Troubleshooting](administration/troubleshooting/sidekiq.md) Debug when Sidekiq appears hung and is not processing jobs
+- [High Availability](administration/high_availability/README.md) Configure multiple servers for scaling or high availability
 
 ## Contributor documentation
 
diff --git a/doc/administration/high_availability/README.md b/doc/administration/high_availability/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..43d85ffb7752cede8d9fe89ee27036c4fda660ca
--- /dev/null
+++ b/doc/administration/high_availability/README.md
@@ -0,0 +1,35 @@
+# High Availability
+
+GitLab supports several different types of clustering and high-availability.
+The solution you choose will be based on the level of scalability and
+availability you require. The easiest solutions are scalable, but not necessarily
+highly available.
+
+## Architecture
+
+### Active/Passive
+
+For pure high-availability/failover with no scaling you can use an
+active/passive configuration. This utilizes DRBD (Distributed Replicated
+Block Device) to keep all data in sync. DRBD requires a low latency link to
+remain in sync. It is not advisable to attempt to run DRBD between data centers
+or in different cloud availability zones.
+
+Components/Servers Required:
+
+- 2 servers/virtual machines (one active/one passive)
+
+### Active/Active
+
+This architecture scales easily because all application servers handle
+user requests simultaneously. The database, Redis, and GitLab application are
+all deployed on separate servers. The configuration is **only** highly-available
+if the database, Redis and storage are also configured as such.
+
+**Steps to configure active/active:**
+
+1. [Configure the database](database.md)
+1. [Configure Redis](redis.md)
+1. [Configure NFS](nfs.md)
+1. [Configure the GitLab application servers](gitlab.md)
+1. [Configure the load balancers](load_balancer.md)
diff --git a/doc/administration/high_availability/database.md b/doc/administration/high_availability/database.md
new file mode 100644
index 0000000000000000000000000000000000000000..538dada1bae96f55a1161c7c12f27e014cf2b0fa
--- /dev/null
+++ b/doc/administration/high_availability/database.md
@@ -0,0 +1,116 @@
+# Configuring a Database for GitLab HA
+
+You can choose to install and manage a database server (PostgreSQL/MySQL)
+yourself, or you can use GitLab Omnibus packages to help. GitLab recommends
+PostgreSQL. This is the database that will be installed if you use the
+Omnibus package to manage your database.
+
+## Configure your own database server
+
+If you're hosting GitLab on a cloud provider, you can optionally use a
+managed service for PostgreSQL. For example, AWS offers a managed Relational
+Database Service (RDS) that runs PostgreSQL.
+
+If you use a cloud-managed service, or provide your own PostgreSQL:
+
+1. Set up a `gitlab` username with a password of your choice. The `gitlab` user
+   needs privileges to create the `gitlabhq_production` database.
+1. Configure the GitLab application servers with the appropriate details.
+   This step is covered in [Configuring GitLab for HA](gitlab.md)
+
+## Configure using Omnibus
+
+1. Download/install GitLab Omnibus using **steps 1 and 2** from
+   [GitLab downloads](https://about.gitlab.com/downloads). Do not complete other
+   steps on the download page.
+1. Create/edit `/etc/gitlab/gitlab.rb` and use the following configuration.
+   Be sure to change the `external_url` to match your eventual GitLab front-end
+   URL.
+
+    ```ruby
+    external_url 'https://gitlab.example.com'
+
+    # Disable all components except PostgreSQL
+    postgresql['enable'] = true
+    bootstrap['enable'] = false
+    nginx['enable'] = false
+    unicorn['enable'] = false
+    sidekiq['enable'] = false
+    redis['enable'] = false
+    gitlab_workhorse['enable'] = false
+    mailroom['enable'] = false
+
+    # PostgreSQL configuration
+    postgresql['sql_password'] = 'DB password'
+    postgresql['md5_auth_cidr_addresses'] = ['0.0.0.0/0']
+    postgresql['listen_address'] = '0.0.0.0'
+    ```
+
+1. Run `sudo gitlab-ctl reconfigure` to install and configure PostgreSQL.
+
+    > **Note**: This `reconfigure` step will result in some errors.
+      That's OK - don't be alarmed.
+
+1. Open a database prompt:
+
+    ```
+    su - gitlab-psql
+    /bin/bash
+    psql -h /var/opt/gitlab/postgresql -d template1
+
+    # Output:
+
+    psql (9.2.15)
+    Type "help" for help.
+
+    template1=#
+    ```
+
+1. Run the following command at the database prompt and you will be asked to
+   enter the new password for the PostgreSQL superuser.
+
+    ```
+    \password
+
+    # Output:
+
+    Enter new password:
+    Enter it again:
+    ```
+
+1. Similarly, set the password for the `gitlab` database user. Use the same
+   password that you specified in the `/etc/gitlab/gitlab.rb` file for
+   `postgresql['sql_password']`.
+
+    ```
+    \password gitlab
+
+    # Output:
+
+    Enter new password:
+    Enter it again:
+    ```
+
+1. Enable the `pg_trgm` extension:
+    ```
+    CREATE EXTENSION pg_trgm;
+
+    # Output:
+
+    CREATE EXTENSION
+    ```
+1. Exit the database prompt by typing `\q` and Enter.
+1. Exit the `gitlab-psql` user by running `exit` twice.
+1. Run `sudo gitlab-ctl reconfigure` a final time.
+1. Run `touch /etc/gitlab/skip-auto-migrations` to prevent database migrations
+   from running on upgrade. Only the primary GitLab application server should
+   handle migrations.
+
+---
+
+Read more on high-availability configuration:
+
+1. [Configure Redis](redis.md)
+1. [Configure NFS](nfs.md)
+1. [Configure the GitLab application servers](gitlab.md)
+1. [Configure the load balancers](load_balancer.md)
diff --git a/doc/administration/high_availability/gitlab.md b/doc/administration/high_availability/gitlab.md
new file mode 100644
index 0000000000000000000000000000000000000000..8a881ce886303ff08ad783cdb87d72f8dd0be09d
--- /dev/null
+++ b/doc/administration/high_availability/gitlab.md
@@ -0,0 +1,131 @@
+# Configuring GitLab for HA
+
+Assuming you have already configured a database, Redis, and NFS, you can
+configure the GitLab application server(s) now. Complete the steps below
+for each GitLab application server in your environment.
+
+> **Note:** There is some additional configuration near the bottom for
+  secondary GitLab application servers. It's important to read and understand
+  these additional steps before proceeding with GitLab installation.
+
+1. If necessary, install the NFS client utility packages using the following
+   commands:
+
+    ```
+    # Ubuntu/Debian
+    apt-get install nfs-common
+
+    # CentOS/Red Hat
+    yum install nfs-utils nfs-utils-lib
+    ```
+
+1. Specify the necessary NFS shares. Mounts are specified in
+   `/etc/fstab`. The exact contents of `/etc/fstab` will depend on how you chose
+   to configure your NFS server. See [NFS documentation](nfs.md) for the various
+   options. Here is an example snippet to add to `/etc/fstab`:
+
+    ```
+    10.1.0.1:/var/opt/gitlab/.ssh /var/opt/gitlab/.ssh nfs defaults,soft,rsize=1048576,wsize=1048576,noatime,nobootwait,lookupcache=positive 0 2
+    10.1.0.1:/var/opt/gitlab/gitlab-rails/uploads /var/opt/gitlab/gitlab-rails/uploads nfs defaults,soft,rsize=1048576,wsize=1048576,noatime,nobootwait,lookupcache=positive 0 2
+    10.1.0.1:/var/opt/gitlab/gitlab-rails/shared /var/opt/gitlab/gitlab-rails/shared nfs defaults,soft,rsize=1048576,wsize=1048576,noatime,nobootwait,lookupcache=positive 0 2
+    10.1.0.1:/var/opt/gitlab/gitlab-ci/builds /var/opt/gitlab/gitlab-ci/builds nfs defaults,soft,rsize=1048576,wsize=1048576,noatime,nobootwait,lookupcache=positive 0 2
+    10.1.1.1:/var/opt/gitlab/git-data /var/opt/gitlab/git-data nfs defaults,soft,rsize=1048576,wsize=1048576,noatime,nobootwait,lookupcache=positive 0 2
+    ```
+
+1. Create the shared directories. These may be different depending on your NFS
+   mount locations.
+
+    ```
+    mkdir -p /var/opt/gitlab/.ssh /var/opt/gitlab/gitlab-rails/uploads /var/opt/gitlab/gitlab-rails/shared /var/opt/gitlab/gitlab-ci/builds /var/opt/gitlab/git-data
+    ```
+
+1. Download/install GitLab Omnibus using **steps 1 and 2** from
+   [GitLab downloads](https://about.gitlab.com/downloads). Do not complete other
+   steps on the download page.
+1. Create/edit `/etc/gitlab/gitlab.rb` and use the following configuration.
+   Be sure to change the `external_url` to match your eventual GitLab front-end
+   URL. Depending your the NFS configuration, you may need to change some GitLab
+   data locations. See [NFS documentation](nfs.md) for `/etc/gitlab/gitlab.rb`
+   configuration values for various scenarios. The example below assumes you've
+   added NFS mounts in the default data locations.
+    
+    ```ruby
+    external_url 'https://gitlab.example.com'
+
+    # Prevent GitLab from starting if NFS data mounts are not available
+    high_availability['mountpoint'] = '/var/opt/gitlab/git-data'
+    
+    # Disable components that will not be on the GitLab application server
+    postgresql['enable'] = false
+    redis['enable'] = false
+    
+    # PostgreSQL connection details
+    gitlab_rails['db_adapter'] = 'postgresql'
+    gitlab_rails['db_encoding'] = 'unicode'
+    gitlab_rails['db_host'] = '10.1.0.5' # IP/hostname of database server
+    gitlab_rails['db_password'] = 'DB password'
+    
+    # Redis connection details
+    gitlab_rails['redis_port'] = '6379'
+    gitlab_rails['redis_host'] = '10.1.0.6' # IP/hostname of Redis server
+    gitlab_rails['redis_password'] = 'Redis Password'
+    ```
+
+1. Run `sudo gitlab-ctl reconfigure` to compile the configuration.
+
+## Primary GitLab application server
+
+As a final step, run the setup rake task on the first GitLab application server.
+It is not necessary to run this on additional application servers.
+
+1. Initialize the database by running `sudo gitlab-rake gitlab:setup`.
+
+> **WARNING:** Only run this setup task on **NEW** GitLab instances because it
+  will wipe any existing data.
+
+> **Note:** When you specify `https` in the `external_url`, as in the example
+  above, GitLab assumes you have SSL certificates in `/etc/gitlab/ssl/`. If
+  certificates are not present, Nginx will fail to start. See
+  [Nginx documentation](http://docs.gitlab.com/omnibus/settings/nginx.html#enable-https)
+  for more information.
+
+## Additional configuration for secondary GitLab application servers
+
+Secondary GitLab servers (servers configured **after** the first GitLab server)
+need some additional configuration.
+
+1. Configure shared secrets. These values can be obtained from the primary
+   GitLab server in `/etc/gitlab/gitlab-secrets.json`. Add these to
+   `/etc/gitlab/gitlab.rb` **prior to** running the first `reconfigure` in
+   the steps above.
+
+    ```ruby
+    gitlab_shell['secret_token'] = 'fbfb19c355066a9afb030992231c4a363357f77345edd0f2e772359e5be59b02538e1fa6cae8f93f7d23355341cea2b93600dab6d6c3edcdced558fc6d739860'
+    gitlab_rails['secret_token'] = 'b719fe119132c7810908bba18315259ed12888d4f5ee5430c42a776d840a396799b0a5ef0a801348c8a357f07aa72bbd58e25a84b8f247a25c72f539c7a6c5fa'
+    gitlab_ci['secret_key_base'] = '6e657410d57c71b4fc3ed0d694e7842b1895a8b401d812c17fe61caf95b48a6d703cb53c112bc01ebd197a85da81b18e29682040e99b4f26594772a4a2c98c6d'
+    gitlab_ci['db_key_base'] = 'bf2e47b68d6cafaef1d767e628b619365becf27571e10f196f98dc85e7771042b9203199d39aff91fcb6837c8ed83f2a912b278da50999bb11a2fbc0fba52964'
+    ```
+
+1. Run `touch /etc/gitlab/skip-auto-migrations` to prevent database migrations
+   from running on upgrade. Only the primary GitLab application server should
+   handle migrations.
+
+## Troubleshooting
+
+- `mount: wrong fs type, bad option, bad superblock on`
+
+You have not installed the necessary NFS client utilities. See step 1 above.
+
+- `mount: mount point /var/opt/gitlab/... does not exist`
+
+This particular directory does not exist on the NFS server. Ensure
+the share is exported and exists on the NFS server and try to remount.
+
+---
+
+Read more on high-availability configuration:
+
+1. [Configure the database](database.md)
+1. [Configure Redis](redis.md)
+1. [Configure NFS](nfs.md)
+1. [Configure the load balancers](load_balancer.md)
diff --git a/doc/administration/high_availability/load_balancer.md b/doc/administration/high_availability/load_balancer.md
new file mode 100644
index 0000000000000000000000000000000000000000..b1fe34ed9a1a307dd92ca21153f9603eef031e36
--- /dev/null
+++ b/doc/administration/high_availability/load_balancer.md
@@ -0,0 +1,63 @@
+# Load Balancer for GitLab HA
+
+In an active/active GitLab configuration, you will need a load balancer to route
+traffic to the application servers. The specifics on which load balancer to use
+or the exact configuration is beyond the scope of GitLab documentation. We hope
+that if you're managing HA systems like GitLab you have a load balancer of
+choice already. Some examples including HAProxy (open-source), F5 Big-IP LTM,
+and Citrix Net Scaler. This documentation will outline what ports and protocols
+you need to use with GitLab.
+
+## Basic ports
+
+| LB Port | Backend Port | Protocol   |
+| ------- | ------------ | --------   |
+| 80      | 80           | HTTP       |
+| 443     | 443          | HTTPS [^1] |
+| 22      | 22           | TCP        |
+
+## GitLab Pages Ports
+
+If you're using GitLab Pages you will need some additional port configurations.
+GitLab Pages requires a separate VIP. Configure DNS to point the
+`pages_external_url` from `/etc/gitlab/gitlab.rb` at the new VIP. See the
+[GitLab Pages documentation][gitlab-pages] for more information.
+
+| LB Port | Backend Port | Protocol |
+| ------- | ------------ | -------- |
+| 80      | Varies [^2]  | HTTP     |
+| 443     | Varies [^2]  | TCP [^3] |
+
+## Alternate SSH Port
+
+Some organizations have policies against opening SSH port 22. In this case,
+it may be helpful to configure an alternate SSH hostname that allows users
+to use SSH on port 443. An alternate SSH hostname will require a new VIP
+compared to the other GitLab HTTP configuration above.
+
+Configure DNS for an alternate SSH hostname such as altssh.gitlab.example.com.
+
+| LB Port | Backend Port | Protocol |
+| ------- | ------------ | -------- |
+| 443     | 22           | TCP      |
+
+---
+
+Read more on high-availability configuration:
+
+1. [Configure the database](database.md)
+1. [Configure Redis](redis.md)
+1. [Configure NFS](nfs.md)
+1. [Configure the GitLab application servers](gitlab.md)
+
+[^1]: When using HTTPS protocol for port 443, you will need to add an SSL
+      certificate to the load balancers. If you wish to terminate SSL at the
+      GitLab application server instead, use TCP protocol.
+[^2]: The backend port for GitLab Pages depends on the
+      `gitlab_pages['external_http']` and `gitlab_pages['external_https']`
+      setting. See [GitLab Pages documentation][gitlab-pages] for more details.
+[^3]: Port 443 for GitLab Pages should always use the TCP protocol. Users can
+      configure custom domains with custom SSL, which would not be possible
+      if SSL was terminated at the load balancer.
+
+[gitlab-pages]: http://doc.gitlab.com/ee/pages/administration.html
diff --git a/doc/administration/high_availability/nfs.md b/doc/administration/high_availability/nfs.md
new file mode 100644
index 0000000000000000000000000000000000000000..e4e124e200a2cff0164ad75c444a2dd3ee826519
--- /dev/null
+++ b/doc/administration/high_availability/nfs.md
@@ -0,0 +1,116 @@
+# NFS
+
+## Required NFS Server features
+
+**File locking**: GitLab **requires** file locking which is only supported
+natively in NFS version 4. NFSv3 also supports locking as long as
+Linux Kernel 2.6.5+ is used. We recommend using version 4 and do not
+specifically test NFSv3.
+
+**no_root_squash**: NFS normally changes the `root` user to `nobody`. This is
+a good security measure when NFS shares will be accessed by many different
+users. However, in this case only GitLab will use the NFS share so it
+is safe. GitLab requires the `no_root_squash` setting because we need to
+manage file permissions automatically. Without the setting you will receive
+errors when the Omnibus package tries to alter permissions. Note that GitLab
+and other bundled components do **not** run as `root` but as non-privileged
+users. The requirement for `no_root_squash` is to allow the Omnibus package to
+set ownership and permissions on files, as needed.
+
+### Recommended options
+
+When you define your NFS exports, we recommend you also add the following
+options:
+
+- `sync` - Force synchronous behavior. Default is asynchronous and under certain
+  circumstances it could lead to data loss if a failure occurs before data has
+  synced.
+
+## Client mount options
+
+Below is an example of an NFS mount point we use on GitLab.com:
+
+```
+10.1.1.1:/var/opt/gitlab/git-data /var/opt/gitlab/git-data nfs4 defaults,soft,rsize=1048576,wsize=1048576,noatime,nobootwait,lookupcache=positive 0 2
+```
+
+Notice several options that you should consider using:
+
+| Setting | Description |
+| ------- | ----------- |
+| `nobootwait` | Don't halt boot process waiting for this mount to become available
+| `lookupcache=positive` | Tells the NFS client to honor `positive` cache results but invalidates any `negative` cache results. Negative cache results cause problems with Git. Specifically, a `git push` can fail to register uniformly across all NFS clients. The negative cache causes the clients to 'remember' that the files did not exist previously.
+
+## Mount locations
+
+When using default Omnibus configuration you will need to share 5 data locations
+between all GitLab cluster nodes. No other locations should be shared. The
+following are the 5 locations you need to mount:
+
+| Location | Description |
+| -------- | ----------- |
+| `/var/opt/gitlab/git-data` | Git repository data. This will account for a large portion of your data
+| `/var/opt/gitlab/.ssh` | SSH `authorized_keys` file and keys used to import repositories from some other Git services
+| `/var/opt/gitlab/gitlab-rails/uploads` | User uploaded attachments
+| `/var/opt/gitlab/gitlab-rails/shared` | Build artifacts, GitLab Pages, LFS objects, temp files, etc. If you're using LFS this may also account for a large portion of your data
+| `/var/opt/gitlab/gitlab-ci/builds` | GitLab CI build traces
+
+Other GitLab directories should not be shared between nodes. They contain
+node-specific files and GitLab code that does not need to be shared. To ship
+logs to a central location consider using remote syslog. GitLab Omnibus packages
+provide configuration for [UDP log shipping][udp-log-shipping].
+
+### Consolidating mount points
+
+If you don't want to configure 5-6 different NFS mount points, you have a few
+alternative options.
+
+#### Change default file locations
+
+Omnibus allows you to configure the file locations. With custom configuration
+you can specify just one main mountpoint and have all of these locations
+as subdirectories. Mount `/gitlab-data` then use the following Omnibus
+configuration to move each data location to a subdirectory:
+
+```ruby
+user['home'] = '/gitlab-data/home'
+git_data_dir '/gitlab-data/git-data'
+gitlab_rails['shared_path'] = '/gitlab-data/shared'
+gitlab_rails['uploads_directory'] = "/gitlab-data/uploads"
+gitlab_ci['builds_directory'] = '/gitlab-data/builds'
+```
+
+To move the `git` home directory, all GitLab services must be stopped. Run
+`gitlab-ctl stop && initctl stop gitlab-runsvdir`. Then continue with the
+reconfigure.
+
+Run `sudo gitlab-ctl reconfigure` to start using the central location. Please
+be aware that if you had existing data you will need to manually copy/rsync it
+to these new locations and then restart GitLab.
+
+#### Bind mounts
+
+Bind mounts provide a way to specify just one NFS mount and then
+bind the default GitLab data locations to the NFS mount. Start by defining your
+single NFS mount point as you normally would in `/etc/fstab`. Let's assume your
+NFS mount point is `/gitlab-data`. Then, add the following bind mounts in
+`/etc/fstab`:
+
+```bash
+/gitlab-data/git-data /var/opt/gitlab/git-data none bind 0 0
+/gitlab-data/.ssh /var/opt/gitlab/.ssh none bind 0 0
+/gitlab-data/uploads /var/opt/gitlab/gitlab-rails/uploads none bind 0 0
+/gitlab-data/shared /var/opt/gitlab/gitlab-rails/shared none bind 0 0
+/gitlab-data/builds /var/opt/gitlab/gitlab-ci/builds none bind 0 0
+```
+
+---
+
+Read more on high-availability configuration:
+
+1. [Configure the database](database.md)
+1. [Configure Redis](redis.md)
+1. [Configure the GitLab application servers](gitlab.md)
+1. [Configure the load balancers](load_balancer.md)
+
+[udp-log-shipping]: http://doc.gitlab.com/omnibus/settings/logs.html#udp-log-shipping-gitlab-enterprise-edition-only "UDP log shipping"
diff --git a/doc/administration/high_availability/redis.md b/doc/administration/high_availability/redis.md
new file mode 100644
index 0000000000000000000000000000000000000000..d89a1e582cacaa18005c26556f97cdd9f7825fa5
--- /dev/null
+++ b/doc/administration/high_availability/redis.md
@@ -0,0 +1,62 @@
+# Configuring Redis for GitLab HA
+
+You can choose to install and manage Redis yourself, or you can use GitLab
+Omnibus packages to help.
+
+## Configure your own Redis server
+
+If you're hosting GitLab on a cloud provider, you can optionally use a
+managed service for Redis. For example, AWS offers a managed ElastiCache service
+that runs Redis.
+
+> **Note:** Redis does not require authentication by default. See
+  [Redis Security](http://redis.io/topics/security) documentation for more
+  information. We recommend using a combination of a Redis password and tight
+  firewall rules to secure your Redis service.
+
+## Configure using Omnibus
+
+1. Download/install GitLab Omnibus using **steps 1 and 2** from
+   [GitLab downloads](https://about.gitlab.com/downloads). Do not complete other
+   steps on the download page.
+1. Create/edit `/etc/gitlab/gitlab.rb` and use the following configuration.
+   Be sure to change the `external_url` to match your eventual GitLab front-end
+   URL.
+
+    ```ruby
+      external_url 'https://gitlab.example.com'
+
+      # Disable all components except PostgreSQL
+      redis['enable'] = true
+      bootstrap['enable'] = false
+      nginx['enable'] = false
+      unicorn['enable'] = false
+      sidekiq['enable'] = false
+      postgresql['enable'] = false
+      gitlab_workhorse['enable'] = false
+      mailroom['enable'] = false
+
+      # Redis configuration
+      redis['port'] = 6379
+      redis['bind'] = '0.0.0.0'
+
+      # If you wish to use Redis authentication (recommended)
+      redis['password'] = 'Redis Password'
+    ```
+
+1. Run `sudo gitlab-ctl reconfigure` to install and configure PostgreSQL.
+
+    > **Note**: This `reconfigure` step will result in some errors.
+      That's OK - don't be alarmed.
+1. Run `touch /etc/gitlab/skip-auto-migrations` to prevent database migrations
+   from running on upgrade. Only the primary GitLab application server should
+   handle migrations.
+
+---
+
+Read more on high-availability configuration:
+
+1. [Configure the database](database.md)
+1. [Configure NFS](nfs.md)
+1. [Configure the GitLab application servers](gitlab.md)
+1. [Configure the load balancers](load_balancer.md)
diff --git a/doc/administration/repository_checks.md b/doc/administration/repository_checks.md
index 61bf8ce61619e4ad9542af5d10a40fbf8f8576ba..3411e4af6a7c7e6b30071477b4859729df7dee86 100644
--- a/doc/administration/repository_checks.md
+++ b/doc/administration/repository_checks.md
@@ -1,7 +1,8 @@
 # Repository checks
 
 >**Note:**
-This feature was [introduced][ce-3232] in GitLab 8.7.
+This feature was [introduced][ce-3232] in GitLab 8.7. It is OFF by
+default because it still causes too many false alarms.
 
 Git has a built-in mechanism, [git fsck][git-fsck], to verify the
 integrity of all data commited to a repository. GitLab administrators
diff --git a/doc/administration/troubleshooting/sidekiq.md b/doc/administration/troubleshooting/sidekiq.md
new file mode 100644
index 0000000000000000000000000000000000000000..134a7583762dc0e2153437746498744b6f12e924
--- /dev/null
+++ b/doc/administration/troubleshooting/sidekiq.md
@@ -0,0 +1,162 @@
+# Troubleshooting Sidekiq
+
+Sidekiq is the background job processor GitLab uses to asynchronously run
+tasks. When things go wrong it can be difficult to troubleshoot. These
+situations also tend to be high-pressure because a production system job queue
+may be filling up. Users will notice when this happens because new branches
+may not show up and merge requests may not be updated. The following are some
+troubleshooting steps that will help you diagnose the bottleneck.
+
+> **Note:** GitLab administrators/users should consider working through these
+debug steps with GitLab Support so the backtraces can be analyzed by our team.
+It may reveal a bug or necessary improvement in GitLab.
+
+> **Note:** In any of the backtraces, be weary of suspecting cases where every
+  thread appears to be waiting in the database, Redis, or waiting to acquire
+  a mutex. This **may** mean there's contention in the database, for example,
+  but look for one thread that is different than the rest. This other thread
+  may be using all available CPU, or have a Ruby Global Interpreter Lock,
+  preventing other threads from continuing.
+
+## Thread dump
+
+Send the Sidekiq process ID the `TTIN` signal and it will output thread
+backtraces in the log file.
+
+```
+kill -TTIN <sidekiq_pid>
+```
+
+Check in `/var/log/gitlab/sidekiq/current` or `$GITLAB_HOME/log/sidekiq.log` for
+the backtrace output. The backtraces will be lengthy and generally start with
+several `WARN` level messages. Here's an example of a single thread's backtrace:
+
+```
+2016-04-13T06:21:20.022Z 31517 TID-orn4urby0 WARN: ActiveRecord::RecordNotFound: Couldn't find Note with 'id'=3375386
+2016-04-13T06:21:20.022Z 31517 TID-orn4urby0 WARN: /opt/gitlab/embedded/service/gem/ruby/2.1.0/gems/activerecord-4.2.5.2/lib/active_record/core.rb:155:in `find'
+/opt/gitlab/embedded/service/gitlab-rails/app/workers/new_note_worker.rb:7:in `perform'
+/opt/gitlab/embedded/service/gem/ruby/2.1.0/gems/sidekiq-4.0.1/lib/sidekiq/processor.rb:150:in `execute_job'
+/opt/gitlab/embedded/service/gem/ruby/2.1.0/gems/sidekiq-4.0.1/lib/sidekiq/processor.rb:132:in `block (2 levels) in process'
+/opt/gitlab/embedded/service/gem/ruby/2.1.0/gems/sidekiq-4.0.1/lib/sidekiq/middleware/chain.rb:127:in `block in invoke'
+/opt/gitlab/embedded/service/gitlab-rails/lib/gitlab/sidekiq_middleware/memory_killer.rb:17:in `call'
+/opt/gitlab/embedded/service/gem/ruby/2.1.0/gems/sidekiq-4.0.1/lib/sidekiq/middleware/chain.rb:129:in `block in invoke'
+/opt/gitlab/embedded/service/gitlab-rails/lib/gitlab/sidekiq_middleware/arguments_logger.rb:6:in `call'
+...
+```
+
+In some cases Sidekiq may be hung and unable to respond to the `TTIN` signal.
+Move on to other troubleshooting methods if this happens.
+
+## Process profiling with `perf`
+
+Linux has a process profiling tool called `perf` that is helpful when a certain
+process is eating up a lot of CPU. If you see high CPU usage and Sidekiq won't
+respond to the `TTIN` signal, this is a good next step.
+
+If `perf` is not installed on your system, install it with `apt-get` or `yum`:
+
+```
+# Debian
+sudo apt-get install linux-tools
+
+# Ubuntu (may require these additional Kernel packages)
+sudo apt-get install linux-tools-common linux-tools-generic linux-tools-`uname -r`
+
+# Red Hat/CentOS
+sudo yum install perf
+```
+
+Run perf against the Sidekiq PID:
+
+```
+sudo perf record -p <sidekiq_pid>
+```
+
+Let this run for 30-60 seconds and then press Ctrl-C. Then view the perf report:
+
+```
+sudo perf report
+
+# Sample output
+Samples: 348K of event 'cycles', Event count (approx.): 280908431073
+ 97.69%            ruby  nokogiri.so         [.] xmlXPathNodeSetMergeAndClear
+  0.18%            ruby  libruby.so.2.1.0    [.] objspace_malloc_increase
+  0.12%            ruby  libc-2.12.so        [.] _int_malloc
+  0.10%            ruby  libc-2.12.so        [.] _int_free
+```
+
+Above you see sample output from a perf report. It shows that 97% of the CPU is
+being spent inside Nokogiri and `xmlXPathNodeSetMergeAndClear`. For something
+this obvious you should then go investigate what job in GitLab would use
+Nokogiri and XPath. Combine with `TTIN` or `gdb` output to show the
+corresponding Ruby code where this is happening.
+
+## The GNU Project Debugger (gdb)
+
+`gdb` can be another effective tool for debugging Sidekiq. It gives you a little
+more interactive way to look at each thread and see what's causing problems.
+
+> **Note:** Attaching to a process with `gdb` will suspends the normal operation
+  of the process (Sidekiq will not process jobs while `gdb` is attached).
+
+Start by attaching to the Sidekiq PID:
+
+```
+gdb -p <sidekiq_pid>
+```
+
+Then gather information on all the threads:
+
+```
+info threads
+
+# Example output
+30 Thread 0x7fe5fbd63700 (LWP 26060) 0x0000003f7cadf113 in poll () from /lib64/libc.so.6
+29 Thread 0x7fe5f2b3b700 (LWP 26533) 0x0000003f7ce0b68c in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
+28 Thread 0x7fe5f2a3a700 (LWP 26534) 0x0000003f7ce0ba5e in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
+27 Thread 0x7fe5f2939700 (LWP 26535) 0x0000003f7ce0b68c in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
+26 Thread 0x7fe5f2838700 (LWP 26537) 0x0000003f7ce0b68c in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
+25 Thread 0x7fe5f2737700 (LWP 26538) 0x0000003f7ce0b68c in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
+24 Thread 0x7fe5f2535700 (LWP 26540) 0x0000003f7ce0b68c in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
+23 Thread 0x7fe5f2434700 (LWP 26541) 0x0000003f7ce0b68c in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
+22 Thread 0x7fe5f2232700 (LWP 26543) 0x0000003f7ce0b68c in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
+21 Thread 0x7fe5f2131700 (LWP 26544) 0x00007fe5f7b570f0 in xmlXPathNodeSetMergeAndClear ()
+from /opt/gitlab/embedded/service/gem/ruby/2.1.0/gems/nokogiri-1.6.7.2/lib/nokogiri/nokogiri.so
+...
+```
+
+If you see a suspicious thread, like the Nokogiri one above, you may want
+to get more information:
+
+```
+thread 21
+bt
+
+# Example output
+#0  0x00007ff0d6afe111 in xmlXPathNodeSetMergeAndClear () from /opt/gitlab/embedded/service/gem/ruby/2.1.0/gems/nokogiri-1.6.7.2/lib/nokogiri/nokogiri.so
+#1  0x00007ff0d6b0b836 in xmlXPathNodeCollectAndTest () from /opt/gitlab/embedded/service/gem/ruby/2.1.0/gems/nokogiri-1.6.7.2/lib/nokogiri/nokogiri.so
+#2  0x00007ff0d6b09037 in xmlXPathCompOpEval () from /opt/gitlab/embedded/service/gem/ruby/2.1.0/gems/nokogiri-1.6.7.2/lib/nokogiri/nokogiri.so
+#3  0x00007ff0d6b09017 in xmlXPathCompOpEval () from /opt/gitlab/embedded/service/gem/ruby/2.1.0/gems/nokogiri-1.6.7.2/lib/nokogiri/nokogiri.so
+#4  0x00007ff0d6b092e0 in xmlXPathCompOpEval () from /opt/gitlab/embedded/service/gem/ruby/2.1.0/gems/nokogiri-1.6.7.2/lib/nokogiri/nokogiri.so
+#5  0x00007ff0d6b0bc37 in xmlXPathRunEval () from /opt/gitlab/embedded/service/gem/ruby/2.1.0/gems/nokogiri-1.6.7.2/lib/nokogiri/nokogiri.so
+#6  0x00007ff0d6b0be5f in xmlXPathEvalExpression () from /opt/gitlab/embedded/service/gem/ruby/2.1.0/gems/nokogiri-1.6.7.2/lib/nokogiri/nokogiri.so
+#7  0x00007ff0d6a97dc3 in evaluate (argc=2, argv=0x1022d058, self=<value optimized out>) at xml_xpath_context.c:221
+#8  0x00007ff0daeab0ea in vm_call_cfunc_with_frame (th=0x1022a4f0, reg_cfp=0x1032b810, ci=<value optimized out>) at vm_insnhelper.c:1510
+```
+
+To output a backtrace from all threads at once:
+
+```
+apply all thread bt
+```
+
+## Check for blocking queries
+
+Sometimes the speed at which Sidekiq processes jobs can be so fast that it can
+cause database contention. Check for blocking queries when backtraces above
+show that many threads are stuck in the database adapter.
+
+The PostgreSQL wiki has details on the query you can run to see blocking
+queries. The query is different based on PostgreSQL version. See
+[Lock Monitoring](https://wiki.postgresql.org/wiki/Lock_Monitoring) for
+the query details.
diff --git a/doc/downgrade_ee_to_ce/README.md b/doc/downgrade_ee_to_ce/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..3625c4191b8283c47bd02cb58ab4fe78d1f1ebd5
--- /dev/null
+++ b/doc/downgrade_ee_to_ce/README.md
@@ -0,0 +1,82 @@
+# Downgrading from EE to CE
+
+If you ever decide to downgrade your Enterprise Edition back to the Community
+Edition, there are a few steps you need take before installing the CE package
+on top of the current EE package, or, if you are in an installation from source,
+before you change remotes and fetch the latest CE code.
+
+## Disable Enterprise-only features
+
+First thing to do is to disable the following features.
+
+### Authentication mechanisms
+
+Kerberos and Atlassian Crowd are only available on the Enterprise Edition, so
+you should disable these mechanisms before downgrading and you should provide
+alternative authentication methods to your users.
+
+### Git Annex
+
+Git Annex is also only available on the Enterprise Edition. This means that if
+you have repositories that use Git Annex to store large files, these files will
+no longer be easily available via Git. You should consider migrating these
+repositories to use Git LFS before downgrading to the Community Edition.
+
+### Remove Jenkins CI Service entries from the database
+
+The `JenkinsService` class is only available on the Enterprise Edition codebase,
+so if you downgrade to the Community Edition, you'll come across the following
+error:
+
+```
+Completed 500 Internal Server Error in 497ms (ActiveRecord: 32.2ms)
+
+ActionView::Template::Error (The single-table inheritance mechanism failed to locate the subclass: 'JenkinsService'. This
+error is raised because the column 'type' is reserved for storing the class in case of inheritance. Please rename this
+column if you didn't intend it to be used for storing the inheritance class or overwrite Service.inheritance_column to
+use another column for that information.)
+```
+
+All services are created automatically for every project you have, so in order
+to avoid getting this error, you need to remove all instances of the
+`JenkinsService` from your database:
+
+**Omnibus Installation**
+
+```
+$ sudo gitlab-rails runner "Service.where(type: 'JenkinsService').delete_all"
+```
+
+**Source Installation**
+
+```
+$ bundle exec rails runner "Service.where(type: 'JenkinsService').delete_all" production
+```
+
+## Downgrade to CE
+
+After performing the above mentioned steps, you are now ready to downgrade your
+GitLab installation to the Community Edition.
+
+**Omnibus Installation**
+
+To downgrade an Omnibus installation, it is sufficient to install the Community
+Edition package on top of the currently installed one. You can do this manually,
+by directly [downloading the package](https://packages.gitlab.com/gitlab/gitlab-ce)
+you need, or by adding our CE package repository and following the
+[CE installation instructions](https://about.gitlab.com/downloads/).
+
+**Source Installation**
+
+To downgrade a source installation, you need to replace the current remote of
+your GitLab installation with the Community Edition's remote, fetch the latest
+changes, and checkout the latest stable branch:
+
+```
+$ git remote set-url origin git@gitlab.com:gitlab-org/gitlab-ce.git
+$ git fetch --all
+$ git checkout 8-x-stable
+```
+
+Remember to follow the correct [update guides](../update/README.md) to make
+sure all dependencies are up to date.
diff --git a/doc/monitoring/performance/grafana_configuration.md b/doc/monitoring/performance/grafana_configuration.md
index a79c8d48d3b825f2ea43548fa2cfffbb4ba85647..168bd85c26a697f714161096c61de9bbfd5fca1d 100644
--- a/doc/monitoring/performance/grafana_configuration.md
+++ b/doc/monitoring/performance/grafana_configuration.md
@@ -59,34 +59,53 @@ This will drop you in to an InfluxDB interactive session. Copy the entire
 contents below and paste it in to the interactive session:
 
 ```
-CREATE RETENTION POLICY gitlab_30d ON gitlab DURATION 30d REPLICATION 1 DEFAULT
-CREATE RETENTION POLICY seven_days ON gitlab DURATION 7d REPLICATION 1
-CREATE CONTINUOUS QUERY rails_transaction_counts_seven_days ON gitlab BEGIN SELECT count("duration") AS "count" INTO gitlab.seven_days.rails_transaction_counts FROM rails_transactions GROUP BY time(1m) END;
-CREATE CONTINUOUS QUERY sidekiq_transaction_counts_seven_days ON gitlab BEGIN SELECT count("duration") AS "count" INTO gitlab.seven_days.sidekiq_transaction_counts FROM sidekiq_transactions GROUP BY time(1m) END;
-CREATE CONTINUOUS QUERY rails_method_call_timings_seven_days ON gitlab BEGIN SELECT percentile("duration", 95.000) AS "duration_95th", percentile("duration", 99.000) AS "duration_99th", mean("duration") AS "duration_mean" INTO gitlab.seven_days.rails_method_call_timings FROM rails_method_calls GROUP BY time(1m) END;
-CREATE CONTINUOUS QUERY sidekiq_method_call_timings_seven_days ON gitlab BEGIN SELECT percentile("duration", 95.000) AS "duration_95th", percentile("duration", 99.000) AS "duration_99th", mean("duration") AS "duration_mean" INTO gitlab.seven_days.sidekiq_method_call_timings FROM sidekiq_method_calls GROUP BY time(1m) END;
-CREATE CONTINUOUS QUERY rails_method_call_timings_per_method_seven_days ON gitlab BEGIN SELECT percentile("duration", 95.000) AS duration_95th, percentile("duration", 99.000) AS duration_99th, mean("duration") AS duration_mean INTO gitlab.seven_days.rails_method_call_timings_per_method FROM rails_method_calls GROUP BY time(1m), method END;
-CREATE CONTINUOUS QUERY sidekiq_method_call_timings_per_method_seven_days ON gitlab BEGIN SELECT percentile("duration", 95.000) AS duration_95th, percentile("duration", 99.000) AS duration_99th, mean("duration") AS duration_mean INTO gitlab.seven_days.sidekiq_method_call_timings_per_method FROM sidekiq_method_calls GROUP BY time(1m), method END;
-CREATE CONTINUOUS QUERY rails_memory_usage_per_minute ON gitlab BEGIN SELECT percentile(value, 95.000) AS memory_95th, percentile(value, 99.000) AS memory_99th, mean(value) AS memory_mean INTO gitlab.seven_days.rails_memory_usage_per_minute FROM rails_memory_usage GROUP BY time(1m) END;
-CREATE CONTINUOUS QUERY sidekiq_memory_usage_per_minute ON gitlab BEGIN SELECT percentile(value, 95.000) AS memory_95th, percentile(value, 99.000) AS memory_99th, mean(value) AS memory_mean INTO gitlab.seven_days.sidekiq_memory_usage_per_minute FROM sidekiq_memory_usage GROUP BY time(1m) END;
-CREATE CONTINUOUS QUERY sidekiq_file_descriptors_per_minute ON gitlab BEGIN SELECT sum(value) AS value INTO gitlab.seven_days.sidekiq_file_descriptors_per_minute FROM sidekiq_file_descriptors GROUP BY time(1m) END;
-CREATE CONTINUOUS QUERY rails_file_descriptors_per_minute ON gitlab BEGIN SELECT sum(value) AS value INTO gitlab.seven_days.rails_file_descriptors_per_minute FROM rails_file_descriptors GROUP BY time(1m) END;
-CREATE CONTINUOUS QUERY rails_gc_counts_per_minute ON gitlab BEGIN SELECT sum(count) AS count INTO gitlab.seven_days.rails_gc_counts_per_minute FROM rails_gc_statistics GROUP BY time(1m) END;
-CREATE CONTINUOUS QUERY sidekiq_gc_counts_per_minute ON gitlab BEGIN SELECT sum(count) AS count INTO gitlab.seven_days.sidekiq_gc_counts_per_minute FROM sidekiq_gc_statistics GROUP BY time(1m) END;
-CREATE CONTINUOUS QUERY rails_gc_timings_per_minute ON gitlab BEGIN SELECT percentile(total_time, 95.000) AS duration_95th, percentile(total_time, 99.000) AS duration_99th, mean(total_time) AS duration_mean INTO gitlab.seven_days.rails_gc_timings_per_minute FROM rails_gc_statistics GROUP BY time(1m) END;
-CREATE CONTINUOUS QUERY sidekiq_gc_timings_per_minute ON gitlab BEGIN SELECT percentile(total_time, 95.000) AS duration_95th, percentile(total_time, 99.000) AS duration_99th, mean(total_time) AS duration_mean INTO gitlab.seven_days.sidekiq_gc_timings_per_minute FROM sidekiq_gc_statistics GROUP BY time(1m) END;
-CREATE CONTINUOUS QUERY rails_gc_major_minor_per_minute ON gitlab BEGIN SELECT sum(major_gc_count) AS major, sum(minor_gc_count) AS minor INTO gitlab.seven_days.rails_gc_major_minor_per_minute FROM rails_gc_statistics GROUP BY time(1m) END;
-CREATE CONTINUOUS QUERY sidekiq_gc_major_minor_per_minute ON gitlab BEGIN SELECT sum(major_gc_count) AS major, sum(minor_gc_count) AS minor INTO gitlab.seven_days.sidekiq_gc_major_minor_per_minute FROM sidekiq_gc_statistics GROUP BY time(1m) END;
-CREATE CONTINUOUS QUERY grape_internal_allowed_request_counts_per_minute ON gitlab BEGIN SELECT count("duration") AS count INTO gitlab.seven_days.grape_internal_allowed_request_counts_per_minute FROM rails_transactions WHERE request_uri = '/api/v3/internal/allowed' GROUP BY time(1m) END;
-CREATE CONTINUOUS QUERY grape_internal_allowed_request_timings_per_minute ON gitlab BEGIN SELECT percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th, mean("duration") AS duration_mean INTO gitlab.seven_days.grape_internal_allowed_request_timings_per_minute FROM rails_transactions WHERE request_uri = '/api/v3/internal/allowed' GROUP BY time(1m) END;
-CREATE CONTINUOUS QUERY grape_internal_allowed_sql_timings_per_minute ON gitlab BEGIN SELECT percentile(sql_duration, 95) AS duration_95th, percentile(sql_duration, 99) AS duration_99th, mean(sql_duration) AS duration_mean INTO gitlab.seven_days.grape_internal_allowed_sql_timings_per_minute FROM rails_transactions WHERE request_uri = '/api/v3/internal/allowed' GROUP BY time(1m) END;
-CREATE CONTINUOUS QUERY grape_internal_authorized_keys_request_counts_per_minute ON gitlab BEGIN SELECT count("duration") AS count INTO gitlab.seven_days.grape_internal_authorized_keys_request_counts_per_minute FROM rails_transactions WHERE request_uri = '/api/v3/internal/authorized_keys' GROUP BY time(1m) END;
-CREATE CONTINUOUS QUERY grape_internal_authorized_keys_request_timings_per_minute ON gitlab BEGIN SELECT percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th, mean("duration") AS duration_mean INTO gitlab.seven_days.grape_internal_authorized_keys_request_timings_per_minute FROM rails_transactions WHERE request_uri = '/api/v3/internal/authorized_keys' GROUP BY time(1m) END;
-CREATE CONTINUOUS QUERY grape_internal_authorized_keys_sql_timings_per_minute ON gitlab BEGIN SELECT percentile(sql_duration, 95) AS duration_95th, percentile(sql_duration, 99) AS duration_99th, mean(sql_duration) AS duration_mean INTO gitlab.seven_days.grape_internal_authorized_keys_sql_timings_per_minute FROM rails_transactions WHERE request_uri = '/api/v3/internal/authorized_keys' GROUP BY time(1m) END;
-CREATE CONTINUOUS QUERY rails_transaction_timings_seven_days ON gitlab BEGIN SELECT percentile("duration", 95.000) AS duration_95th, percentile("duration", 99.000) AS duration_99th, mean("duration") AS duration_mean, percentile(sql_duration, 95.000) AS sql_duration_95th, percentile(sql_duration, 99.000) AS sql_duration_99th, mean(sql_duration) AS sql_duration_mean, percentile(view_duration, 95.000) AS view_duration_95th, percentile(view_duration, 99.000) AS view_duration_99th, mean(view_duration) AS view_duration_mean, percentile(cache_read_duration, 99) AS cache_read_duration_99th, percentile(cache_read_duration, 95) AS cache_read_duration_95th, mean(cache_read_duration) AS cache_read_duration_mean, percentile(cache_write_duration, 99) AS cache_write_duration_99th, percentile(cache_write_duration, 95) AS cache_write_duration_95th, mean(cache_write_duration) AS cache_write_duration_mean, percentile(cache_delete_duration, 99) AS cache_delete_duration_99th, percentile(cache_delete_duration, 95) AS cache_delete_duration_95th, mean(cache_delete_duration) AS cache_delete_duration_mean, percentile(cache_exists_duration, 99) AS cache_exists_duration_99th, percentile(cache_exists_duration, 95) AS cache_exists_duration_95th, mean(cache_exists_duration) AS cache_exists_duration_mean, percentile(cache_duration, 99) AS cache_duration_99th, percentile(cache_duration, 95) AS cache_duration_95th, mean(cache_duration) AS cache_duration_mean INTO gitlab.seven_days.rails_transaction_timings FROM rails_transactions GROUP BY time(1m) END;
-CREATE CONTINUOUS QUERY sidekiq_transaction_timings_seven_days ON gitlab BEGIN SELECT percentile("duration", 95.000) AS duration_95th, percentile("duration", 99.000) AS duration_99th, mean("duration") AS duration_mean, percentile(sql_duration, 95.000) AS sql_duration_95th, percentile(sql_duration, 99.000) AS sql_duration_99th, mean(sql_duration) AS sql_duration_mean, percentile(view_duration, 95.000) AS view_duration_95th, percentile(view_duration, 99.000) AS view_duration_99th, mean(view_duration) AS view_duration_mean, percentile(cache_read_duration, 99) AS cache_read_duration_99th, percentile(cache_read_duration, 95) AS cache_read_duration_95th, mean(cache_read_duration) AS cache_read_duration_mean, percentile(cache_write_duration, 99) AS cache_write_duration_99th, percentile(cache_write_duration, 95) AS cache_write_duration_95th, mean(cache_write_duration) AS cache_write_duration_mean, percentile(cache_delete_duration, 99) AS cache_delete_duration_99th, percentile(cache_delete_duration, 95) AS cache_delete_duration_95th, mean(cache_delete_duration) AS cache_delete_duration_mean, percentile(cache_exists_duration, 99) AS cache_exists_duration_99th, percentile(cache_exists_duration, 95) AS cache_exists_duration_95th, mean(cache_exists_duration) AS cache_exists_duration_mean, percentile(cache_duration, 99) AS cache_duration_99th, percentile(cache_duration, 95) AS cache_duration_95th, mean(cache_duration) AS cache_duration_mean INTO gitlab.seven_days.sidekiq_transaction_timings FROM sidekiq_transactions GROUP BY time(1m) END;
-CREATE CONTINUOUS QUERY grape_transaction_counts_seven_days ON gitlab BEGIN SELECT count("duration") AS count INTO gitlab.seven_days.grape_transaction_counts FROM rails_transactions WHERE action !~ /.+/ GROUP BY time(1m) END;
-CREATE CONTINUOUS QUERY grape_transaction_timings_seven_days ON gitlab BEGIN SELECT percentile("duration", 95.000) AS duration_95th, percentile("duration", 99.000) AS duration_99th, mean("duration") AS duration_mean, percentile(sql_duration, 95.000) AS sql_duration_95th, percentile(sql_duration, 99.000) AS sql_duration_99th, mean(sql_duration) AS sql_duration_mean, percentile(cache_read_duration, 99) AS cache_read_duration_99th, percentile(cache_read_duration, 95) AS cache_read_duration_95th, mean(cache_read_duration) AS cache_read_duration_mean, percentile(cache_write_duration, 99) AS cache_write_duration_99th, percentile(cache_write_duration, 95) AS cache_write_duration_95th, mean(cache_write_duration) AS cache_write_duration_mean, percentile(cache_delete_duration, 99) AS cache_delete_duration_99th, percentile(cache_delete_duration, 95) AS cache_delete_duration_95th, mean(cache_delete_duration) AS cache_delete_duration_mean, percentile(cache_exists_duration, 99) AS cache_exists_duration_99th, percentile(cache_exists_duration, 95) AS cache_exists_duration_95th, mean(cache_exists_duration) AS cache_exists_duration_mean, percentile(cache_duration, 99) AS cache_duration_99th, percentile(cache_duration, 95) AS cache_duration_95th, mean(cache_duration) AS cache_duration_mean INTO gitlab.seven_days.grape_transaction_timings FROM rails_transactions WHERE action !~ /.+/ GROUP BY time(1m) END;
+CREATE RETENTION POLICY default ON gitlab DURATION 1h REPLICATION 1 DEFAULT
+CREATE RETENTION POLICY downsampled ON gitlab DURATION 7d REPLICATION 1
+CREATE CONTINUOUS QUERY grape_git_timings_per_action ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th INTO gitlab.downsampled.grape_git_timings_per_action FROM gitlab."default".rails_method_calls WHERE (action !~ /.+/ OR action =~ /^Grape#/) AND method =~ /^(Rugged|Gitlab::Git)/ GROUP BY time(1m), action END;
+CREATE CONTINUOUS QUERY grape_markdown_render_timings_overall ON gitlab BEGIN SELECT mean(banzai_cached_render_real_time) AS cached_real_mean, percentile(banzai_cached_render_real_time, 95) AS cached_real_95th, percentile(banzai_cached_render_real_time, 99) AS cached_real_99th, mean(banzai_cached_render_cpu_time) AS cached_cpu_mean, percentile(banzai_cached_render_cpu_time, 95) AS cached_cpu_95th, percentile(banzai_cached_render_cpu_time, 99) AS cached_cpu_99th, sum(banzai_cached_render_call_count) AS cached_call_count, mean(banzai_cacheless_render_real_time) AS cacheless_real_mean, percentile(banzai_cacheless_render_real_time, 95) AS cacheless_real_95th, percentile(banzai_cacheless_render_real_time, 99) AS cacheless_real_99th, mean(banzai_cacheless_render_cpu_time) AS cacheless_cpu_mean, percentile(banzai_cacheless_render_cpu_time, 95) AS cacheless_cpu_95th, percentile(banzai_cacheless_render_cpu_time, 99) AS cacheless_cpu_99th, sum(banzai_cacheless_render_call_count) AS cacheless_call_count INTO gitlab.downsampled.grape_markdown_render_timings_overall FROM gitlab."default".rails_transactions WHERE (action !~ /.+/ OR action =~ /^Grape#/) AND (banzai_cached_render_call_count > 0 OR banzai_cacheless_render_call_count > 0) GROUP BY time(1m) END;
+CREATE CONTINUOUS QUERY grape_markdown_render_timings_per_action ON gitlab BEGIN SELECT mean(banzai_cached_render_real_time) AS cached_real_mean, percentile(banzai_cached_render_real_time, 95) AS cached_real_95th, percentile(banzai_cached_render_real_time, 99) AS cached_real_99th, mean(banzai_cached_render_cpu_time) AS cached_cpu_mean, percentile(banzai_cached_render_cpu_time, 95) AS cached_cpu_95th, percentile(banzai_cached_render_cpu_time, 99) AS cached_cpu_99th, sum(banzai_cached_render_call_count) AS cached_call_count, mean(banzai_cacheless_render_real_time) AS cacheless_real_mean, percentile(banzai_cacheless_render_real_time, 95) AS cacheless_real_95th, percentile(banzai_cacheless_render_real_time, 99) AS cacheless_real_99th, mean(banzai_cacheless_render_cpu_time) AS cacheless_cpu_mean, percentile(banzai_cacheless_render_cpu_time, 95) AS cacheless_cpu_95th, percentile(banzai_cacheless_render_cpu_time, 99) AS cacheless_cpu_99th, sum(banzai_cacheless_render_call_count) AS cacheless_call_count INTO gitlab.downsampled.grape_markdown_render_timings_per_action FROM gitlab."default".rails_transactions WHERE (action !~ /.+/ OR action =~ /^Grape#/) AND (banzai_cached_render_call_count > 0 OR banzai_cacheless_render_call_count > 0) GROUP BY time(1m), action END;
+CREATE CONTINUOUS QUERY grape_markdown_timings_overall ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th INTO gitlab.downsampled.grape_markdown_timings_overall FROM gitlab."default".rails_method_calls WHERE (action !~ /.+/ OR action =~ /^Grape#/) AND method =~ /^Banzai/ GROUP BY time(1m) END;
+CREATE CONTINUOUS QUERY grape_method_call_timings_per_action_and_method ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th INTO gitlab.downsampled.grape_method_call_timings_per_action_and_method FROM gitlab."default".rails_method_calls WHERE action !~ /.+/ OR action =~ /^Grape#/ GROUP BY time(1m), method, action END;
+CREATE CONTINUOUS QUERY grape_method_call_timings_per_method ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th INTO gitlab.downsampled.grape_method_call_timings_per_method FROM gitlab."default".rails_method_calls WHERE action !~ /.+/ OR action =~ /^Grape#/ GROUP BY time(1m), method END;
+CREATE CONTINUOUS QUERY grape_transaction_counts_overall ON gitlab BEGIN SELECT count("duration") AS count INTO gitlab.downsampled.grape_transaction_counts_overall FROM gitlab."default".rails_transactions WHERE action !~ /.+/ OR action =~ /^Grape#/ GROUP BY time(1m) END;
+CREATE CONTINUOUS QUERY grape_transaction_counts_per_action ON gitlab BEGIN SELECT count("duration") AS count INTO gitlab.downsampled.grape_transaction_counts_per_action FROM gitlab."default".rails_transactions WHERE action !~ /.+/ OR action =~ /^Grape#/ GROUP BY time(1m), action END;
+CREATE CONTINUOUS QUERY grape_transaction_timings_overall ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th, mean(sql_duration) AS sql_duration_mean, percentile(sql_duration, 95) AS sql_duration_95th, percentile(sql_duration, 99) AS sql_duration_99th, mean(view_duration) AS view_duration_mean, percentile(view_duration, 95) AS view_duration_95th, percentile(view_duration, 99) AS view_duration_99th, mean(cache_read_duration) AS cache_read_duration_mean, percentile(cache_read_duration, 99) AS cache_read_duration_99th, percentile(cache_read_duration, 95) AS cache_read_duration_95th, mean(cache_write_duration) AS cache_write_duration_mean, percentile(cache_write_duration, 99) AS cache_write_duration_99th, percentile(cache_write_duration, 95) AS cache_write_duration_95th, mean(cache_delete_duration) AS cache_delete_duration_mean, percentile(cache_delete_duration, 99) AS cache_delete_duration_99th, percentile(cache_delete_duration, 95) AS cache_delete_duration_95th, mean(cache_exists_duration) AS cache_exists_duration_mean, percentile(cache_exists_duration, 99) AS cache_exists_duration_99th, percentile(cache_exists_duration, 95) AS cache_exists_duration_95th, mean(cache_duration) AS cache_duration_mean, percentile(cache_duration, 99) AS cache_duration_99th, percentile(cache_duration, 95) AS cache_duration_95th, mean(method_duration) AS method_duration_mean, percentile(method_duration, 99) AS method_duration_99th, percentile(method_duration, 95) AS method_duration_95th INTO gitlab.downsampled.grape_transaction_timings_overall FROM gitlab."default".rails_transactions WHERE action !~ /.+/ OR action =~ /^Grape#/ GROUP BY time(1m) END;
+CREATE CONTINUOUS QUERY grape_transaction_timings_per_action ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th, mean(sql_duration) AS sql_duration_mean, percentile(sql_duration, 95) AS sql_duration_95th, percentile(sql_duration, 99) AS sql_duration_99th, mean(view_duration) AS view_duration_mean, percentile(view_duration, 95) AS view_duration_95th, percentile(view_duration, 99) AS view_duration_99th, mean(cache_read_duration) AS cache_read_duration_mean, percentile(cache_read_duration, 99) AS cache_read_duration_99th, percentile(cache_read_duration, 95) AS cache_read_duration_95th, mean(cache_write_duration) AS cache_write_duration_mean, percentile(cache_write_duration, 99) AS cache_write_duration_99th, percentile(cache_write_duration, 95) AS cache_write_duration_95th, mean(cache_delete_duration) AS cache_delete_duration_mean, percentile(cache_delete_duration, 99) AS cache_delete_duration_99th, percentile(cache_delete_duration, 95) AS cache_delete_duration_95th, mean(cache_exists_duration) AS cache_exists_duration_mean, percentile(cache_exists_duration, 99) AS cache_exists_duration_99th, percentile(cache_exists_duration, 95) AS cache_exists_duration_95th, mean(cache_duration) AS cache_duration_mean, percentile(cache_duration, 99) AS cache_duration_99th, percentile(cache_duration, 95) AS cache_duration_95th, mean(method_duration) AS method_duration_mean, percentile(method_duration, 99) AS method_duration_99th, percentile(method_duration, 95) AS method_duration_95th INTO gitlab.downsampled.grape_transaction_timings_per_action FROM gitlab."default".rails_transactions WHERE action !~ /.+/ OR action =~ /^Grape#/ GROUP BY time(1m), action END;
+CREATE CONTINUOUS QUERY rails_file_descriptor_counts ON gitlab BEGIN SELECT sum(value) AS count INTO gitlab.downsampled.rails_file_descriptor_counts FROM gitlab."default".rails_file_descriptors GROUP BY time(1m) END;
+CREATE CONTINUOUS QUERY rails_gc_counts ON gitlab BEGIN SELECT sum(count) AS total, sum(minor_gc_count) AS minor, sum(major_gc_count) AS major INTO gitlab.downsampled.rails_gc_counts FROM gitlab."default".rails_gc_statistics GROUP BY time(1m) END;
+CREATE CONTINUOUS QUERY rails_gc_timings ON gitlab BEGIN SELECT mean(total_time) AS duration_mean, percentile(total_time, 95) AS duration_95th, percentile(total_time, 99) AS duration_99th INTO gitlab.downsampled.rails_gc_timings FROM gitlab."default".rails_gc_statistics GROUP BY time(1m) END;
+CREATE CONTINUOUS QUERY rails_git_timings_per_action ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th INTO gitlab.downsampled.rails_git_timings_per_action FROM gitlab."default".rails_method_calls WHERE (action =~ /.+/ AND action !~ /^Grape#/) AND method =~ /^(Rugged|Gitlab::Git)/ GROUP BY time(1m), action END;
+CREATE CONTINUOUS QUERY rails_markdown_render_timings_overall ON gitlab BEGIN SELECT mean(banzai_cached_render_real_time) AS cached_real_mean, percentile(banzai_cached_render_real_time, 95) AS cached_real_95th, percentile(banzai_cached_render_real_time, 99) AS cached_real_99th, mean(banzai_cached_render_cpu_time) AS cached_cpu_mean, percentile(banzai_cached_render_cpu_time, 95) AS cached_cpu_95th, percentile(banzai_cached_render_cpu_time, 99) AS cached_cpu_99th, sum(banzai_cached_render_call_count) AS cached_call_count, mean(banzai_cacheless_render_real_time) AS cacheless_real_mean, percentile(banzai_cacheless_render_real_time, 95) AS cacheless_real_95th, percentile(banzai_cacheless_render_real_time, 99) AS cacheless_real_99th, mean(banzai_cacheless_render_cpu_time) AS cacheless_cpu_mean, percentile(banzai_cacheless_render_cpu_time, 95) AS cacheless_cpu_95th, percentile(banzai_cacheless_render_cpu_time, 99) AS cacheless_cpu_99th, sum(banzai_cacheless_render_call_count) AS cacheless_call_count INTO gitlab.downsampled.rails_markdown_render_timings_overall FROM gitlab."default".rails_transactions WHERE (action =~ /.+/ AND action !~ /^Grape#/) AND (banzai_cached_render_call_count > 0 OR banzai_cacheless_render_call_count > 0) GROUP BY time(1m) END;
+CREATE CONTINUOUS QUERY rails_markdown_render_timings_per_action ON gitlab BEGIN SELECT mean(banzai_cached_render_real_time) AS cached_real_mean, percentile(banzai_cached_render_real_time, 95) AS cached_real_95th, percentile(banzai_cached_render_real_time, 99) AS cached_real_99th, mean(banzai_cached_render_cpu_time) AS cached_cpu_mean, percentile(banzai_cached_render_cpu_time, 95) AS cached_cpu_95th, percentile(banzai_cached_render_cpu_time, 99) AS cached_cpu_99th, sum(banzai_cached_render_call_count) AS cached_call_count, mean(banzai_cacheless_render_real_time) AS cacheless_real_mean, percentile(banzai_cacheless_render_real_time, 95) AS cacheless_real_95th, percentile(banzai_cacheless_render_real_time, 99) AS cacheless_real_99th, mean(banzai_cacheless_render_cpu_time) AS cacheless_cpu_mean, percentile(banzai_cacheless_render_cpu_time, 95) AS cacheless_cpu_95th, percentile(banzai_cacheless_render_cpu_time, 99) AS cacheless_cpu_99th, sum(banzai_cacheless_render_call_count) AS cacheless_call_count INTO gitlab.downsampled.rails_markdown_render_timings_per_action FROM gitlab."default".rails_transactions WHERE (action =~ /.+/ AND action !~ /^Grape#/) AND (banzai_cached_render_call_count > 0 OR banzai_cacheless_render_call_count > 0) GROUP BY time(1m), action END;
+CREATE CONTINUOUS QUERY rails_markdown_timings_overall ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th INTO gitlab.downsampled.rails_markdown_timings_overall FROM gitlab."default".rails_method_calls WHERE (action =~ /.+/ AND action !~ /^Grape#/) AND method =~ /^Banzai/ GROUP BY time(1m) END;
+CREATE CONTINUOUS QUERY rails_memory_usage_overall ON gitlab BEGIN SELECT mean(value) AS memory_mean, percentile(value, 95) AS memory_95th, percentile(value, 99) AS memory_99th INTO gitlab.downsampled.rails_memory_usage_overall FROM gitlab."default".rails_memory_usage GROUP BY time(1m) END;
+CREATE CONTINUOUS QUERY rails_method_call_timings_per_action_and_method ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th INTO gitlab.downsampled.rails_method_call_timings_per_action_and_method FROM gitlab."default".rails_method_calls WHERE action =~ /.+/ AND action !~ /^Grape#/ GROUP BY time(1m), method, action END;
+CREATE CONTINUOUS QUERY rails_method_call_timings_per_method ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th INTO gitlab.downsampled.rails_method_call_timings_per_method FROM gitlab."default".rails_method_calls WHERE action =~ /.+/ AND action !~ /^Grape#/ GROUP BY time(1m), method END;
+CREATE CONTINUOUS QUERY rails_object_counts_overall ON gitlab BEGIN SELECT sum(count) AS count INTO gitlab.downsampled.rails_object_counts_overall FROM gitlab."default".rails_object_counts GROUP BY time(1m) END;
+CREATE CONTINUOUS QUERY rails_object_counts_per_type ON gitlab BEGIN SELECT sum(count) AS count INTO gitlab.downsampled.rails_object_counts_per_type FROM gitlab."default".rails_object_counts GROUP BY time(1m), type END;
+CREATE CONTINUOUS QUERY rails_transaction_counts_overall ON gitlab BEGIN SELECT count("duration") AS count INTO gitlab.downsampled.rails_transaction_counts_overall FROM gitlab."default".rails_transactions WHERE action =~ /.+/ AND action !~ /^Grape#/ GROUP BY time(1m) END;
+CREATE CONTINUOUS QUERY rails_transaction_counts_per_action ON gitlab BEGIN SELECT count("duration") AS count INTO gitlab.downsampled.rails_transaction_counts_per_action FROM gitlab."default".rails_transactions WHERE action =~ /.+/ AND action !~ /^Grape#/ GROUP BY time(1m), action END;
+CREATE CONTINUOUS QUERY rails_transaction_timings_overall ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th, mean(sql_duration) AS sql_duration_mean, percentile(sql_duration, 95) AS sql_duration_95th, percentile(sql_duration, 99) AS sql_duration_99th, mean(view_duration) AS view_duration_mean, percentile(view_duration, 95) AS view_duration_95th, percentile(view_duration, 99) AS view_duration_99th, mean(cache_read_duration) AS cache_read_duration_mean, percentile(cache_read_duration, 99) AS cache_read_duration_99th, percentile(cache_read_duration, 95) AS cache_read_duration_95th, mean(cache_write_duration) AS cache_write_duration_mean, percentile(cache_write_duration, 99) AS cache_write_duration_99th, percentile(cache_write_duration, 95) AS cache_write_duration_95th, mean(cache_delete_duration) AS cache_delete_duration_mean, percentile(cache_delete_duration, 99) AS cache_delete_duration_99th, percentile(cache_delete_duration, 95) AS cache_delete_duration_95th, mean(cache_exists_duration) AS cache_exists_duration_mean, percentile(cache_exists_duration, 99) AS cache_exists_duration_99th, percentile(cache_exists_duration, 95) AS cache_exists_duration_95th, mean(cache_duration) AS cache_duration_mean, percentile(cache_duration, 99) AS cache_duration_99th, percentile(cache_duration, 95) AS cache_duration_95th, mean(method_duration) AS method_duration_mean, percentile(method_duration, 99) AS method_duration_99th, percentile(method_duration, 95) AS method_duration_95th INTO gitlab.downsampled.rails_transaction_timings_overall FROM gitlab."default".rails_transactions WHERE action =~ /.+/ AND action !~ /^Grape#/ GROUP BY time(1m) END;
+CREATE CONTINUOUS QUERY rails_transaction_timings_per_action ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th, mean(sql_duration) AS sql_duration_mean, percentile(sql_duration, 95) AS sql_duration_95th, percentile(sql_duration, 99) AS sql_duration_99th, mean(view_duration) AS view_duration_mean, percentile(view_duration, 95) AS view_duration_95th, percentile(view_duration, 99) AS view_duration_99th, mean(cache_read_duration) AS cache_read_duration_mean, percentile(cache_read_duration, 99) AS cache_read_duration_99th, percentile(cache_read_duration, 95) AS cache_read_duration_95th, mean(cache_write_duration) AS cache_write_duration_mean, percentile(cache_write_duration, 99) AS cache_write_duration_99th, percentile(cache_write_duration, 95) AS cache_write_duration_95th, mean(cache_delete_duration) AS cache_delete_duration_mean, percentile(cache_delete_duration, 99) AS cache_delete_duration_99th, percentile(cache_delete_duration, 95) AS cache_delete_duration_95th, mean(cache_exists_duration) AS cache_exists_duration_mean, percentile(cache_exists_duration, 99) AS cache_exists_duration_99th, percentile(cache_exists_duration, 95) AS cache_exists_duration_95th, mean(cache_duration) AS cache_duration_mean, percentile(cache_duration, 99) AS cache_duration_99th, percentile(cache_duration, 95) AS cache_duration_95th, mean(method_duration) AS method_duration_mean, percentile(method_duration, 99) AS method_duration_99th, percentile(method_duration, 95) AS method_duration_95th INTO gitlab.downsampled.rails_transaction_timings_per_action FROM gitlab."default".rails_transactions WHERE action =~ /.+/ AND action !~ /^Grape#/ GROUP BY time(1m), action END;
+CREATE CONTINUOUS QUERY rails_view_timings_per_action_and_view ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th INTO gitlab.downsampled.rails_view_timings_per_action_and_view FROM gitlab."default".rails_views WHERE action =~ /.+/ AND action !~ /^Grape#/ GROUP BY time(1m), action, view END;
+CREATE CONTINUOUS QUERY sidekiq_file_descriptor_counts ON gitlab BEGIN SELECT sum(value) AS count INTO gitlab.downsampled.sidekiq_file_descriptor_counts FROM gitlab."default".sidekiq_file_descriptors GROUP BY time(1m) END;
+CREATE CONTINUOUS QUERY sidekiq_gc_counts ON gitlab BEGIN SELECT sum(count) AS total, sum(minor_gc_count) AS minor, sum(major_gc_count) AS major INTO gitlab.downsampled.sidekiq_gc_counts FROM gitlab."default".sidekiq_gc_statistics GROUP BY time(1m) END;
+CREATE CONTINUOUS QUERY sidekiq_gc_timings ON gitlab BEGIN SELECT mean(total_time) AS duration_mean, percentile(total_time, 95) AS duration_95th, percentile(total_time, 99) AS duration_99th INTO gitlab.downsampled.sidekiq_gc_timings FROM gitlab."default".sidekiq_gc_statistics GROUP BY time(1m) END;
+CREATE CONTINUOUS QUERY sidekiq_git_timings_per_action ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th INTO gitlab.downsampled.sidekiq_git_timings_per_action FROM gitlab."default".sidekiq_method_calls WHERE method =~ /^(Rugged|Gitlab::Git)/ GROUP BY time(1m), action END;
+CREATE CONTINUOUS QUERY sidekiq_markdown_render_timings_overall ON gitlab BEGIN SELECT mean(banzai_cached_render_real_time) AS cached_real_mean, percentile(banzai_cached_render_real_time, 95) AS cached_real_95th, percentile(banzai_cached_render_real_time, 99) AS cached_real_99th, mean(banzai_cached_render_cpu_time) AS cached_cpu_mean, percentile(banzai_cached_render_cpu_time, 95) AS cached_cpu_95th, percentile(banzai_cached_render_cpu_time, 99) AS cached_cpu_99th, sum(banzai_cached_render_call_count) AS cached_call_count, mean(banzai_cacheless_render_real_time) AS cacheless_real_mean, percentile(banzai_cacheless_render_real_time, 95) AS cacheless_real_95th, percentile(banzai_cacheless_render_real_time, 99) AS cacheless_real_99th, mean(banzai_cacheless_render_cpu_time) AS cacheless_cpu_mean, percentile(banzai_cacheless_render_cpu_time, 95) AS cacheless_cpu_95th, percentile(banzai_cacheless_render_cpu_time, 99) AS cacheless_cpu_99th, sum(banzai_cacheless_render_call_count) AS cacheless_call_count INTO gitlab.downsampled.sidekiq_markdown_render_timings_overall FROM gitlab."default".sidekiq_transactions WHERE (banzai_cached_render_call_count > 0 OR banzai_cacheless_render_call_count > 0) GROUP BY time(1m) END;
+CREATE CONTINUOUS QUERY sidekiq_markdown_render_timings_per_action ON gitlab BEGIN SELECT mean(banzai_cached_render_real_time) AS cached_real_mean, percentile(banzai_cached_render_real_time, 95) AS cached_real_95th, percentile(banzai_cached_render_real_time, 99) AS cached_real_99th, mean(banzai_cached_render_cpu_time) AS cached_cpu_mean, percentile(banzai_cached_render_cpu_time, 95) AS cached_cpu_95th, percentile(banzai_cached_render_cpu_time, 99) AS cached_cpu_99th, sum(banzai_cached_render_call_count) AS cached_call_count, mean(banzai_cacheless_render_real_time) AS cacheless_real_mean, percentile(banzai_cacheless_render_real_time, 95) AS cacheless_real_95th, percentile(banzai_cacheless_render_real_time, 99) AS cacheless_real_99th, mean(banzai_cacheless_render_cpu_time) AS cacheless_cpu_mean, percentile(banzai_cacheless_render_cpu_time, 95) AS cacheless_cpu_95th, percentile(banzai_cacheless_render_cpu_time, 99) AS cacheless_cpu_99th, sum(banzai_cacheless_render_call_count) AS cacheless_call_count INTO gitlab.downsampled.sidekiq_markdown_render_timings_per_action FROM gitlab."default".sidekiq_transactions WHERE (banzai_cached_render_call_count > 0 OR banzai_cacheless_render_call_count > 0) GROUP BY time(1m), action END;
+CREATE CONTINUOUS QUERY sidekiq_markdown_timings_overall ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th INTO gitlab.downsampled.sidekiq_markdown_timings_overall FROM gitlab."default".sidekiq_method_calls WHERE method =~ /^Banzai/ GROUP BY time(1m) END;
+CREATE CONTINUOUS QUERY sidekiq_memory_usage_overall ON gitlab BEGIN SELECT mean(value) AS memory_mean, percentile(value, 95) AS memory_95th, percentile(value, 99) AS memory_99th INTO gitlab.downsampled.sidekiq_memory_usage_overall FROM gitlab."default".sidekiq_memory_usage GROUP BY time(1m) END;
+CREATE CONTINUOUS QUERY sidekiq_method_call_timings_per_action_and_method ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th INTO gitlab.downsampled.sidekiq_method_call_timings_per_action_and_method FROM gitlab."default".sidekiq_method_calls GROUP BY time(1m), method, action END;
+CREATE CONTINUOUS QUERY sidekiq_method_call_timings_per_method ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th INTO gitlab.downsampled.sidekiq_method_call_timings_per_method FROM gitlab."default".sidekiq_method_calls GROUP BY time(1m), method END;
+CREATE CONTINUOUS QUERY sidekiq_object_counts_overall ON gitlab BEGIN SELECT sum(count) AS count INTO gitlab.downsampled.sidekiq_object_counts_overall FROM gitlab."default".sidekiq_object_counts GROUP BY time(1m) END;
+CREATE CONTINUOUS QUERY sidekiq_object_counts_per_type ON gitlab BEGIN SELECT sum(count) AS count INTO gitlab.downsampled.sidekiq_object_counts_per_type FROM gitlab."default".sidekiq_object_counts GROUP BY time(1m), type END;
+CREATE CONTINUOUS QUERY sidekiq_transaction_counts_overall ON gitlab BEGIN SELECT count("duration") AS count INTO gitlab.downsampled.sidekiq_transaction_counts_overall FROM gitlab."default".sidekiq_transactions GROUP BY time(1m) END;
+CREATE CONTINUOUS QUERY sidekiq_transaction_counts_per_action ON gitlab BEGIN SELECT count("duration") AS count INTO gitlab.downsampled.sidekiq_transaction_counts_per_action FROM gitlab."default".sidekiq_transactions GROUP BY time(1m), action END;
+CREATE CONTINUOUS QUERY sidekiq_transaction_timings_overall ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th, mean(sql_duration) AS sql_duration_mean, percentile(sql_duration, 95) AS sql_duration_95th, percentile(sql_duration, 99) AS sql_duration_99th, mean(view_duration) AS view_duration_mean, percentile(view_duration, 95) AS view_duration_95th, percentile(view_duration, 99) AS view_duration_99th, mean(cache_read_duration) AS cache_read_duration_mean, percentile(cache_read_duration, 99) AS cache_read_duration_99th, percentile(cache_read_duration, 95) AS cache_read_duration_95th, mean(cache_write_duration) AS cache_write_duration_mean, percentile(cache_write_duration, 99) AS cache_write_duration_99th, percentile(cache_write_duration, 95) AS cache_write_duration_95th, mean(cache_delete_duration) AS cache_delete_duration_mean, percentile(cache_delete_duration, 99) AS cache_delete_duration_99th, percentile(cache_delete_duration, 95) AS cache_delete_duration_95th, mean(cache_exists_duration) AS cache_exists_duration_mean, percentile(cache_exists_duration, 99) AS cache_exists_duration_99th, percentile(cache_exists_duration, 95) AS cache_exists_duration_95th, mean(cache_duration) AS cache_duration_mean, percentile(cache_duration, 99) AS cache_duration_99th, percentile(cache_duration, 95) AS cache_duration_95th, mean(method_duration) AS method_duration_mean, percentile(method_duration, 99) AS method_duration_99th, percentile(method_duration, 95) AS method_duration_95th INTO gitlab.downsampled.sidekiq_transaction_timings_overall FROM gitlab."default".sidekiq_transactions GROUP BY time(1m) END;
+CREATE CONTINUOUS QUERY sidekiq_transaction_timings_per_action ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th, mean(sql_duration) AS sql_duration_mean, percentile(sql_duration, 95) AS sql_duration_95th, percentile(sql_duration, 99) AS sql_duration_99th, mean(view_duration) AS view_duration_mean, percentile(view_duration, 95) AS view_duration_95th, percentile(view_duration, 99) AS view_duration_99th, mean(cache_read_duration) AS cache_read_duration_mean, percentile(cache_read_duration, 99) AS cache_read_duration_99th, percentile(cache_read_duration, 95) AS cache_read_duration_95th, mean(cache_write_duration) AS cache_write_duration_mean, percentile(cache_write_duration, 99) AS cache_write_duration_99th, percentile(cache_write_duration, 95) AS cache_write_duration_95th, mean(cache_delete_duration) AS cache_delete_duration_mean, percentile(cache_delete_duration, 99) AS cache_delete_duration_99th, percentile(cache_delete_duration, 95) AS cache_delete_duration_95th, mean(cache_exists_duration) AS cache_exists_duration_mean, percentile(cache_exists_duration, 99) AS cache_exists_duration_99th, percentile(cache_exists_duration, 95) AS cache_exists_duration_95th, mean(cache_duration) AS cache_duration_mean, percentile(cache_duration, 99) AS cache_duration_99th, percentile(cache_duration, 95) AS cache_duration_95th, mean(method_duration) AS method_duration_mean, percentile(method_duration, 99) AS method_duration_99th, percentile(method_duration, 95) AS method_duration_95th INTO gitlab.downsampled.sidekiq_transaction_timings_per_action FROM gitlab."default".sidekiq_transactions GROUP BY time(1m), action END;
+CREATE CONTINUOUS QUERY sidekiq_view_timings_per_action_and_view ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th INTO gitlab.downsampled.sidekiq_view_timings_per_action_and_view FROM gitlab."default".sidekiq_views GROUP BY time(1m), action, view END;
+CREATE CONTINUOUS QUERY web_transaction_counts_overall ON gitlab BEGIN SELECT count("duration") AS count INTO gitlab.downsampled.web_transaction_counts_overall FROM gitlab."default".rails_transactions GROUP BY time(1m) END;
 ```
 
 ## Import Dashboards
diff --git a/doc/update/8.6-to-8.7.md b/doc/update/8.6-to-8.7.md
index 8599133a726c292de860f8cf8353b9718cc646d9..4a2c6ea91d25570870da82c1b4386aeb7861b061 100644
--- a/doc/update/8.6-to-8.7.md
+++ b/doc/update/8.6-to-8.7.md
@@ -45,8 +45,8 @@ sudo -u git -H git checkout 8-7-stable-ee
 
 ```bash
 cd /home/git/gitlab-shell
-sudo -u git -H git fetch --all
-sudo -u git -H git checkout v2.7.0
+sudo -u git -H git fetch --all --tags
+sudo -u git -H git checkout v2.7.2
 ```
 
 ### 5. Update gitlab-workhorse
diff --git a/doc/update/README.md b/doc/update/README.md
index 0241f0368306f2abca2910c79cb6ca326e4a685f..a770633c9b8f9ace9b78b7950c9ac6c9d7dc30ff 100644
--- a/doc/update/README.md
+++ b/doc/update/README.md
@@ -1,18 +1,95 @@
-Depending on the installation method and your GitLab version, there are multiple update guides. Choose one that fits your needs.
+# Updating GitLab
+
+Depending on the installation method and your GitLab version, there are multiple
+update guides.
+
+There are currently 3 official ways to install GitLab:
+
+- Omnibus packages
+- Source installation
+- Docker installation
+
+Based on your installation, choose a section below that fits your needs.
+
+---
+
+<!-- START doctoc generated TOC please keep comment here to allow auto update -->
+<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
+**Table of Contents**  *generated with [DocToc](https://github.com/thlorenz/doctoc)*
+
+- [Omnibus Packages](#omnibus-packages)
+- [Installation from source](#installation-from-source)
+- [Installation using Docker](#installation-using-docker)
+- [Upgrading between editions](#upgrading-between-editions)
+    - [Community to Enterprise Edition](#community-to-enterprise-edition)
+    - [Enterprise to Community Edition](#enterprise-to-community-edition)
+- [Miscellaneous](#miscellaneous)
+
+<!-- END doctoc generated TOC please keep comment here to allow auto update -->
 
 ## Omnibus Packages
 
-- [Omnibus update guide](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/update.md) contains the steps needed to update a GitLab [package](https://about.gitlab.com/downloads/).
+- The [Omnibus update guide](http://doc.gitlab.com/omnibus/update/README.html)
+  contains the steps needed to update an Omnibus GitLab package.
 
 ## Installation from source
 
-- [The individual upgrade guides](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/update) are for those who have installed GitLab from source.
-- [The CE to EE update guides](https://gitlab.com/subscribers/gitlab-ee/tree/master/doc/update) are for subscribers of the Enterprise Edition only. The steps are very similar to a version upgrade: stop the server, get the code, update config files for the new functionality, install libs and do migrations, update the init script, start the application and check the application status.
-- [Upgrader](upgrader.md) is an automatic ruby script that performs the update for installations from source.
-- [Patch versions](patch_versions.md) guide includes the steps needed for a patch version, eg. 6.2.0 to 6.2.1.
+- [Upgrading Community Edition from source][source-ce] - The individual
+  upgrade guides are for those who have installed GitLab CE from source.
+- [Upgrading Enterprise Edition from source][source-ee] - The individual
+  upgrade guides are for those who have installed GitLab EE from source.
+- [Patch versions](patch_versions.md) guide includes the steps needed for a
+  patch version, eg. 6.2.0 to 6.2.1, and apply to both Community and Enterprise
+  Editions.
+
+## Installation using Docker
+
+GitLab provides official Docker images for both Community and Enterprise
+editions. They are based on the Omnibus package and instructions on how to
+update them are in [a separate document][omnidocker].
+
+## Upgrading between editions
+
+GitLab comes in two flavors: [Community Edition][ce] which is MIT licensed,
+and [Enterprise Edition][ee] which builds on top of the Community Edition and
+includes extra features mainly aimed at organizations with more than 100 users.
+
+Below you can find some guides to help you change editions easily.
+
+### Community to Enterprise Edition
+
+>**Note:**
+The following guides are for subscribers of the Enterprise Edition only.
+
+If you wish to upgrade your GitLab installation from Community to Enterprise
+Edition, follow the guides below based on the installation method:
+
+- [Source CE to EE update guides][source-ee] - Find your version, and follow the
+  `-ce-to-ee.md` guide. The steps are very similar to a version upgrade: stop
+  the server, get the code, update config files for the new functionality,
+  install libraries and do migrations, update the init script, start the
+  application and check its status.
+- [Omnibus CE to EE][omni-ce-ee] - Follow this guide to update your Omnibus
+  GitLab Community Edition to the Enterprise Edition.
+
+### Enterprise to Community Edition
+
+If you need to downgrade your Enterprise Edition installation back to Community
+Edition, you can follow [this guide][ee-ce] to make the process as smooth as
+possible.
 
 ## Miscellaneous
 
-- [MySQL to PostgreSQL](mysql_to_postgresql.md) guides you through migrating your database from MySQL to PostgreSQL.
-- [MySQL installation guide](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/install/database_mysql.md) contains additional information about configuring GitLab to work with a MySQL database.
+- [MySQL to PostgreSQL](mysql_to_postgresql.md) guides you through migrating
+  your database from MySQL to PostgreSQL.
+- [MySQL installation guide](../install/database_mysql.md) contains additional
+  information about configuring GitLab to work with a MySQL database.
 - [Restoring from backup after a failed upgrade](restore_after_failure.md)
+
+[omnidocker]: http://doc.gitlab.com/omnibus/docker/README.html
+[source-ee]: https://gitlab.com/gitlab-org/gitlab-ee/tree/master/doc/update
+[source-ce]: https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/update
+[ee-ce]: ../downgrade_ee_to_ce/README.md
+[ce]: https://about.gitlab.com/features/#community
+[ee]: https://about.gitlab.com/features/#enterprise
+[omni-ce-ee]: http://doc.gitlab.com/omnibus/update/README.html#from-community-edition-to-enterprise-edition
diff --git a/doc/workflow/cherry_pick_changes.md b/doc/workflow/cherry_pick_changes.md
index b0ca0879643a4ee3a910b85d3ec3c9d565d656c5..4a4990098429c19e989b1570da951fc2c6a00ace 100644
--- a/doc/workflow/cherry_pick_changes.md
+++ b/doc/workflow/cherry_pick_changes.md
@@ -1,6 +1,7 @@
 # Cherry-pick changes
 
-_**Note:** This feature was [introduced][ce-3514] in GitLab 8.7._
+>**Note:**
+This feature was [introduced][ce-3514] in GitLab 8.7.
 
 ---
 
diff --git a/doc/workflow/importing/import_projects_from_github.md b/doc/workflow/importing/import_projects_from_github.md
index f693f430a4235e6e0fc0aaa4eb6ae42f43499654..e670e415c7151ae9624ca1fce9bd390a483411a9 100644
--- a/doc/workflow/importing/import_projects_from_github.md
+++ b/doc/workflow/importing/import_projects_from_github.md
@@ -1,7 +1,8 @@
 # Import your project from GitHub to GitLab
 
-_**Note:** In order to enable the GitHub import setting, you should first
-enable the [GitHub integration][gh-import] in your GitLab instance._
+>**Note:**
+In order to enable the GitHub import setting, you should first
+enable the [GitHub integration][gh-import] in your GitLab instance.
 
 At its current state, GitHub importer can import:
 
@@ -10,10 +11,13 @@ At its current state, GitHub importer can import:
 - the issues (introduced in GitLab 7.7)
 - the pull requests (introduced in GitLab 8.4)
 - the wiki pages (introduced in GitLab 8.4)
+- the milestones (introduced in GitLab 8.7)
+- the labels (introduced in GitLab 8.7)
 
-It is not yet possible to import your labels, milestones and cross-repository
-pull requests (those from forks). We are working on improving this in the near
-future.
+With GitLab 8.7+, references to pull requests and issues are preserved.
+
+It is not yet possible to import your cross-repository pull requests (those from
+forks). We are working on improving this in the near future.
 
 The importer page is visible when you [create a new project][new-project].
 Click on the **GitHub** link and you will be redirected to GitHub for
diff --git a/lib/api/project_hooks.rb b/lib/api/project_hooks.rb
index cf9938d25a7ff9b6bf328701f162fc0a605c255e..ccca65cbe1cdf17febadf23e70f6336648a5d2e8 100644
--- a/lib/api/project_hooks.rb
+++ b/lib/api/project_hooks.rb
@@ -103,10 +103,10 @@ module API
         required_attributes! [:hook_id]
 
         begin
-          @hook = ProjectHook.find(params[:hook_id])
-          @hook.destroy
+          @hook = user_project.hooks.destroy(params[:hook_id])
         rescue
           # ProjectHook can raise Error if hook_id not found
+          not_found!("Error deleting hook #{params[:hook_id]}")
         end
       end
     end
diff --git a/lib/banzai/filter/external_link_filter.rb b/lib/banzai/filter/external_link_filter.rb
index d179bea181e7f10385609a2ba7edcf16194ea7e7..38c4219518e52b811105affb7805057a34001876 100644
--- a/lib/banzai/filter/external_link_filter.rb
+++ b/lib/banzai/filter/external_link_filter.rb
@@ -1,7 +1,6 @@
 module Banzai
   module Filter
-    # HTML Filter to add a `rel="nofollow"` attribute to external links
-    #
+    # HTML Filter to modify the attributes of external links
     class ExternalLinkFilter < HTML::Pipeline::Filter
       def call
         doc.search('a').each do |node|
@@ -15,7 +14,7 @@ module Banzai
           # Skip internal links
           next if link.start_with?(internal_url)
 
-          node.set_attribute('rel', 'nofollow')
+          node.set_attribute('rel', 'nofollow noreferrer')
         end
 
         doc
diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb
index ff9887cba1eeb9c0d66d5dc1db250800859d5f21..504d3df9d349916d77437726eac22afc9eb0318d 100644
--- a/lib/ci/gitlab_ci_yaml_processor.rb
+++ b/lib/ci/gitlab_ci_yaml_processor.rb
@@ -61,23 +61,21 @@ module Ci
       @stages = @config[:stages] || @config[:types]
       @variables = @config[:variables] || {}
       @cache = @config[:cache]
+      @jobs = {}
+
       @config.except!(*ALLOWED_YAML_KEYS)
+      @config.each { |name, param| add_job(name, param) }
 
-      # anything that doesn't have script is considered as unknown
-      @config.each do |name, param|
-        raise ValidationError, "Unknown parameter: #{name}" unless param.is_a?(Hash) && param.has_key?(:script)
-      end
+      raise ValidationError, "Please define at least one job" if @jobs.none?
+    end
 
-      unless @config.values.any?{|job| job.is_a?(Hash)}
-        raise ValidationError, "Please define at least one job"
-      end
+    def add_job(name, job)
+      return if name.to_s.start_with?('.')
 
-      @jobs = {}
-      @config.each do |key, job|
-        next if key.to_s.start_with?('.')
-        stage = job[:stage] || job[:type] || DEFAULT_STAGE
-        @jobs[key] = { stage: stage }.merge(job)
-      end
+      raise ValidationError, "Unknown parameter: #{name}" unless job.is_a?(Hash) && job.has_key?(:script)
+
+      stage = job[:stage] || job[:type] || DEFAULT_STAGE
+      @jobs[name] = { stage: stage }.merge(job)
     end
 
     def build_job(name, job)
@@ -112,8 +110,6 @@ module Ci
       true
     end
 
-    private
-
     def validate_global!
       unless validate_array_of_strings(@before_script)
         raise ValidationError, "before_script should be an array of strings"
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index c54e83339a120540d87175171ff31166798c5504..c0a1f45195f8a9eb2ed7e3a38406c6e9d8d5ed23 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -300,14 +300,6 @@ describe Projects::MergeRequestsController do
 
       expect(response.cookies['diff_view']).to eq('parallel')
     end
-
-    it 'assigns :view param based on cookie' do
-      request.cookies['diff_view'] = 'parallel'
-
-      go
-
-      expect(controller.params[:view]).to eq 'parallel'
-    end
   end
 
   describe 'GET commits' do
diff --git a/spec/features/dashboard/user_filters_projects_spec.rb b/spec/features/dashboard/user_filters_projects_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..cf86e2c85e95b51cb52e76f65e2b70f71b397495
--- /dev/null
+++ b/spec/features/dashboard/user_filters_projects_spec.rb
@@ -0,0 +1,27 @@
+require 'spec_helper'
+
+describe "Dashboard > User filters projects", feature: true do
+
+  describe 'filtering personal projects' do
+    before do
+      user = create(:user)
+      project = create(:project, name: "Victorialand", namespace: user.namespace)
+      project.team << [user, :master]
+
+      user2 = create(:user)
+      project2 = create(:project, name: "Treasure", namespace: user2.namespace)
+      project2.team << [user, :developer]
+
+      login_as(user)
+      visit dashboard_projects_path
+    end
+
+    it 'filters by projects "Owned by me"' do
+      click_link "Owned by me"
+
+      expect(page).to have_css('.is-active', text: 'Owned by me')
+      expect(page).to have_content('Victorialand')
+      expect(page).not_to have_content('Treasure')
+    end
+  end
+end
diff --git a/spec/features/issues/issue_sidebar_spec.rb b/spec/features/issues/issue_sidebar_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..5739bc64dfb2b8c723000a459e4fbc03affb8197
--- /dev/null
+++ b/spec/features/issues/issue_sidebar_spec.rb
@@ -0,0 +1,79 @@
+require 'rails_helper'
+
+feature 'Issue Sidebar', feature: true do
+  let(:project) { create(:project) }
+  let(:issue) { create(:issue, project: project) }
+  let!(:user) { create(:user)}
+
+  before do
+    create(:label, project: project, title: 'bug')
+    login_as(user)
+  end
+
+  context 'as a allowed user' do
+    before do
+      project.team << [user, :developer]
+      visit_issue(project, issue)
+    end
+
+    describe 'when clicking on edit labels', js: true do
+      it 'dropdown has an option to create a new label' do
+        find('.block.labels .edit-link').click
+
+        page.within('.block.labels') do
+          expect(page).to have_content 'Create new'
+        end
+      end
+    end
+
+    context 'creating a new label', js: true do
+      it 'option to crate a new label is present' do
+        page.within('.block.labels') do
+          find('.edit-link').click
+
+          expect(page).to have_content 'Create new'
+        end
+      end
+
+      it 'dropdown switches to "create label" section' do
+        page.within('.block.labels') do
+          find('.edit-link').click
+          click_link 'Create new'
+
+          expect(page).to have_content 'Create new label'
+        end
+      end
+
+      it 'new label is added' do
+        page.within('.block.labels') do
+          find('.edit-link').click
+          sleep 1
+          click_link 'Create new'
+
+          fill_in 'new_label_name', with: 'wontfix'
+          page.find(".suggest-colors a", match: :first).click
+          click_button 'Create'
+
+          page.within('.dropdown-page-one') do
+            expect(page).to have_content 'wontfix'
+          end
+        end
+      end
+    end
+  end
+
+  context 'as a guest' do
+    before do
+      project.team << [user, :guest]
+      visit_issue(project, issue)
+    end
+
+    it 'does not have a option to edit labels' do
+      expect(page).not_to have_selector('.block.labels .edit-link')
+    end
+  end
+
+  def visit_issue(project, issue)
+    visit namespace_project_issue_path(project.namespace, project, issue)
+  end
+end
diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb
index 90476ab369be4dfbd4beca16dbb8f5ea5308987e..b57131f68d57ca08a79f85fee0761e0f7f8c78a7 100644
--- a/spec/features/issues_spec.rb
+++ b/spec/features/issues_spec.rb
@@ -178,6 +178,19 @@ describe 'Issues', feature: true do
 
         expect(first_issue).to include('foo')
       end
+
+      context 'with a filter on labels' do
+        let(:label) { create(:label, project: project) }
+        before { create(:label_link, label: label, target: foo) }
+
+        it 'sorts by least recently due date by excluding nil due dates' do
+          bar.update(due_date: nil)
+
+          visit namespace_project_issues_path(project.namespace, project, label_names: [label.name], sort: sort_value_due_date_later)
+
+          expect(first_issue).to include('foo')
+        end
+      end
     end
 
     describe 'filtering by due date' do
@@ -304,6 +317,27 @@ describe 'Issues', feature: true do
 
         expect(issue.reload.assignee).to be_nil
       end
+
+      it 'allows user to select an assignee', js: true do
+        issue2 = create(:issue, project: project, author: @user)
+        visit namespace_project_issue_path(project.namespace, project, issue2)
+
+        page.within('.assignee') do
+          expect(page).to have_content "No assignee"
+        end
+
+        page.within '.assignee' do
+          click_link 'Edit'
+        end
+        
+        page.within '.dropdown-menu-user' do
+          click_link @user.name
+        end
+
+        page.within('.assignee') do
+          expect(page).to have_content @user.name
+        end
+      end
     end
 
     context 'by unauthorized user' do
diff --git a/spec/features/markdown_spec.rb b/spec/features/markdown_spec.rb
index 3d0d0e59fd7fd027db6c05953b285b3f6e165a47..0148c87084a6bc449157094598b2f07bde965376 100644
--- a/spec/features/markdown_spec.rb
+++ b/spec/features/markdown_spec.rb
@@ -165,7 +165,12 @@ describe 'GitLab Markdown', feature: true do
     describe 'ExternalLinkFilter' do
       it 'adds nofollow to external link' do
         link = doc.at_css('a:contains("Google")')
-        expect(link.attr('rel')).to match 'nofollow'
+        expect(link.attr('rel')).to include('nofollow')
+      end
+
+      it 'adds noreferrer to external link' do
+        link = doc.at_css('a:contains("Google")')
+        expect(link.attr('rel')).to include('noreferrer')
       end
 
       it 'ignores internal link' do
diff --git a/spec/features/project/commits/cherry_pick_spec.rb b/spec/features/projects/commits/cherry_pick_spec.rb
similarity index 100%
rename from spec/features/project/commits/cherry_pick_spec.rb
rename to spec/features/projects/commits/cherry_pick_spec.rb
diff --git a/spec/features/projects/members/anonymous_user_sees_members_spec.rb b/spec/features/projects/members/anonymous_user_sees_members_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c5e3d143d919ae4b25d7c6dd764fc6748ce4f68e
--- /dev/null
+++ b/spec/features/projects/members/anonymous_user_sees_members_spec.rb
@@ -0,0 +1,20 @@
+require 'spec_helper'
+
+feature 'Projects > Members > Anonymous user sees members', feature: true do
+  let(:user) { create(:user) }
+  let(:group) { create(:group, :public) }
+  let(:project) { create(:empty_project, :public) }
+
+  background do
+    project.team << [user, :master]
+    create(:project_group_link, project: project, group: group)
+  end
+
+  scenario "anonymous user visits the project's members page and sees the list of members" do
+    visit namespace_project_project_members_path(project.namespace, project)
+
+    expect(current_path).to eq(
+      namespace_project_project_members_path(project.namespace, project))
+    expect(page).to have_content(user.name)
+  end
+end
diff --git a/spec/features/signup_spec.rb b/spec/features/signup_spec.rb
index 01472743b2aaa3593bba79b75d50e595d827dd9c..51b754ff85c54e3d69ac6817db6f27b80ec9104a 100644
--- a/spec/features/signup_spec.rb
+++ b/spec/features/signup_spec.rb
@@ -13,8 +13,8 @@ feature 'Signup', feature: true do
       fill_in 'user_password_sign_up',    with: user.password
       click_button "Sign up"
 
-      expect(current_path).to eq user_session_path
-      expect(page).to have_content("A message with a confirmation link has been sent to your email address.")
+      expect(current_path).to eq users_almost_there_path
+      expect(page).to have_content("Please check your email to confirm your account")
     end
   end
 
diff --git a/spec/features/todos/todos_spec.rb b/spec/features/todos/todos_spec.rb
index 113d4c40cfca493d28d5c97bd7a2e76fc3ec26e9..248e004ba6eae6f9be72668072126cf958b82fdd 100644
--- a/spec/features/todos/todos_spec.rb
+++ b/spec/features/todos/todos_spec.rb
@@ -1,12 +1,10 @@
 require 'spec_helper'
 
 describe 'Dashboard Todos', feature: true do
-  let(:user){ create(:user) }
-  let(:author){ create(:user) }
-  let(:project){ create(:project) }
-  let(:issue){ create(:issue) }
-  let(:todos_per_page){ Todo.default_per_page }
-  let(:todos_total){ todos_per_page + 1 }
+  let(:user)    { create(:user) }
+  let(:author)  { create(:user) }
+  let(:project) { create(:project) }
+  let(:issue)   { create(:issue) }
 
   describe 'GET /dashboard/todos' do
     context 'User does not have todos' do
@@ -46,31 +44,35 @@ describe 'Dashboard Todos', feature: true do
     end
 
     context 'User has multiple pages of Todos' do
-      let(:todo_total_pages){ (todos_total.to_f/todos_per_page).ceil }
-
       before do
-        todos_total.times do
-          create(:todo, :mentioned, user: user, project: project, target: issue, author: author)
-        end
+        allow(Todo).to receive(:default_per_page).and_return(1)
+
+        # Create just enough records to cause us to paginate
+        create_list(:todo, 2, :mentioned, user: user, project: project, target: issue, author: author)
 
         login_as(user)
-        visit dashboard_todos_path
       end
 
       it 'is paginated' do
+        visit dashboard_todos_path
+
         expect(page).to have_selector('.gl-pagination')
       end
 
       it 'is has the right number of pages' do
-        expect(page).to have_selector('.gl-pagination .page', count: todo_total_pages)
+        visit dashboard_todos_path
+
+        expect(page).to have_selector('.gl-pagination .page', count: 2)
       end
 
-      describe 'deleting last todo from last page', js: true do
+      describe 'completing last todo from last page', js: true do
         it 'redirects to the previous page' do
-          page.within('.gl-pagination') do
-            click_link todo_total_pages.to_s
-          end
-          first('.done-todo').click
+          visit dashboard_todos_path(page: 2)
+          expect(page).to have_content(Todo.first.body)
+
+          click_link('Done')
+
+          expect(current_path).to eq dashboard_todos_path
           expect(page).to have_content(Todo.last.body)
         end
       end
diff --git a/spec/helpers/diff_helper_spec.rb b/spec/helpers/diff_helper_spec.rb
index 982c113e84b0cec5780fca4c5b5155fdf12d7b71..b7810185d168bff4608a01c8c15cada472295d3d 100644
--- a/spec/helpers/diff_helper_spec.rb
+++ b/spec/helpers/diff_helper_spec.rb
@@ -11,6 +11,26 @@ describe DiffHelper do
   let(:diff_refs) { [commit.parent, commit] }
   let(:diff_file) { Gitlab::Diff::File.new(diff, diff_refs) }
 
+  describe 'diff_view' do
+    it 'returns a valid value when cookie is set' do
+      helper.request.cookies[:diff_view] = 'parallel'
+
+      expect(helper.diff_view).to eq 'parallel'
+    end
+
+    it 'returns a default value when cookie is invalid' do
+      helper.request.cookies[:diff_view] = 'invalid'
+
+      expect(helper.diff_view).to eq 'inline'
+    end
+
+    it 'returns a default value when cookie is nil' do
+      expect(helper.request.cookies).to be_empty
+
+      expect(helper.diff_view).to eq 'inline'
+    end
+  end
+
   describe 'diff_hard_limit_enabled?' do
     it 'should return true if param is provided' do
       allow(controller).to receive(:params) { { force_show_diff: true } }
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index c258cfebd732c0bc77c1b700586720f6ebbd3fcd..62389188d2c8add2479e86b6bf0f1c13017776d5 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -105,4 +105,30 @@ describe ProjectsHelper do
       end
     end
   end
+
+  describe '#license_short_name' do
+    let(:project) { create(:project) }
+
+    context 'when project.repository has a license_key' do
+      it 'returns the nickname of the license if present' do
+        allow(project.repository).to receive(:license_key).and_return('agpl-3.0')
+
+        expect(helper.license_short_name(project)).to eq('GNU AGPLv3')
+      end
+
+      it 'returns the name of the license if nickname is not present' do
+        allow(project.repository).to receive(:license_key).and_return('mit')
+
+        expect(helper.license_short_name(project)).to eq('MIT License')
+      end
+    end
+
+    context 'when project.repository has no license_key but a license_blob' do
+      it 'returns LICENSE' do
+        allow(project.repository).to receive(:license_key).and_return(nil)
+
+        expect(helper.license_short_name(project)).to eq('LICENSE')
+      end
+    end
+  end
 end
diff --git a/spec/lib/banzai/filter/external_link_filter_spec.rb b/spec/lib/banzai/filter/external_link_filter_spec.rb
index e3a8e15330e228f448986f6c0615fff6a4dcea72..f4c5c621bd0d0c2ec069e618968f007b4a8f5356 100644
--- a/spec/lib/banzai/filter/external_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/external_link_filter_spec.rb
@@ -24,6 +24,14 @@ describe Banzai::Filter::ExternalLinkFilter, lib: true do
     doc = filter(act)
 
     expect(doc.at_css('a')).to have_attribute('rel')
-    expect(doc.at_css('a')['rel']).to eq 'nofollow'
+    expect(doc.at_css('a')['rel']).to include 'nofollow'
+  end
+
+  it 'adds rel="noreferrer" to external links' do
+    act = %q(<a href="https://google.com/">Google</a>)
+    doc = filter(act)
+
+    expect(doc.at_css('a')).to have_attribute('rel')
+    expect(doc.at_css('a')['rel']).to include 'noreferrer'
   end
 end
diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
index 643acf0303c560504b43e5ca3c46821aaec3193c..c7ab3185378f2c5402f16259e110749ebc1a2aed 100644
--- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
+++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
@@ -648,70 +648,131 @@ module Ci
     end
 
     describe "Hidden jobs" do
-      let(:config) do
-        YAML.dump({
-                    '.hidden_job' => { script: 'test' },
-                    'normal_job' => { script: 'test' }
-                  })
+      let(:config_processor) { GitlabCiYamlProcessor.new(config) }
+      subject { config_processor.builds_for_stage_and_ref("test", "master") }
+
+      shared_examples 'hidden_job_handling' do
+        it "doesn't create jobs that start with dot" do
+          expect(subject.size).to eq(1)
+          expect(subject.first).to eq({
+            except: nil,
+            stage: "test",
+            stage_idx: 1,
+            name: :normal_job,
+            only: nil,
+            commands: "test",
+            tag_list: [],
+            options: {},
+            when: "on_success",
+            allow_failure: false
+          })
+        end
       end
 
-      let(:config_processor) { GitlabCiYamlProcessor.new(config) }
+      context 'when hidden job have a script definition' do
+        let(:config) do
+          YAML.dump({
+                      '.hidden_job' => { image: 'ruby:2.1', script: 'test' },
+                      'normal_job' => { script: 'test' }
+                    })
+        end
 
-      subject { config_processor.builds_for_stage_and_ref("test", "master") }
+        it_behaves_like 'hidden_job_handling'
+      end
 
-      it "doesn't create jobs that starts with dot" do
-        expect(subject.size).to eq(1)
-        expect(subject.first).to eq({
-          except: nil,
-          stage: "test",
-          stage_idx: 1,
-          name: :normal_job,
-          only: nil,
-          commands: "test",
-          tag_list: [],
-          options: {},
-          when: "on_success",
-          allow_failure: false
-        })
+      context "when hidden job doesn't have a script definition" do
+        let(:config) do
+          YAML.dump({
+                      '.hidden_job' => { image: 'ruby:2.1' },
+                      'normal_job' => { script: 'test' }
+                    })
+        end
+
+        it_behaves_like 'hidden_job_handling'
       end
     end
 
     describe "YAML Alias/Anchor" do
-      it "is correctly supported for jobs" do
-        config = <<EOT
+      let(:config_processor) { GitlabCiYamlProcessor.new(config) }
+      subject { config_processor.builds_for_stage_and_ref("build", "master") }
+
+      shared_examples 'job_templates_handling' do
+        it "is correctly supported for jobs" do
+          expect(subject.size).to eq(2)
+          expect(subject.first).to eq({
+            except: nil,
+            stage: "build",
+            stage_idx: 0,
+            name: :job1,
+            only: nil,
+            commands: "execute-script-for-job",
+            tag_list: [],
+            options: {},
+            when: "on_success",
+            allow_failure: false
+          })
+          expect(subject.second).to eq({
+            except: nil,
+            stage: "build",
+            stage_idx: 0,
+            name: :job2,
+            only: nil,
+            commands: "execute-script-for-job",
+            tag_list: [],
+            options: {},
+            when: "on_success",
+            allow_failure: false
+          })
+        end
+      end
+
+      context 'when template is a job' do
+        let(:config) do
+          <<EOT
 job1: &JOBTMPL
+  stage: build
   script: execute-script-for-job
 
 job2: *JOBTMPL
 EOT
+        end
 
-        config_processor = GitlabCiYamlProcessor.new(config)
+        it_behaves_like 'job_templates_handling'
+      end
 
-        expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(2)
-        expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({
-          except: nil,
-          stage: "test",
-          stage_idx: 1,
-          name: :job1,
-          only: nil,
-          commands: "execute-script-for-job",
-          tag_list: [],
-          options: {},
-          when: "on_success",
-          allow_failure: false
-        })
-        expect(config_processor.builds_for_stage_and_ref("test", "master").second).to eq({
-          except: nil,
-          stage: "test",
-          stage_idx: 1,
-          name: :job2,
-          only: nil,
-          commands: "execute-script-for-job",
-          tag_list: [],
-          options: {},
-          when: "on_success",
-          allow_failure: false
-        })
+      context 'when template is a hidden job' do
+        let(:config) do
+          <<EOT
+.template: &JOBTMPL
+  stage: build
+  script: execute-script-for-job
+
+job1: *JOBTMPL
+
+job2: *JOBTMPL
+EOT
+        end
+
+        it_behaves_like 'job_templates_handling'
+      end
+
+      context 'when job adds its own keys to a template definition' do
+        let(:config) do
+          <<EOT
+.template: &JOBTMPL
+  stage: build
+
+job1:
+  <<: *JOBTMPL
+  script: execute-script-for-job
+
+job2:
+  <<: *JOBTMPL
+  script: execute-script-for-job
+EOT
+        end
+
+        it_behaves_like 'job_templates_handling'
       end
     end
 
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index becc743de3113e8baa2a7842fefdfbe4f481c8da..e33c7d62ff42ecfd8b5bf262dd43b18aa9503dd7 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -719,11 +719,8 @@ describe Project, models: true do
         with('foo.wiki', project).
         and_return(wiki)
 
-      expect(repo).to receive(:expire_cache)
-      expect(repo).to receive(:expire_emptiness_caches)
-
-      expect(wiki).to receive(:expire_cache)
-      expect(wiki).to receive(:expire_emptiness_caches)
+      expect(repo).to receive(:before_delete)
+      expect(wiki).to receive(:before_delete)
 
       project.expire_caches_before_rename('foo')
     end
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index b561aa663d1da757f074ecf7e079eef6a0b15f2b..c19524a01f871eb369d4293e46b5fecc1f90dd71 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -132,7 +132,6 @@ describe Repository, models: true do
         it { expect(subject.basename).to eq('a/b/c') }
       end
     end
-
   end
 
   describe '#license_blob' do
@@ -148,39 +147,18 @@ describe Repository, models: true do
       expect(repository.license_blob).to be_nil
     end
 
-    it 'favors license file with no extension' do
-      repository.commit_file(user, 'LICENSE', Licensee::License.new('mit').content, 'Add LICENSE', 'master', false)
-      repository.commit_file(user, 'LICENSE.md', Licensee::License.new('mit').content, 'Add LICENSE.md', 'master', false)
-
-      expect(repository.license_blob.name).to eq('LICENSE')
-    end
-
-    it 'favors .md file to .txt' do
-      repository.commit_file(user, 'LICENSE.md', Licensee::License.new('mit').content, 'Add LICENSE.md', 'master', false)
-      repository.commit_file(user, 'LICENSE.txt', Licensee::License.new('mit').content, 'Add LICENSE.txt', 'master', false)
-
-      expect(repository.license_blob.name).to eq('LICENSE.md')
-    end
-
-    it 'favors LICENCE to LICENSE' do
-      repository.commit_file(user, 'LICENSE', Licensee::License.new('mit').content, 'Add LICENSE', 'master', false)
-      repository.commit_file(user, 'LICENCE', Licensee::License.new('mit').content, 'Add LICENCE', 'master', false)
-
-      expect(repository.license_blob.name).to eq('LICENCE')
-    end
-
-    it 'favors LICENSE to COPYING' do
-      repository.commit_file(user, 'LICENSE', Licensee::License.new('mit').content, 'Add LICENSE', 'master', false)
-      repository.commit_file(user, 'COPYING', Licensee::License.new('mit').content, 'Add COPYING', 'master', false)
+    it 'detects license file with no recognizable open-source license content' do
+      repository.commit_file(user, 'LICENSE', 'Copyright!', 'Add LICENSE', 'master', false)
 
       expect(repository.license_blob.name).to eq('LICENSE')
     end
 
-    it 'favors LICENCE to COPYING' do
-      repository.commit_file(user, 'LICENCE', Licensee::License.new('mit').content, 'Add LICENCE', 'master', false)
-      repository.commit_file(user, 'COPYING', Licensee::License.new('mit').content, 'Add COPYING', 'master', false)
+    %w[LICENSE LICENCE LiCensE LICENSE.md LICENSE.foo COPYING COPYING.md].each do |filename|
+      it "detects '#{filename}'" do
+        repository.commit_file(user, filename, Licensee::License.new('mit').content, "Add #{filename}", 'master', false)
 
-      expect(repository.license_blob.name).to eq('LICENCE')
+        expect(repository.license_blob.name).to eq(filename)
+      end
     end
   end
 
@@ -190,8 +168,14 @@ describe Repository, models: true do
       repository.remove_file(user, 'LICENSE', 'Remove LICENSE', 'master')
     end
 
-    it 'returns "no-license" when no license is detected' do
-      expect(repository.license_key).to eq('no-license')
+    it 'returns nil when no license is detected' do
+      expect(repository.license_key).to be_nil
+    end
+
+    it 'detects license file with no recognizable open-source license content' do
+      repository.commit_file(user, 'LICENSE', 'Copyright!', 'Add LICENSE', 'master', false)
+
+      expect(repository.license_key).to be_nil
     end
 
     it 'returns the license key' do
diff --git a/spec/requests/api/project_hooks_spec.rb b/spec/requests/api/project_hooks_spec.rb
index 142b637d2913a2512801d58cb3b1f7335dc37dee..ffb93bbb120d1d37f9a8ae6ebeb7c989c66b19c5 100644
--- a/spec/requests/api/project_hooks_spec.rb
+++ b/spec/requests/api/project_hooks_spec.rb
@@ -148,14 +148,24 @@ describe API::API, 'ProjectHooks', api: true do
       expect(response.status).to eq(200)
     end
 
-    it "should return success when deleting non existent hook" do
+    it "should return a 404 error when deleting non existent hook" do
       delete api("/projects/#{project.id}/hooks/42", user)
-      expect(response.status).to eq(200)
+      expect(response.status).to eq(404)
     end
 
     it "should return a 405 error if hook id not given" do
       delete api("/projects/#{project.id}/hooks", user)
       expect(response.status).to eq(405)
     end
+
+    it "shold return a 404 if a user attempts to delete project hooks he/she does not own" do
+      test_user = create(:user)
+      other_project = create(:project)
+      other_project.team << [test_user, :master]
+
+      delete api("/projects/#{other_project.id}/hooks/#{hook.id}", test_user)
+      expect(response.status).to eq(404)
+      expect(WebHook.exists?(hook.id)).to be_truthy
+    end
   end
 end
diff --git a/spec/services/issues/bulk_update_service_spec.rb b/spec/services/issues/bulk_update_service_spec.rb
index 6a7ea4b2f44511819617816aab1dca883463f083..e91906d0d4975433eefa2eb29c908112d0efea52 100644
--- a/spec/services/issues/bulk_update_service_spec.rb
+++ b/spec/services/issues/bulk_update_service_spec.rb
@@ -100,7 +100,7 @@ describe Issues::BulkUpdateService, services: true do
   describe :update_milestone do
 
     before do
-      @milestone = create :milestone
+      @milestone = create(:milestone, project: @project)
       @params = {
         issues_ids: [issue.id],
         milestone_id: @milestone.id
diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb
index 5e7915db7e133e2923dc407a587870e75e5bac13..ac28b6f71f9a9465c2e864695bf1ec4077975790 100644
--- a/spec/services/issues/create_service_spec.rb
+++ b/spec/services/issues/create_service_spec.rb
@@ -3,40 +3,75 @@ require 'spec_helper'
 describe Issues::CreateService, services: true do
   let(:project) { create(:empty_project) }
   let(:user) { create(:user) }
-  let(:assignee) { create(:user) }
 
-  describe :execute do
-    context 'valid params' do
+  describe '#execute' do
+    let(:issue) { described_class.new(project, user, opts).execute }
+
+    context 'when params are valid' do
+      let(:assignee) { create(:user) }
+      let(:milestone) { create(:milestone, project: project) }
+      let(:labels) { create_pair(:label, project: project) }
+
       before do
         project.team << [user, :master]
         project.team << [assignee, :master]
+      end
 
-        opts = {
-          title: 'Awesome issue',
+      let(:opts) do
+        { title: 'Awesome issue',
           description: 'please fix',
-          assignee: assignee
-        }
-
-        @issue = Issues::CreateService.new(project, user, opts).execute
+          assignee: assignee,
+          label_ids: labels.map(&:id),
+          milestone_id: milestone.id }
       end
 
-      it { expect(@issue).to be_valid }
-      it { expect(@issue.title).to eq('Awesome issue') }
-      it { expect(@issue.assignee).to eq assignee }
+      it { expect(issue).to be_valid }
+      it { expect(issue.title).to eq('Awesome issue') }
+      it { expect(issue.assignee).to eq assignee }
+      it { expect(issue.labels).to match_array labels }
+      it { expect(issue.milestone).to eq milestone }
 
       it 'creates a pending todo for new assignee' do
         attributes = {
           project: project,
           author: user,
           user: assignee,
-          target_id: @issue.id,
-          target_type: @issue.class.name,
+          target_id: issue.id,
+          target_type: issue.class.name,
           action: Todo::ASSIGNED,
           state: :pending
         }
 
         expect(Todo.where(attributes).count).to eq 1
       end
+
+      context 'when label belongs to different project' do
+        let(:label) { create(:label) }
+
+        let(:opts) do
+          { title: 'Title',
+            description: 'Description',
+            label_ids: [label.id] }
+        end
+
+        it 'does not assign label'do
+          expect(issue.labels).to_not include label
+        end
+      end
+
+      context 'when milestone belongs to different project' do
+        let(:milestone) { create(:milestone) }
+
+        let(:opts) do
+          { title: 'Title',
+            description: 'Description',
+            milestone_id: milestone.id }
+        end
+
+        it 'does not assign milestone' do
+          expect(issue.milestone).to_not eq milestone
+        end
+      end
     end
   end
 end
diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb
index 6b214a0d96bbf592979542639bf440af2ce16663..52f693069945eb3c8c818071e902d798f40ceaa0 100644
--- a/spec/services/issues/update_service_spec.rb
+++ b/spec/services/issues/update_service_spec.rb
@@ -4,10 +4,15 @@ describe Issues::UpdateService, services: true do
   let(:user) { create(:user) }
   let(:user2) { create(:user) }
   let(:user3) { create(:user) }
-  let(:issue) { create(:issue, title: 'Old title', assignee_id: user3.id) }
-  let(:label) { create(:label) }
+  let(:project) { create(:empty_project) }
+  let(:label) { create(:label, project: project) }
   let(:label2) { create(:label) }
-  let(:project) { issue.project }
+
+  let(:issue) do
+    create(:issue, title: 'Old title',
+                   assignee_id: user3.id,
+                   project: project)
+  end
 
   before do
     project.team << [user, :master]
diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb
index cb8cff2fa8ca62e2dffc75983ff3bf847bde9579..213e8c2eb3a17139a45ec7bb48d7682998b281db 100644
--- a/spec/services/merge_requests/update_service_spec.rb
+++ b/spec/services/merge_requests/update_service_spec.rb
@@ -1,14 +1,19 @@
 require 'spec_helper'
 
 describe MergeRequests::UpdateService, services: true do
+  let(:project) { create(:project) }
   let(:user) { create(:user) }
   let(:user2) { create(:user) }
   let(:user3) { create(:user) }
-  let(:merge_request) { create(:merge_request, :simple, title: 'Old title', assignee_id: user3.id) }
-  let(:project) { merge_request.project }
-  let(:label) { create(:label) }
+  let(:label) { create(:label, project: project) }
   let(:label2) { create(:label) }
 
+  let(:merge_request) do
+    create(:merge_request, :simple, title: 'Old title',
+                                    assignee_id: user3.id,
+                                    source_project: project)
+  end
+
   before do
     project.team << [user, :master]
     project.team << [user2, :developer]