diff --git a/.gitignore b/.gitignore
index 2a97eacad489f02225935e3130421ec2c18bd1be..73bde4cc7615d532ec8c3fc0b6f5ce1a546ba553 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,7 +25,6 @@ config/initializers/rack_attack.rb
 config/initializers/smtp_settings.rb
 config/resque.yml
 config/unicorn.rb
-config/mail_room.yml
 config/secrets.yml
 coverage/*
 db/*.sqlite3
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index ddf4e31204ac3d2d7712ed9adfebfe5ddbe9af23..cf6d28b01af06af94652b4ee11f42d007fcc7975 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -24,6 +24,14 @@ spec:api:
     - ruby
     - mysql
 
+spec:benchmark:
+  script:
+    - RAILS_ENV=test bundle exec rake spec:benchmark
+  tags:
+    - ruby
+    - mysql
+  allow_failure: true
+
 spec:other:
   script:
     - RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:other
diff --git a/.rubocop.yml b/.rubocop.yml
index 05b8ecc3b00ef6af0f7b54e17381812a8c9b07c0..11e4502849a2f909983a4f05b9e8ff6c3f2437ad 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -932,7 +932,7 @@ Lint/UselessAccessModifier:
 Lint/UselessAssignment:
   Description: 'Checks for useless assignment to a local variable.'
   StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#underscore-unused-vars'
-  Enabled: false
+  Enabled: true
 
 Lint/UselessComparison:
   Description: 'Checks for comparison of something with itself.'
diff --git a/CHANGELOG b/CHANGELOG
index 8ff61cd6e9f52f5e49893bf409f30e0dea4a8198..fa630f354c4f1adf316e2f8b77405d4113d8435b 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,19 +1,118 @@
 Please view this file on the master branch, on stable branches it's out of date.
 
-v 8.1.0 (unreleased)
-  - Fix bug where projects would appear to be stuck in the forked import state (Stan Hu)
-  - Fix Error 500 in creating merge requests with > 1000 diffs (Stan Hu)
+v 8.2.0 (unreleased)
+  - Improved performance of replacing references in comments
+  - Show last project commit to default branch on project home page
+  - Highlight comment based on anchor in URL
+  - Adds ability to remove the forked relationship from project settings screen. (Han Loong Liauw)
+  - Improved performance of sorting milestone issues
+  - Allow users to select the Files view as default project view (Cristian Bica)
+  - Show "Empty Repository Page" for repository without branches (Artem V. Navrotskiy)
+
+v 8.1.0
+  - Ensure MySQL CI limits DB migrations occur after the fields have been created (Stan Hu)
+  - Fix duplicate repositories in GitHub import page (Stan Hu)
+  - Redirect to a default path if HTTP_REFERER is not set (Stan Hu)
+  - Fix CSS for runner status
+  - Send an email to admin email when a user is reported for spam (Jonathan Rochkind)
+  - Show notifications button when user is member of group rather than project (Grzegorz Bizon)
+  - Fix bug preventing mentioned issued from being closed when MR is merged using fast-forward merge.
+  - Fix nonatomic database update potentially causing project star counts to go negative (Stan Hu)
+  - Don't show "Add README" link in an empty repository if user doesn't have access to push (Stan Hu)
+  - Fix error preventing displaying of commit data for a directory with a leading dot (Stan Hu)
+  - Speed up load times of issue detail pages by roughly 1.5x
+  - Require CI jobs to be named
+  - If a merge request is to close an issue, show this on the issue page (Zeger-Jan van de Weg)
+  - Add a system note and update relevant merge requests when a branch is deleted or re-added (Stan Hu)
+  - Make diff file view easier to use on mobile screens (Stan Hu)
+  - Improved performance of finding users by username or Email address
+  - Fix 500 when editing CI service
+  - Fix bug where merge request comments created by API would not trigger notifications (Stan Hu)
+  - Add support for creating directories from Files page (Stan Hu)
+  - Allow removing of project without confirmation when JavaScript is disabled (Stan Hu)
+  - Support filtering by "Any" milestone or issue and fix "No Milestone" and "No Label" filters (Stan Hu)
+  - Improved performance of the trending projects page
+  - Remove CI migration task
+  - Improved performance of finding projects by their namespace
+  - Fix bug where transferring a project would result in stale commit links (Stan Hu)
+  - Fix build trace updating
+  - Include full path of source and target branch names in New Merge Request page (Stan Hu)
+  - Add user preference to view activities as default dashboard (Stan Hu)
+  - Add option to admin area to sign in as a specific user (Pavel Forkert)
   - Show CI status on all pages where commits list is rendered
   - Automatically enable CI when push .gitlab-ci.yml file to repository
   - Move CI charts to project graphs area
   - Fix cases where Markdown did not render links in activity feed (Stan Hu)
   - Add first and last to pagination (Zeger-Jan van de Weg)
+  - Added Commit Status API
+  - Added Builds View
+  - Added when to .gitlab-ci.yml
   - Show CI status on commit page
+  - Added CI_BUILD_TAG, _STAGE, _NAME and _TRIGGERED to CI builds
   - Show CI status on Your projects page and Starred projects page
   - Remove "Continuous Integration" page from dashboard
   - Add notes and SSL verification entries to hook APIs (Ben Boeckel)
+  - Fix grammar in admin area "labels" .nothing-here-block when no labels exist.
+  - Move CI runners page to project settings area
+  - Move CI variables page to project settings area
+  - Move CI triggers page to project settings area
+  - Move CI project settings page to CE project settings area
+  - Fix bug when removed file was not appearing in merge request diff
+  - Show warning when build cannot be served by any of the available CI runners
+  - Note the original location of a moved project when notifying users of the move
+  - Improve error message when merging fails
+  - Add support of multibyte characters in LDAP UID (Roman Petrov)
+  - Show additions/deletions stats on merge request diff
+  - Remove footer text in emails (Zeger-Jan van de Weg)
+  - Ensure code blocks are properly highlighted after a note is updated
+  - Fix wrong access level badge on MR comments
+  - Hide password in the service settings form
+  - Move CI web hooks page to project settings area
+  - Fix User Identities API. It now allows you to properly create or update user's identities.
+  - Add user preference to change layout width (Peter Göbel)
+  - Use commit status in merge request widget as preferred source of CI status
+  - Integrate CI commit and build pages into project pages
+  - Move CI services page to project settings area
+  - Add "Quick Submit" behavior to input fields throughout the application. Use
+    Cmd+Enter on Mac and Ctrl+Enter on Windows/Linux.
+  - Fix position of hamburger in header for smaller screens (Han Loong Liauw)
+  - Fix bug where Emojis in Markdown would truncate remaining text (Sakata Sinji)
+  - Persist filters when sorting on admin user page (Jerry Lukins)
+  - Update style of snippets pages (Han Loong Liauw)
+  - Allow dashboard and group issues/MRs to be filtered by label
+  - Add spellcheck=false to certain input fields
+  - Invalidate stored service password if the endpoint URL is changed
+  - Project names are not fully shown if group name is too big, even on group page view
+  - Apply new design for Files page
+  - Add "New Page" button to Wiki Pages tab (Stan Hu)
+  - Only render 404 page from /public
+  - Hide passwords from services API (Alex Lossent)
+  - Fix: Images cannot show when projects' path was changed
+  - Let gitlab-git-http-server generate and serve 'git archive' downloads
+  - Optimize query when filtering on issuables (Zeger-Jan van de Weg)
+  - Fix padding of outdated discussion item.
+  - Animate the logo on hover
+
+v 8.0.5
+  - Correct lookup-by-email for LDAP logins
+  - Fix loading spinner sometimes not being hidden on Merge Request tab switches
+
+v 8.0.4
+  - Fix Message-ID header to be RFC 2111-compliant to prevent e-mails being dropped (Stan Hu)
+  - Fix referrals for :back and relative URL installs
+  - Fix anchors to comments in diffs
+  - Remove CI token from build traces
+  - Fix "Assign All" button on Runner admin page
+  - Fix search in Files
+  - Add full project namespace to payload of system webhooks (Ricardo Band)
+
+v 8.0.3
+  - Fix URL shown in Slack notifications
+  - Fix bug where projects would appear to be stuck in the forked import state (Stan Hu)
+  - Fix Error 500 in creating merge requests with > 1000 diffs (Stan Hu)
+  - Add work_in_progress key to MR web hooks (Ben Boeckel)
 
-v 8.0.2 (unreleased)
+v 8.0.2
   - Fix default avatar not rendering in network graph (Stan Hu)
   - Skip check_initd_configured_correctly on omnibus installs
   - Prevent double-prefixing of help page paths
@@ -21,9 +120,11 @@ v 8.0.2 (unreleased)
   - Make commit graphs responsive to window width changes (Stan Hu)
   - Fix top margin for sign-in button on public pages
   - Fix LDAP attribute mapping
+  - Remove git refs used internally by GitLab from network graph (Stan Hu)
   - Use standard Markdown font in Markdown preview instead of fixed-width font (Stan Hu)
   - Fix Reply by email for non-UTF-8 messages.
   - Add option to use StartTLS with Reply by email IMAP server.
+  - Allow AWS S3 Server-Side Encryption with Amazon S3-Managed Keys for backups (Paul Beattie)
 
 v 8.0.1
   - Remove git refs used internally by GitLab from network graph (Stan Hu)
@@ -90,6 +191,8 @@ v 8.0.0
   - Webhook for issue now contains repository field (Jungkook Park)
   - Add ability to add custom text to the help page (Jeroen van Baarsen)
   - Add pg_schema to backup config
+  - Fix references to target project issues in Merge Requests markdown preview and textareas (Francesco Levorato)
+  - Redirect from incorrectly cased group or project path to correct one (Francesco Levorato)
   - Removed API calls from CE to CI
 
 v 7.14.3
diff --git a/CHANGELOG-CI b/CHANGELOG-CI
deleted file mode 100644
index d1ad661d88bf14a5e9102fd92fcd8c292c77815a..0000000000000000000000000000000000000000
--- a/CHANGELOG-CI
+++ /dev/null
@@ -1,298 +0,0 @@
-v7.14.0 (unreleased)
-  - Truncate commit messages after subject line in table
-  - Adjust CI config to support Docker executors
-  - Added Application Settings
-  - Randomize test database for CI tests
-  - Make YAML validation stricter
-  - Use avatars received from GitLab
-  - Refactor GitLab API usage to use either access_token or private_token depending on what was specified during login
-  - Allow to use access_token for API requests
-  - Fix project API listing returning empty list when first projects are not added to CI
-  - Allow to define variables from YAML
-  - Added support for CI skipped status
-  - Fix broken yaml error saving
-  - Add committed_at to commits to properly order last commit (the force push issue)
-  - Rename type(s) to stage(s)
-  - Fix navigation icons
-  - Add missing stage when doing retry
-  - Require variable keys to be not-empty and unique
-  - Fix variable saving issue
-  - Display variable saving errors in variables page not the project's
-  - Added Build Triggers API
-  
-v7.13.1
-  - Fix: user could steal specific runner
-  - Fix: don't send notifications for jobs with allow_failure set
-  - Fix invalid link to doc.gitlab.com
-
-v7.13.0
-  - Fix inline edit runner-description
-  - Allow to specify image and services in yml that can be used with docker
-  - Fix: No runner notification can see managers only
-  - Fix service testing for slack
-  - Ability to cancel all builds in commit at once
-  - Disable colors in rake tasks automatically (if IO is not a TTY)
-  - Implemented "rake env:info". Rake task to receive system information
-  - Fix coverage calculation on commit page
-  - Enhance YAML validation
-  - Redirect back after authorization
-  - Change favicon
-  - Refactoring: Get rid of private_token usage in the frontend.
-  - Allow to specify allow_failure for job
-  - Build traces is stored in the file instead of database
-  - Make the builds path configurable
-  - Disable link to runner if it's not assigned to specific project
-  - Store all secrets in config/secrets.yml
-  - Encrypt variables
-  - Allow to specify flexible list of types in yaml
-
-v7.12.2
-  - Revert: Runner without tag should pick builds without tag only
-
-v7.12.1
-  - Runner without tag should pick builds without tag only
-  - Explicit error in the GitLab when commit not found.
-  - Fix: lint with relative subpath
-  - Update webhook example
-  - Improved Lint stability
-  - Add warning when .gitlab-ci.yml not found
-  - Improved validation for .gitlab-ci.yml
-  - Fix list of branches in only section
-  - Fix "Status Badge" button
-
-v7.12.0
-  - Endless scroll on the dashboard
-  - Add notification if there are no runners
-  - Fix pagination on dashboard
-  - Remove ID column from runners list in the admin area
-  - Increase default timeout for builds to 60 minutes
-  - Using .gitlab-ci.yml file instead of jobs
-  - Link to the runner from the build page for admin user
-  - Ability to set secret variables for runner
-  - Dont retry build when push same commit in same ref twice
-  - Admin area: show amount of runners with last contact less than a minute ago
-  - Fix re-adding project with the same name but different gitlab_id
-  - Implementation of Lint (.gitlab-ci.yml validation tool)
-  - Updated rails to 4.1.11
-  - API fix: project create call
-  - Link to web-editor with .gitlab-ci.yml
-  - Updated examples in the documentation
-
-v7.11.0
-  - Deploy Jobs API calls
-  - Projects search on dashboard page
-  - Improved runners page
-  - Running and Pending tabs on admin builds page
-  - Fix [ci skip] tag, so you can skip CI triggering now
-  - Add HipChat notifications
-  - Clean up project advanced settings.
-  - Add a GitLab project path parameter to the project API
-  - Remove projects IDs from dashboard
-  - UI fix: Remove page headers from the admin area
-  - Improve Email templates
-  - Add backup/restore utility
-  - Coordinator stores information(version, platform, revision, etc.) about runners.
-  - Fixed pagination on dashboard
-  - Public accessible build and commit pages of public projects
-  - Fix vulnerability in the API when MySQL is used
-
-v7.10.1
-  - Fix failing migration when update to 7.10 from 7.8 and older versions
-
-sidekiq_wirker_fix
-	- added sidekiq.yml
-	- integrated in script/background_jobs
-v7.10.0
-  - Projects sorting by last commit date
-  - Add project search at runner page
-  - Fix GitLab and CI projects collision
-  - Events for admin
-  - Events per projects
-  - Search for runners in admin area
-  - UI improvements: created separated admin section, removed useless project show page
-  - Runners sorting in admin area (by id)
-  - Remove protected_attributes gem
-  - Skip commit creation if there is no appropriate job
-
-v7.9.3
-  - Contains no changes
-  - Developers can cancel and retry jobs
-
-v7.9.2
-  - [Security] Already existing projects should not be served by shared runners
-  - Ability to run deploy job without test jobs (every push will trigger deploy job)
-
-v7.9.1
-  - [Security] Adding explicit is_shared parameter to runner
-  - [Security] By default new projects are not served by shared runners
-
-v7.9.0
-  - Reset user session if token is invalid
-  - Runner delete api endpoint
-  - Fix bug about showing edit button on commit page if user does not have permissions
-  - Allow to pass description and tag list during Runner's registration
-  - Added api for project jobs
-  - Implementation of deploy jobs after all parallel jobs(tests).
-  - Add scroll up/down buttons for better mobile experience with large build traces
-  - Add runner last contact (Kamil Trzciński)
-  - Allow to pause runners - when paused runner will not receive any new build (Kamil Trzciński)
-  - Add brakeman (security scanner for Ruby on Rails)
-  - Changed a color of the canceled builds
-  - Fix of show the same commits in different branches
-
-v7.8.2
-  - Fix the broken build failed email
-  - Notify only pusher instead of commiter
-
-v7.8.0
-  - Fix OAuth login with GitLab installed in relative URL
-  - GitLab CI has same version as GitLab since now
-  - Allow to pass description and tag list during Runner's registration (Kamil Trzciński)
-  - Update documentation (API, Install, Update)
-  - Skip refs field supports for wildcard branch name (ex. feature/*)
-  - Migrate E-mail notification to Services menu (Kamil Trzciński)
-  - Added Slack notifications (Kamil Trzciński)
-  - Disable turbolink on links pointing out to GitLab server
-  - Add test coverage parsing example for pytest-cov
-  - Upgrade raindrops gem
-
-v5.4.2
-  - Fix exposure of project token via build data
-
-v5.4.1
-  - Fix 500 if on builds page if build has no job
-  - Truncate project token from build trace
-  - Allow users with access to project see build trace
-
-v5.4.0 (Requires GitLab 7.7)
-  - Fixed 500 error for badge if build is pending
-  - Non-admin users can now register specific runners for their projects
-  - Project specific runners page which users can access
-  - Remove progress output from schedule_builds cron job
-  - Fix schedule_builds rake task
-  - Fix test webhook button
-  - Job can be branch specific or tag specific or both
-  - Shared runners builds projects which are not assigned to specific ones
-  - Job can be runner specific through tags
-  - Runner have tags
-  - Move job settings to separate page
-  - Add authorization level managing projects
-  - OAuth authentication via GitLab.
-
-v5.3
-  - Remove annoying 'Done' message from schedule_builds cron job
-  - Fix a style issue with the navbar
-  - Skip CSRF check on the project's build page
-  - Fix showing wrong build script on admin projects page
-  - Add branch and commit message to build result emails
-
-v5.2
-  - Improve performance by adding new indicies
-  - Separate Commit logic from Build logic in prep for Parallel Builds
-  - Parallel builds
-  - You can have multiple build scripts per project
-
-v5.1
-  - Registration token and runner token are named differently
-  - Redirect to previous page after sign-in
-  - Dont show archived projects
-  - Add support for skip branches from build
-  - Add coverage parsing feature
-  - Update rails to 4.0.10
-  - Look for a REVISION file before running `git log`
-  - All builds page for admin
-
-v5.0.1
-  - Update rails to 4.0.5
-
-v5.0.0
-  - Set build timeout in minutes
-  - Web Hooks for builds
-  - Nprogress bar
-  - Remove extra spaces in build script
-  - Requires runner v5
-    * All script commands executed as one file
-    * Cancel button works correctly now
-    * Runner stability increased
-    * Timeout applies to build now instead of line of script
-
-v4.3.0
-  - Refactor build js
-  - Redirect to build page with sha + bid if build id is not provided
-  - Update rails to 4.0.3
-  - Restyle project settings page
-  - Improve help page
-  - Replaced puma with unicorn
-  - Improved init.d script
-  - Add submodule init to default build script for new projects
-
-v4.2.0
-  - Build duration chart
-  - Bootstrap 3 with responsive UI
-  - Improved init.d script
-  - Refactoring
-  - Changed http codes for POST /projects/:id/build action
-  - Turbolinks
-
-v4.1.0
-  - Rails 4
-  - Click on build branch to see other builds for this branch
-  - Email notifications (Jeroen Knoops)
-
-v4.0.0
-  - Shared runners (no need to add runner to every project)
-  - Admin area (only available for GitLab admins)
-  - Hide all runners management into admin area
-  - Use http cloning for builds instead of deploy keys
-  - Allow choose between git clone and git fetch when get code for build
-  - Make build timeout actually works
-  - Requires GitLab 6.3 or higher
-  - GitLab CI settings go to GitLab project via api on creation
-
-v3.2.0
-  - Limit visibility of projects by gitlab authorized projects
-  - Use one page for both gitlab and gitlab-ci projects
-
-v3.1.0
-  - Login with both username, email or LDAP credentials (if GitLab 6.0+)
-  - Retry build button functionality
-  - UI fixes for resolution 1366px and lower
-  - Fix gravatar ssl warning
-
-v3.0.0
-  - Build running functionality extracted in gitlab-ci-runner
-  - Added API for runners and builds
-  - Redesigned application
-  - Added charts
-  - Use GitLab auth
-  - Add projects via UI with few clicks
-
-v2.2.0
-  - replaced unicorn with puma
-  - replaced grit with rugged
-  - Runner.rb more transactional safe now
-  - updated rails to 3.2.13
-  - updated devise to 2.2
-  - fixed issue when build left in running status if exception triggered
-  - rescue build timeout correctly
-  - badge helper with markdown & html
-  - increased test coverage to 85%
-
-v2.1.0
-  - Removed horizontal scroll for build trace
-  - new status badges
-  - better encode
-  - added several CI_* env variables
-
-v2.0.0
-  - Replace resque with sidekiq
-  - Run only one build at time per project
-  - Added whenever for schedule jobs
-
-v1.2.0
-  - Added Github web hook support
-  - Added build schedule
-
-v1.1.0
-  - Added JSON response for builds status
-  - Compatible with GitLab v4.0.0
\ No newline at end of file
diff --git a/GITLAB_GIT_HTTP_SERVER_VERSION b/GITLAB_GIT_HTTP_SERVER_VERSION
new file mode 100644
index 0000000000000000000000000000000000000000..0d91a54c7d439e84e3dd17d3594f1b2b6737f430
--- /dev/null
+++ b/GITLAB_GIT_HTTP_SERVER_VERSION
@@ -0,0 +1 @@
+0.3.0
diff --git a/Gemfile b/Gemfile
index 6950091b2b0284730be14d0425213fb5192c5224..9254ce2ccfa176109d65b019091a9a48031323c4 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,13 +1,5 @@
 source "https://rubygems.org"
 
-def darwin_only(require_as)
-  RUBY_PLATFORM.include?('darwin') && require_as
-end
-
-def linux_only(require_as)
-  RUBY_PLATFORM.include?('linux') && require_as
-end
-
 gem 'rails', '4.1.12'
 
 # Specify a sprockets version due to security issue
@@ -22,20 +14,20 @@ gem "mysql2", '~> 0.3.16', group: :mysql
 gem "pg", '~> 0.18.2', group: :postgres
 
 # Authentication libraries
-gem "devise", '~> 3.5.2'
-gem "devise-async", '~> 0.9.0'
-gem 'omniauth', "~> 1.2.2"
-gem 'omniauth-google-oauth2', '~> 0.2.5'
-gem 'omniauth-twitter', '~> 1.0.1'
-gem 'omniauth-github', '~> 1.1.1'
-gem 'omniauth-shibboleth', '~> 1.1.1'
-gem 'omniauth-kerberos', '~> 0.2.0', group: :kerberos
-gem 'omniauth-gitlab', '~> 1.0.0'
-gem 'omniauth-bitbucket', '~> 0.0.2'
-gem 'omniauth-saml', '~> 1.4.0'
-gem 'doorkeeper', '~> 2.1.3'
+gem 'devise',                 '~> 3.5.2'
+gem 'devise-async',           '~> 0.9.0'
+gem 'doorkeeper',             '~> 2.1.3'
+gem 'omniauth',               '~> 1.2.2'
+gem 'omniauth-bitbucket',     '~> 0.0.2'
+gem 'omniauth-github',        '~> 1.1.1'
+gem 'omniauth-gitlab',        '~> 1.0.0'
+gem 'omniauth-google-oauth2', '~> 0.2.0'
+gem 'omniauth-kerberos',      '~> 0.3.0', group: :kerberos
+gem 'omniauth-saml',          '~> 1.4.0'
+gem 'omniauth-shibboleth',    '~> 1.2.0'
+gem 'omniauth-twitter',       '~> 1.2.0'
 gem 'omniauth_crowd'
-gem "rack-oauth2", "~> 1.0.5"
+gem 'rack-oauth2',            '~> 1.0.5'
 
 # Two-factor authentication
 gem 'devise-two-factor', '~> 2.0.0'
@@ -47,7 +39,7 @@ gem "browser", '~> 1.0.0'
 
 # Extracting information from a git repository
 # Provide access to Gitlab::Git library
-gem "gitlab_git", '~> 7.2.15'
+gem "gitlab_git", '~> 7.2.19'
 
 # LDAP Auth
 # GitLab fork with several improvements to original library. For full list of changes
@@ -65,9 +57,9 @@ gem 'gollum-lib', '~> 4.0.2'
 gem "gitlab-linguist", "~> 3.0.1", require: "linguist"
 
 # API
-gem "grape", "~> 0.6.1"
-gem "grape-entity", "~> 0.4.2"
-gem 'rack-cors', '~> 0.2.9', require: 'rack/cors'
+gem 'grape',        '~> 0.6.1'
+gem 'grape-entity', '~> 0.4.2'
+gem 'rack-cors',    '~> 0.4.0', require: 'rack/cors'
 
 # Format dates and times
 # based on human-friendly examples
@@ -80,7 +72,7 @@ gem 'enumerize', '~> 0.7.0'
 gem "kaminari", "~> 0.16.3"
 
 # HAML
-gem "haml-rails", '~> 0.5.3'
+gem "haml-rails", '~> 0.9.0'
 
 # Files attachments
 gem "carrierwave", '~> 0.9.0'
@@ -102,7 +94,7 @@ gem "seed-fu", '~> 2.3.5'
 gem 'html-pipeline', '~> 1.11.0'
 gem 'task_list',     '~> 1.0.2', require: 'task_list/railtie'
 gem 'github-markup', '~> 1.3.1'
-gem 'redcarpet',     '~> 3.3.2'
+gem 'redcarpet',     '~> 3.3.3'
 gem 'RedCloth',      '~> 4.2.9'
 gem 'rdoc',          '~>3.6'
 gem 'org-ruby',      '~> 0.9.12'
@@ -128,7 +120,6 @@ gem 'after_commit_queue'
 gem 'acts-as-taggable-on', '~> 3.4'
 
 # Background jobs
-gem 'slim', '~> 2.0.2'
 gem 'sinatra', '~> 1.4.4', require: nil
 gem 'sidekiq', '3.3.0'
 gem 'sidetiq', '~> 0.6.3'
@@ -151,7 +142,7 @@ gem 'version_sorter', '~> 2.0.0'
 gem "redis-rails", '~> 4.0.0'
 
 # Campfire integration
-gem 'tinder', '~> 1.9.2'
+gem 'tinder', '~> 1.10.0'
 
 # HipChat integration
 gem 'hipchat', '~> 1.5.0'
@@ -163,7 +154,7 @@ gem "gitlab-flowdock-git-hook", "~> 1.0.1"
 gem "gemnasium-gitlab-service", "~> 0.2"
 
 # Slack integration
-gem "slack-notifier", "~> 1.0.0"
+gem "slack-notifier", "~> 1.2.0"
 
 # Asana integration
 gem 'asana', '~> 0.0.6'
@@ -197,7 +188,7 @@ gem 'charlock_holmes', '~> 0.6.9.4'
 
 gem "sass-rails", '~> 4.0.5'
 gem "coffee-rails", '~> 4.1.0'
-gem "uglifier", '~> 2.3.2'
+gem "uglifier", '~> 2.7.2'
 gem 'turbolinks', '~> 2.5.0'
 gem 'jquery-turbolinks', '~> 2.0.1'
 
@@ -225,6 +216,9 @@ group :development do
   gem 'quiet_assets', '~> 1.0.2'
   gem 'rack-mini-profiler', '~> 0.9.0', require: false
   gem 'rerun', '~> 0.10.0'
+  gem 'bullet', require: false
+  gem 'active_record_query_trace', require: false
+  gem 'rack-lineprof', platform: :mri
 
   # Better errors handler
   gem 'better_errors', '~> 1.0.1'
@@ -270,6 +264,8 @@ group :development, :test do
   gem 'rubocop',  '~> 0.28.0',  require: false
   gem 'coveralls',  '~> 0.8.2', require: false
   gem 'simplecov', '~> 0.10.0', require: false
+
+  gem 'benchmark-ips', require: false
 end
 
 group :test do
@@ -289,7 +285,7 @@ gem 'newrelic-grape'
 
 gem 'octokit', '~> 3.7.0'
 
-gem "mail_room", "~> 0.5.2"
+gem "mail_room", "~> 0.6.1"
 
 gem 'email_reply_parser', '~> 0.5.8'
 
@@ -298,19 +294,8 @@ gem 'activerecord-deprecated_finders', '~> 1.0.3'
 gem 'activerecord-session_store', '~> 0.1.0'
 gem "nested_form", '~> 0.3.2'
 
-# Scheduled
-gem 'whenever', '~> 0.8.4', require: false
-
 # OAuth
 gem 'oauth2', '~> 1.0.0'
 
 # Soft deletion
 gem "paranoia", "~> 2.0"
-
-group :development, :test do
-  gem 'guard-rspec', '~> 4.2.0'
-
-  gem 'rb-fsevent', require: darwin_only('rb-fsevent')
-  gem 'growl',      require: darwin_only('growl')
-  gem 'rb-inotify', require: linux_only('rb-inotify')
-end
diff --git a/Gemfile.lock b/Gemfile.lock
index 4386c6b9abb2d39ab067d1e63e85ca91a04d0bf9..53122898b0750b5aaafe2673254c541ac5d25dc0 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -17,6 +17,7 @@ GEM
       activesupport (= 4.1.12)
       builder (~> 3.1)
       erubis (~> 2.7.0)
+    active_record_query_trace (1.5)
     activemodel (4.1.12)
       activesupport (= 4.1.12)
       builder (~> 3.1)
@@ -66,6 +67,7 @@ GEM
       ice_nine (~> 0.11.0)
       thread_safe (~> 0.3, >= 0.3.1)
     bcrypt (3.1.10)
+    benchmark-ips (2.3.0)
     better_errors (1.0.1)
       coderay (>= 1.0.0)
       erubis (>= 2.6.6)
@@ -86,6 +88,9 @@ GEM
       terminal-table (~> 1.4)
     browser (1.0.0)
     builder (3.2.2)
+    bullet (4.14.9)
+      activesupport (>= 3.0.0)
+      uniform_notifier (~> 1.9.0)
     byebug (6.0.2)
     cal-heatmap-rails (0.0.1)
     capybara (2.4.4)
@@ -104,7 +109,6 @@ GEM
     celluloid (0.16.0)
       timers (~> 4.0.0)
     charlock_holmes (0.6.9.4)
-    chronic (0.10.2)
     chunky_png (1.3.4)
     cliver (0.3.2)
     coderay (1.1.0)
@@ -134,6 +138,7 @@ GEM
     daemons (1.2.3)
     database_cleaner (1.4.1)
     debug_inspector (0.0.2)
+    debugger-ruby_core_source (1.3.8)
     default_value_for (3.0.1)
       activerecord (>= 3.2.0, < 5.0)
     descendants_tracker (0.0.4)
@@ -181,8 +186,8 @@ GEM
     factory_girl_rails (4.3.0)
       factory_girl (~> 4.3.0)
       railties (>= 3.0.0)
-    faraday (0.8.10)
-      multipart-post (~> 1.2.0)
+    faraday (0.9.2)
+      multipart-post (>= 1.2, < 3)
     faraday_middleware (0.10.0)
       faraday (>= 0.7.4, < 0.10)
     fastercsv (1.5.5)
@@ -278,7 +283,7 @@ GEM
       mime-types (~> 1.19)
     gitlab_emoji (0.1.1)
       gemojione (~> 2.0)
-    gitlab_git (7.2.15)
+    gitlab_git (7.2.19)
       activesupport (~> 4.0)
       charlock_holmes (~> 0.6)
       gitlab-linguist (~> 3.0)
@@ -314,27 +319,15 @@ GEM
     grape-entity (0.4.8)
       activesupport
       multi_json (>= 1.3.2)
-    growl (1.0.3)
-    guard (2.13.0)
-      formatador (>= 0.2.4)
-      listen (>= 2.7, <= 4.0)
-      lumberjack (~> 1.0)
-      nenv (~> 0.1)
-      notiffany (~> 0.0)
-      pry (>= 0.9.12)
-      shellany (~> 0.0)
-      thor (>= 0.18.1)
-    guard-rspec (4.2.10)
-      guard (~> 2.1)
-      rspec (>= 2.14, < 4.0)
     haml (4.0.7)
       tilt
-    haml-rails (0.5.3)
+    haml-rails (0.9.0)
       actionpack (>= 4.0.1)
       activesupport (>= 4.0.1)
-      haml (>= 3.1, < 5.0)
+      haml (>= 4.0.6, < 5.0)
+      html2haml (>= 1.0.1)
       railties (>= 4.0.1)
-    hashie (2.1.2)
+    hashie (3.4.2)
     highline (1.6.21)
     hike (1.2.3)
     hipchat (1.5.2)
@@ -344,6 +337,11 @@ GEM
     html-pipeline (1.11.0)
       activesupport (>= 2)
       nokogiri (~> 1.4)
+    html2haml (2.0.0)
+      erubis (~> 2.7.0)
+      haml (~> 4.0.0)
+      nokogiri (~> 1.6.0)
+      ruby_parser (~> 3.5)
     http-cookie (1.0.2)
       domain_name (~> 0.5)
     http_parser.rb (0.5.3)
@@ -381,12 +379,11 @@ GEM
       celluloid (~> 0.16.0)
       rb-fsevent (>= 0.9.3)
       rb-inotify (>= 0.9)
-    lumberjack (1.0.9)
     macaddr (1.7.1)
       systemu (~> 2.6.2)
     mail (2.6.3)
       mime-types (>= 1.16, < 3)
-    mail_room (0.5.2)
+    mail_room (0.6.1)
     method_source (0.8.2)
     mime-types (1.25.1)
     mimemagic (0.3.0)
@@ -395,9 +392,8 @@ GEM
     mousetrap-rails (1.4.6)
     multi_json (1.11.2)
     multi_xml (0.5.5)
-    multipart-post (1.2.0)
+    multipart-post (2.0.0)
     mysql2 (0.3.20)
-    nenv (0.2.0)
     nested_form (0.3.2)
     net-ldap (0.11)
     net-scp (1.2.1)
@@ -410,9 +406,6 @@ GEM
     newrelic_rpm (3.9.4.245)
     nokogiri (1.6.6.2)
       mini_portile (~> 0.6.0)
-    notiffany (0.0.7)
-      nenv (~> 0.1)
-      shellany (~> 0.0)
     nprogress-rails (0.1.2.3)
     oauth (0.4.7)
     oauth2 (1.0.0)
@@ -439,7 +432,7 @@ GEM
     omniauth-google-oauth2 (0.2.6)
       omniauth (> 1.0)
       omniauth-oauth2 (~> 1.1)
-    omniauth-kerberos (0.2.0)
+    omniauth-kerberos (0.3.0)
       omniauth-multipassword
       timfel-krb5-auth (~> 0.8)
     omniauth-multipassword (0.4.2)
@@ -453,11 +446,11 @@ GEM
     omniauth-saml (1.4.1)
       omniauth (~> 1.1)
       ruby-saml (~> 1.0.0)
-    omniauth-shibboleth (1.1.2)
+    omniauth-shibboleth (1.2.1)
       omniauth (>= 1.0.0)
-    omniauth-twitter (1.0.1)
-      multi_json (~> 1.3)
-      omniauth-oauth (~> 1.0)
+    omniauth-twitter (1.2.1)
+      json (~> 1.3)
+      omniauth-oauth (~> 1.1)
     omniauth_crowd (2.2.3)
       activesupport
       nokogiri (>= 1.4.4)
@@ -495,7 +488,11 @@ GEM
       rack (>= 0.4)
     rack-attack (4.3.0)
       rack
-    rack-cors (0.2.9)
+    rack-cors (0.4.0)
+    rack-lineprof (0.0.3)
+      rack (~> 1.5)
+      rblineprof (~> 0.3.6)
+      term-ansicolor (~> 1.3)
     rack-mini-profiler (0.9.7)
       rack (>= 1.1.3)
     rack-mount (0.8.3)
@@ -534,13 +531,15 @@ GEM
     rb-fsevent (0.9.5)
     rb-inotify (0.9.5)
       ffi (>= 0.5.0)
+    rblineprof (0.3.6)
+      debugger-ruby_core_source (~> 1.3)
     rbvmomi (1.8.2)
       builder
       nokogiri (>= 1.4.1)
       trollop
     rdoc (3.12.2)
       json (~> 1.4)
-    redcarpet (3.3.2)
+    redcarpet (3.3.3)
     redis (3.2.1)
     redis-actionpack (4.0.0)
       actionpack (~> 4)
@@ -641,7 +640,6 @@ GEM
     sexp_processor (4.6.0)
     sham_rack (1.3.6)
       rack
-    shellany (0.0.1)
     shoulda-matchers (2.8.0)
       activesupport (>= 3.0.0)
     sidekiq (3.3.0)
@@ -665,10 +663,7 @@ GEM
       rack-protection (~> 1.4)
       tilt (>= 1.3, < 3)
     six (0.2.0)
-    slack-notifier (1.0.0)
-    slim (2.0.3)
-      temple (~> 0.6.6)
-      tilt (>= 1.3.3, < 2.1)
+    slack-notifier (1.2.1)
     slop (3.6.0)
     spinach (0.8.10)
       colorize
@@ -704,7 +699,6 @@ GEM
       railties (>= 3.2.5, < 5)
     teaspoon-jasmine (2.2.0)
       teaspoon (>= 1.0.0)
-    temple (0.6.10)
     term-ansicolor (1.3.2)
       tins (~> 1.0)
     terminal-table (1.5.2)
@@ -720,13 +714,13 @@ GEM
     timers (4.0.4)
       hitimes
     timfel-krb5-auth (0.8.3)
-    tinder (1.9.4)
+    tinder (1.10.1)
       eventmachine (~> 1.0)
-      faraday (~> 0.8.9)
+      faraday (~> 0.9.0)
       faraday_middleware (~> 0.9)
-      hashie (>= 1.0, < 3)
+      hashie (>= 1.0)
       json (~> 1.8.0)
-      mime-types (~> 1.19)
+      mime-types
       multi_json (~> 1.7)
       twitter-stream (~> 0.1)
     tins (1.6.0)
@@ -739,7 +733,7 @@ GEM
       simple_oauth (~> 0.1.4)
     tzinfo (1.2.2)
       thread_safe (~> 0.1)
-    uglifier (2.3.3)
+    uglifier (2.7.2)
       execjs (>= 0.3.0)
       json (>= 1.8.0)
     underscore-rails (1.4.4)
@@ -753,6 +747,7 @@ GEM
     unicorn-worker-killer (0.4.3)
       get_process_mem (~> 0)
       unicorn (~> 4)
+    uniform_notifier (1.9.0)
     uuid (2.3.8)
       macaddr (~> 1.0)
     version_sorter (2.0.0)
@@ -769,9 +764,6 @@ GEM
     websocket-driver (0.6.2)
       websocket-extensions (>= 0.1.0)
     websocket-extensions (0.1.2)
-    whenever (0.8.4)
-      activesupport (>= 2.3.4)
-      chronic (>= 0.6.3)
     wikicloth (0.8.1)
       builder
       expression_parser
@@ -785,6 +777,7 @@ PLATFORMS
 DEPENDENCIES
   RedCloth (~> 4.2.9)
   ace-rails-ap (~> 2.0.1)
+  active_record_query_trace
   activerecord-deprecated_finders (~> 1.0.3)
   activerecord-session_store (~> 0.1.0)
   acts-as-taggable-on (~> 3.4)
@@ -795,11 +788,13 @@ DEPENDENCIES
   asciidoctor (~> 1.5.2)
   attr_encrypted (~> 1.3.4)
   awesome_print (~> 1.2.0)
+  benchmark-ips
   better_errors (~> 1.0.1)
   binding_of_caller (~> 0.7.2)
   bootstrap-sass (~> 3.0)
   brakeman (= 3.0.1)
   browser (~> 1.0.0)
+  bullet
   byebug
   cal-heatmap-rails (~> 0.0.1)
   capybara (~> 2.4.0)
@@ -834,16 +829,14 @@ DEPENDENCIES
   gitlab-flowdock-git-hook (~> 1.0.1)
   gitlab-linguist (~> 3.0.1)
   gitlab_emoji (~> 0.1)
-  gitlab_git (~> 7.2.15)
+  gitlab_git (~> 7.2.19)
   gitlab_meta (= 7.0)
   gitlab_omniauth-ldap (~> 1.2.1)
   gollum-lib (~> 4.0.2)
   gon (~> 5.0.0)
   grape (~> 0.6.1)
   grape-entity (~> 0.4.2)
-  growl
-  guard-rspec (~> 4.2.0)
-  haml-rails (~> 0.5.3)
+  haml-rails (~> 0.9.0)
   hipchat (~> 1.5.0)
   html-pipeline (~> 1.11.0)
   httparty (~> 0.13.3)
@@ -854,7 +847,7 @@ DEPENDENCIES
   jquery-ui-rails (~> 4.2.1)
   kaminari (~> 0.16.3)
   letter_opener (~> 1.1.2)
-  mail_room (~> 0.5.2)
+  mail_room (~> 0.6.1)
   minitest (~> 5.7.0)
   mousetrap-rails (~> 1.4.6)
   mysql2 (~> 0.3.16)
@@ -868,11 +861,11 @@ DEPENDENCIES
   omniauth-bitbucket (~> 0.0.2)
   omniauth-github (~> 1.1.1)
   omniauth-gitlab (~> 1.0.0)
-  omniauth-google-oauth2 (~> 0.2.5)
-  omniauth-kerberos (~> 0.2.0)
+  omniauth-google-oauth2 (~> 0.2.0)
+  omniauth-kerberos (~> 0.3.0)
   omniauth-saml (~> 1.4.0)
-  omniauth-shibboleth (~> 1.1.1)
-  omniauth-twitter (~> 1.0.1)
+  omniauth-shibboleth (~> 1.2.0)
+  omniauth-twitter (~> 1.2.0)
   omniauth_crowd
   org-ruby (~> 0.9.12)
   paranoia (~> 2.0)
@@ -881,15 +874,14 @@ DEPENDENCIES
   pry-rails
   quiet_assets (~> 1.0.2)
   rack-attack (~> 4.3.0)
-  rack-cors (~> 0.2.9)
+  rack-cors (~> 0.4.0)
+  rack-lineprof
   rack-mini-profiler (~> 0.9.0)
   rack-oauth2 (~> 1.0.5)
   rails (= 4.1.12)
   raphael-rails (~> 2.1.2)
-  rb-fsevent
-  rb-inotify
   rdoc (~> 3.6)
-  redcarpet (~> 3.3.2)
+  redcarpet (~> 3.3.3)
   redis-rails (~> 4.0.0)
   request_store (~> 1.2.0)
   rerun (~> 0.10.0)
@@ -910,8 +902,7 @@ DEPENDENCIES
   simplecov (~> 0.10.0)
   sinatra (~> 1.4.4)
   six (~> 0.2.0)
-  slack-notifier (~> 1.0.0)
-  slim (~> 2.0.2)
+  slack-notifier (~> 1.2.0)
   spinach-rails (~> 0.2.1)
   spring (~> 1.3.6)
   spring-commands-rspec (~> 1.0.4)
@@ -925,9 +916,9 @@ DEPENDENCIES
   teaspoon-jasmine (~> 2.2.0)
   test_after_commit (~> 0.2.2)
   thin (~> 1.6.1)
-  tinder (~> 1.9.2)
+  tinder (~> 1.10.0)
   turbolinks (~> 2.5.0)
-  uglifier (~> 2.3.2)
+  uglifier (~> 2.7.2)
   underscore-rails (~> 1.4.4)
   unf (~> 0.1.4)
   unicorn (~> 4.8.2)
@@ -935,5 +926,7 @@ DEPENDENCIES
   version_sorter (~> 2.0.0)
   virtus (~> 1.0.1)
   webmock (~> 1.21.0)
-  whenever (~> 0.8.4)
   wikicloth (= 0.8.1)
+
+BUNDLED WITH
+   1.10.6
diff --git a/PROCESS.md b/PROCESS.md
index 1b6b3e7d32d053ac6124be3c1637b3f8db12c204..9f4b708d2b56b1c558e93e361284c802f707cba5 100644
--- a/PROCESS.md
+++ b/PROCESS.md
@@ -79,7 +79,11 @@ Thanks for the issue report but we only support issues for the latest stable ver
 
 ### Support requests and configuration questions
 
-Thanks for your interest in GitLab. We don't use the issue tracker for support requests and configuration questions. Please use the \[support forum\]\(https://groups.google.com/forum/#!forum/gitlabhq), \[Stack Overflow\]\(http://stackoverflow.com/questions/tagged/gitlab), the #gitlab IRC channel on Freenode or the http://about.gitlab.com paid services for this purpose. Have a look at the \[contribution guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md) for more information.
+Thanks for your interest in GitLab. We don't use the issue tracker for support
+requests and configuration questions. Please check our
+\[getting help\]\(https://about.gitlab.com/getting-help/) page to see all of the available
+support options. Also, have a look at the \[contribution guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md)
+for more information.
 
 ### Code format
 
diff --git a/README.md b/README.md
index 99d5bc0b6ca8de7aaadccfad97078bce634d1950..52e2d9776208e95b7d5c11bcfc7f2fe63fcab34c 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 # GitLab
 
-[![build status](https://ci.gitlab.com/projects/1/status.png?ref=master)](https://ci.gitlab.com/projects/1?ref=master)
+[![build status](https://ci.gitlab.com/projects/1/status.svg?ref=master)](https://ci.gitlab.com/projects/1?ref=master)
 [![Build Status](https://semaphoreci.com/api/v1/projects/2f1a5809-418b-4cc2-a1f4-819607579fe7/400484/shields_badge.svg)](https://semaphoreci.com/gitlabhq/gitlabhq)
 [![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.svg)](https://codeclimate.com/github/gitlabhq/gitlabhq)
 [![Coverage Status](https://coveralls.io/repos/gitlabhq/gitlabhq/badge.svg?branch=master)](https://coveralls.io/r/gitlabhq/gitlabhq?branch=master)
@@ -71,7 +71,7 @@ GitLab is a Ruby on Rails application that runs on the following software:
 - Ubuntu/Debian/CentOS/RHEL
 - Ruby (MRI) 2.1
 - Git 1.7.10+
-- Redis 2.0+
+- Redis 2.4+
 - MySQL or PostgreSQL
 
 For more information please see the [architecture documentation](http://doc.gitlab.com/ce/development/architecture.html).
diff --git a/app/assets/fonts/SourceSansPro-Bold.ttf b/app/assets/fonts/SourceSansPro-Bold.ttf
index 50d81bdad58b06dbf4e3b6201cbdb31814aa5030..5d65c93242fc3776b379ab98bb5e6e33af4b25df 100755
Binary files a/app/assets/fonts/SourceSansPro-Bold.ttf and b/app/assets/fonts/SourceSansPro-Bold.ttf differ
diff --git a/app/assets/fonts/SourceSansPro-Light.ttf b/app/assets/fonts/SourceSansPro-Light.ttf
index 5f64679f6b98169bd9b877939b94e0387f503b88..83a0a3366619a3a4927441ff70782c9af51688d4 100755
Binary files a/app/assets/fonts/SourceSansPro-Light.ttf and b/app/assets/fonts/SourceSansPro-Light.ttf differ
diff --git a/app/assets/fonts/SourceSansPro-Regular.ttf b/app/assets/fonts/SourceSansPro-Regular.ttf
index 91e9ea5757fdff812d6690ca14f3a18589c0a723..44486cdc6702b42d1ed03b02779d6f47520a0e4e 100755
Binary files a/app/assets/fonts/SourceSansPro-Regular.ttf and b/app/assets/fonts/SourceSansPro-Regular.ttf differ
diff --git a/app/assets/fonts/SourceSansPro-Semibold.ttf b/app/assets/fonts/SourceSansPro-Semibold.ttf
index 5020594826b603961399cec009188a8d11a437d5..86b00c067e0a15e5fdfe4f4d97e4665de8ad0410 100755
Binary files a/app/assets/fonts/SourceSansPro-Semibold.ttf and b/app/assets/fonts/SourceSansPro-Semibold.ttf differ
diff --git a/app/assets/images/logo.svg b/app/assets/images/logo.svg
index c09785cb96f49f6f59f1d62012016b477e75eae6..f4e19b67008ddfc7710d85858baa8dcf096fea2b 100644
--- a/app/assets/images/logo.svg
+++ b/app/assets/images/logo.svg
@@ -10,17 +10,17 @@
                 <g id="Fill-1-+-Group-24">
                     <g id="Group-24">
                         <g id="Group">
-                            <path d="M105.0614,193.655 L105.0614,193.655 L143.7014,74.734 L66.4214,74.734 L105.0614,193.655 L105.0614,193.655 Z" id="Fill-4" fill="#E24329"></path>
-                            <path d="M105.0614,193.6548 L66.4214,74.7338 L12.2684,74.7338 L105.0614,193.6548 L105.0614,193.6548 Z" id="Fill-8" fill="#FC6D26"></path>
-                            <path d="M12.2685,74.7341 L12.2685,74.7341 L0.5265,110.8731 C-0.5445,114.1691 0.6285,117.7801 3.4325,119.8171 L105.0615,193.6551 L12.2685,74.7341 L12.2685,74.7341 Z" id="Fill-12" fill="#FCA326"></path>
-                            <path d="M12.2685,74.7342 L66.4215,74.7342 L43.1485,3.1092 C41.9515,-0.5768 36.7375,-0.5758 35.5405,3.1092 L12.2685,74.7342 L12.2685,74.7342 Z" id="Fill-16" fill="#E24329"></path>
-                            <path d="M105.0614,193.6548 L143.7014,74.7338 L197.8544,74.7338 L105.0614,193.6548 L105.0614,193.6548 Z" id="Fill-18" fill="#FC6D26"></path>
-                            <path d="M197.8544,74.7341 L197.8544,74.7341 L209.5964,110.8731 C210.6674,114.1691 209.4944,117.7801 206.6904,119.8171 L105.0614,193.6551 L197.8544,74.7341 L197.8544,74.7341 Z" id="Fill-20" fill="#FCA326"></path>
-                            <path d="M197.8544,74.7342 L143.7014,74.7342 L166.9744,3.1092 C168.1714,-0.5768 173.3854,-0.5758 174.5824,3.1092 L197.8544,74.7342 L197.8544,74.7342 Z" id="Fill-22" fill="#E24329"></path>
+                            <path d="M105.0614,193.655 L105.0614,193.655 L143.7014,74.734 L66.4214,74.734 L105.0614,193.655 L105.0614,193.655 Z" id="Fill-4" fill="#E24329" class="tanuki-shape"></path>
+                            <path d="M105.0614,193.6548 L66.4214,74.7338 L12.2684,74.7338 L105.0614,193.6548 L105.0614,193.6548 Z" id="Fill-8" fill="#FC6D26" class="tanuki-shape"></path>
+                            <path d="M12.2685,74.7341 L12.2685,74.7341 L0.5265,110.8731 C-0.5445,114.1691 0.6285,117.7801 3.4325,119.8171 L105.0615,193.6551 L12.2685,74.7341 L12.2685,74.7341 Z" id="Fill-12" fill="#FCA326" class="tanuki-shape"></path>
+                            <path d="M12.2685,74.7342 L66.4215,74.7342 L43.1485,3.1092 C41.9515,-0.5768 36.7375,-0.5758 35.5405,3.1092 L12.2685,74.7342 L12.2685,74.7342 Z" id="Fill-16" fill="#E24329" class="tanuki-shape"></path>
+                            <path d="M105.0614,193.6548 L143.7014,74.7338 L197.8544,74.7338 L105.0614,193.6548 L105.0614,193.6548 Z" id="Fill-18" fill="#FC6D26" class="tanuki-shape"></path>
+                            <path d="M197.8544,74.7341 L197.8544,74.7341 L209.5964,110.8731 C210.6674,114.1691 209.4944,117.7801 206.6904,119.8171 L105.0614,193.6551 L197.8544,74.7341 L197.8544,74.7341 Z" id="Fill-20" fill="#FCA326" class="tanuki-shape"></path>
+                            <path d="M197.8544,74.7342 L143.7014,74.7342 L166.9744,3.1092 C168.1714,-0.5768 173.3854,-0.5758 174.5824,3.1092 L197.8544,74.7342 L197.8544,74.7342 Z" id="Fill-22" fill="#E24329" class="tanuki-shape"></path>
                         </g>
                     </g>
                 </g>
             </g>
         </g>
     </g>
-</svg>
\ No newline at end of file
+</svg>
diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee
index 8e987ac4e83ee5fb34299fc33af6d8c784f3a362..945ffb660e66783325f44014185f1604b502c480 100644
--- a/app/assets/javascripts/application.js.coffee
+++ b/app/assets/javascripts/application.js.coffee
@@ -180,6 +180,7 @@ $ ->
   $('.navbar-toggle').on 'click', ->
     $('.header-content .title').toggle()
     $('.header-content .navbar-collapse').toggle()
+    $('.navbar-toggle').toggleClass('active')
 
   # Show/hide comments on diff
   $("body").on "click", ".js-toggle-diff-comments", (e) ->
diff --git a/app/assets/javascripts/behaviors/quick_submit.js.coffee b/app/assets/javascripts/behaviors/quick_submit.js.coffee
new file mode 100644
index 0000000000000000000000000000000000000000..4ec8531d58027a532df183a42c02aa70cfb10b53
--- /dev/null
+++ b/app/assets/javascripts/behaviors/quick_submit.js.coffee
@@ -0,0 +1,29 @@
+# Quick Submit behavior
+#
+# When an input field with the `js-quick-submit` class receives a "Meta+Enter"
+# (Mac) or "Ctrl+Enter" (Linux/Windows) key combination, its parent form is
+# submitted.
+#
+#= require extensions/jquery
+#
+# ### Example Markup
+#
+#   <form action="/foo">
+#     <input type="text" class="js-quick-submit" />
+#     <textarea class="js-quick-submit"></textarea>
+#   </form>
+#
+$(document).on 'keydown.quick_submit', '.js-quick-submit', (e) ->
+  return if (e.originalEvent && e.originalEvent.repeat) || e.repeat
+  return unless e.keyCode == 13 # Enter
+
+  if navigator.userAgent.match(/Macintosh/)
+    return unless (e.metaKey && !e.altKey && !e.ctrlKey && !e.shiftKey)
+  else
+    return unless (e.ctrlKey && !e.altKey && !e.metaKey && !e.shiftKey)
+
+  e.preventDefault()
+
+  $form = $(e.target).closest('form')
+  $form.find('input[type=submit], button[type=submit]').disable()
+  $form.submit()
diff --git a/app/assets/javascripts/behaviors/requires_input.js.coffee b/app/assets/javascripts/behaviors/requires_input.js.coffee
index 8318fe435b3911f5ca44d8b4597e8e675a1ab65d..79d750d1847730a401af9b20ab576fc15064c657 100644
--- a/app/assets/javascripts/behaviors/requires_input.js.coffee
+++ b/app/assets/javascripts/behaviors/requires_input.js.coffee
@@ -34,6 +34,5 @@ $.fn.requiresInput = ->
 
   $form.on 'change input', fieldSelector, requireInput
 
-# Triggered on standard document `ready` and on Turbolinks `page:load` events
-$(document).on 'ready page:load', ->
+$ ->
   $('form.js-requires-input').requiresInput()
diff --git a/app/assets/javascripts/blob/blob_file_dropzone.js.coffee b/app/assets/javascripts/blob/blob_file_dropzone.js.coffee
index 3ab3ba66754a9d3cb4400cbb68998c316145f190..5b604adbbb1bca76236caaee1f5395f6cb7f4059 100644
--- a/app/assets/javascripts/blob/blob_file_dropzone.js.coffee
+++ b/app/assets/javascripts/blob/blob_file_dropzone.js.coffee
@@ -47,6 +47,7 @@ class @BlobFileDropzone
           return
 
         this.on 'sending', (file, xhr, formData) ->
+          formData.append('new_branch', form.find('#new_branch').val())
           formData.append('commit_message', form.find('#commit_message').val())
           return
 
diff --git a/app/assets/javascripts/ci/Chart.min.js b/app/assets/javascripts/ci/Chart.min.js
deleted file mode 100644
index ab63588108763378ebc76ea1bb73191a70d70b12..0000000000000000000000000000000000000000
--- a/app/assets/javascripts/ci/Chart.min.js
+++ /dev/null
@@ -1,39 +0,0 @@
-var Chart=function(s){function v(a,c,b){a=A((a-c.graphMin)/(c.steps*c.stepValue),1,0);return b*c.steps*a}function x(a,c,b,e){function h(){g+=f;var k=a.animation?A(d(g),null,0):1;e.clearRect(0,0,q,u);a.scaleOverlay?(b(k),c()):(c(),b(k));if(1>=g)D(h);else if("function"==typeof a.onAnimationComplete)a.onAnimationComplete()}var f=a.animation?1/A(a.animationSteps,Number.MAX_VALUE,1):1,d=B[a.animationEasing],g=a.animation?0:1;"function"!==typeof c&&(c=function(){});D(h)}function C(a,c,b,e,h,f){var d;a=
-Math.floor(Math.log(e-h)/Math.LN10);h=Math.floor(h/(1*Math.pow(10,a)))*Math.pow(10,a);e=Math.ceil(e/(1*Math.pow(10,a)))*Math.pow(10,a)-h;a=Math.pow(10,a);for(d=Math.round(e/a);d<b||d>c;)a=d<b?a/2:2*a,d=Math.round(e/a);c=[];z(f,c,d,h,a);return{steps:d,stepValue:a,graphMin:h,labels:c}}function z(a,c,b,e,h){if(a)for(var f=1;f<b+1;f++)c.push(E(a,{value:(e+h*f).toFixed(0!=h%1?h.toString().split(".")[1].length:0)}))}function A(a,c,b){return!isNaN(parseFloat(c))&&isFinite(c)&&a>c?c:!isNaN(parseFloat(b))&&
-isFinite(b)&&a<b?b:a}function y(a,c){var b={},e;for(e in a)b[e]=a[e];for(e in c)b[e]=c[e];return b}function E(a,c){var b=!/\W/.test(a)?F[a]=F[a]||E(document.getElementById(a).innerHTML):new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+a.replace(/[\r\t\n]/g," ").split("<%").join("\t").replace(/((^|%>)[^\t]*)'/g,"$1\r").replace(/\t=(.*?)%>/g,"',$1,'").split("\t").join("');").split("%>").join("p.push('").split("\r").join("\\'")+"');}return p.join('');");return c?
-b(c):b}var r=this,B={linear:function(a){return a},easeInQuad:function(a){return a*a},easeOutQuad:function(a){return-1*a*(a-2)},easeInOutQuad:function(a){return 1>(a/=0.5)?0.5*a*a:-0.5*(--a*(a-2)-1)},easeInCubic:function(a){return a*a*a},easeOutCubic:function(a){return 1*((a=a/1-1)*a*a+1)},easeInOutCubic:function(a){return 1>(a/=0.5)?0.5*a*a*a:0.5*((a-=2)*a*a+2)},easeInQuart:function(a){return a*a*a*a},easeOutQuart:function(a){return-1*((a=a/1-1)*a*a*a-1)},easeInOutQuart:function(a){return 1>(a/=0.5)?
-0.5*a*a*a*a:-0.5*((a-=2)*a*a*a-2)},easeInQuint:function(a){return 1*(a/=1)*a*a*a*a},easeOutQuint:function(a){return 1*((a=a/1-1)*a*a*a*a+1)},easeInOutQuint:function(a){return 1>(a/=0.5)?0.5*a*a*a*a*a:0.5*((a-=2)*a*a*a*a+2)},easeInSine:function(a){return-1*Math.cos(a/1*(Math.PI/2))+1},easeOutSine:function(a){return 1*Math.sin(a/1*(Math.PI/2))},easeInOutSine:function(a){return-0.5*(Math.cos(Math.PI*a/1)-1)},easeInExpo:function(a){return 0==a?1:1*Math.pow(2,10*(a/1-1))},easeOutExpo:function(a){return 1==
-a?1:1*(-Math.pow(2,-10*a/1)+1)},easeInOutExpo:function(a){return 0==a?0:1==a?1:1>(a/=0.5)?0.5*Math.pow(2,10*(a-1)):0.5*(-Math.pow(2,-10*--a)+2)},easeInCirc:function(a){return 1<=a?a:-1*(Math.sqrt(1-(a/=1)*a)-1)},easeOutCirc:function(a){return 1*Math.sqrt(1-(a=a/1-1)*a)},easeInOutCirc:function(a){return 1>(a/=0.5)?-0.5*(Math.sqrt(1-a*a)-1):0.5*(Math.sqrt(1-(a-=2)*a)+1)},easeInElastic:function(a){var c=1.70158,b=0,e=1;if(0==a)return 0;if(1==(a/=1))return 1;b||(b=0.3);e<Math.abs(1)?(e=1,c=b/4):c=b/(2*
-Math.PI)*Math.asin(1/e);return-(e*Math.pow(2,10*(a-=1))*Math.sin((1*a-c)*2*Math.PI/b))},easeOutElastic:function(a){var c=1.70158,b=0,e=1;if(0==a)return 0;if(1==(a/=1))return 1;b||(b=0.3);e<Math.abs(1)?(e=1,c=b/4):c=b/(2*Math.PI)*Math.asin(1/e);return e*Math.pow(2,-10*a)*Math.sin((1*a-c)*2*Math.PI/b)+1},easeInOutElastic:function(a){var c=1.70158,b=0,e=1;if(0==a)return 0;if(2==(a/=0.5))return 1;b||(b=1*0.3*1.5);e<Math.abs(1)?(e=1,c=b/4):c=b/(2*Math.PI)*Math.asin(1/e);return 1>a?-0.5*e*Math.pow(2,10*
-(a-=1))*Math.sin((1*a-c)*2*Math.PI/b):0.5*e*Math.pow(2,-10*(a-=1))*Math.sin((1*a-c)*2*Math.PI/b)+1},easeInBack:function(a){return 1*(a/=1)*a*(2.70158*a-1.70158)},easeOutBack:function(a){return 1*((a=a/1-1)*a*(2.70158*a+1.70158)+1)},easeInOutBack:function(a){var c=1.70158;return 1>(a/=0.5)?0.5*a*a*(((c*=1.525)+1)*a-c):0.5*((a-=2)*a*(((c*=1.525)+1)*a+c)+2)},easeInBounce:function(a){return 1-B.easeOutBounce(1-a)},easeOutBounce:function(a){return(a/=1)<1/2.75?1*7.5625*a*a:a<2/2.75?1*(7.5625*(a-=1.5/2.75)*
-a+0.75):a<2.5/2.75?1*(7.5625*(a-=2.25/2.75)*a+0.9375):1*(7.5625*(a-=2.625/2.75)*a+0.984375)},easeInOutBounce:function(a){return 0.5>a?0.5*B.easeInBounce(2*a):0.5*B.easeOutBounce(2*a-1)+0.5}},q=s.canvas.width,u=s.canvas.height;window.devicePixelRatio&&(s.canvas.style.width=q+"px",s.canvas.style.height=u+"px",s.canvas.height=u*window.devicePixelRatio,s.canvas.width=q*window.devicePixelRatio,s.scale(window.devicePixelRatio,window.devicePixelRatio));this.PolarArea=function(a,c){r.PolarArea.defaults={scaleOverlay:!0,
-scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleShowLine:!0,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!0,scaleLabel:"<%=value%>",scaleFontFamily:"'Arial'",scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",scaleShowLabelBackdrop:!0,scaleBackdropColor:"rgba(255,255,255,0.75)",scaleBackdropPaddingY:2,scaleBackdropPaddingX:2,segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,animation:!0,animationSteps:100,animationEasing:"easeOutBounce",
-animateRotate:!0,animateScale:!1,onAnimationComplete:null};var b=c?y(r.PolarArea.defaults,c):r.PolarArea.defaults;return new G(a,b,s)};this.Radar=function(a,c){r.Radar.defaults={scaleOverlay:!1,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleShowLine:!0,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!1,scaleLabel:"<%=value%>",scaleFontFamily:"'Arial'",scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",scaleShowLabelBackdrop:!0,scaleBackdropColor:"rgba(255,255,255,0.75)",
-scaleBackdropPaddingY:2,scaleBackdropPaddingX:2,angleShowLineOut:!0,angleLineColor:"rgba(0,0,0,.1)",angleLineWidth:1,pointLabelFontFamily:"'Arial'",pointLabelFontStyle:"normal",pointLabelFontSize:12,pointLabelFontColor:"#666",pointDot:!0,pointDotRadius:3,pointDotStrokeWidth:1,datasetStroke:!0,datasetStrokeWidth:2,datasetFill:!0,animation:!0,animationSteps:60,animationEasing:"easeOutQuart",onAnimationComplete:null};var b=c?y(r.Radar.defaults,c):r.Radar.defaults;return new H(a,b,s)};this.Pie=function(a,
-c){r.Pie.defaults={segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,animation:!0,animationSteps:100,animationEasing:"easeOutBounce",animateRotate:!0,animateScale:!1,onAnimationComplete:null};var b=c?y(r.Pie.defaults,c):r.Pie.defaults;return new I(a,b,s)};this.Doughnut=function(a,c){r.Doughnut.defaults={segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,percentageInnerCutout:50,animation:!0,animationSteps:100,animationEasing:"easeOutBounce",animateRotate:!0,animateScale:!1,
-onAnimationComplete:null};var b=c?y(r.Doughnut.defaults,c):r.Doughnut.defaults;return new J(a,b,s)};this.Line=function(a,c){r.Line.defaults={scaleOverlay:!1,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!0,scaleLabel:"<%=value%>",scaleFontFamily:"'Arial'",scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",scaleShowGridLines:!0,scaleGridLineColor:"rgba(0,0,0,.05)",scaleGridLineWidth:1,bezierCurve:!0,
-pointDot:!0,pointDotRadius:4,pointDotStrokeWidth:2,datasetStroke:!0,datasetStrokeWidth:2,datasetFill:!0,animation:!0,animationSteps:60,animationEasing:"easeOutQuart",onAnimationComplete:null};var b=c?y(r.Line.defaults,c):r.Line.defaults;return new K(a,b,s)};this.Bar=function(a,c){r.Bar.defaults={scaleOverlay:!1,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!0,scaleLabel:"<%=value%>",scaleFontFamily:"'Arial'",
-scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",scaleShowGridLines:!0,scaleGridLineColor:"rgba(0,0,0,.05)",scaleGridLineWidth:1,barShowStroke:!0,barStrokeWidth:2,barValueSpacing:5,barDatasetSpacing:1,animation:!0,animationSteps:60,animationEasing:"easeOutQuart",onAnimationComplete:null};var b=c?y(r.Bar.defaults,c):r.Bar.defaults;return new L(a,b,s)};var G=function(a,c,b){var e,h,f,d,g,k,j,l,m;g=Math.min.apply(Math,[q,u])/2;g-=Math.max.apply(Math,[0.5*c.scaleFontSize,0.5*c.scaleLineWidth]);
-d=2*c.scaleFontSize;c.scaleShowLabelBackdrop&&(d+=2*c.scaleBackdropPaddingY,g-=1.5*c.scaleBackdropPaddingY);l=g;d=d?d:5;e=Number.MIN_VALUE;h=Number.MAX_VALUE;for(f=0;f<a.length;f++)a[f].value>e&&(e=a[f].value),a[f].value<h&&(h=a[f].value);f=Math.floor(l/(0.66*d));d=Math.floor(0.5*(l/d));m=c.scaleShowLabels?c.scaleLabel:null;c.scaleOverride?(j={steps:c.scaleSteps,stepValue:c.scaleStepWidth,graphMin:c.scaleStartValue,labels:[]},z(m,j.labels,j.steps,c.scaleStartValue,c.scaleStepWidth)):j=C(l,f,d,e,h,
-m);k=g/j.steps;x(c,function(){for(var a=0;a<j.steps;a++)if(c.scaleShowLine&&(b.beginPath(),b.arc(q/2,u/2,k*(a+1),0,2*Math.PI,!0),b.strokeStyle=c.scaleLineColor,b.lineWidth=c.scaleLineWidth,b.stroke()),c.scaleShowLabels){b.textAlign="center";b.font=c.scaleFontStyle+" "+c.scaleFontSize+"px "+c.scaleFontFamily;var e=j.labels[a];if(c.scaleShowLabelBackdrop){var d=b.measureText(e).width;b.fillStyle=c.scaleBackdropColor;b.beginPath();b.rect(Math.round(q/2-d/2-c.scaleBackdropPaddingX),Math.round(u/2-k*(a+
-1)-0.5*c.scaleFontSize-c.scaleBackdropPaddingY),Math.round(d+2*c.scaleBackdropPaddingX),Math.round(c.scaleFontSize+2*c.scaleBackdropPaddingY));b.fill()}b.textBaseline="middle";b.fillStyle=c.scaleFontColor;b.fillText(e,q/2,u/2-k*(a+1))}},function(e){var d=-Math.PI/2,g=2*Math.PI/a.length,f=1,h=1;c.animation&&(c.animateScale&&(f=e),c.animateRotate&&(h=e));for(e=0;e<a.length;e++)b.beginPath(),b.arc(q/2,u/2,f*v(a[e].value,j,k),d,d+h*g,!1),b.lineTo(q/2,u/2),b.closePath(),b.fillStyle=a[e].color,b.fill(),
-c.segmentShowStroke&&(b.strokeStyle=c.segmentStrokeColor,b.lineWidth=c.segmentStrokeWidth,b.stroke()),d+=h*g},b)},H=function(a,c,b){var e,h,f,d,g,k,j,l,m;a.labels||(a.labels=[]);g=Math.min.apply(Math,[q,u])/2;d=2*c.scaleFontSize;for(e=l=0;e<a.labels.length;e++)b.font=c.pointLabelFontStyle+" "+c.pointLabelFontSize+"px "+c.pointLabelFontFamily,h=b.measureText(a.labels[e]).width,h>l&&(l=h);g-=Math.max.apply(Math,[l,1.5*(c.pointLabelFontSize/2)]);g-=c.pointLabelFontSize;l=g=A(g,null,0);d=d?d:5;e=Number.MIN_VALUE;
-h=Number.MAX_VALUE;for(f=0;f<a.datasets.length;f++)for(m=0;m<a.datasets[f].data.length;m++)a.datasets[f].data[m]>e&&(e=a.datasets[f].data[m]),a.datasets[f].data[m]<h&&(h=a.datasets[f].data[m]);f=Math.floor(l/(0.66*d));d=Math.floor(0.5*(l/d));m=c.scaleShowLabels?c.scaleLabel:null;c.scaleOverride?(j={steps:c.scaleSteps,stepValue:c.scaleStepWidth,graphMin:c.scaleStartValue,labels:[]},z(m,j.labels,j.steps,c.scaleStartValue,c.scaleStepWidth)):j=C(l,f,d,e,h,m);k=g/j.steps;x(c,function(){var e=2*Math.PI/
-a.datasets[0].data.length;b.save();b.translate(q/2,u/2);if(c.angleShowLineOut){b.strokeStyle=c.angleLineColor;b.lineWidth=c.angleLineWidth;for(var d=0;d<a.datasets[0].data.length;d++)b.rotate(e),b.beginPath(),b.moveTo(0,0),b.lineTo(0,-g),b.stroke()}for(d=0;d<j.steps;d++){b.beginPath();if(c.scaleShowLine){b.strokeStyle=c.scaleLineColor;b.lineWidth=c.scaleLineWidth;b.moveTo(0,-k*(d+1));for(var f=0;f<a.datasets[0].data.length;f++)b.rotate(e),b.lineTo(0,-k*(d+1));b.closePath();b.stroke()}c.scaleShowLabels&&
-(b.textAlign="center",b.font=c.scaleFontStyle+" "+c.scaleFontSize+"px "+c.scaleFontFamily,b.textBaseline="middle",c.scaleShowLabelBackdrop&&(f=b.measureText(j.labels[d]).width,b.fillStyle=c.scaleBackdropColor,b.beginPath(),b.rect(Math.round(-f/2-c.scaleBackdropPaddingX),Math.round(-k*(d+1)-0.5*c.scaleFontSize-c.scaleBackdropPaddingY),Math.round(f+2*c.scaleBackdropPaddingX),Math.round(c.scaleFontSize+2*c.scaleBackdropPaddingY)),b.fill()),b.fillStyle=c.scaleFontColor,b.fillText(j.labels[d],0,-k*(d+
-1)))}for(d=0;d<a.labels.length;d++){b.font=c.pointLabelFontStyle+" "+c.pointLabelFontSize+"px "+c.pointLabelFontFamily;b.fillStyle=c.pointLabelFontColor;var f=Math.sin(e*d)*(g+c.pointLabelFontSize),h=Math.cos(e*d)*(g+c.pointLabelFontSize);b.textAlign=e*d==Math.PI||0==e*d?"center":e*d>Math.PI?"right":"left";b.textBaseline="middle";b.fillText(a.labels[d],f,-h)}b.restore()},function(d){var e=2*Math.PI/a.datasets[0].data.length;b.save();b.translate(q/2,u/2);for(var g=0;g<a.datasets.length;g++){b.beginPath();
-b.moveTo(0,d*-1*v(a.datasets[g].data[0],j,k));for(var f=1;f<a.datasets[g].data.length;f++)b.rotate(e),b.lineTo(0,d*-1*v(a.datasets[g].data[f],j,k));b.closePath();b.fillStyle=a.datasets[g].fillColor;b.strokeStyle=a.datasets[g].strokeColor;b.lineWidth=c.datasetStrokeWidth;b.fill();b.stroke();if(c.pointDot){b.fillStyle=a.datasets[g].pointColor;b.strokeStyle=a.datasets[g].pointStrokeColor;b.lineWidth=c.pointDotStrokeWidth;for(f=0;f<a.datasets[g].data.length;f++)b.rotate(e),b.beginPath(),b.arc(0,d*-1*
-v(a.datasets[g].data[f],j,k),c.pointDotRadius,2*Math.PI,!1),b.fill(),b.stroke()}b.rotate(e)}b.restore()},b)},I=function(a,c,b){for(var e=0,h=Math.min.apply(Math,[u/2,q/2])-5,f=0;f<a.length;f++)e+=a[f].value;x(c,null,function(d){var g=-Math.PI/2,f=1,j=1;c.animation&&(c.animateScale&&(f=d),c.animateRotate&&(j=d));for(d=0;d<a.length;d++){var l=j*a[d].value/e*2*Math.PI;b.beginPath();b.arc(q/2,u/2,f*h,g,g+l);b.lineTo(q/2,u/2);b.closePath();b.fillStyle=a[d].color;b.fill();c.segmentShowStroke&&(b.lineWidth=
-c.segmentStrokeWidth,b.strokeStyle=c.segmentStrokeColor,b.stroke());g+=l}},b)},J=function(a,c,b){for(var e=0,h=Math.min.apply(Math,[u/2,q/2])-5,f=h*(c.percentageInnerCutout/100),d=0;d<a.length;d++)e+=a[d].value;x(c,null,function(d){var k=-Math.PI/2,j=1,l=1;c.animation&&(c.animateScale&&(j=d),c.animateRotate&&(l=d));for(d=0;d<a.length;d++){var m=l*a[d].value/e*2*Math.PI;b.beginPath();b.arc(q/2,u/2,j*h,k,k+m,!1);b.arc(q/2,u/2,j*f,k+m,k,!0);b.closePath();b.fillStyle=a[d].color;b.fill();c.segmentShowStroke&&
-(b.lineWidth=c.segmentStrokeWidth,b.strokeStyle=c.segmentStrokeColor,b.stroke());k+=m}},b)},K=function(a,c,b){var e,h,f,d,g,k,j,l,m,t,r,n,p,s=0;g=u;b.font=c.scaleFontStyle+" "+c.scaleFontSize+"px "+c.scaleFontFamily;t=1;for(d=0;d<a.labels.length;d++)e=b.measureText(a.labels[d]).width,t=e>t?e:t;q/a.labels.length<t?(s=45,q/a.labels.length<Math.cos(s)*t?(s=90,g-=t):g-=Math.sin(s)*t):g-=c.scaleFontSize;d=c.scaleFontSize;g=g-5-d;e=Number.MIN_VALUE;h=Number.MAX_VALUE;for(f=0;f<a.datasets.length;f++)for(l=
-0;l<a.datasets[f].data.length;l++)a.datasets[f].data[l]>e&&(e=a.datasets[f].data[l]),a.datasets[f].data[l]<h&&(h=a.datasets[f].data[l]);f=Math.floor(g/(0.66*d));d=Math.floor(0.5*(g/d));l=c.scaleShowLabels?c.scaleLabel:"";c.scaleOverride?(j={steps:c.scaleSteps,stepValue:c.scaleStepWidth,graphMin:c.scaleStartValue,labels:[]},z(l,j.labels,j.steps,c.scaleStartValue,c.scaleStepWidth)):j=C(g,f,d,e,h,l);k=Math.floor(g/j.steps);d=1;if(c.scaleShowLabels){b.font=c.scaleFontStyle+" "+c.scaleFontSize+"px "+c.scaleFontFamily;
-for(e=0;e<j.labels.length;e++)h=b.measureText(j.labels[e]).width,d=h>d?h:d;d+=10}r=q-d-t;m=Math.floor(r/(a.labels.length-1));n=q-t/2-r;p=g+c.scaleFontSize/2;x(c,function(){b.lineWidth=c.scaleLineWidth;b.strokeStyle=c.scaleLineColor;b.beginPath();b.moveTo(q-t/2+5,p);b.lineTo(q-t/2-r-5,p);b.stroke();0<s?(b.save(),b.textAlign="right"):b.textAlign="center";b.fillStyle=c.scaleFontColor;for(var d=0;d<a.labels.length;d++)b.save(),0<s?(b.translate(n+d*m,p+c.scaleFontSize),b.rotate(-(s*(Math.PI/180))),b.fillText(a.labels[d],
-0,0),b.restore()):b.fillText(a.labels[d],n+d*m,p+c.scaleFontSize+3),b.beginPath(),b.moveTo(n+d*m,p+3),c.scaleShowGridLines&&0<d?(b.lineWidth=c.scaleGridLineWidth,b.strokeStyle=c.scaleGridLineColor,b.lineTo(n+d*m,5)):b.lineTo(n+d*m,p+3),b.stroke();b.lineWidth=c.scaleLineWidth;b.strokeStyle=c.scaleLineColor;b.beginPath();b.moveTo(n,p+5);b.lineTo(n,5);b.stroke();b.textAlign="right";b.textBaseline="middle";for(d=0;d<j.steps;d++)b.beginPath(),b.moveTo(n-3,p-(d+1)*k),c.scaleShowGridLines?(b.lineWidth=c.scaleGridLineWidth,
-b.strokeStyle=c.scaleGridLineColor,b.lineTo(n+r+5,p-(d+1)*k)):b.lineTo(n-0.5,p-(d+1)*k),b.stroke(),c.scaleShowLabels&&b.fillText(j.labels[d],n-8,p-(d+1)*k)},function(d){function e(b,c){return p-d*v(a.datasets[b].data[c],j,k)}for(var f=0;f<a.datasets.length;f++){b.strokeStyle=a.datasets[f].strokeColor;b.lineWidth=c.datasetStrokeWidth;b.beginPath();b.moveTo(n,p-d*v(a.datasets[f].data[0],j,k));for(var g=1;g<a.datasets[f].data.length;g++)c.bezierCurve?b.bezierCurveTo(n+m*(g-0.5),e(f,g-1),n+m*(g-0.5),
-e(f,g),n+m*g,e(f,g)):b.lineTo(n+m*g,e(f,g));b.stroke();c.datasetFill?(b.lineTo(n+m*(a.datasets[f].data.length-1),p),b.lineTo(n,p),b.closePath(),b.fillStyle=a.datasets[f].fillColor,b.fill()):b.closePath();if(c.pointDot){b.fillStyle=a.datasets[f].pointColor;b.strokeStyle=a.datasets[f].pointStrokeColor;b.lineWidth=c.pointDotStrokeWidth;for(g=0;g<a.datasets[f].data.length;g++)b.beginPath(),b.arc(n+m*g,p-d*v(a.datasets[f].data[g],j,k),c.pointDotRadius,0,2*Math.PI,!0),b.fill(),b.stroke()}}},b)},L=function(a,
-c,b){var e,h,f,d,g,k,j,l,m,t,r,n,p,s,w=0;g=u;b.font=c.scaleFontStyle+" "+c.scaleFontSize+"px "+c.scaleFontFamily;t=1;for(d=0;d<a.labels.length;d++)e=b.measureText(a.labels[d]).width,t=e>t?e:t;q/a.labels.length<t?(w=45,q/a.labels.length<Math.cos(w)*t?(w=90,g-=t):g-=Math.sin(w)*t):g-=c.scaleFontSize;d=c.scaleFontSize;g=g-5-d;e=Number.MIN_VALUE;h=Number.MAX_VALUE;for(f=0;f<a.datasets.length;f++)for(l=0;l<a.datasets[f].data.length;l++)a.datasets[f].data[l]>e&&(e=a.datasets[f].data[l]),a.datasets[f].data[l]<
-h&&(h=a.datasets[f].data[l]);f=Math.floor(g/(0.66*d));d=Math.floor(0.5*(g/d));l=c.scaleShowLabels?c.scaleLabel:"";c.scaleOverride?(j={steps:c.scaleSteps,stepValue:c.scaleStepWidth,graphMin:c.scaleStartValue,labels:[]},z(l,j.labels,j.steps,c.scaleStartValue,c.scaleStepWidth)):j=C(g,f,d,e,h,l);k=Math.floor(g/j.steps);d=1;if(c.scaleShowLabels){b.font=c.scaleFontStyle+" "+c.scaleFontSize+"px "+c.scaleFontFamily;for(e=0;e<j.labels.length;e++)h=b.measureText(j.labels[e]).width,d=h>d?h:d;d+=10}r=q-d-t;m=
-Math.floor(r/a.labels.length);s=(m-2*c.scaleGridLineWidth-2*c.barValueSpacing-(c.barDatasetSpacing*a.datasets.length-1)-(c.barStrokeWidth/2*a.datasets.length-1))/a.datasets.length;n=q-t/2-r;p=g+c.scaleFontSize/2;x(c,function(){b.lineWidth=c.scaleLineWidth;b.strokeStyle=c.scaleLineColor;b.beginPath();b.moveTo(q-t/2+5,p);b.lineTo(q-t/2-r-5,p);b.stroke();0<w?(b.save(),b.textAlign="right"):b.textAlign="center";b.fillStyle=c.scaleFontColor;for(var d=0;d<a.labels.length;d++)b.save(),0<w?(b.translate(n+
-d*m,p+c.scaleFontSize),b.rotate(-(w*(Math.PI/180))),b.fillText(a.labels[d],0,0),b.restore()):b.fillText(a.labels[d],n+d*m+m/2,p+c.scaleFontSize+3),b.beginPath(),b.moveTo(n+(d+1)*m,p+3),b.lineWidth=c.scaleGridLineWidth,b.strokeStyle=c.scaleGridLineColor,b.lineTo(n+(d+1)*m,5),b.stroke();b.lineWidth=c.scaleLineWidth;b.strokeStyle=c.scaleLineColor;b.beginPath();b.moveTo(n,p+5);b.lineTo(n,5);b.stroke();b.textAlign="right";b.textBaseline="middle";for(d=0;d<j.steps;d++)b.beginPath(),b.moveTo(n-3,p-(d+1)*
-k),c.scaleShowGridLines?(b.lineWidth=c.scaleGridLineWidth,b.strokeStyle=c.scaleGridLineColor,b.lineTo(n+r+5,p-(d+1)*k)):b.lineTo(n-0.5,p-(d+1)*k),b.stroke(),c.scaleShowLabels&&b.fillText(j.labels[d],n-8,p-(d+1)*k)},function(d){b.lineWidth=c.barStrokeWidth;for(var e=0;e<a.datasets.length;e++){b.fillStyle=a.datasets[e].fillColor;b.strokeStyle=a.datasets[e].strokeColor;for(var f=0;f<a.datasets[e].data.length;f++){var g=n+c.barValueSpacing+m*f+s*e+c.barDatasetSpacing*e+c.barStrokeWidth*e;b.beginPath();
-b.moveTo(g,p);b.lineTo(g,p-d*v(a.datasets[e].data[f],j,k)+c.barStrokeWidth/2);b.lineTo(g+s,p-d*v(a.datasets[e].data[f],j,k)+c.barStrokeWidth/2);b.lineTo(g+s,p);c.barShowStroke&&b.stroke();b.closePath();b.fill()}}},b)},D=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a){window.setTimeout(a,1E3/60)},F={}};
\ No newline at end of file
diff --git a/app/assets/javascripts/ci/build.coffee b/app/assets/javascripts/ci/build.coffee
index c30859b484bd8bfe6fba1194b091d6b95c1563a4..93385b32a13a888880976378e893ba2687a199e5 100644
--- a/app/assets/javascripts/ci/build.coffee
+++ b/app/assets/javascripts/ci/build.coffee
@@ -22,7 +22,7 @@ class CiBuild
       # Only valid for runnig build when output changes during time
       #
       CiBuild.interval = setInterval =>
-        if window.location.href is build_url
+        if window.location.href.split("#").first() is build_url
           $.ajax
             url: build_url
             dataType: "json"
diff --git a/app/assets/javascripts/ci/projects.js.coffee b/app/assets/javascripts/ci/projects.js.coffee
index 7e028b4e115216e557728ca1928db877ef5f3f2e..e6406011d11438a454784b786f62a7c22d38a30f 100644
--- a/app/assets/javascripts/ci/projects.js.coffee
+++ b/app/assets/javascripts/ci/projects.js.coffee
@@ -1,6 +1,3 @@
 $(document).on 'click', '.badge-codes-toggle', ->
   $('.badge-codes-block').toggleClass("hide")
   return false
-
-$(document).on 'click', '.sync-now', ->
-  $(this).find('i').addClass('fa-spin')
diff --git a/app/assets/javascripts/line_highlighter.js.coffee b/app/assets/javascripts/line_highlighter.js.coffee
index e604e6025c2fb0caf51f826c08493126f3a2f268..2254a3f91aeb35dc08e06d43aea64a129d8598a2 100644
--- a/app/assets/javascripts/line_highlighter.js.coffee
+++ b/app/assets/javascripts/line_highlighter.js.coffee
@@ -6,7 +6,7 @@
 #
 # ### Example Markup
 #
-#   <div id="tree-content-holder">
+#   <div id="blob-content-holder">
 #     <div class="file-content">
 #       <div class="line-numbers">
 #         <a href="#L1" id="L1" data-line-number="1">1</a>
@@ -53,7 +53,7 @@ class @LineHighlighter
         $.scrollTo("#L#{range[0]}", offset: -150)
 
   bindEvents: ->
-    $('#tree-content-holder').on 'mousedown', 'a[data-line-number]', @clickHandler
+    $('#blob-content-holder').on 'mousedown', 'a[data-line-number]', @clickHandler
 
     # While it may seem odd to bind to the mousedown event and then throw away
     # the click event, there is a method to our madness.
@@ -62,7 +62,7 @@ class @LineHighlighter
     # active state even when the event is cancelled, resulting in an ugly border
     # around the link and/or a persisted underline text decoration.
 
-    $('#tree-content-holder').on 'click', 'a[data-line-number]', (event) ->
+    $('#blob-content-holder').on 'click', 'a[data-line-number]', (event) ->
       event.preventDefault()
 
   clickHandler: (event) =>
diff --git a/app/assets/javascripts/merge_request_tabs.js.coffee b/app/assets/javascripts/merge_request_tabs.js.coffee
index 19a07b6a03315bed8b769c9c8732f37d82897ab3..593a8f42130d560598656814753d48df5fde3cde 100644
--- a/app/assets/javascripts/merge_request_tabs.js.coffee
+++ b/app/assets/javascripts/merge_request_tabs.js.coffee
@@ -66,6 +66,11 @@ class @MergeRequestTabs
 
     @setCurrentAction(action)
 
+  scrollToElement: (container) ->
+    if window.location.hash
+      $el = $("#{container} #{window.location.hash}")
+      $('body').scrollTo($el.offset().top) if $el.length
+
   # Activate a tab based on the current action
   activateTab: (action) ->
     action = 'notes' if action == 'show'
@@ -122,6 +127,7 @@ class @MergeRequestTabs
         document.getElementById('commits').innerHTML = data.html
         $('.js-timeago').timeago()
         @commitsLoaded = true
+        @scrollToElement("#commits")
 
   loadDiff: (source) ->
     return if @diffsLoaded
@@ -131,14 +137,18 @@ class @MergeRequestTabs
       success: (data) =>
         document.getElementById('diffs').innerHTML = data.html
         @diffsLoaded = true
+        @scrollToElement("#diffs")
 
-  toggleLoading: ->
-    $('.mr-loading-status .loading').toggle()
+  # Show or hide the loading spinner
+  #
+  # status - Boolean, true to show, false to hide
+  toggleLoading: (status) ->
+    $('.mr-loading-status .loading').toggle(status)
 
   _get: (options) ->
     defaults = {
-      beforeSend: @toggleLoading
-      complete: @toggleLoading
+      beforeSend: => @toggleLoading(true)
+      complete:   => @toggleLoading(false)
       dataType: 'json'
       type: 'GET'
     }
diff --git a/app/assets/javascripts/merge_request_widget.js.coffee b/app/assets/javascripts/merge_request_widget.js.coffee
index 995a2f24093357901806713a49774fdb2d3018bb..3176e5a89652b72256342fc822bc485efeaaa780 100644
--- a/app/assets/javascripts/merge_request_widget.js.coffee
+++ b/app/assets/javascripts/merge_request_widget.js.coffee
@@ -15,11 +15,12 @@ class @MergeRequestWidget
       type: 'GET'
       url: $('.merge-request').data('url')
       success: (data) =>
-        switch data.state
-          when 'merged'
-            location.reload()
-          else
-            setTimeout(merge_request_widget.mergeInProgress, 2000)
+        if data.state == "merged"
+          location.reload()
+        else if data.merge_error
+          $('.mr-widget-body').html("<h4>" + data.merge_error + "</h4>")
+        else
+          setTimeout(merge_request_widget.mergeInProgress, 2000)
       dataType: 'json'
 
   getMergeStatus: ->
diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee
index ce638c2641b9c9f2dc6259791ccf1bb2f4cf707f..ea75c656bccb5025a2b556913d6b66aefda73c32 100644
--- a/app/assets/javascripts/notes.js.coffee
+++ b/app/assets/javascripts/notes.js.coffee
@@ -63,12 +63,6 @@ class @Notes
     # fetch notes when tab becomes visible
     $(document).on "visibilitychange", @visibilityChange
 
-    # Chrome doesn't fire keypress or keyup for Command+Enter, so we need keydown.
-    $(document).on 'keydown', '.js-note-text', (e) ->
-      return if e.originalEvent.repeat
-      if e.keyCode == 10 || ((e.metaKey || e.ctrlKey) && e.keyCode == 13)
-        $(@).closest('form').submit()
-
   cleanBinding: ->
     $(document).off "ajax:success", ".js-main-target-form"
     $(document).off "ajax:success", ".js-discussion-note-form"
@@ -82,7 +76,6 @@ class @Notes
     $(document).off "click", ".js-discussion-reply-button"
     $(document).off "click", ".js-add-diff-note-button"
     $(document).off "visibilitychange"
-    $(document).off "keydown", ".js-note-text"
     $(document).off "keyup", ".js-note-text"
     $(document).off "click", ".js-note-target-reopen"
     $(document).off "click", ".js-note-target-close"
@@ -277,13 +270,15 @@ class @Notes
 
   Updates the current note field.
   ###
-  updateNote: (xhr, note, status) =>
-    note_li = $(".note-row-" + note.id)
-    note_li.replaceWith(note.html)
-    note_li.find('.note-edit-form').hide()
-    note_li.find('.note-body > .note-text').show()
-    note_li.find('js-task-list-container').taskList('enable')
-    @enableTaskList()
+  updateNote: (_xhr, note, _status) =>
+    # Convert returned HTML to a jQuery object so we can modify it further
+    $html = $(note.html)
+    $html.syntaxHighlight()
+    $html.find('.js-task-list-container').taskList('enable')
+
+    # Find the note's `li` element by ID and replace it with the updated HTML
+    $note_li = $("#note_#{note.id}")
+    $note_li.replaceWith($html)
 
   ###
   Called in response to clicking the edit note link
diff --git a/app/assets/javascripts/shortcuts_navigation.coffee b/app/assets/javascripts/shortcuts_navigation.coffee
index 5b6f9e7e3f25e3f75bdba43a28725cf8303ec722..8decaedd87bac29dc05d547dfbfb6ee48d2e341f 100644
--- a/app/assets/javascripts/shortcuts_navigation.coffee
+++ b/app/assets/javascripts/shortcuts_navigation.coffee
@@ -7,6 +7,7 @@ class @ShortcutsNavigation extends Shortcuts
     Mousetrap.bind('g e', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-project-activity'))
     Mousetrap.bind('g f', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-tree'))
     Mousetrap.bind('g c', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-commits'))
+    Mousetrap.bind('g b', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-builds'))
     Mousetrap.bind('g n', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-network'))
     Mousetrap.bind('g g', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-graphs'))
     Mousetrap.bind('g i', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-issues'))
diff --git a/app/assets/javascripts/tree.js.coffee b/app/assets/javascripts/tree.js.coffee
index d428db5b4227096ab1481fe345f6d4f764a49bb7..de8eebcd0b2c6c14a456bba0ceebadac817522b3 100644
--- a/app/assets/javascripts/tree.js.coffee
+++ b/app/assets/javascripts/tree.js.coffee
@@ -16,6 +16,9 @@ class @TreeView
     li = $("tr.tree-item")
     liSelected = null
     $('body').keydown (e) ->
+      if $("input:focus").length > 0 && (e.which == 38 || e.which == 40)
+        return false
+
       if e.which is 40
         if liSelected
           next = liSelected.next()
@@ -38,4 +41,4 @@ class @TreeView
         $(liSelected).focus()
       else if e.which is 13
         path = $('.tree-item.selected .tree-item-file-name a').attr('href')
-        Turbolinks.visit(path)
+        if path then Turbolinks.visit(path)
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index d9ede6379440525a0d6935209cb58a5841c6db56..7b060ce48532c36dadd52950c5f8f293a7515821 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -11,59 +11,41 @@
  *= require cal-heatmap
 */
 
+/*
+ * Welcome to GitLab css!
+ * If you need to add or modify UI component that is common for many pages
+ * like a table or typography then make changes in the framework/ directory.
+ * If you need to add unique style that should affect only one page - use pages/
+ * directory.
+ */
 
-@import "base/fonts";
-@import "base/variables";
-@import "base/mixins";
-@import "base/layout";
-
-
-/**
- * Customized Twitter bootstrap
+/*
+ * GitLab UI framework
  */
-@import 'base/gl_variables';
-@import 'base/gl_bootstrap';
+@import "framework";
 
-/**
+/*
  * NProgress load bar css
  */
 @import 'nprogress';
 @import 'nprogress-bootstrap';
 
-/**
+/*
  * Font icons
- *
  */
 @import "font-awesome";
 
-/**
- * UI themes:
- */
-@import "themes/**/*";
-
-/**
- * Generic css (forms, nav etc):
- */
-@import "generic/**/*";
-
-/**
+/*
  * Page specific styles (issues, projects etc):
  */
-
 @import "pages/**/*";
 
-/**
+/*
  * Code highlight
  */
 @import "highlight/**/*";
 
-/**
+/*
  * Styles for JS behaviors.
  */
-@import "behaviors.scss";
-
-/**
- * CI specific styles:
- */
-@import "ci/**/*";
-
+@import "behaviors.scss";
\ No newline at end of file
diff --git a/app/assets/stylesheets/base/variables.scss b/app/assets/stylesheets/base/variables.scss
deleted file mode 100644
index 2fc7bf1720a625d6a722fa5ffadee5f8ad958804..0000000000000000000000000000000000000000
--- a/app/assets/stylesheets/base/variables.scss
+++ /dev/null
@@ -1,43 +0,0 @@
-$hover: #FFFAF1;
-$gl-text-color: #54565b;
-$gl-header-color: #4c4e54;
-$gl-link-color: #333c48;
-$md-text-color: #444;
-$md-link-color: #3084bb;
-$nprogress-color: #c0392b;
-$gl-font-size: 15px;
-$list-font-size: 15px;
-$sidebar_collapsed_width: 62px;
-$sidebar_width: 230px;
-$avatar_radius: 50%;
-$code_font_size: 13px;
-$code_line_height: 1.5;
-$border-color: #E7E9ED;
-$background-color: #F8FAFC;
-$header-height: 58px;
-$fixed-layout-width: 1200px;
-$gl-gray: #7f8fa4;
-$gl-padding: 16px;
-$gl-avatar-size: 46px;
-
-
-/*
- * State colors:
- */
-$gl-primary: #446e9b;
-$gl-success: #44c679;
-$gl-info: #00aaff;
-$gl-warning: #EB9532;
-$gl-danger: #d9534f;
-
-/*
- * Commit Diff Colors
- */
-$added: #63c363;
-$deleted: #f77;
-
-/*
- * Fonts
- */
-$monospace_font: 'Menlo', 'Liberation Mono', 'Consolas', 'DejaVu Sans Mono', 'Ubuntu Mono', 'Courier New', 'andale mono', 'lucida console', monospace;
-$regular_font: 'Source Sans Pro', "Helvetica Neue", Helvetica, Arial, sans-serif;
diff --git a/app/assets/stylesheets/ci/runners.scss b/app/assets/stylesheets/ci/runners.scss
deleted file mode 100644
index 2b15ab8312947d712810ab4a9552cee569af0136..0000000000000000000000000000000000000000
--- a/app/assets/stylesheets/ci/runners.scss
+++ /dev/null
@@ -1,36 +0,0 @@
-.ci-body {
-  .runner-state {
-    padding: 6px 12px;
-    margin-right: 10px;
-    color: #FFF;
-
-    &.runner-state-shared {
-      background: #32b186;
-    }
-    &.runner-state-specific {
-      background: #3498db;
-    }
-  }
-
-  .runner-status-online {
-    color: green;
-  }
-
-  .runner-status-offline {
-    color: gray;
-  }
-
-  .runner-status-paused {
-    color: red;
-  }
-
-  .runner {
-    .btn {
-      padding: 1px 6px;
-    }
-
-    h4 {
-      font-weight: normal;
-    }
-  }
-}
diff --git a/app/assets/stylesheets/framework.scss b/app/assets/stylesheets/framework.scss
new file mode 100644
index 0000000000000000000000000000000000000000..1ec9d2fd84f1fe0e5c69104c7a33c7564f085458
--- /dev/null
+++ b/app/assets/stylesheets/framework.scss
@@ -0,0 +1,33 @@
+@import "framework/fonts";
+@import "framework/variables";
+@import "framework/mixins";
+@import "framework/layout";
+@import 'framework/tw_bootstrap_variables';
+@import 'framework/tw_bootstrap';
+
+@import "framework/avatar.scss";
+@import "framework/blocks.scss";
+@import "framework/buttons.scss";
+@import "framework/calendar.scss";
+@import "framework/callout.scss";
+@import "framework/common.scss";
+@import "framework/files.scss";
+@import "framework/filters.scss";
+@import "framework/flash.scss";
+@import "framework/forms.scss";
+@import "framework/gfm.scss";
+@import "framework/gitlab-theme.scss";
+@import "framework/header.scss";
+@import "framework/highlight.scss";
+@import "framework/issue_box.scss";
+@import "framework/jquery.scss";
+@import "framework/lists.scss";
+@import "framework/markdown_area.scss";
+@import "framework/mobile.scss";
+@import "framework/pagination.scss";
+@import "framework/selects.scss";
+@import "framework/sidebar.scss";
+@import "framework/tables.scss";
+@import "framework/timeline.scss";
+@import "framework/typography.scss";
+@import "framework/zen.scss";
diff --git a/app/assets/stylesheets/generic/avatar.scss b/app/assets/stylesheets/framework/avatar.scss
similarity index 91%
rename from app/assets/stylesheets/generic/avatar.scss
rename to app/assets/stylesheets/framework/avatar.scss
index 221cb6a04a511472fce53f6a23b94a53a24e7da0..36e582d48544bc790c09ca56c3dd1c6702f7be74 100644
--- a/app/assets/stylesheets/generic/avatar.scss
+++ b/app/assets/stylesheets/framework/avatar.scss
@@ -28,6 +28,7 @@
   &.s48 { width: 48px; height: 48px; margin-right: 10px; }
   &.s60 { width: 60px; height: 60px; margin-right: 12px; }
   &.s90 { width: 90px; height: 90px; margin-right: 15px; }
+  &.s110 { width: 110px; height: 110px; margin-right: 15px; }
   &.s140 { width: 140px; height: 140px; margin-right: 20px; }
   &.s160 { width: 160px; height: 160px; margin-right: 20px; }
 }
@@ -42,6 +43,7 @@
   &.s32 { font-size: 22px; line-height: 32px; }
   &.s60 { font-size: 32px; line-height: 60px; }
   &.s90 { font-size: 36px; line-height: 90px; }
+  &.s110 { font-size: 40px; line-height: 112px; font-weight: 300; }
   &.s140 { font-size: 72px; line-height: 140px; }
   &.s160 { font-size: 96px; line-height: 160px; }
 }
diff --git a/app/assets/stylesheets/generic/blocks.scss b/app/assets/stylesheets/framework/blocks.scss
similarity index 55%
rename from app/assets/stylesheets/generic/blocks.scss
rename to app/assets/stylesheets/framework/blocks.scss
index 6ce34b5c3e8f3c691dafa24dfa0900afc718b28c..5949a0fd5adc0ac65509f2c675170f9b5f4acccf 100644
--- a/app/assets/stylesheets/generic/blocks.scss
+++ b/app/assets/stylesheets/framework/blocks.scss
@@ -18,6 +18,7 @@
   line-height: 36px;
 }
 
+.content-block,
 .gray-content-block {
   margin: -$gl-padding;
   background-color: $background-color;
@@ -27,6 +28,10 @@
   border-bottom: 1px solid $border-color;
   color: $gl-gray;
 
+  &.white {
+    background-color: white;
+  }
+
   &.top-block {
     border-top: none;
   }
@@ -60,3 +65,48 @@
     line-height: 42px;
   }
 }
+
+.cover-block {
+  text-align: center;
+  background: #f7f8fa;
+  margin: -$gl-padding;
+  margin-bottom: 0;
+  padding: 44px $gl-padding;
+  border-bottom: 1px solid $border-color;
+  position: relative;
+
+  .avatar-holder {
+    margin-bottom: 16px;
+
+    .avatar, .identicon {
+      margin: 0 auto;
+      float: none;
+    }
+
+    .identicon {
+      @include border-radius(50%);
+    }
+  }
+
+  .cover-title {
+    color: $gl-header-color;
+    margin: 0;
+    font-size: 23px;
+    font-weight: normal;
+    margin: 16px 0 5px 0;
+    color: #4c4e54;
+    font-size: 23px;
+    line-height: 1.1;
+  }
+
+  .cover-desc {
+    padding: 0 $gl-padding;
+    color: $gl-text-color;
+  }
+
+  .cover-controls {
+    position: absolute;
+    top: 10px;
+    right: 10px;
+  }
+}
diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss
new file mode 100644
index 0000000000000000000000000000000000000000..04024419584e39ef6c732e6f92b5c667aeb00181
--- /dev/null
+++ b/app/assets/stylesheets/framework/buttons.scss
@@ -0,0 +1,182 @@
+@mixin btn-default {
+  @include border-radius(2px);
+  border-width: 1px;
+  border-style: solid;
+  text-transform: uppercase;
+  font-size: 13px;
+  font-weight: 600;
+  line-height: 18px;
+  padding: 11px $gl-padding;
+  letter-spacing: .4px;
+
+  &:focus,
+  &:active {
+    outline: none;
+    @include box-shadow(inset 0 0 4px rgba(0, 0, 0, 0.12));
+  }
+}
+
+@mixin btn-middle {
+  @include btn-default;
+  @include border-radius(2px);
+  padding: 11px 24px;
+}
+
+@mixin btn-color($light, $border-light, $normal, $border-normal, $dark, $border-dark, $color) {
+  background-color: $light;
+  border-color: $border-light;
+  color: $color;
+
+  &:hover,
+  &:focus {
+    background-color: $normal;
+    border-color: $border-normal;
+    color: $color;
+  }
+
+  &:active {
+    @include box-shadow (inset 0 0 4px rgba(0, 0, 0, 0.12));
+
+    background-color: $dark;
+    border-color: $border-dark;
+    color: $color;
+  }
+}
+
+@mixin btn-green {
+  @include btn-color($green-light, $border-green-light, $green-normal, $border-green-normal, $green-dark, $border-green-dark, #FFFFFF);
+}
+
+@mixin btn-blue {
+  @include btn-color($blue-light, $border-blue-light, $blue-normal, $border-blue-normal, $blue-dark, $border-blue-dark, #FFFFFF);
+}
+
+@mixin btn-orange {
+  @include btn-color($orange-light, $border-orange-light, $orange-normal, $border-orange-normal, $orange-dark, $border-orange-dark, #FFFFFF);
+}
+
+@mixin btn-red {
+  @include btn-color($red-light, $border-red-light, $red-normal, $border-red-normal, $red-dark, $border-red-dark, #FFFFFF);
+}
+
+@mixin btn-gray {
+  @include btn-color($gray-light, $border-gray-light, $gray-normal, $border-gray-normal, $gray-dark, $border-gray-dark, #313236);
+}
+
+@mixin btn-white {
+  @include btn-color($white-light, $border-white-light, $white-normal, $border-white-normal, $white-dark, $border-white-dark, #313236);
+}
+
+.btn {
+  @include btn-default;
+  @include btn-white;
+
+  &.btn-sm {
+    padding: 5px 10px;
+  }
+
+  &.btn-xs {
+    padding: 1px 5px;
+  }
+
+  &.btn-success,
+  &.btn-new,
+  &.btn-create,
+  &.btn-save,
+  &.btn-green {
+    @include btn-green;
+  }
+
+  &.btn-gray {
+    @include btn-gray;
+  }
+
+  &.btn-primary,
+  &.btn-info {
+    @include btn-blue;
+  }
+
+  &.btn-warning {
+    @include btn-orange;
+  }
+
+  &.btn-danger,
+  &.btn-remove,
+  &.btn-red {
+    @include btn-red;
+  }
+
+  &.btn-cancel {
+    float: right;
+  }
+
+  &.btn-close {
+    color: $gl-danger;
+    border-color: $gl-danger;
+    &:hover {
+      color: #B94A48;
+    }
+  }
+
+  &.btn-reopen {
+    color: $gl-success;
+    border-color: $gl-success;
+    &:hover {
+      color: #468847;
+    }
+  }
+
+  &.btn-grouped {
+    margin-right: 7px;
+    float: left;
+    &:last-child {
+      margin-right: 0px;
+    }
+  }
+}
+
+.btn-block {
+  width: 100%;
+  margin: 0;
+  margin-bottom: 15px;
+  &.btn {
+    padding: 6px 0;
+  }
+}
+
+.btn-group {
+  &.btn-grouped {
+    margin-right: 7px;
+    float: left;
+    &:last-child {
+      margin-right: 0px;
+    }
+  }
+}
+
+.btn-group-next {
+  .btn {
+    padding: 9px 0px;
+    font-size: 15px;
+    color: #7f8fa4;
+    border-color: #e7e9ed;
+    width: 140px;
+
+    .badge {
+      font-weight: normal;
+      background-color: #eee;
+      color: #78a;
+    }
+
+    &.active {
+      border-color: $gl-info;
+      background: $gl-info;
+      color: #fff;
+
+      .badge {
+        color: $gl-info;
+        background-color: white;
+      }
+    }
+  }
+}
diff --git a/app/assets/stylesheets/generic/calendar.scss b/app/assets/stylesheets/framework/calendar.scss
similarity index 100%
rename from app/assets/stylesheets/generic/calendar.scss
rename to app/assets/stylesheets/framework/calendar.scss
diff --git a/app/assets/stylesheets/generic/callout.scss b/app/assets/stylesheets/framework/callout.scss
similarity index 100%
rename from app/assets/stylesheets/generic/callout.scss
rename to app/assets/stylesheets/framework/callout.scss
diff --git a/app/assets/stylesheets/generic/common.scss b/app/assets/stylesheets/framework/common.scss
similarity index 97%
rename from app/assets/stylesheets/generic/common.scss
rename to app/assets/stylesheets/framework/common.scss
index b659717b4e1804368ef1b6bb608941bed3168c94..e1a1793be9c1564e787fd3c1c2bd0876d2cf6626 100644
--- a/app/assets/stylesheets/generic/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -1,8 +1,8 @@
 /** COLORS **/
 .cgray { color: $gl-gray; }
 .clgray { color: #BBB }
-.cred { color: #D12F19 }
-.cgreen { color: #4a2 }
+.cred { color: $gl-text-red; }
+.cgreen { color: $gl-text-green; }
 .cdark { color: #444 }
 
 /** COMMON CLASSES **/
@@ -313,7 +313,7 @@ table {
 }
 
 .wiki .highlight, .note-body .highlight {
-  margin-bottom: 9px;
+  margin: 12px 0 12px 0;
 }
 
 .wiki .code {
@@ -381,6 +381,10 @@ table {
   &.no-bottom {
     margin-bottom: 0;
   }
+
+  &.no-top {
+    margin-top: 0;
+  }
 }
 
 .dropzone .dz-preview .dz-progress {
@@ -390,3 +394,7 @@ table {
 .dropzone .dz-preview .dz-progress .dz-upload {
   background: $gl-success !important;
 }
+
+.space-right {
+  margin-right: 10px;
+}
diff --git a/app/assets/stylesheets/generic/files.scss b/app/assets/stylesheets/framework/files.scss
similarity index 98%
rename from app/assets/stylesheets/generic/files.scss
rename to app/assets/stylesheets/framework/files.scss
index 9dd77747884d10b387268140401c5530b7012160..35db00281e5d26b055c65aac9432fd12ce68b996 100644
--- a/app/assets/stylesheets/generic/files.scss
+++ b/app/assets/stylesheets/framework/files.scss
@@ -10,6 +10,10 @@
   border-bottom: 1px solid #E7E9EE;
   margin-bottom: 1em;
 
+  &.readme-holder {
+    border-bottom: 0;
+  }
+
   table {
     @extend .table;
   }
@@ -94,7 +98,6 @@
           border-right: none;
         }
         background: #fff;
-        padding: 10px $gl-padding;
       }
       .lines {
         pre {
diff --git a/app/assets/stylesheets/generic/filters.scss b/app/assets/stylesheets/framework/filters.scss
similarity index 100%
rename from app/assets/stylesheets/generic/filters.scss
rename to app/assets/stylesheets/framework/filters.scss
diff --git a/app/assets/stylesheets/generic/flash.scss b/app/assets/stylesheets/framework/flash.scss
similarity index 100%
rename from app/assets/stylesheets/generic/flash.scss
rename to app/assets/stylesheets/framework/flash.scss
diff --git a/app/assets/stylesheets/base/fonts.scss b/app/assets/stylesheets/framework/fonts.scss
similarity index 100%
rename from app/assets/stylesheets/base/fonts.scss
rename to app/assets/stylesheets/framework/fonts.scss
diff --git a/app/assets/stylesheets/generic/forms.scss b/app/assets/stylesheets/framework/forms.scss
similarity index 86%
rename from app/assets/stylesheets/generic/forms.scss
rename to app/assets/stylesheets/framework/forms.scss
index 4282832e2bf66494d65f577cb588d7e527f09094..0edfe24f19584c8d340f4e79caa861b06901f726 100644
--- a/app/assets/stylesheets/generic/forms.scss
+++ b/app/assets/stylesheets/framework/forms.scss
@@ -29,12 +29,6 @@ input[type='text'].danger {
   border-top: 1px solid $border-color;
 }
 
-@media (min-width: $screen-sm-min) {
-  .form-actions {
-    padding-left: 17%;
-  }
-}
-
 label {
   &.control-label {
     @extend .col-sm-2;
@@ -84,3 +78,17 @@ label {
 .wiki-content {
   margin-top: 35px;
 }
+
+.form-group .control-label {
+  font-weight: normal;
+}
+
+.form-control::-webkit-input-placeholder {
+  color: #7f8fa4;
+}
+
+.input-group {
+  .input-group-addon {
+    background-color: #f7f8fa;
+  }
+}
diff --git a/app/assets/stylesheets/generic/gfm.scss b/app/assets/stylesheets/framework/gfm.scss
similarity index 95%
rename from app/assets/stylesheets/generic/gfm.scss
rename to app/assets/stylesheets/framework/gfm.scss
index bd9200ace23a84ed73376793970d34d7a0e20d6e..5ae0520fd7b6d9eabe815bef2bfbc80be70b6227 100644
--- a/app/assets/stylesheets/generic/gfm.scss
+++ b/app/assets/stylesheets/framework/gfm.scss
@@ -22,4 +22,5 @@
 
 .gfm-commit, .gfm-commit_range {
   font-family: $monospace_font;
+  font-size: 90%;
 }
diff --git a/app/assets/stylesheets/themes/gitlab-theme.scss b/app/assets/stylesheets/framework/gitlab-theme.scss
similarity index 100%
rename from app/assets/stylesheets/themes/gitlab-theme.scss
rename to app/assets/stylesheets/framework/gitlab-theme.scss
diff --git a/app/assets/stylesheets/generic/header.scss b/app/assets/stylesheets/framework/header.scss
similarity index 96%
rename from app/assets/stylesheets/generic/header.scss
rename to app/assets/stylesheets/framework/header.scss
index b758a526fbbb49649bd9b5c2cab9f4d1ad48acda..91e6975e2694eafd7a5a01a3a115199fd3184d1d 100644
--- a/app/assets/stylesheets/generic/header.scss
+++ b/app/assets/stylesheets/framework/header.scss
@@ -26,7 +26,6 @@ header {
     min-height: $header-height;
     background-color: #fff;
     border: none;
-    border-bottom: 1px solid #EEE;
 
     .container-fluid {
       width: 100% !important;
@@ -51,15 +50,17 @@ header {
 
       .navbar-toggle {
         color: #666;
-        margin: 0;
+        margin: 6px 0;
         border-radius: 0;
         position: absolute;
         right: 2px;
-        top: 15px;
 
         &:hover {
           background-color: #EEE;
         }
+        &.active {
+          color: #7f8fa4;
+        }
       }
     }
   }
@@ -88,6 +89,7 @@ header {
 
     .navbar-collapse {
       float: right;
+      border-top: none;
     }
   }
 
diff --git a/app/assets/stylesheets/generic/highlight.scss b/app/assets/stylesheets/framework/highlight.scss
similarity index 100%
rename from app/assets/stylesheets/generic/highlight.scss
rename to app/assets/stylesheets/framework/highlight.scss
diff --git a/app/assets/stylesheets/generic/issue_box.scss b/app/assets/stylesheets/framework/issue_box.scss
similarity index 94%
rename from app/assets/stylesheets/generic/issue_box.scss
rename to app/assets/stylesheets/framework/issue_box.scss
index b1fb87a683014f1990bfd9c0c2aee649133d16aa..93377e45e70a52aec9571670bb99b1233e9f978f 100644
--- a/app/assets/stylesheets/generic/issue_box.scss
+++ b/app/assets/stylesheets/framework/issue_box.scss
@@ -5,7 +5,7 @@
  */
 
 .issue-box {
-  @include border-radius(3px);
+  @include border-radius(2px);
 
   display: inline-block;
   padding: 10px $gl-padding;
diff --git a/app/assets/stylesheets/generic/jquery.scss b/app/assets/stylesheets/framework/jquery.scss
similarity index 100%
rename from app/assets/stylesheets/generic/jquery.scss
rename to app/assets/stylesheets/framework/jquery.scss
diff --git a/app/assets/stylesheets/base/layout.scss b/app/assets/stylesheets/framework/layout.scss
similarity index 88%
rename from app/assets/stylesheets/base/layout.scss
rename to app/assets/stylesheets/framework/layout.scss
index b91c15d8910f0b2fe2da7dca14863d9414685434..c7b3b60e76943a0fe77fde788b9b8529105cea3a 100644
--- a/app/assets/stylesheets/base/layout.scss
+++ b/app/assets/stylesheets/framework/layout.scss
@@ -5,6 +5,7 @@ html {
 
   body {
     padding-top: $header-height;
+    text-rendering: geometricPrecision;
   }
 }
 
diff --git a/app/assets/stylesheets/generic/lists.scss b/app/assets/stylesheets/framework/lists.scss
similarity index 93%
rename from app/assets/stylesheets/generic/lists.scss
rename to app/assets/stylesheets/framework/lists.scss
index 3bfed8de7720d9d0a0fa9de37d17c93a1d0863ba..f6942db5816966e22989f3505a25a449d4497226 100644
--- a/app/assets/stylesheets/generic/lists.scss
+++ b/app/assets/stylesheets/framework/lists.scss
@@ -107,7 +107,7 @@ ul.content-list {
 
   > li {
     padding: $gl-padding;
-    border-color: #f1f2f4;
+    border-color: $table-border-color;
     margin-left: -$gl-padding;
     margin-right: -$gl-padding;
     color: $gl-gray;
@@ -117,8 +117,12 @@ ul.content-list {
     }
 
     .controls {
-      padding-top: 10px;
+      padding-top: 4px;
       float: right;
+
+      .btn {
+        padding: 10px 14px;
+      }
     }
   }
 }
diff --git a/app/assets/stylesheets/generic/markdown_area.scss b/app/assets/stylesheets/framework/markdown_area.scss
similarity index 100%
rename from app/assets/stylesheets/generic/markdown_area.scss
rename to app/assets/stylesheets/framework/markdown_area.scss
diff --git a/app/assets/stylesheets/base/mixins.scss b/app/assets/stylesheets/framework/mixins.scss
similarity index 54%
rename from app/assets/stylesheets/base/mixins.scss
rename to app/assets/stylesheets/framework/mixins.scss
index 421588f64d8d05a1d96e12f485ddffe3eda0b864..fe078d016d7a267ecb7f85b8cec3f5620dd57f8e 100644
--- a/app/assets/stylesheets/base/mixins.scss
+++ b/app/assets/stylesheets/framework/mixins.scss
@@ -54,146 +54,6 @@
   @include box-shadow(0 0 0 3px #f1f1f1);
 }
 
-@mixin md-typography {
-  color: $md-text-color;
-
-  a {
-    color: $md-link-color;
-  }
-
-  img {
-    max-width: 100%;
-  }
-
-  *:first-child {
-    margin-top: 0;
-  }
-
-  code {
-    font-family: $monospace_font;
-    white-space: pre;
-    word-wrap: normal;
-    padding: 1px 2px;
-  }
-
-  kbd {
-    display: inline-block;
-    padding: 3px 5px;
-    font-size: 11px;
-    line-height: 10px;
-    color: #555;
-    vertical-align: middle;
-    background-color: #FCFCFC;
-    border-width: 1px;
-    border-style: solid;
-    border-color: #CCC #CCC #BBB;
-    border-image: none;
-    border-radius: 3px;
-    box-shadow: 0px -1px 0px #BBB inset;
-  }
-
-  h1 {
-    font-size: 1.3em;
-    font-weight: 600;
-    margin: 24px 0 12px 0;
-    padding: 0 0 10px 0;
-    border-bottom: 1px solid #e7e9ed;
-    color: #313236;
-  }
-
-  h2 {
-    font-size: 1.2em;
-    font-weight: 600;
-    margin: 24px 0 12px 0;
-    color: #313236;
-  }
-
-  h3 {
-    margin: 24px 0 12px 0;
-    font-size: 1.25em;
-  }
-
-  h4 {
-    margin: 24px 0 12px 0;
-    font-size: 1.1em;
-  }
-  
-  h5 {
-    margin: 24px 0 12px 0;
-    font-size: 1em;
-  }
-  
-  h6 {
-    margin: 24px 0 12px 0;
-    font-size: 0.90em;
-  }
-
-  blockquote {
-    padding: 8px 21px;
-    margin: 12px 0 12px;
-    border-left: 3px solid #e7e9ed;
-  }
-  
-  blockquote p {
-    color: #7f8fa4 !important;
-    font-size: 15px;
-    line-height: 1.5;
-  }
-  
-  p {
-    color:#5c5d5e;
-    margin:6px 0 0 0;
-  }
-  
-  table {
-    @extend .table;
-    @extend .table-bordered;
-    margin: 12px 0 12px 0;
-    color: #5c5d5e;
-    th {
-      background: #f8fafc;
-    } 
-  }
-  
-  pre {
-    margin: 12px 0 12px 0 !important;
-    background-color: #f8fafc !important;
-    font-size: 13px !important;
-    color: #5b6169 !important;
-    line-height: 1.6em !important;
-  }
-
-  p > code {
-    font-weight: inherit;
-  }
-
-
-  ul {
-    color: #5c5d5e;
-  }
-  
-  li {
-    line-height: 1.6em;
-  }
-
-  a[href*="/uploads/"], a[href*="storage.googleapis.com/google-code-attachments/"] {
-    &:before {
-      margin-right: 4px;
-
-      font: normal normal normal 14px/1 FontAwesome;
-      font-size: inherit;
-      text-rendering: auto;
-      -webkit-font-smoothing: antialiased;
-      content: "\f0c6";
-    }
-
-    &:hover:before {
-      text-decoration: none;
-    }
-  }
-}
-
-
 @mixin str-truncated($max_width: 82%) {
   display: inline-block;
   overflow: hidden;
@@ -287,7 +147,6 @@
 
     .badge {
       font-weight: normal;
-      background-color: #fff;
       background-color: #eee;
       color: #78a;
     }
diff --git a/app/assets/stylesheets/generic/mobile.scss b/app/assets/stylesheets/framework/mobile.scss
similarity index 91%
rename from app/assets/stylesheets/generic/mobile.scss
rename to app/assets/stylesheets/framework/mobile.scss
index 36ae126f8653e12a2b67e0f8de7c6dcd9079b4b4..cea47fba19226c8ba688f5f9882c44a7b7a29549 100644
--- a/app/assets/stylesheets/generic/mobile.scss
+++ b/app/assets/stylesheets/framework/mobile.scss
@@ -23,7 +23,7 @@
     margin-right: 0;
   }
 
-  .issues-filters,
+  .issues-details-filters,
   .dash-projects-filters,
   .check-all-holder {
     display: none;
@@ -83,6 +83,7 @@
 
   .center-top-menu {
     height: 45px;
+    margin-bottom: 30px;
 
     li a {
       font-size: 14px;
@@ -90,9 +91,11 @@
     }
   }
 
-  .projects-search-form {
-    margin: 0 -5px !important;
+  .activity-filter-block {
+    display: none;
+  }
 
+  .projects-search-form {
     .btn {
       display: none;
     }
@@ -100,6 +103,11 @@
 }
 
 @media (max-width: $screen-sm-max) {
+  .page-with-sidebar .content-wrapper {
+    padding: 0;
+    padding-top: 1px;
+  }
+
   .issues-filters {
     .milestone-filter, .labels-filter {
       display: none;
diff --git a/app/assets/stylesheets/generic/pagination.scss b/app/assets/stylesheets/framework/pagination.scss
similarity index 100%
rename from app/assets/stylesheets/generic/pagination.scss
rename to app/assets/stylesheets/framework/pagination.scss
diff --git a/app/assets/stylesheets/generic/selects.scss b/app/assets/stylesheets/framework/selects.scss
similarity index 69%
rename from app/assets/stylesheets/generic/selects.scss
rename to app/assets/stylesheets/framework/selects.scss
index f0860de1c4964ff383d5cb35028c431d17e39c76..78fff58d2328dcf57e6d6f4fb462675e05803323 100644
--- a/app/assets/stylesheets/generic/selects.scss
+++ b/app/assets/stylesheets/framework/selects.scss
@@ -8,7 +8,7 @@
     font-size: $gl-font-size;
     line-height: 1.42857143;
 
-    @include border-radius(4px);
+    @include border-radius(2px);
 
     .select2-arrow {
       background: #FFF;
@@ -18,8 +18,39 @@
   }
 }
 
+.select2-container .select2-choice, .select2-container.select2-drop-above .select2-choice{
+  color: #7f8fa4;
+  border: 1px solid #e7e9ed;
+}
+
+.select2-drop {
+  @include box-shadow(rgba(76, 86, 103, 0.247059) 0px 0px 1px 0px, rgba(31, 37, 50, 0.317647) 0px 2px 18px 0px);
+  @include border-radius (0px);
+
+  padding: 16px;
+  border: none !important;
+}
+
+.select2-results .select2-result-label {
+  padding: 9px;
+}
+
+.select2-drop{
+  color: #7f8fa4;
+}
+
+.select2-highlighted {
+  background: #3084bb !important;
+}
+
+.select2-results li.select2-result-with-children > .select2-result-label {
+  font-weight: 600;
+  color: #313236;
+}
+
+
 .select2-container-multi .select2-choices {
-  @include border-radius(4px);
+  @include border-radius(2px);
   border-color: #CCC;
 }
 
@@ -63,7 +94,7 @@
 
 .ajax-users-dropdown, .ajax-project-users-dropdown {
   .select2-search {
-    padding-top: 4px;
+    padding-top: 2px;
   }
 }
 
@@ -97,9 +128,6 @@
   }
   .user-name {
   }
-  .user-username {
-    color: #999;
-  }
 }
 
 .namespace-result {
@@ -114,5 +142,5 @@
 }
 
 .ajax-users-dropdown {
-  min-width: 225px !important;
-}
+  min-width: 250px !important;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/generic/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss
similarity index 96%
rename from app/assets/stylesheets/generic/sidebar.scss
rename to app/assets/stylesheets/framework/sidebar.scss
index 3d055f0e66f8fbabac09fab06ead82036d24a0da..985ea16457621c91278182d3cd33a5a1e1b9f06a 100644
--- a/app/assets/stylesheets/generic/sidebar.scss
+++ b/app/assets/stylesheets/framework/sidebar.scss
@@ -21,12 +21,11 @@
   min-height: 100vh;
   width: 100%;
   padding: 20px;
-  background: #f1f4f8;
+  background: #EAEBEC;
 
   .container-fluid {
     background: #FFF;
     padding: $gl-padding;
-    border: 1px solid #e7e9ed;
     min-height: 90vh;
 
     &.container-blank {
@@ -243,6 +242,9 @@
       img {
         width: 36px;
         height: 36px;
+      }
+
+      #tanuki-logo, img {
         float: left;
       }
 
@@ -266,3 +268,13 @@
     }
   }
 }
+
+
+.tanuki-shape {
+  transition: all 0.8s;
+
+  &:hover {
+    fill: rgb(255, 255, 255);
+    transition: all 0.1s;
+  }
+}
diff --git a/app/assets/stylesheets/framework/tables.scss b/app/assets/stylesheets/framework/tables.scss
new file mode 100644
index 0000000000000000000000000000000000000000..66e16e8df75764e9838c46ee4e63d7d5e9df8e7f
--- /dev/null
+++ b/app/assets/stylesheets/framework/tables.scss
@@ -0,0 +1,44 @@
+.table-holder {
+  margin: -$gl-padding;
+  margin-top: 0;
+  margin-bottom: 0;
+}
+
+table {
+  &.table {
+    .dropdown-menu a {
+      text-decoration: none;
+    }
+
+    .success,
+    .warning,
+    .danger,
+    .info {
+      color: #fff;
+
+      a:not(.btn) {
+        text-decoration: underline;
+        color: #fff;
+      }
+    }
+
+    tr {
+      td, th {
+        padding: 10px $gl-padding;
+        line-height: 20px;
+        vertical-align: middle;
+      }
+
+      th {
+        font-weight: normal;
+        font-size: 15px;
+        border-bottom: 1px solid $border-color !important;
+      }
+
+      td {
+        border-color: $table-border-color !important;
+        border-bottom: 1px solid;
+      }
+    }
+  }
+}
diff --git a/app/assets/stylesheets/generic/timeline.scss b/app/assets/stylesheets/framework/timeline.scss
similarity index 85%
rename from app/assets/stylesheets/generic/timeline.scss
rename to app/assets/stylesheets/framework/timeline.scss
index 74bbaabad3974a57a581ff7c1487a2b01bd46418..eb53c4153d3e794e48443da57f213ae6315538cd 100644
--- a/app/assets/stylesheets/generic/timeline.scss
+++ b/app/assets/stylesheets/framework/timeline.scss
@@ -6,12 +6,16 @@
 
   .timeline-entry {
     padding: $gl-padding;
-    border-color: #f1f2f4;
+    border-color: $table-border-color;
     margin-left: -$gl-padding;
     margin-right: -$gl-padding;
     color: $gl-gray;
-    border-bottom: 1px solid #f1f2f4;
-    border-right: 1px solid #f1f2f4;
+    border-bottom: 1px solid #ECEEF1;
+    border-right: 1px solid #ECEEF1;
+
+    &:target {
+      background: $hover;
+    }
 
     &:last-child {
       border-bottom: none;
diff --git a/app/assets/stylesheets/base/gl_bootstrap.scss b/app/assets/stylesheets/framework/tw_bootstrap.scss
similarity index 92%
rename from app/assets/stylesheets/base/gl_bootstrap.scss
rename to app/assets/stylesheets/framework/tw_bootstrap.scss
index eb8d23d6453cc477e8a13cbb8b4401816958920b..99d028d1228ee84bb88394051806b27943db204e 100644
--- a/app/assets/stylesheets/base/gl_bootstrap.scss
+++ b/app/assets/stylesheets/framework/tw_bootstrap.scss
@@ -32,8 +32,6 @@
 @import "bootstrap/pager";
 @import "bootstrap/labels";
 @import "bootstrap/badges";
-@import "bootstrap/jumbotron";
-@import "bootstrap/thumbnails";
 @import "bootstrap/alerts";
 @import "bootstrap/progress-bars";
 @import "bootstrap/list-group";
@@ -251,23 +249,3 @@
 .text-info:hover {
   color: $brand-info;
 }
-
-// Tables =====================================================================
-
-table.table {
-  .dropdown-menu a {
-    text-decoration: none;
-  }
-
-  .success,
-  .warning,
-  .danger,
-  .info {
-    color: #fff;
-
-    a:not(.btn) {
-      text-decoration: underline;
-      color: #fff;
-    }
-  }
-}
diff --git a/app/assets/stylesheets/base/gl_variables.scss b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss
similarity index 97%
rename from app/assets/stylesheets/base/gl_variables.scss
rename to app/assets/stylesheets/framework/tw_bootstrap_variables.scss
index 7378d404008d04b9bc8fad66d255bfe0f071274e..63868a34e2a1aa4855e561f25540ae746683f8af 100644
--- a/app/assets/stylesheets/base/gl_variables.scss
+++ b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss
@@ -22,8 +22,8 @@ $brand-info:     $gl-info;
 $brand-warning:  $gl-warning;
 $brand-danger:   $gl-danger;
 
-$border-radius-base:        3px !default;
-$border-radius-large:       5px !default;
+$border-radius-base:        2px !default;
+$border-radius-large:       2px !default;
 $border-radius-small:       2px !default;
 
 
@@ -156,3 +156,5 @@ $nav-link-padding: 13px $gl-padding;
 $pre-bg:           #f8fafc !default;
 $pre-color:        $gl-gray !default;
 $pre-border-color: #e7e9ed;
+
+$table-bg-accent: $background-color;
diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss
new file mode 100644
index 0000000000000000000000000000000000000000..e6558a2385802336acff5444bd4be4660ba822e3
--- /dev/null
+++ b/app/assets/stylesheets/framework/typography.scss
@@ -0,0 +1,259 @@
+@mixin md-typography {
+  color: $md-text-color;
+  word-wrap: break-word;
+
+  a {
+    color: $md-link-color;
+  }
+
+  img {
+    max-width: 100%;
+  }
+
+  *:first-child {
+    margin-top: 0;
+  }
+
+  code {
+    font-family: $monospace_font;
+    white-space: pre;
+    word-wrap: normal;
+  }
+
+  kbd {
+    display: inline-block;
+    padding: 3px 5px;
+    font-size: 11px;
+    line-height: 10px;
+    color: #555;
+    vertical-align: middle;
+    background-color: #FCFCFC;
+    border-width: 1px;
+    border-style: solid;
+    border-color: #CCC #CCC #BBB;
+    border-image: none;
+    border-radius: 3px;
+    box-shadow: 0px -1px 0px #BBB inset;
+  }
+
+  h1 {
+    font-size: 1.3em;
+    font-weight: 600;
+    margin: 24px 0 12px 0;
+    padding: 0 0 10px 0;
+    border-bottom: 1px solid #e7e9ed;
+    color: #313236;
+  }
+
+  h2 {
+    font-size: 1.2em;
+    font-weight: 600;
+    margin: 24px 0 12px 0;
+    color: #313236;
+  }
+
+  h3 {
+    margin: 24px 0 12px 0;
+    font-size: 1.25em;
+  }
+
+  h4 {
+    margin: 24px 0 12px 0;
+    font-size: 1.1em;
+  }
+
+  h5 {
+    margin: 24px 0 12px 0;
+    font-size: 1em;
+  }
+
+  h6 {
+    margin: 24px 0 12px 0;
+    font-size: 0.90em;
+  }
+
+  blockquote {
+    color: #7f8fa4;
+    font-size: inherit;
+    padding: 8px 21px;
+    margin: 12px 0 12px;
+    border-left: 3px solid #e7e9ed;
+  }
+
+  blockquote p {
+    color: #7f8fa4 !important;
+    font-size: inherit;
+    line-height: 1.5;
+  }
+
+  p {
+    color:#5c5d5e;
+    margin:6px 0 0 0;
+  }
+
+  table {
+    @extend .table;
+    @extend .table-bordered;
+    margin: 12px 0 12px 0;
+    color: #5c5d5e;
+    th {
+      background: #f8fafc;
+    }
+  }
+
+  pre {
+    margin: 12px 0 12px 0 !important;
+    background-color: #f8fafc;
+    font-size: 13px !important;
+    color: #5b6169;
+    line-height: 1.6em !important;
+    @include border-radius(2px);
+  }
+
+  p > code {
+    font-weight: inherit;
+  }
+
+  ul, ol {
+    padding: 0;
+    margin: 6px 0 6px 18px !important;
+  }
+
+  li {
+    line-height: 1.6em;
+  }
+
+  a[href*="/uploads/"], a[href*="storage.googleapis.com/google-code-attachments/"] {
+    &:before {
+      margin-right: 4px;
+
+      font: normal normal normal 14px/1 FontAwesome;
+      font-size: inherit;
+      text-rendering: auto;
+      -webkit-font-smoothing: antialiased;
+      content: "\f0c6";
+    }
+
+    &:hover:before {
+      text-decoration: none;
+    }
+  }
+
+  /* Link to current header. */
+  h1, h2, h3, h4, h5, h6 {
+    position: relative;
+
+    a.anchor {
+      // Setting `display: none` would prevent the anchor being scrolled to, so
+      // instead we set the height to 0 and it gets updated on hover.
+      height: 0;
+    }
+
+    &:hover > a.anchor {
+      $size: 16px;
+      position: absolute;
+      right: 100%;
+      top: 50%;
+      margin-top: -$size/2;
+      margin-right: 0px;
+      padding-right: 20px;
+      display: inline-block;
+      width: $size;
+      height: $size;
+      background-image: image-url("icon-link.png");
+      background-size: contain;
+      background-repeat: no-repeat;
+    }
+  }
+}
+
+
+/**
+ * Headers
+ *
+ */
+body {
+  text-rendering:optimizeLegibility;
+  -webkit-text-shadow: rgba(255,255,255,0.01) 0 0 1px;
+}
+
+.page-title {
+  margin-top: 0px;
+  line-height: 1.3;
+  font-size: 1.25em;
+  font-weight: 600;
+}
+
+.page-title-empty {
+  margin-top: 0px;
+  line-height: 1.3;
+  font-size: 1.25em;
+  font-weight: 600;
+  margin: 12px 7px 12px 7px;
+}
+
+h1, h2, h3, h4, h5, h6 {
+  color: $gl-header-color;
+  font-weight: 500;
+}
+
+/** CODE **/
+pre {
+  font-family: $monospace_font;
+
+  &.dark {
+    background: #333;
+    color: $background-color;
+  }
+
+  &.plain-readme {
+    background: none;
+    border: none;
+    padding: 0;
+    margin: 0;
+    font-size: 14px;
+  }
+}
+
+.monospace {
+  font-family: $monospace_font;
+}
+
+code {
+  &.key-fingerprint {
+    background: $body-bg;
+    color: $text-color;
+  }
+}
+
+a > code {
+  color: $link-color;
+}
+
+/**
+ * Apply Markdown typography
+ *
+ */
+.wiki {
+  @include md-typography;
+}
+
+.md {
+  @include md-typography;
+}
+
+/**
+ * Textareas intended for GFM
+ *
+ */
+textarea.js-gfm-input {
+  font-family: $monospace_font;
+  color: $gl-text-color;
+}
+
+.md-preview {
+}
+
+.strikethrough {
+  text-decoration: line-through;
+}
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
new file mode 100644
index 0000000000000000000000000000000000000000..91954683c3e8db28989abfd7fd970c2e35cd3a73
--- /dev/null
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -0,0 +1,99 @@
+$hover: #FFFAF1;
+$gl-text-color: #54565B;
+$gl-text-green: #4A2;
+$gl-text-red: #D12F19;
+$gl-text-orange: #D90;
+$gl-header-color: #4c4e54;
+$gl-link-color: #333c48;
+$md-text-color: #444;
+$md-link-color: #3084bb;
+$nprogress-color: #c0392b;
+$gl-font-size: 15px;
+$list-font-size: 15px;
+$sidebar_collapsed_width: 62px;
+$sidebar_width: 230px;
+$avatar_radius: 50%;
+$code_font_size: 13px;
+$code_line_height: 1.5;
+$border-color: #dce0e6;
+$table-border-color: #eef0f2;
+$background-color: #F7F8FA;
+$header-height: 58px;
+$fixed-layout-width: 1200px;
+$gl-gray: #7f8fa4;
+$gl-padding: 16px;
+$gl-avatar-size: 46px;
+
+/*
+ * Color schema
+ */
+
+$white-light: #FFFFFF;
+$white-normal: #DCE0E5;
+$white-dark: #E4E7ED;
+
+$gray-light: #F0F2F5;
+$gray-normal: #DCE0E5;
+$gray-dark: #E4E7ED;
+
+$green-light: #31AF64;
+$green-normal: #2FAA60;
+$green-dark: #2CA05B;
+
+$blue-light: #2EA8E5;
+$blue-normal: #2D9FD8;
+$blue-dark: #2897CE;
+
+$orange-light: #FC6443;
+$orange-normal: #E75E40;
+$orange-dark: #CE5237;
+
+$red-light: #F43263;
+$red-normal: #E52C5A;
+$red-dark: #D22852;
+
+$border-white-light: #E3E7EC;
+$border-white-normal: #D6DAE2;
+$border-white-dark: #C6CACF;
+
+$border-gray-light: #DCE0E5;
+$border-gray-normal: #D6DAE2;
+$border-gray-dark: #C6CACF;
+
+$border-green-light: #2FAA60;
+$border-green-normal: #2CA05B;
+$border-green-dark: #279654;
+
+$border-blue-light: #2D9FD8;
+$border-blue-normal: #2897CE;
+$border-blue-dark: #258DC1;
+
+$border-orange-light: #ED5C3D;
+$border-orange-normal: #CE5237;
+$border-orange-dark: #C14E35;
+
+$border-red-light: #E52C5A;
+$border-red-normal: #D22852;
+$border-red-dark: #CA264F;
+
+
+/*
+ * State colors:
+ */
+$gl-primary: $blue-normal;
+$gl-success: $green-normal;
+$gl-info: $blue-normal;
+$gl-warning: $orange-normal;
+$gl-danger: $red-normal;
+
+/*
+ * Commit Diff Colors
+ */
+$added: #63c363;
+$deleted: #f77;
+
+/*
+ * Fonts
+ */
+$monospace_font: 'Menlo', 'Liberation Mono', 'Consolas', 'DejaVu Sans Mono', 'Ubuntu Mono', 'Courier New', 'andale mono', 'lucida console', monospace;
+$regular_font: 'Source Sans Pro', "Helvetica Neue", Helvetica, Arial, sans-serif;
diff --git a/app/assets/stylesheets/generic/zen.scss b/app/assets/stylesheets/framework/zen.scss
similarity index 100%
rename from app/assets/stylesheets/generic/zen.scss
rename to app/assets/stylesheets/framework/zen.scss
diff --git a/app/assets/stylesheets/generic/buttons.scss b/app/assets/stylesheets/generic/buttons.scss
deleted file mode 100644
index 46ef595ddf0e6a00c6e2e18ed2660ba4b8b773ed..0000000000000000000000000000000000000000
--- a/app/assets/stylesheets/generic/buttons.scss
+++ /dev/null
@@ -1,90 +0,0 @@
-.btn {
-  @extend .btn-default;
-
-  &.btn-new {
-    @extend .btn-success;
-  }
-
-  &.btn-create {
-    @extend .btn-success;
-  }
-
-  &.btn-save {
-    @extend .btn-success;
-  }
-
-  &.btn-remove {
-    @extend .btn-danger;
-  }
-
-  &.btn-cancel {
-    float: right;
-  }
-
-  &.btn-close {
-    color: $gl-danger;
-    border-color: $gl-danger;
-    &:hover {
-      color: #B94A48;
-    }
-  }
-
-  &.btn-reopen {
-    color: $gl-success;
-    border-color: $gl-success;
-    &:hover {
-      color: #468847;
-    }
-  }
-
-  &.btn-grouped {
-    margin-right: 7px;
-    float: left;
-    &:last-child {
-      margin-right: 0px;
-    }
-  }
-
-  &.btn-save {
-    @extend .btn-primary;
-  }
-
-  &.btn-new, &.btn-create {
-    @extend .btn-success;
-  }
-}
-
-.btn-block {
-  width: 100%;
-  margin: 0;
-  margin-bottom: 15px;
-  &.btn {
-    padding: 6px 0;
-  }
-}
-
-.btn-group {
-  &.btn-grouped {
-    margin-right: 7px;
-    float: left;
-    &:last-child {
-      margin-right: 0px;
-    }
-  }
-}
-
-.btn-group-next {
-  .btn {
-    padding: 9px 0px;
-    font-size: 15px;
-    color: #7f8fa4;
-    border-color: #e7e9ed;
-    width: 140px;
-
-    &.active {
-      border-color: $gl-info;
-      background: $gl-info;
-      color: #fff;
-    }
-  }
-}
diff --git a/app/assets/stylesheets/generic/tables.scss b/app/assets/stylesheets/generic/tables.scss
deleted file mode 100644
index a66e45577de181764870e87bae2937d4b3dd6ccf..0000000000000000000000000000000000000000
--- a/app/assets/stylesheets/generic/tables.scss
+++ /dev/null
@@ -1,20 +0,0 @@
-table {
-  &.table {
-    tr {
-      td, th {
-        padding: 8px 10px;
-        line-height: 20px;
-        vertical-align: middle;
-      }
-      th {
-        font-weight: normal;
-        font-size: 15px;
-        border-bottom: 1px solid $border-color !important;
-      }
-      td {
-        border-color: #F1F1F1 !important;
-        border-bottom: 1px solid;
-      }
-    }
-  }
-}
diff --git a/app/assets/stylesheets/generic/typography.scss b/app/assets/stylesheets/generic/typography.scss
deleted file mode 100644
index 551db31db1287c6670b4e9debec27e0a58795ec9..0000000000000000000000000000000000000000
--- a/app/assets/stylesheets/generic/typography.scss
+++ /dev/null
@@ -1,117 +0,0 @@
-/**
- * Headers
- *
- */
-.page-title {
-  margin-top: 0px;
-  line-height: 1.5;
-  font-weight: normal;
-  margin-bottom: 5px;
-}
-
-h1, h2, h3, h4, h5, h6 {
-  color: $gl-header-color;
-  font-weight: 500;
-}
-
-/** CODE **/
-pre {
-  font-family: $monospace_font;
-
-  &.dark {
-    background: #333;
-    color: $background-color;
-  }
-
-  &.plain-readme {
-    background: none;
-    border: none;
-    padding: 0;
-    margin: 0;
-    font-size: 14px;
-  }
-}
-
-.monospace {
-  font-family: $monospace_font;
-}
-
-code {
-  &.key-fingerprint {
-    background: $body-bg;
-    color: $text-color;
-  }
-}
-
-a > code {
-  color: $link-color;
-}
-
-/**
- * Wiki typography
- *
- */
-.wiki {
-  @include md-typography;
-
-  word-wrap: break-word;
-  padding: 7px;
-
-  /* Link to current header. */
-  h1, h2, h3, h4, h5, h6 {
-    position: relative;
-
-    a.anchor {
-      // Setting `display: none` would prevent the anchor being scrolled to, so
-      // instead we set the height to 0 and it gets updated on hover.
-      height: 0;
-    }
-
-    &:hover > a.anchor {
-      $size: 16px;
-      position: absolute;
-      right: 100%;
-      top: 50%;
-      margin-top: -$size/2;
-      margin-right: 0px;
-      padding-right: 20px;
-      display: inline-block;
-      width: $size;
-      height: $size;
-      background-image: image-url("icon-link.png");
-      background-size: contain;
-      background-repeat: no-repeat;
-    }
-  }
-
-  ul,ol {
-    padding: 0;
-    margin: 6px 0 6px 18px !important;
-  }
-  ol {
-    color: #5c5d5e;
-  }
-}
-
-.md-area {
-  @include md-typography;
-}
-
-.md {
-  @include md-typography;
-}
-
-/**
- * Textareas intended for GFM
- *
- */
-textarea.js-gfm-input {
-  font-family: $monospace_font;
-}
-
-.md-preview {
-}
-
-.strikethrough {
-  text-decoration: line-through;
-}
diff --git a/app/assets/stylesheets/highlight/dark.scss b/app/assets/stylesheets/highlight/dark.scss
index 8323a8598ec7d546e363f7640e5d753f943a7df4..6a2b25ddc67905a29767100b831a84fe5a456be2 100644
--- a/app/assets/stylesheets/highlight/dark.scss
+++ b/app/assets/stylesheets/highlight/dark.scss
@@ -1,11 +1,10 @@
 /* https://github.com/MozMorris/tomorrow-pygments */
-pre.code.highlight.dark,
 .code.dark {
 
-  background-color: #1d1f21;
-  color: #c5c8c6;
+  background-color: #1d1f21 !important;
+  color: #c5c8c6 !important;
 
-  pre.code,
+  pre.highlight,
   .line-numbers,
   .line-numbers a {
     background-color: #1d1f21 !important;
@@ -23,8 +22,8 @@ pre.code.highlight.dark,
 
   // Search result highlight
   span.highlight_word {
-    background: #ffe792;
-    color: #000000;
+    background-color: #ffe792 !important;
+    color: #000000 !important;
   }
 
   .hll { background-color: #373b41 }
diff --git a/app/assets/stylesheets/highlight/monokai.scss b/app/assets/stylesheets/highlight/monokai.scss
index e83816743363941298c580cf677fb962cc4485a6..8560c3c490fc1e3070148bb05828d97bbfee3ced 100644
--- a/app/assets/stylesheets/highlight/monokai.scss
+++ b/app/assets/stylesheets/highlight/monokai.scss
@@ -1,15 +1,14 @@
 /* https://github.com/richleland/pygments-css/blob/master/monokai.css */
-pre.code.monokai,
 .code.monokai {
 
-  background: #272822;
-  color: #f8f8f2;
+  background-color: #272822 !important;
+  color: #f8f8f2 !important;
 
   pre.highlight,
   .line-numbers,
   .line-numbers a {
-    background:#272822 !important;
-    color:#f8f8f2 !important;
+    background-color :#272822 !important;
+    color: #f8f8f2 !important;
   }
 
   pre.code {
@@ -23,8 +22,8 @@ pre.code.monokai,
 
   // Search result highlight
   span.highlight_word {
-    background: #ffe792;
-    color: #000000;
+    background-color: #ffe792 !important;
+    color: #000000 !important;
   }
 
   .hll { background-color: #49483e }
diff --git a/app/assets/stylesheets/highlight/solarized_dark.scss b/app/assets/stylesheets/highlight/solarized_dark.scss
index bd41480aefb4706d6f7dc5ced47e501ec15c1611..7d489a9666b8b0828a5b7f4bf7670b0d6cdb23a4 100644
--- a/app/assets/stylesheets/highlight/solarized_dark.scss
+++ b/app/assets/stylesheets/highlight/solarized_dark.scss
@@ -1,11 +1,10 @@
 /* https://gist.github.com/qguv/7936275 */
-pre.code.highlight.solarized-dark,
 .code.solarized-dark {
 
-  background-color: #002b36;
-  color: #93a1a1;
+  background-color: #002b36 !important;
+  color: #93a1a1 !important;
 
-  pre.code,
+  pre.highlight,
   .line-numbers,
   .line-numbers a {
     background-color: #002b36 !important;
@@ -23,7 +22,7 @@ pre.code.highlight.solarized-dark,
 
   // Search result highlight
   span.highlight_word {
-    background: #094554;
+    background-color: #094554 !important;
   }
 
   /* Solarized Dark
diff --git a/app/assets/stylesheets/highlight/solarized_light.scss b/app/assets/stylesheets/highlight/solarized_light.scss
index 4cc62863870e701867d3bd67cd212c4dd44c0854..200ed346446e1dc110c09563a2a872914323f564 100644
--- a/app/assets/stylesheets/highlight/solarized_light.scss
+++ b/app/assets/stylesheets/highlight/solarized_light.scss
@@ -1,11 +1,10 @@
 /* https://gist.github.com/qguv/7936275 */
-pre.code.highlight.solarized-light,
 .code.solarized-light {
 
-  background-color: #fdf6e3;
-  color: #586e75;
+  background-color: #fdf6e3 !important;
+  color: #586e75 !important;
 
-  pre.code,
+  pre.highlight,
   .line-numbers,
   .line-numbers a {
     background-color: #fdf6e3 !important;
@@ -23,7 +22,7 @@ pre.code.highlight.solarized-light,
 
   // Search result highlight
   span.highlight_word {
-    background: #eee8d5;
+    background-color: #eee8d5 !important;
   }
 
   /* Solarized Light
diff --git a/app/assets/stylesheets/highlight/white.scss b/app/assets/stylesheets/highlight/white.scss
index 5de589109bd11962aa345d42eac6cf2435ac3d4e..e2626da78712858274a8fb233595f770ce765254 100644
--- a/app/assets/stylesheets/highlight/white.scss
+++ b/app/assets/stylesheets/highlight/white.scss
@@ -1,23 +1,20 @@
 /* https://github.com/aahan/pygments-github-style */
-pre.code.highlight.white,
 .code.white {
 
-  background-color: #fff;
-  color: #333;
+  background-color: #f8fafc !important;
+  color: #5b6169 !important;
 
+  pre.highlight,
   .line-numbers,
   .line-numbers a {
     background-color: $background-color !important;
     color: $gl-gray !important;
   }
 
-  pre.highlight {
-    background-color: #fff !important;
-    color: #333 !important;
-  }
-
   pre.code {
     border-left: 1px solid $border-color;
+    background-color: #fff !important;
+    color: #333 !important;
   }
 
   // highlight line via anchor
@@ -27,7 +24,7 @@ pre.code.highlight.white,
 
   // Search result highlight
   span.highlight_word {
-    background: #fafe3d;
+    background-color: #fafe3d !important;
   }
 
   .hll { background-color: #f8f8f8 }
diff --git a/app/assets/stylesheets/ci/builds.scss b/app/assets/stylesheets/pages/builds.scss
similarity index 93%
rename from app/assets/stylesheets/ci/builds.scss
rename to app/assets/stylesheets/pages/builds.scss
index a11a935b54dab46e41c45e6a86cb960e6533adfd..74dc3e321c1c6e2cfdfffe0faf9c79b20971ebb6 100644
--- a/app/assets/stylesheets/ci/builds.scss
+++ b/app/assets/stylesheets/pages/builds.scss
@@ -1,4 +1,4 @@
-.ci-body {
+.build-page {
   pre.trace {
     background: #111111;
     color: #fff;
@@ -67,4 +67,9 @@
       color: #3084bb !important;
     }
   }
+
+  .build-top-menu {
+    margin-top: 0;
+    margin-bottom: 2px;
+  }
 }
diff --git a/app/assets/stylesheets/ci/projects.scss b/app/assets/stylesheets/pages/ci_projects.scss
similarity index 89%
rename from app/assets/stylesheets/ci/projects.scss
rename to app/assets/stylesheets/pages/ci_projects.scss
index 8c5273abcdaa07bf6ebf0a9c42cb567875ac04c6..2a7b5cfc7fd6c4a041118d747e445bedba4dbc30 100644
--- a/app/assets/stylesheets/ci/projects.scss
+++ b/app/assets/stylesheets/pages/ci_projects.scss
@@ -6,11 +6,6 @@
     line-height: 1.5;
   }
 
-  .wide-table-holder {
-    margin-left: -$gl-padding;
-    margin-right: -$gl-padding;
-  }
-
   .builds,
   .projects-table {
     .light {
diff --git a/app/assets/stylesheets/pages/commit.scss b/app/assets/stylesheets/pages/commit.scss
index 051ca3792c307b6d9dd0d1394890447d3a60bb14..fbd7c363de108f414325d5714496668c9827259f 100644
--- a/app/assets/stylesheets/pages/commit.scss
+++ b/app/assets/stylesheets/pages/commit.scss
@@ -49,30 +49,33 @@
 }
 
 .file-stats {
+  ul {
+    list-style: none;
+    margin: 0;
+    padding: 10px 0;
+
+    li {
+      padding: 3px 0px;
+    }
+  }
   .new-file {
     a {
-      color: #090;
-    }
-    i {
-      color: #1BCF00;
+      color: $gl-text-green;
     }
   }
   .renamed-file {
-    i {
-      color: #FE9300;
+    a {
+      color: $gl-text-orange;
     }
   }
   .deleted-file {
     a {
-      color: #B00;
-    }
-    i {
-      color: #EE0000;
+      color: $gl-text-red;
     }
   }
   .edit-file{
-    i{
-      color: #555;
+    a {
+      color: $gl-text-color;
     }
   }
 }
@@ -104,3 +107,16 @@
     z-index: 2;
   }
 }
+
+.commit-ci-menu {
+  padding: 0;
+  margin: 0;
+  list-style: none;
+  margin-top: 5px;
+  height: 56px;
+  margin: -16px;
+  padding: 16px;
+  text-align: center;
+  margin-top: 0px;
+  margin-bottom: 2px;
+}
diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss
index de2ae93df378b8ccfce5f5f24764bd10729dc874..4e121b95d13b14986749373eec8d66667eb3b998 100644
--- a/app/assets/stylesheets/pages/commits.scss
+++ b/app/assets/stylesheets/pages/commits.scss
@@ -1,5 +1,6 @@
 .commits-compare-switch{
-  @extend .btn;
+  @include btn-default;
+  @include btn-white;
   background: image-url("switch_icon.png") no-repeat center center;
   text-indent: -9999px;
   float: left;
diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss
index 5e7e59a6af82162ac5b999c33b1c884fe32ee220..d9ef06dc6b650ef7ea962a7ccac01f8a047aa664 100644
--- a/app/assets/stylesheets/pages/diff.scss
+++ b/app/assets/stylesheets/pages/diff.scss
@@ -1,3 +1,4 @@
+// Common
 .diff-file {
   margin-left: -$gl-padding;
   margin-right: -$gl-padding;
@@ -12,24 +13,17 @@
     color: #555;
     z-index: 10;
 
-    > span {
+    .diff-title {
       font-family: $monospace_font;
       word-break: break-all;
-      margin-right: 200px;
       display: block;
 
       .file-mode {
-        margin-left: 10px;
         color: #777;
       }
     }
 
-    .diff-btn-group {
-      float: right;
-      position: absolute;
-      top: 5px;
-      right: 15px;
-
+    .diff-controls {
       .btn {
         padding: 0px 10px;
         font-size: 13px;
@@ -90,12 +84,12 @@
       }
     }
 
-    tr.line_holder.parallel{
+    tr.line_holder.parallel {
       .old_line, .new_line, .diff_line {
         min-width: 50px;
       }
 
-      td.line_content.parallel{
+      td.line_content.parallel {
         width: 50%;
       }
     }
@@ -105,7 +99,7 @@
       padding: 0px;
       border: none;
       background: $background-color;
-      color: rgba(0,0,0,0.3);
+      color: rgba(0, 0, 0, 0.3);
       padding: 0px 5px;
       border-right: 1px solid $border-color;
       text-align: right;
@@ -117,7 +111,7 @@
         float: left;
         width: 35px;
         font-weight: normal;
-        color: rgba(0,0,0,0.3);
+        color: rgba(0, 0, 0, 0.3);
         &:hover {
           text-decoration: underline;
         }
@@ -168,7 +162,7 @@
     background: #ddd;
     text-align: center;
     padding: 30px;
-    .wrap{
+    .wrap {
       display: inline-block;
     }
 
@@ -176,7 +170,7 @@
       display: inline-block;
       background-color: #fff;
       line-height: 0;
-      img{
+      img {
         border: 1px solid #FFF;
         background: image-url('trans_bg.gif');
         max-width: 100%;
@@ -189,21 +183,21 @@
         border: 1px solid $added;
       }
     }
-    .image-info{
+    .image-info {
       font-size: 12px;
       margin: 5px 0 0 0;
       color: grey;
     }
 
-    .view.swipe{
+    .view.swipe {
       position: relative;
 
-      .swipe-frame{
+      .swipe-frame {
         display: block;
         margin: auto;
         position: relative;
       }
-      .swipe-wrap{
+      .swipe-wrap {
         overflow: hidden;
         border-left: 1px solid #999;
         position: absolute;
@@ -211,33 +205,33 @@
         top: 13px;
         right: 7px;
       }
-      .frame{
+      .frame {
         top: 0;
         right: 0;
         position: absolute;
-        &.deleted{
+        &.deleted {
           margin: 0;
           display: block;
           top: 13px;
           right: 7px;
         }
       }
-      .swipe-bar{
+      .swipe-bar {
         display: block;
         height: 100%;
         width: 15px;
         z-index: 100;
         position: absolute;
         cursor: pointer;
-        &:hover{
-          .top-handle{
+        &:hover {
+          .top-handle {
             background-position: -15px 3px;
           }
-          .bottom-handle{
+          .bottom-handle {
             background-position: -15px -11px;
           }
-        };
-        .top-handle{
+        }
+        .top-handle {
           display: block;
           height: 14px;
           width: 15px;
@@ -245,7 +239,7 @@
           top: 0px;
           background: image-url('swipemode_sprites.gif') 0 3px no-repeat;
         }
-        .bottom-handle{
+        .bottom-handle {
           display: block;
           height: 14px;
           width: 15px;
@@ -254,9 +248,10 @@
           background: image-url('swipemode_sprites.gif') 0 -11px no-repeat;
         }
       }
-    } //.view.swipe
-    .view.onion-skin{
-      .onion-skin-frame{
+    }
+    //.view.swipe
+    .view.onion-skin {
+      .onion-skin-frame {
         display: block;
         margin: auto;
         position: relative;
@@ -267,7 +262,7 @@
         top: 0px;
         left: 0px;
       }
-      .controls{
+      .controls {
         display: block;
         height: 14px;
         width: 300px;
@@ -277,7 +272,7 @@
         left: 50%;
         margin-left: -150px;
 
-        .drag-track{
+        .drag-track {
           display: block;
           position: absolute;
           left: 12px;
@@ -317,39 +312,40 @@
           background: image-url('onion_skin_sprites.gif') -2px -10px no-repeat;
         }
       }
-    } //.view.onion-skin
+    }
+    //.view.onion-skin
   }
-  .view-modes{
+  .view-modes {
     padding: 10px;
     text-align: center;
     background: #EEE;
 
-    ul, li{
+    ul, li {
       list-style: none;
       margin: 0;
       padding: 0;
       display: inline-block;
     }
 
-    li{
+    li {
       color: grey;
       border-left: 1px solid #c1c1c1;
       padding: 0 12px 0 16px;
       cursor: pointer;
-      &:first-child{
+      &:first-child {
         border-left: none;
       }
-      &:hover{
+      &:hover {
         text-decoration: underline;
       }
-      &.active{
-        &:hover{
+      &.active {
+        &:hover {
           text-decoration: none;
         }
         cursor: default;
         color: #333;
       }
-      &.disabled{
+      &.disabled {
         display: none;
       }
     }
@@ -373,3 +369,37 @@
   float: right;
   margin-top: -5px;
 }
+
+// Mobile
+@media (max-width: 480px) {
+  .diff-title {
+    margin: 0;
+
+    .file-mode {
+      display: none;
+    }
+  }
+
+  .diff-controls {
+    position: static;
+    text-align: center;
+  }
+}
+
+// Bigger screens
+@media (min-width: 481px) {
+  .diff-title {
+    margin-right: 200px;
+
+    .file-mode {
+      margin-left: 10px;
+    }
+  }
+
+  .diff-controls {
+    float: right;
+    position: absolute;
+    top: 5px;
+    right: 15px;
+  }
+}
diff --git a/app/assets/stylesheets/pages/events.scss b/app/assets/stylesheets/pages/events.scss
index ca2ee455423b7b182097f4114920009043c57777..dfb901652bf8480938773975f907852178c602d2 100644
--- a/app/assets/stylesheets/pages/events.scss
+++ b/app/assets/stylesheets/pages/events.scss
@@ -7,7 +7,7 @@
   padding: $gl-padding;
   margin-left: -$gl-padding;
   margin-right: -$gl-padding;
-  border-bottom: 1px solid #f1f2f4;
+  border-bottom: 1px solid $table-border-color;
   color: #7f8fa4;
 
   &.event-inline {
diff --git a/app/assets/stylesheets/pages/groups.scss b/app/assets/stylesheets/pages/groups.scss
index 2b1b747139a71d9cc080161d2c19d253934862a1..07a38a19fad6b465d3082c6fa9cdaeae48a06704 100644
--- a/app/assets/stylesheets/pages/groups.scss
+++ b/app/assets/stylesheets/pages/groups.scss
@@ -10,3 +10,9 @@
 .milestone-row {
   @include str-truncated(90%);
 }
+
+.dashboard .side .panel .panel-heading .input-group {
+  .form-control {
+    height: 42px;
+  }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/pages/help.scss b/app/assets/stylesheets/pages/help.scss
index 6da7a2511a2dd0b3c0f05f4e4c10c679f1936a43..bd224705f04aa29366c410542713eccabdfdc39b 100644
--- a/app/assets/stylesheets/pages/help.scss
+++ b/app/assets/stylesheets/pages/help.scss
@@ -68,3 +68,7 @@ body.modal-open {
 .modal .modal-dialog {
   width: 860px;
 }
+
+.documentation {
+  padding: 7px;
+}
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index b5c61f7f91da6bed6e589992331739b41c2c6824..c60aa5c7fe7f5e80b78b44c7483c34bf0e7c7385 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -54,21 +54,22 @@
     margin-top: -15px;
     padding: 10px 0;
     margin-bottom: 0;
-    color: $gl-gray;
+    color: #5c5d5e;
     font-size: 16px;
 
     .author {
-      color: $gl-gray;
+      color: #5c5d5e;
     }
 
     .issue-id {
-      font-size: 19px;
-      color: $gl-text-color;
+      color: #5c5d5e;
     }
   }
 
   .issue-title {
     margin: 0;
+    font-size: 23px;
+    color: #313236;
   }
 
   .description {
@@ -79,3 +80,11 @@
     }
   }
 }
+
+.issuable-filter-count {
+  span {
+    display: block;
+    margin-bottom: -16px;
+    padding: 13px 0;
+  }
+}
diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss
index 4bf58cb4a590e3a02a69167416ce3d2299037a82..41c069f0ad375eeb49d38675ebe53676580cf976 100644
--- a/app/assets/stylesheets/pages/issues.scss
+++ b/app/assets/stylesheets/pages/issues.scss
@@ -132,6 +132,11 @@ form.edit-issue {
   }
 }
 
+.issue-closed-by-widget {
+  padding: 16px 0;
+  margin: 0px;
+}
+
 .issue-form .select2-container {
   width: 250px !important;
 }
diff --git a/app/assets/stylesheets/ci/lint.scss b/app/assets/stylesheets/pages/lint.scss
similarity index 100%
rename from app/assets/stylesheets/ci/lint.scss
rename to app/assets/stylesheets/pages/lint.scss
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index d8c8e5ad0a4687fd510f08245bde00394d55f733..a1a5208c59c29c555660fc6465a29c6320a48b3d 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -3,12 +3,11 @@
  *
  */
 .mr-state-widget {
-  background: #f8fafc;
+  background: #F7F8FA;
   margin-bottom: 20px;
   color: $gl-gray;
-  border: 1px solid #eef0f2;
-  @include box-shadow(0 1px 1px rgba(0, 0, 0, 0.05));
-  @include border-radius(3px);
+  border: 1px solid #dce0e6;
+  @include border-radius(2px);
 
   form {
     margin-bottom: 0;
@@ -77,10 +76,16 @@
     padding: 15px;
   }
 
+  .normal {
+    color: #5c5d5e;
+  }
+
   .mr-widget-body {
     h4 {
-      font-weight: bold;
+      font-weight: 600;
+      font-size: 17px;
       margin: 5px 0;
+      color: #313236;
     }
 
     p:last-child {
@@ -97,14 +102,26 @@
   }
 }
 
-.merge-request .merge-request-tabs{
+.merge-request .merge-request-tabs {
   @include nav-menu;
   margin: -$gl-padding;
   padding: $gl-padding;
   text-align: center;
-  border-top: 1px solid #e7e9ed;
-  margin-top: 18px;
-  margin-bottom: 3px;
+  margin-bottom: 1px;
+}
+
+// Mobile
+@media (max-width: 480px) {
+  .merge-request .merge-request-tabs {
+    margin: 0;
+    padding: 0;
+
+    li {
+      a {
+        padding: 0;
+      }
+    }
+  }
 }
 
 .mr_source_commit,
@@ -120,10 +137,12 @@
 }
 
 .label-branch {
-  color: #222;
+  color: #313236;
   font-family: $monospace_font;
   font-weight: bold;
   overflow: hidden;
+  font-size: 14px;
+  margin: 0 3px;
 }
 
 .mr-list {
diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss
index fdc2c3332df913b35fcc2ad7c799b3cf99263279..4392f08942b6d939daecfe9ab670f8a955496adf 100644
--- a/app/assets/stylesheets/pages/note_form.scss
+++ b/app/assets/stylesheets/pages/note_form.scss
@@ -65,19 +65,18 @@
 
 .note-image-attach {
   @extend .col-md-4;
-  @extend .thumbnail;
   margin-left: 45px;
   float: none;
 }
 
 .common-note-form {
   margin: 0;
-  background: #f8fafc;
+  background: #F7F8FA;
   padding: $gl-padding;
   margin-left: -$gl-padding;
   margin-right: -$gl-padding;
-  border-right: 1px solid #f1f2f4;
-  border-top: 1px solid #f1f2f4;
+  border-right: 1px solid #ECEEF1;
+  border-top: 1px solid #ECEEF1;
   margin-bottom: -$gl-padding;
 }
 
@@ -168,7 +167,7 @@
 .comment-hints {
   color: #999;
   background: #FFF;
-  padding: 5px;
+  padding: 7px;
   margin-top: -11px;
   border: 1px solid $border-color;
   font-size: 13px;
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index 2a77f065aedce8566ada8b89d30f8614d10697ea..1980fe0d4580e4f5d39bc87a6bfe35f2e2f79623 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -18,7 +18,7 @@ ul.notes {
     font-size: 14px;
     padding-top: 10px;
     padding-bottom: 10px;
-    background: #f8fafc;
+    background: #FDFDFD;
 
     .timeline-icon {
       .avatar {
@@ -30,7 +30,6 @@ ul.notes {
   .discussion-header,
   .note-header {
     @extend .cgray;
-    padding-bottom: 15px;
 
     a:hover {
       text-decoration: none;
@@ -75,6 +74,10 @@ ul.notes {
     }
   }
 
+  .discussion-body {
+    padding-top: 15px;
+  }
+
   .discussion {
     overflow: hidden;
     display: block;
diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss
index 8e4f0eb2b252cff1d87a72518350b1f1bd9531fb..b7391e5303bff8f0bdbc5096c78fdd1e90af0125 100644
--- a/app/assets/stylesheets/pages/profile.scss
+++ b/app/assets/stylesheets/pages/profile.scss
@@ -47,3 +47,9 @@
     }
   }
 }
+
+.calendar-hint {
+  margin-top: -12px;
+  float: right;
+  font-size: 12px;
+}
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index 8d75f3aad499db9de31fd9e777388abc4fad4bd0..6eb659dae17acb7559e585fd6a9c95798b5e8b1d 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -1,12 +1,27 @@
+.alert_holder {
+  margin: -16px;
+
+  .alert-link {
+    font-weight: normal;
+  }
+}
+.no-ssh-key-message {
+  background-color: #f28d35;
+  margin-bottom: 16px;
+}
 .new_project,
 .edit_project {
   fieldset.features {
     .control-label {
-      font-weight: bold;
+      font-weight: normal;
     }
   }
 }
 
+.project-edit-content {
+  padding: 7px;
+}
+
 .project-name-holder {
   .help-inline {
     vertical-align: top;
@@ -19,10 +34,10 @@
   background: #f7f8fa;
   margin: -$gl-padding;
   padding: $gl-padding;
-  padding-top: 40px;
+  padding: 44px 0 17px 0;
 
   .project-identicon-holder {
-    margin-bottom: 15px;
+    margin-bottom: 16px;
 
     .avatar, .identicon {
       margin: 0 auto;
@@ -35,28 +50,42 @@
   }
 
   .project-home-dropdown {
-    margin: 11px 3px 0;
+    margin: 13px 0px 0;
+  }
+
+  .notifications-btn {
+    .fa-bell {
+      margin-right: 6px;
+    }
+
+    .fa-angle-down {
+      margin-left: 6px;
+    }
   }
 
   .project-home-desc {
     h1 {
+      color: #313236;
       margin: 0;
-      margin-bottom: 10px;
+      margin-bottom: 6px;
       font-size: 23px;
       font-weight: normal;
     }
 
     p {
-      color: #7f8fa4;
+      padding: 0 $gl-padding;
+      color: #5c5d5e;
     }
   }
 
   .git-clone-holder {
-    max-width: 600px;
-    margin: 20px auto;
+    max-width: 498px;
 
     .form-control {
       background: #FFF;
+      font-size: 14px;
+      height: 42px;
+      margin-left: -1px;
     }
   }
 
@@ -67,29 +96,36 @@
     }
   }
 
+  .input-group {
+    display: inline-table;
+    position: relative;
+    top: 17px;
+    margin-bottom: 44px;
+  }
+
   .project-repo-buttons {
-    margin-top: $gl-padding;
-    margin-bottom: 25px;
+    margin-top: 12px;
+    margin-bottom: 0px;
 
     .btn {
-      @extend .btn-info;
-
-      text-transform: uppercase;
-      font-size: 15px;
-      line-height: 20px;
-      padding: 8px 14px;
-      border-radius: 3px;
-      margin-left: 10px;
+      @include btn-gray;
 
       .count {
-        padding-left: 7px;
         display: inline-block;
-        margin-left: 7px;
       }
     }
   }
 }
 
+.split-one {
+  display: inline-table;
+  margin-right: 12px;
+
+  a {
+    margin: -1px !important;
+  }
+}
+
 .git-clone-holder {
   .project-home-dropdown + & {
     margin-right: 45px;
@@ -99,11 +135,11 @@
     cursor: auto;
     @extend .monospace;
     background: #FAFAFA;
-    width: 100%;
+    width: 101%;
   }
 
   .input-group-addon {
-    background: #FAFAFA;
+    background: #f7f8fa;
 
     &.git-protocols {
       padding: 0;
@@ -111,28 +147,126 @@
 
       .input-group-btn:last-child > .btn {
         @include border-radius-right(0);
+
+        border-left: 1px solid #c6cacf;
+        margin-left: -2px !important;
       }
     }
   }
 }
 
+.projects-search-form {
+
+  .input-group .form-control {
+    height: 42px;
+  }
+}
+
+.input-group-btn {
+  .btn {
+    @include btn-gray;
+    @include btn-middle;
+
+    &:hover {
+      outline: none;
+    }
+
+    &:focus {
+      outline: none;
+    }
+
+    &:active {
+      outline: none;
+    }
+  }
+
+  .active {
+    @include box-shadow(inset 0 0 4px rgba(0, 0, 0, 0.12));
+
+    border: 1px solid #c6cacf !important;
+    background-color: #e4e7ed !important;
+  }
+
+  .btn-green {
+    @include btn-green
+  }
+
+}
+
+.split-repo-buttons {
+  display: inline-table;
+  margin: 0 12px 0 12px;
+
+  .btn{
+    @include btn-gray;
+    @include btn-default;
+  }
+
+  .dropdown-toggle  {
+    margin: -5px;
+  }
+}
+
+#notification-form {
+  margin-left: 5px;
+}
+
+.dropdown-new {
+  margin-left: -5px;
+}
+
+.open > .dropdown-new.btn {
+  @include box-shadow(inset 0 0 4px rgba(0, 0, 0, 0.12));
+
+  border: 1px solid #c6cacf !important;
+  background-color: #e4e7ed !important;
+  text-transform: uppercase;
+  color: #313236 !important;
+  font-size: 13px;
+  font-weight: 600;
+}
+
+.dropdown-menu {
+  @include box-shadow(rgba(76, 86, 103, 0.247059) 0px 0px 1px 0px, rgba(31, 37, 50, 0.317647) 0px 2px 18px 0px);
+  @include border-radius (0px);
+
+  border: none;
+  padding: 16px 0;
+  font-size: 14px;
+  font-weight: 100;
+
+  li a {
+    color: #5f697a;
+    line-height: 30px;
+
+    &:hover {
+      background-color: #3084bb !important;
+    }
+  }
+
+  i {
+    margin-right: 8px;
+  }
+}
+
 .project-visibility-level-holder {
   .radio {
     margin-bottom: 10px;
 
     i {
-      margin: 0 3px;
+      margin: 2px 0;
       font-size: 20px;
     }
 
     .option-title {
-      font-weight: bold;
+      font-weight: normal;
       display: inline-block;
+      color: #313236;
     }
 
     .option-descr {
-      margin-left: 36px;
-      color: $gray;
+      margin-left: 29px;
+      color: #54565b;
     }
   }
 }
@@ -232,15 +366,28 @@ table.table.protected-branches-list tr.no-border {
 
 .project-stats {
   text-align: center;
-  margin-top: 0;
+  margin-top: 15px;
   margin-bottom: 0;
-  padding-top: 5px;
-  padding-bottom: 0;
+  padding-top: 10px;
+  padding-bottom: 4px;
 
   ul.nav-pills {
     display:inline-block;
   }
 
+  .nav-pills li {
+    display:inline;
+  }
+
+  .nav > li > a {
+    @include btn-default;
+    @include btn-gray;
+
+    background-color: transparent;
+    border: 1px solid #f7f8fa;
+    margin-left: 12px;
+  }
+
   li {
     display:inline;
   }
@@ -251,11 +398,11 @@ table.table.protected-branches-list tr.no-border {
   }
 
   li.missing a {
-    color: #bbb;
-    border: 1px dashed #ccc;
+    color: #5a6069;
+    border: 1px dashed #dce0e5;
 
     &:hover {
-      background-color: #FAFAFA;
+      background-color: #f0f2f5;
     }
   }
 }
@@ -273,15 +420,43 @@ pre.light-well {
   border-bottom: 1px solid #e7e9ed;
 }
 
+.git-empty {
+  margin: 0 7px 0 7px;
+
+  h5 {
+    color: #5c5d5e;
+  }
+
+  .light-well {
+    @include border-radius (2px);
+
+    color: #5b6169;
+    font-size: 13px;
+    line-height: 1.6em;
+  }
+}
+
+.project-footer {
+  margin-top: 20px;
+
+  .btn-remove {
+    @include btn-middle;
+    @include btn-red;
+
+    float: left !important;
+  }
+}
+
 /*
  * Projects list rendered on dashboard and user page
  */
+
 .projects-list {
   @include basic-list;
 
   .project-row {
     padding: $gl-padding;
-    border-color: #f1f2f4;
+    border-color: $table-border-color;
     margin-left: -$gl-padding;
     margin-right: -$gl-padding;
 
@@ -336,6 +511,45 @@ pre.light-well {
   }
 }
 
-.inline-form {
-  display: inline-block;
+.project-last-commit {
+  margin: 0 7px;
+
+  .ci-status {
+    margin-right: 16px;
+  }
+
+  .commit-row-message {
+    color: $gl-gray;
+  }
+
+  .commit_short_id {
+    margin-right: 5px;
+    color: $gl-link-color;
+    font-weight: 600;
+  }
+
+  .commit-author-link {
+    margin-left: 7px;
+    text-decoration: none;
+    .avatar {
+      float: none;
+      margin-right: 4px;
+    }
+
+    .commit-author-name {
+      font-weight: 600;
+    }
+  }
+}
+
+.project-show-readme .readme-holder {
+  margin-left: -$gl-padding;
+  margin-right: -$gl-padding;
+  padding: ($gl-padding + 7px);
+  border-top: 0;
+
+  .edit-project-readme {
+    z-index: 100;
+    position: relative;
+  }
 }
diff --git a/app/assets/stylesheets/pages/runners.scss b/app/assets/stylesheets/pages/runners.scss
new file mode 100644
index 0000000000000000000000000000000000000000..a9111a7388fec3fb5cd8d5800b2f09803a7544de
--- /dev/null
+++ b/app/assets/stylesheets/pages/runners.scss
@@ -0,0 +1,34 @@
+.runner-state {
+  padding: 6px 12px;
+  margin-right: 10px;
+  color: #FFF;
+
+  &.runner-state-shared {
+    background: #32b186;
+  }
+  &.runner-state-specific {
+    background: #3498db;
+  }
+}
+
+.runner-status-online {
+  color: green;
+}
+
+.runner-status-offline {
+  color: gray;
+}
+
+.runner-status-paused {
+  color: red;
+}
+
+.runner {
+  .btn {
+    padding: 1px 6px;
+  }
+
+  h4 {
+    font-weight: normal;
+  }
+}
diff --git a/app/assets/stylesheets/pages/snippets.scss b/app/assets/stylesheets/pages/snippets.scss
index a3d7aba054d21d654efe5152023b67910bb772d6..242783a7b7e13b46b94423017d4ba60457f86657 100644
--- a/app/assets/stylesheets/pages/snippets.scss
+++ b/app/assets/stylesheets/pages/snippets.scss
@@ -1,8 +1,3 @@
-.my-snippets li:first-child {
-  h4 { margin-top: 0; }
-  padding-top: 0;
-}
-
 .snippet-form-holder .file-holder .file-title {
   padding: 2px;
 }
@@ -30,3 +25,58 @@
     }
   }
 }
+
+.snippet-holder {
+  .snippet-details {
+    .page-title {
+      margin-top: -15px;
+      padding: 10px 0;
+      margin-bottom: 0;
+      color: #5c5d5e;
+      font-size: 16px;
+
+      .author {
+        color: #5c5d5e;
+      }
+
+      .snippet-id {
+        color: #5c5d5e;
+      }
+    }
+
+    .snippet-title {
+      margin: 0;
+      font-size: 23px;
+      color: #313236;
+    }
+
+    @media (max-width: $screen-md-max) {
+      .new-snippet-link {
+        display: none;
+      }
+    }
+
+    @media (max-width: $screen-sm-max) {
+      .creator,
+      .page-title .btn-close {
+        display: none;
+      }
+    }
+  }
+
+  .file-holder {
+    border-top: 0;
+  }
+}
+
+
+.snippet-box {
+  @include border-radius(2px);
+
+  display: inline-block;
+  padding: 10px $gl-padding;
+  font-weight: normal;
+  margin-right: 10px;
+  font-size: $gl-font-size;
+  border: 1px solid;
+}
diff --git a/app/assets/stylesheets/ci/status.scss b/app/assets/stylesheets/pages/status.scss
similarity index 100%
rename from app/assets/stylesheets/ci/status.scss
rename to app/assets/stylesheets/pages/status.scss
diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss
index 271cc547e2b31faa7c101b4b5c9242d29d9bc529..d4ab6967ccde757e6cb6586368a11e29c9daad40 100644
--- a/app/assets/stylesheets/pages/tree.scss
+++ b/app/assets/stylesheets/pages/tree.scss
@@ -1,22 +1,13 @@
 .tree-holder {
-  .tree-content-holder {
-    float: left;
-    width: 100%;
-  }
-
-  .tree_progress {
-    display: none;
-    margin: 20px;
-    &.loading {
-      display: block;
-    }
-  }
 
   .tree-table {
-    @extend .table;
-    @include border-radius(0);
+    margin-bottom: 0;
 
     tr {
+      > td, > th {
+        line-height: 28px;
+      }
+
       &:hover {
         td {
           background: $hover;
@@ -27,9 +18,9 @@
       }
       &.selected {
         td {
-          background: $background-color;
-          border-top: 1px solid #EEE;
-          border-bottom: 1px solid #EEE;
+          background: $gray-dark;
+          border-top: 1px solid $border-gray-dark;
+          border-bottom: 1px solid $border-gray-dark;
         }
       }
     }
@@ -85,19 +76,6 @@
   margin-right: 15px;
 }
 
-.readme-holder {
-  margin: 0 auto;
-
-  .readme-file-title {
-    font-size: 14px;
-    font-weight: bold;
-    margin-bottom: 20px;
-    color: #777;
-    border-bottom: 1px solid #DDD;
-    padding: 10px 0;
-  }
-}
-
 .blob-commit-info {
   list-style: none;
   margin: 0;
diff --git a/app/assets/stylesheets/ci/xterm.scss b/app/assets/stylesheets/pages/xterm.scss
similarity index 99%
rename from app/assets/stylesheets/ci/xterm.scss
rename to app/assets/stylesheets/pages/xterm.scss
index 532dede0b2345cbe1a67bf7d0e1d956f541b5113..9a50096c0d07563086ca7ffa83bf997fd790ffbe 100644
--- a/app/assets/stylesheets/ci/xterm.scss
+++ b/app/assets/stylesheets/pages/xterm.scss
@@ -1,4 +1,4 @@
-.ci-body {
+.build-page {
   // color codes are based on http://en.wikipedia.org/wiki/File:Xterm_256color_chart.svg
   // see also: https://gist.github.com/jasonm23/2868981
 
diff --git a/app/controllers/abuse_reports_controller.rb b/app/controllers/abuse_reports_controller.rb
index 65dbd5ef5512cb107e4871ba54bb0b3cf02630aa..2f4054eaa117e2fd1403905c77b2e894858dcde7 100644
--- a/app/controllers/abuse_reports_controller.rb
+++ b/app/controllers/abuse_reports_controller.rb
@@ -9,6 +9,10 @@ class AbuseReportsController < ApplicationController
     @abuse_report.reporter = current_user
 
     if @abuse_report.save
+      if current_application_settings.admin_notification_email.present?
+        AbuseReportMailer.delay.notify(@abuse_report.id)
+      end
+
       message = "Thank you for your report. A GitLab administrator will look into it shortly."
       redirect_to root_path, notice: message
     else
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index 5f70582cbb7128adbd2b1bdaadbb57a6bf6024a1..039f18f23e0cf18bc432ea45ef26bb54c3eb7b3f 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -55,8 +55,8 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
       :default_snippet_visibility,
       :restricted_signup_domains_raw,
       :version_check_enabled,
+      :admin_notification_email,
       :user_oauth_applications,
-      :ci_enabled,
       restricted_visibility_levels: [],
       import_sources: []
     )
diff --git a/app/controllers/admin/broadcast_messages_controller.rb b/app/controllers/admin/broadcast_messages_controller.rb
index 0808024fc39a46b39f49c298f7983a0080f39e6c..497c34f8f493bd9dfa31dc67656dbf5deb6b5151 100644
--- a/app/controllers/admin/broadcast_messages_controller.rb
+++ b/app/controllers/admin/broadcast_messages_controller.rb
@@ -19,7 +19,7 @@ class Admin::BroadcastMessagesController < Admin::ApplicationController
     BroadcastMessage.find(params[:id]).destroy
 
     respond_to do |format|
-      format.html { redirect_to :back }
+      format.html { redirect_back_or_default(default: { action: 'index' }) }
       format.js { render nothing: true }
     end
   end
diff --git a/app/controllers/admin/hooks_controller.rb b/app/controllers/admin/hooks_controller.rb
index d670386f8c62afdca3ef174da86df8dae1de4cba..0bd19c49d8f1f9a1e616ca9113049a47af614592 100644
--- a/app/controllers/admin/hooks_controller.rb
+++ b/app/controllers/admin/hooks_controller.rb
@@ -35,7 +35,7 @@ class Admin::HooksController < Admin::ApplicationController
     }
     @hook.execute(data, 'system_hooks')
 
-    redirect_to :back
+    redirect_back_or_default
   end
 
   def hook_params
diff --git a/app/controllers/admin/services_controller.rb b/app/controllers/admin/services_controller.rb
index a62170662e12c34070374c69f6396a616b82aeeb..461335883325e2c7b33b29c83114ce6ff880e5db 100644
--- a/app/controllers/admin/services_controller.rb
+++ b/app/controllers/admin/services_controller.rb
@@ -39,7 +39,13 @@ class Admin::ServicesController < Admin::ApplicationController
   end
 
   def application_services_params
-    params.permit(:id,
+    application_services_params = params.permit(:id,
       service: Projects::ServicesController::ALLOWED_PARAMS)
+    if application_services_params[:service].is_a?(Hash)
+      Projects::ServicesController::FILTER_BLANK_PARAMS.each do |param|
+        application_services_params[:service].delete(param) if application_services_params[:service][param].blank? 
+      end
+    end
+    application_services_params
   end
 end
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index a19b1abee272c7eef524610c127d0d87e64bd069..c63d0793e3141dde9c10d2fb500b374004d04d08 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -33,36 +33,42 @@ class Admin::UsersController < Admin::ApplicationController
 
   def block
     if user.block
-      redirect_to :back, notice: "Successfully blocked"
+      redirect_back_or_admin_user(notice: "Successfully blocked")
     else
-      redirect_to :back, alert: "Error occurred. User was not blocked"
+      redirect_back_or_admin_user(alert: "Error occurred. User was not blocked")
     end
   end
 
   def unblock
     if user.activate
-      redirect_to :back, notice: "Successfully unblocked"
+      redirect_back_or_admin_user(notice: "Successfully unblocked")
     else
-      redirect_to :back, alert: "Error occurred. User was not unblocked"
+      redirect_back_or_admin_user(alert: "Error occurred. User was not unblocked")
     end
   end
 
   def unlock
     if user.unlock_access!
-      redirect_to :back, alert: "Successfully unlocked"
+      redirect_back_or_admin_user(alert: "Successfully unlocked")
     else
-      redirect_to :back, alert: "Error occurred. User was not unlocked"
+      redirect_back_or_admin_user(alert: "Error occurred. User was not unlocked")
     end
   end
 
   def confirm
     if user.confirm
-      redirect_to :back, notice: "Successfully confirmed"
+      redirect_back_or_admin_user(notice: "Successfully confirmed")
     else
-      redirect_to :back, alert: "Error occurred. User was not confirmed"
+      redirect_back_or_admin_user(alert: "Error occurred. User was not confirmed")
     end
   end
 
+  def login_as
+    sign_in(user)
+    flash[:alert] = "Logged in as #{user.username}"
+    redirect_to root_path
+  end
+
   def disable_two_factor
     user.disable_two_factor!
     redirect_to admin_user_path(user),
@@ -132,7 +138,7 @@ class Admin::UsersController < Admin::ApplicationController
     user.update_secondary_emails!
 
     respond_to do |format|
-      format.html { redirect_to :back, notice: "Successfully removed email." }
+      format.html { redirect_back_or_admin_user(notice: "Successfully removed email.") }
       format.js { render nothing: true }
     end
   end
@@ -151,4 +157,12 @@ class Admin::UsersController < Admin::ApplicationController
       :projects_limit, :can_create_group, :admin, :key_id
     )
   end
+
+  def redirect_back_or_admin_user(options = {})
+    redirect_back_or_default(default: default_route, options: options)
+  end
+
+  def default_route
+    [:admin, @user]
+  end
 end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 9b6472a7b13e0e1ae5b50e91a14b44eff85bc490..1b0609e279ef19e1c2580620e2abcf94d468c31a 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -30,7 +30,11 @@ class ApplicationController < ActionController::Base
 
   rescue_from ActiveRecord::RecordNotFound do |exception|
     log_exception(exception)
-    render "errors/not_found", layout: "errors", status: 404
+    render_404
+  end
+
+  def redirect_back_or_default(default: root_path, options: {})
+    redirect_to request.referer.present? ? :back : default, options
   end
 
   protected
@@ -117,9 +121,13 @@ class ApplicationController < ActionController::Base
         redirect_to request.original_url.gsub(/\.git\Z/, '') and return
       end
 
-      @project = Project.find_with_namespace("#{namespace}/#{id}")
+      project_path = "#{namespace}/#{id}"
+      @project = Project.find_with_namespace(project_path)
 
       if @project and can?(current_user, :read_project, @project)
+        if @project.path_with_namespace != project_path
+          redirect_to request.original_url.gsub(project_path, @project.path_with_namespace) and return
+        end
         @project
       elsif current_user.nil?
         @project = nil
@@ -144,12 +152,8 @@ class ApplicationController < ActionController::Base
     render "errors/access_denied", layout: "errors", status: 404
   end
 
-  def not_found!
-    render "errors/not_found", layout: "errors", status: 404
-  end
-
   def git_not_found!
-    render "errors/git_not_found", layout: "errors", status: 404
+    render html: "errors/git_not_found", layout: "errors", status: 404
   end
 
   def method_missing(method_sym, *arguments, &block)
diff --git a/app/controllers/ci/admin/runners_controller.rb b/app/controllers/ci/admin/runners_controller.rb
index dc3508b49dd47f268b3f3c0f9f19cc98947bc510..110954a612d04cfee9bab683345fb1e772b47596 100644
--- a/app/controllers/ci/admin/runners_controller.rb
+++ b/app/controllers/ci/admin/runners_controller.rb
@@ -6,13 +6,16 @@ module Ci
       @runners = Ci::Runner.order('id DESC')
       @runners = @runners.search(params[:search]) if params[:search].present?
       @runners = @runners.page(params[:page]).per(30)
-      @active_runners_cnt = Ci::Runner.where("contacted_at > ?", 1.minutes.ago).count
+      @active_runners_cnt = Ci::Runner.online.count
     end
 
     def show
       @builds = @runner.builds.order('id DESC').first(30)
       @projects = Ci::Project.all
-      @projects = @projects.search(params[:search]) if params[:search].present?
+      if params[:search].present?
+        @gl_projects = ::Project.search(params[:search])
+        @projects = @projects.where(gitlab_id: @gl_projects.select(:id))
+      end
       @projects = @projects.where("ci_projects.id NOT IN (?)", @runner.projects.pluck(:id)) if @runner.projects.any?
       @projects = @projects.page(params[:page]).per(30)
     end
@@ -63,7 +66,7 @@ module Ci
     end
 
     def runner_params
-      params.require(:runner).permit(:token, :description, :tag_list, :contacted_at, :active)
+      params.require(:runner).permit(:token, :description, :tag_list, :active)
     end
   end
 end
diff --git a/app/controllers/ci/application_controller.rb b/app/controllers/ci/application_controller.rb
index d8227e632e4d58794a75ccddb3c343755a613a68..9be470660e6cd85f70fc6c235f6154c6a8b3520e 100644
--- a/app/controllers/ci/application_controller.rb
+++ b/app/controllers/ci/application_controller.rb
@@ -1,7 +1,5 @@
 module Ci
   class ApplicationController < ::ApplicationController
-    before_action :check_enable_flag!
-
     def self.railtie_helpers_paths
       "app/helpers/ci"
     end
@@ -10,13 +8,6 @@ module Ci
 
     private
 
-    def check_enable_flag!
-      unless current_application_settings.ci_enabled
-        redirect_to(disabled_ci_projects_path)
-        return
-      end
-    end
-
     def authenticate_public_page!
       unless project.public
         authenticate_user!
diff --git a/app/controllers/ci/builds_controller.rb b/app/controllers/ci/builds_controller.rb
deleted file mode 100644
index 80ee866679266013bc5098fe9e9dba0e82632ed6..0000000000000000000000000000000000000000
--- a/app/controllers/ci/builds_controller.rb
+++ /dev/null
@@ -1,78 +0,0 @@
-module Ci
-  class BuildsController < Ci::ApplicationController
-    before_action :authenticate_user!, except: [:status, :show]
-    before_action :authenticate_public_page!, only: :show
-    before_action :project
-    before_action :authorize_access_project!, except: [:status, :show]
-    before_action :authorize_manage_project!, except: [:status, :show, :retry, :cancel]
-    before_action :authorize_manage_builds!, only: [:retry, :cancel]
-    before_action :build, except: [:show]
-    layout 'ci/build'
-
-    def show
-      if params[:id] =~ /\A\d+\Z/
-        @build = build
-      else
-        # try to find commit by sha
-        commit = commit_by_sha
-
-        if commit
-          # Redirect to commit page
-          redirect_to ci_project_ref_commit_path(@project, @build.commit.ref, @build.commit.sha)
-          return
-        end
-      end
-
-      raise ActiveRecord::RecordNotFound unless @build
-
-      @builds = @project.commits.find_by_sha(@build.sha).builds.order('id DESC')
-      @builds = @builds.where("id not in (?)", @build.id).page(params[:page]).per(20)
-      @commit = @build.commit
-
-      respond_to do |format|
-        format.html
-        format.json do
-          render json: @build.to_json(methods: :trace_html)
-        end
-      end
-    end
-
-    def retry
-      if @build.commands.blank?
-        return page_404
-      end
-
-      build = Ci::Build.retry(@build)
-
-      if params[:return_to]
-        redirect_to URI.parse(params[:return_to]).path
-      else
-        redirect_to ci_project_build_path(project, build)
-      end
-    end
-
-    def status
-      render json: @build.to_json(only: [:status, :id, :sha, :coverage], methods: :sha)
-    end
-
-    def cancel
-      @build.cancel
-
-      redirect_to ci_project_build_path(@project, @build)
-    end
-
-    protected
-
-    def project
-      @project = Ci::Project.find(params[:project_id])
-    end
-
-    def build
-      @build ||= project.builds.unscoped.find_by(id: params[:id])
-    end
-
-    def commit_by_sha
-      @project.commits.find_by(sha: params[:id])
-    end
-  end
-end
diff --git a/app/controllers/ci/commits_controller.rb b/app/controllers/ci/commits_controller.rb
deleted file mode 100644
index 7a0a500fbe6f4f5455e3076350b16cec1d175cab..0000000000000000000000000000000000000000
--- a/app/controllers/ci/commits_controller.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-module Ci
-  class CommitsController < Ci::ApplicationController
-    before_action :authenticate_user!, except: [:status, :show]
-    before_action :authenticate_public_page!, only: :show
-    before_action :project
-    before_action :authorize_access_project!, except: [:status, :show, :cancel]
-    before_action :authorize_manage_builds!, only: [:cancel]
-    before_action :commit, only: :show
-    layout 'ci/commit'
-
-    def show
-      @builds = @commit.builds
-    end
-
-    def status
-      commit = Ci::Project.find(params[:project_id]).commits.find_by_sha_and_ref!(params[:id], params[:ref_id])
-      render json: commit.to_json(only: [:id, :sha], methods: [:status, :coverage])
-    rescue ActiveRecord::RecordNotFound
-      render json: { status: "not_found" }
-    end
-
-    def cancel
-      commit.builds.running_or_pending.each(&:cancel)
-
-      redirect_to ci_project_ref_commits_path(project, commit.ref, commit.sha)
-    end
-
-    private
-
-    def project
-      @project ||= Ci::Project.find(params[:project_id])
-    end
-
-    def commit
-      @commit ||= Ci::Project.find(params[:project_id]).commits.find_by_sha_and_ref!(params[:id], params[:ref_id])
-    end
-  end
-end
diff --git a/app/controllers/ci/lints_controller.rb b/app/controllers/ci/lints_controller.rb
index a81e4e319ffdc16556aedf4136346e52668385a2..24dd1b5c93aba542c1edb9c4a96ce036886f7bd8 100644
--- a/app/controllers/ci/lints_controller.rb
+++ b/app/controllers/ci/lints_controller.rb
@@ -18,7 +18,7 @@ module Ci
     rescue Ci::GitlabCiYamlProcessor::ValidationError => e
       @error = e.message
       @status = false
-    rescue Exception => e
+    rescue Exception
       @error = "Undefined error"
       @status = false
     end
diff --git a/app/controllers/ci/projects_controller.rb b/app/controllers/ci/projects_controller.rb
index 6111753a7fbc638a5d0e8c509458171d925abb49..809b44387ba0df263dc335101cc8dd884367a176 100644
--- a/app/controllers/ci/projects_controller.rb
+++ b/app/controllers/ci/projects_controller.rb
@@ -1,48 +1,15 @@
 module Ci
   class ProjectsController < Ci::ApplicationController
-    before_action :authenticate_user!, except: [:build, :badge, :show]
-    before_action :authenticate_public_page!, only: :show
-    before_action :project, only: [:build, :show, :badge, :edit, :update, :destroy, :toggle_shared_runners, :dumped_yaml]
-    before_action :authorize_access_project!, except: [:build, :badge, :show, :new, :disabled]
-    before_action :authorize_manage_project!, only: [:edit, :update, :destroy, :toggle_shared_runners, :dumped_yaml]
-    before_action :authenticate_token!, only: [:build]
+    before_action :project, except: [:index]
+    before_action :authenticate_user!, except: [:index, :build, :badge]
+    before_action :authorize_access_project!, except: [:index, :badge]
+    before_action :authorize_manage_project!, only: [:toggle_shared_runners, :dumped_yaml]
     before_action :no_cache, only: [:badge]
-    skip_before_action :check_enable_flag!, only: [:disabled]
-    protect_from_forgery except: :build
-
-    layout 'ci/project', except: [:index, :disabled]
-
-    def disabled
-    end
+    protect_from_forgery
 
     def show
-      @ref = params[:ref]
-
-      @commits = @project.commits.reverse_order
-      @commits = @commits.where(ref: @ref) if @ref
-      @commits = @commits.page(params[:page]).per(20)
-    end
-
-    def edit
-    end
-
-    def update
-      if project.update_attributes(project_params)
-        Ci::EventService.new.change_project_settings(current_user, project)
-
-        redirect_to :back, notice: 'Project was successfully updated.'
-      else
-        render action: "edit"
-      end
-    end
-
-    def destroy
-      project.gl_project.gitlab_ci_service.update_attributes(active: false)
-      project.destroy
-
-      Ci::EventService.new.remove_project(current_user, project)
-
-      redirect_to ci_projects_url
+      # Temporary compatibility with CI badges pointing to CI project page
+      redirect_to namespace_project_path(project.gl_project.namespace, project.gl_project)
     end
 
     # Project status badge
@@ -55,7 +22,8 @@ module Ci
 
     def toggle_shared_runners
       project.toggle!(:shared_runners_enabled)
-      redirect_to :back
+
+      redirect_to namespace_project_runners_path(project.gl_project.namespace, project.gl_project)
     end
 
     def dumped_yaml
@@ -73,12 +41,5 @@ module Ci
       response.headers["Pragma"] = "no-cache"
       response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT"
     end
-
-    def project_params
-      params.require(:project).permit(:path, :timeout, :timeout_in_minutes, :default_ref, :always_build,
-        :polling_interval, :public, :ssh_url_to_repo, :allow_git_fetch, :email_recipients,
-        :email_add_pusher, :email_only_broken_builds, :coverage_regex, :shared_runners_enabled, :token,
-        { variables_attributes: [:id, :key, :value, :_destroy] })
-    end
   end
 end
diff --git a/app/controllers/ci/runner_projects_controller.rb b/app/controllers/ci/runner_projects_controller.rb
index a8bdd5bb36252dfa7efd9bad4b6ac1f301d70163..97f01d40af553dd3831dc2a83a39059626084d35 100644
--- a/app/controllers/ci/runner_projects_controller.rb
+++ b/app/controllers/ci/runner_projects_controller.rb
@@ -11,10 +11,12 @@ module Ci
 
       return head(403) unless current_user.ci_authorized_runners.include?(@runner)
 
+      path = runners_path(@project.gl_project)
+
       if @runner.assign_to(project, current_user)
-        redirect_to ci_project_runners_path(project)
+        redirect_to path
       else
-        redirect_to ci_project_runners_path(project), alert: 'Failed adding runner to project'
+        redirect_to path, alert: 'Failed adding runner to project'
       end
     end
 
@@ -22,7 +24,7 @@ module Ci
       runner_project = project.runner_projects.find(params[:id])
       runner_project.destroy
 
-      redirect_to ci_project_runners_path(project)
+      redirect_to runners_path(@project.gl_project)
     end
 
     private
diff --git a/app/controllers/ci/runners_controller.rb b/app/controllers/ci/runners_controller.rb
deleted file mode 100644
index a672370302baa8ab2d5b35b658e46d1abecf9a10..0000000000000000000000000000000000000000
--- a/app/controllers/ci/runners_controller.rb
+++ /dev/null
@@ -1,73 +0,0 @@
-module Ci
-  class RunnersController < Ci::ApplicationController
-    before_action :authenticate_user!
-    before_action :project
-    before_action :set_runner, only: [:edit, :update, :destroy, :pause, :resume, :show]
-    before_action :authorize_access_project!
-    before_action :authorize_manage_project!
-
-    layout 'ci/project'
-
-    def index
-      @runners = @project.runners.order('id DESC')
-      @specific_runners =
-        Ci::Runner.specific.includes(:runner_projects).
-        where(Ci::RunnerProject.table_name => { project_id: current_user.authorized_projects } ).
-        where.not(id:  @runners).order("#{Ci::Runner.table_name}.id DESC").page(params[:page]).per(20)
-      @shared_runners = Ci::Runner.shared.active
-      @shared_runners_count = @shared_runners.count(:all)
-    end
-
-    def edit
-    end
-
-    def update
-      if @runner.update_attributes(runner_params)
-        redirect_to edit_ci_project_runner_path(@project, @runner), notice: 'Runner was successfully updated.'
-      else
-        redirect_to edit_ci_project_runner_path(@project, @runner), alert: 'Runner was not updated.'
-      end
-    end
-
-    def destroy
-      if @runner.only_for?(@project)
-        @runner.destroy
-      end
-
-      redirect_to ci_project_runners_path(@project)
-    end
-
-    def resume
-      if @runner.update_attributes(active: true)
-        redirect_to ci_project_runners_path(@project, @runner), notice: 'Runner was successfully updated.'
-      else
-        redirect_to ci_project_runners_path(@project, @runner), alert: 'Runner was not updated.'
-      end
-    end
-
-    def pause
-      if @runner.update_attributes(active: false)
-        redirect_to ci_project_runners_path(@project, @runner), notice: 'Runner was successfully updated.'
-      else
-        redirect_to ci_project_runners_path(@project, @runner), alert: 'Runner was not updated.'
-      end
-    end
-
-    def show
-    end
-
-    protected
-
-    def project
-      @project = Ci::Project.find(params[:project_id])
-    end
-
-    def set_runner
-      @runner ||= @project.runners.find(params[:id])
-    end
-
-    def runner_params
-      params.require(:runner).permit(:description, :tag_list, :contacted_at, :active)
-    end
-  end
-end
diff --git a/app/controllers/ci/services_controller.rb b/app/controllers/ci/services_controller.rb
deleted file mode 100644
index 52c96a34ce88499ff1b2897dfcd561b9f96992fa..0000000000000000000000000000000000000000
--- a/app/controllers/ci/services_controller.rb
+++ /dev/null
@@ -1,59 +0,0 @@
-module Ci
-  class ServicesController < Ci::ApplicationController
-    before_action :authenticate_user!
-    before_action :project
-    before_action :authorize_access_project!
-    before_action :authorize_manage_project!
-    before_action :service, only: [:edit, :update, :test]
-
-    respond_to :html
-
-    layout 'ci/project'
-
-    def index
-      @project.build_missing_services
-      @services = @project.services.reload
-    end
-
-    def edit
-    end
-
-    def update
-      if @service.update_attributes(service_params)
-        redirect_to edit_ci_project_service_path(@project, @service.to_param)
-      else
-        render 'edit'
-      end
-    end
-
-    def test
-      last_build = @project.builds.last
-
-      if @service.execute(last_build)
-        message = { notice: 'We successfully tested the service' }
-      else
-        message = { alert: 'We tried to test the service but error occurred' }
-      end
-
-      redirect_to :back, message
-    end
-
-    private
-
-    def project
-      @project = Ci::Project.find(params[:project_id])
-    end
-
-    def service
-      @service ||= @project.services.find { |service| service.to_param == params[:id] }
-    end
-
-    def service_params
-      params.require(:service).permit(
-        :type, :active, :webhook, :notify_only_broken_builds,
-        :email_recipients, :email_only_broken_builds, :email_add_pusher,
-        :hipchat_token, :hipchat_room, :hipchat_server
-      )
-    end
-  end
-end
diff --git a/app/controllers/ci/triggers_controller.rb b/app/controllers/ci/triggers_controller.rb
deleted file mode 100644
index a39cc5d3a56d3128909b3c0db962588074e4d59f..0000000000000000000000000000000000000000
--- a/app/controllers/ci/triggers_controller.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-module Ci
-  class TriggersController < Ci::ApplicationController
-    before_action :authenticate_user!
-    before_action :project
-    before_action :authorize_access_project!
-    before_action :authorize_manage_project!
-
-    layout 'ci/project'
-
-    def index
-      @triggers = @project.triggers
-      @trigger = Ci::Trigger.new
-    end
-
-    def create
-      @trigger = @project.triggers.new
-      @trigger.save
-
-      if @trigger.valid?
-        redirect_to ci_project_triggers_path(@project)
-      else
-        @triggers = @project.triggers.select(&:persisted?)
-        render :index
-      end
-    end
-
-    def destroy
-      trigger.destroy
-
-      redirect_to ci_project_triggers_path(@project)
-    end
-
-    private
-
-    def trigger
-      @trigger ||= @project.triggers.find(params[:id])
-    end
-
-    def project
-      @project = Ci::Project.find(params[:project_id])
-    end
-  end
-end
diff --git a/app/controllers/ci/variables_controller.rb b/app/controllers/ci/variables_controller.rb
deleted file mode 100644
index 9c6c775fde805c990304265d7b21fa3c59326345..0000000000000000000000000000000000000000
--- a/app/controllers/ci/variables_controller.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-module Ci
-  class VariablesController < Ci::ApplicationController
-    before_action :authenticate_user!
-    before_action :project
-    before_action :authorize_access_project!
-    before_action :authorize_manage_project!
-
-    layout 'ci/project'
-
-    def show
-    end
-
-    def update
-      if project.update_attributes(project_params)
-        Ci::EventService.new.change_project_settings(current_user, project)
-
-        redirect_to ci_project_variables_path(project), notice: 'Variables were successfully updated.'
-      else
-        render action: 'show'
-      end
-    end
-
-    private
-
-    def project
-      @project ||= Ci::Project.find(params[:project_id])
-    end
-
-    def project_params
-      params.require(:project).permit({ variables_attributes: [:id, :key, :value, :_destroy] })
-    end
-  end
-end
diff --git a/app/controllers/ci/web_hooks_controller.rb b/app/controllers/ci/web_hooks_controller.rb
deleted file mode 100644
index 24074a6d9acf4200e25387780aff40b4584b5d77..0000000000000000000000000000000000000000
--- a/app/controllers/ci/web_hooks_controller.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-module Ci
-  class WebHooksController < Ci::ApplicationController
-    before_action :authenticate_user!
-    before_action :project
-    before_action :authorize_access_project!
-    before_action :authorize_manage_project!
-
-    layout 'ci/project'
-
-    def index
-      @web_hooks = @project.web_hooks
-      @web_hook = Ci::WebHook.new
-    end
-
-    def create
-      @web_hook = @project.web_hooks.new(web_hook_params)
-      @web_hook.save
-
-      if @web_hook.valid?
-        redirect_to ci_project_web_hooks_path(@project)
-      else
-        @web_hooks = @project.web_hooks.select(&:persisted?)
-        render :index
-      end
-    end
-
-    def test
-      Ci::TestHookService.new.execute(hook, current_user)
-
-      redirect_to :back
-    end
-
-    def destroy
-      hook.destroy
-
-      redirect_to ci_project_web_hooks_path(@project)
-    end
-
-    private
-
-    def hook
-      @web_hook ||= @project.web_hooks.find(params[:id])
-    end
-
-    def project
-      @project = Ci::Project.find(params[:project_id])
-    end
-
-    def web_hook_params
-      params.require(:web_hook).permit(:url)
-    end
-  end
-end
diff --git a/app/controllers/dashboard/projects_controller.rb b/app/controllers/dashboard/projects_controller.rb
index 467d0f81acac3628f5bfab7ed60568b63114445a..58e9049f158e0f7191f1cdcc0fac1bec293cb63b 100644
--- a/app/controllers/dashboard/projects_controller.rb
+++ b/app/controllers/dashboard/projects_controller.rb
@@ -20,6 +20,7 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
     @projects = current_user.starred_projects
     @projects = @projects.includes(:namespace, :forked_from_project, :tags)
     @projects = @projects.sort(@sort = params[:sort])
+    @last_push = current_user.recent_push
     @groups = []
 
     respond_to do |format|
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index 524218290c6635323bd2e038803cd2501560aafa..40fb15a5b3682b50fc00e96c9e3766f54869889f 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -88,7 +88,7 @@ class GroupsController < Groups::ApplicationController
   def destroy
     DestroyGroupService.new(@group, current_user).execute
 
-    redirect_to root_path, alert: "Group '#{@group.name} was deleted."
+    redirect_to root_path, alert: "Group '#{@group.name}' was successfully deleted."
   end
 
   protected
diff --git a/app/controllers/import/bitbucket_controller.rb b/app/controllers/import/bitbucket_controller.rb
index f84f85a7df842a522d7131b88cd269054cf78518..25e587248606ccde522f0b0f86fe2c4d35875107 100644
--- a/app/controllers/import/bitbucket_controller.rb
+++ b/app/controllers/import/bitbucket_controller.rb
@@ -62,7 +62,7 @@ class Import::BitbucketController < Import::BaseController
   end
 
   def verify_bitbucket_import_enabled
-    not_found! unless bitbucket_import_enabled?
+    render_404 unless bitbucket_import_enabled?
   end
 
   def bitbucket_auth
diff --git a/app/controllers/import/fogbugz_controller.rb b/app/controllers/import/fogbugz_controller.rb
index 849646cd6652403006d9a601a2909d03e70b474f..18300390851edcc3d2177ecd253951466b6e159b 100644
--- a/app/controllers/import/fogbugz_controller.rb
+++ b/app/controllers/import/fogbugz_controller.rb
@@ -99,6 +99,6 @@ class Import::FogbugzController < Import::BaseController
   end
 
   def verify_fogbugz_import_enabled
-    not_found! unless fogbugz_import_enabled?
+    render_404 unless fogbugz_import_enabled?
   end
 end
diff --git a/app/controllers/import/github_controller.rb b/app/controllers/import/github_controller.rb
index f21fbd9eccac0f02b41fbf40530d5c7364b68ff8..67bf4190e7e66ca5b84fc27cb8cb4b96f378fab0 100644
--- a/app/controllers/import/github_controller.rb
+++ b/app/controllers/import/github_controller.rb
@@ -11,10 +11,6 @@ class Import::GithubController < Import::BaseController
 
   def status
     @repos = client.repos
-    client.orgs.each do |org|
-      @repos += client.org_repos(org.login)
-    end
-
     @already_added_projects = current_user.created_projects.where(import_type: "github")
     already_added_projects_names = @already_added_projects.pluck(:import_source)
 
@@ -47,7 +43,7 @@ class Import::GithubController < Import::BaseController
   end
 
   def verify_github_import_enabled
-    not_found! unless github_import_enabled?
+    render_404 unless github_import_enabled?
   end
 
   def github_auth
diff --git a/app/controllers/import/gitlab_controller.rb b/app/controllers/import/gitlab_controller.rb
index 27af19f5f616f89f19580fd03f95f6bd49faa573..23a396e8084f3dd2b32646f35b1d13f22a2bf0b3 100644
--- a/app/controllers/import/gitlab_controller.rb
+++ b/app/controllers/import/gitlab_controller.rb
@@ -44,7 +44,7 @@ class Import::GitlabController < Import::BaseController
   end
 
   def verify_gitlab_import_enabled
-    not_found! unless gitlab_import_enabled?
+    render_404 unless gitlab_import_enabled?
   end
 
   def gitlab_auth
diff --git a/app/controllers/import/gitorious_controller.rb b/app/controllers/import/gitorious_controller.rb
index f24cdb3709a0246eac25ef0c3807d6ebf9b170a2..eecbe380c9e7f7da752020f67833519bfb7c7f71 100644
--- a/app/controllers/import/gitorious_controller.rb
+++ b/app/controllers/import/gitorious_controller.rb
@@ -42,7 +42,7 @@ class Import::GitoriousController < Import::BaseController
   end
 
   def verify_gitorious_import_enabled
-    not_found! unless gitorious_import_enabled?
+    render_404 unless gitorious_import_enabled?
   end
 
 end
diff --git a/app/controllers/import/google_code_controller.rb b/app/controllers/import/google_code_controller.rb
index 82fadeb7e832deba7f88860e3db3dd9a0e9cb9b4..e0de31f225146f61172b8d7d1984552fda48f2f6 100644
--- a/app/controllers/import/google_code_controller.rb
+++ b/app/controllers/import/google_code_controller.rb
@@ -10,18 +10,18 @@ class Import::GoogleCodeController < Import::BaseController
     dump_file = params[:dump_file]
 
     unless dump_file.respond_to?(:read)
-      return redirect_to :back, alert: "You need to upload a Google Takeout archive."
+      return redirect_back_or_default(options: { alert: "You need to upload a Google Takeout archive." })
     end
 
     begin
       dump = JSON.parse(dump_file.read)
     rescue
-      return redirect_to :back, alert: "The uploaded file is not a valid Google Takeout archive."
+      return redirect_back_or_default(options: { alert: "The uploaded file is not a valid Google Takeout archive." })
     end
 
     client = Gitlab::GoogleCodeImport::Client.new(dump)
     unless client.valid?
-      return redirect_to :back, alert: "The uploaded file is not a valid Google Takeout archive."
+      return redirect_back_or_default(options: { alert: "The uploaded file is not a valid Google Takeout archive." })
     end
 
     session[:google_code_dump] = dump
@@ -106,7 +106,7 @@ class Import::GoogleCodeController < Import::BaseController
   end
 
   def verify_google_code_import_enabled
-    not_found! unless google_code_import_enabled?
+    render_404 unless google_code_import_enabled?
   end
 
   def user_map
diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb
index 8ef10a17f5582cea6d55a210426c85f2c0b81a44..94bb108c5f58228de0f2c5c8883bf377e971ebcc 100644
--- a/app/controllers/invites_controller.rb
+++ b/app/controllers/invites_controller.rb
@@ -14,7 +14,7 @@ class InvitesController < ApplicationController
 
       redirect_to path, notice: "You have been granted #{member.human_access} access to #{label}."
     else
-      redirect_to :back, alert: "The invitation could not be accepted."
+      redirect_back_or_default(options: { alert: "The invitation could not be accepted." })
     end
   end
 
@@ -31,7 +31,7 @@ class InvitesController < ApplicationController
 
       redirect_to path, notice: "You have declined the invitation to join #{label}."
     else
-      redirect_to :back, alert: "The invitation could not be declined."
+      redirect_back_or_default(options: { alert: "The invitation could not be declined." })
     end
   end
 
diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb
index 523264b8ea9170b71701901ccd4ac3fca5d56b35..f809fa7500a09fd37a547238198987e80501f5ea 100644
--- a/app/controllers/omniauth_callbacks_controller.rb
+++ b/app/controllers/omniauth_callbacks_controller.rb
@@ -71,7 +71,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
         redirect_to omniauth_error_path(oauth['provider'], error: error_message) and return
       end
     end
-  rescue Gitlab::OAuth::SignupDisabledError => e
+  rescue Gitlab::OAuth::SignupDisabledError
     label = Gitlab::OAuth::Provider.label_for(oauth['provider'])
     message = "Signing in using your #{label} account without a pre-existing GitLab account is not allowed."
 
@@ -80,7 +80,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
     end
 
     flash[:notice] = message
-    
+
     redirect_to new_user_session_path
   end
 
diff --git a/app/controllers/passwords_controller.rb b/app/controllers/passwords_controller.rb
index 8450ba31021ffd0781b69dbf0f062c064b389dbe..2025158d06598cc86e42af1a232fb4ad2ff823cd 100644
--- a/app/controllers/passwords_controller.rb
+++ b/app/controllers/passwords_controller.rb
@@ -1,41 +1,7 @@
 class PasswordsController < Devise::PasswordsController
-
-  def create
-    email = resource_params[:email]
-    resource_found = resource_class.find_by_email(email)
-    if resource_found && resource_found.ldap_user?
-      flash[:alert] = "Cannot reset password for LDAP user."
-      respond_with({}, location: after_sending_reset_password_instructions_path_for(resource_name)) and return
-    end
-
-    self.resource = resource_class.send_reset_password_instructions(resource_params)
-    if successfully_sent?(resource)
-      respond_with({}, location: after_sending_reset_password_instructions_path_for(resource_name))
-    else
-      respond_with(resource)
-    end
-  end
-
-  # After a user resets their password, prompt for 2FA code if enabled instead
-  # of signing in automatically
-  #
-  # See http://git.io/vURrI
-  def update
-    super do |resource|
-      # TODO (rspeicher): In Devise master (> 3.4.1), we can set
-      # `Devise.sign_in_after_reset_password = false` and avoid this mess.
-      if resource.errors.empty? && resource.try(:two_factor_enabled?)
-        resource.unlock_access! if unlockable?(resource)
-
-        # Since we are not signing this user in, we use the :updated_not_active
-        # message which only contains "Your password was changed successfully."
-        set_flash_message(:notice, :updated_not_active) if is_flashing_format?
-
-        # Redirect to sign in so they can enter 2FA code
-        respond_with(resource, location: new_session_path(resource)) and return
-      end
-    end
-  end
+  before_action :resource_from_email, only: [:create]
+  before_action :prevent_ldap_reset,  only: [:create]
+  before_action :throttle_reset,      only: [:create]
 
   def edit
     super
@@ -56,4 +22,25 @@ class PasswordsController < Devise::PasswordsController
       end
     end
   end
+
+  protected
+
+  def resource_from_email
+    email = resource_params[:email]
+    self.resource = resource_class.find_by_email(email)
+  end
+
+  def prevent_ldap_reset
+    return unless resource && resource.ldap_user?
+
+    redirect_to after_sending_reset_password_instructions_path_for(resource_name),
+      alert: "Cannot reset password for LDAP user."
+  end
+
+  def throttle_reset
+    return unless resource && resource.recently_sent_password_reset?
+
+    redirect_to new_password_path(resource_name),
+      alert: I18n.t('devise.passwords.recently_reset')
+  end
 end
diff --git a/app/controllers/profiles/notifications_controller.rb b/app/controllers/profiles/notifications_controller.rb
index 22423651c1747c9928f32999f009fc78f7c0cf1f..1fd1d6882dfee07654367a6ad2272a073e319397 100644
--- a/app/controllers/profiles/notifications_controller.rb
+++ b/app/controllers/profiles/notifications_controller.rb
@@ -29,7 +29,7 @@ class Profiles::NotificationsController < Profiles::ApplicationController
           flash[:alert] = "Failed to save new settings"
         end
 
-        redirect_to :back
+        redirect_back_or_default(default: profile_notifications_path)
       end
 
       format.js
diff --git a/app/controllers/profiles/preferences_controller.rb b/app/controllers/profiles/preferences_controller.rb
index f83b4abd1e2f8753cd4ffd9ccb291505884ed6db..a9a06ecc80801f30d380e69f3e08a0ba7bf18590 100644
--- a/app/controllers/profiles/preferences_controller.rb
+++ b/app/controllers/profiles/preferences_controller.rb
@@ -31,6 +31,7 @@ class Profiles::PreferencesController < Profiles::ApplicationController
   def preferences_params
     params.require(:user).permit(
       :color_scheme_id,
+      :layout,
       :dashboard,
       :project_view,
       :theme_id
diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb
index 26a4de1546266b4f0e6197364c8254f9946fd6bc..8da7b4d50ea669faf70c3027b2a6d8c01cc593b6 100644
--- a/app/controllers/profiles_controller.rb
+++ b/app/controllers/profiles_controller.rb
@@ -26,7 +26,7 @@ class ProfilesController < Profiles::ApplicationController
     end
 
     respond_to do |format|
-      format.html { redirect_to :back }
+      format.html { redirect_back_or_default(default: { action: 'show' }) }
     end
   end
 
diff --git a/app/controllers/projects/application_controller.rb b/app/controllers/projects/application_controller.rb
index 48c922f450c085b820821346d6e2d23d839704a2..519d6d6127e44e596f1d2be05e5871e361eff3df 100644
--- a/app/controllers/projects/application_controller.rb
+++ b/app/controllers/projects/application_controller.rb
@@ -31,4 +31,8 @@ class Projects::ApplicationController < ApplicationController
   def ci_enabled
     return render_404 unless @project.gitlab_ci?
   end
+
+  def ci_project
+    @ci_project ||= @project.ensure_gitlab_ci_project
+  end
 end
diff --git a/app/controllers/projects/avatars_controller.rb b/app/controllers/projects/avatars_controller.rb
index 9c3763d5934e0245cc7e8133b2e136fdd7510fa1..548f1b9ebfec092ac360e8a7860a20b311cae950 100644
--- a/app/controllers/projects/avatars_controller.rb
+++ b/app/controllers/projects/avatars_controller.rb
@@ -12,7 +12,7 @@ class Projects::AvatarsController < Projects::ApplicationController
         filename: @blob.name
       )
     else
-      not_found!
+      render_404
     end
   end
 
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index 8776721d243d7283b26b26728b23c7dd4e78077f..8cc2f21d8871ca974a4e8dce3e73b6d6cd67b920 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -8,7 +8,7 @@ class Projects::BlobController < Projects::ApplicationController
 
   before_action :require_non_empty_project, except: [:new, :create]
   before_action :authorize_download_code!
-  before_action :authorize_push_code!, only: [:destroy]
+  before_action :authorize_push_code!, only: [:destroy, :create]
   before_action :assign_blob_vars
   before_action :commit, except: [:new, :create]
   before_action :blob, except: [:new, :create]
@@ -25,7 +25,7 @@ class Projects::BlobController < Projects::ApplicationController
     result = Files::CreateService.new(@project, current_user, @commit_params).execute
 
     if result[:status] == :success
-      flash[:notice] = "Your changes have been successfully committed"
+      flash[:notice] = "The changes have been successfully committed"
       respond_to do |format|
         format.html { redirect_to namespace_project_blob_path(@project.namespace, @project, File.join(@target_branch, @file_path)) }
         format.json { render json: { message: "success", filePath: namespace_project_blob_path(@project.namespace, @project, File.join(@target_branch, @file_path)) } }
@@ -34,7 +34,7 @@ class Projects::BlobController < Projects::ApplicationController
       flash[:alert] = result[:message]
       respond_to do |format|
         format.html { render :new }
-        format.json { render json: { message: "failed", filePath: namespace_project_new_blob_path(@project.namespace, @project, @id) } }
+        format.json { render json: { message: "failed", filePath: namespace_project_blob_path(@project.namespace, @project, @id) } }
       end
     end
   end
@@ -113,14 +113,14 @@ class Projects::BlobController < Projects::ApplicationController
         end
       end
 
-      return not_found!
+      return render_404
     end
   end
 
   def commit
     @commit = @repository.commit(@ref)
 
-    return not_found! unless @commit
+    return render_404 unless @commit
   end
 
   def assign_blob_vars
@@ -128,7 +128,7 @@ class Projects::BlobController < Projects::ApplicationController
     @ref, @path = extract_ref(@id)
 
   rescue InvalidPathError
-    not_found!
+    render_404
   end
 
   def after_edit_path
@@ -154,7 +154,7 @@ class Projects::BlobController < Projects::ApplicationController
 
   def editor_variables
     @current_branch = @ref
-    @target_branch = (sanitized_new_branch_name || @ref)
+    @target_branch = params[:new_branch].present? ? sanitized_new_branch_name : @ref
 
     @file_path =
       if action_name.to_s == 'create'
diff --git a/app/controllers/projects/builds_controller.rb b/app/controllers/projects/builds_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..816012762ce9021c45687551792a77dc23457a21
--- /dev/null
+++ b/app/controllers/projects/builds_controller.rb
@@ -0,0 +1,76 @@
+class Projects::BuildsController < Projects::ApplicationController
+  before_action :ci_project
+  before_action :build, except: [:index, :cancel_all]
+
+  before_action :authorize_admin_project!, except: [:index, :show, :status]
+
+  layout "project"
+
+  def index
+    @scope = params[:scope]
+    @all_builds = project.ci_builds
+    @builds =
+      case @scope
+      when 'all'
+        @all_builds
+      when 'finished'
+        @all_builds.finished
+      else
+        @all_builds.running_or_pending
+      end
+    @builds = @builds.order('created_at DESC').page(params[:page]).per(30)
+  end
+
+  def cancel_all
+    @project.ci_builds.running_or_pending.each(&:cancel)
+
+    redirect_to namespace_project_builds_path(project.namespace, project)
+  end
+
+  def show
+    @builds = @ci_project.commits.find_by_sha(@build.sha).builds.order('id DESC')
+    @builds = @builds.where("id not in (?)", @build.id).page(params[:page]).per(20)
+    @commit = @build.commit
+
+    respond_to do |format|
+      format.html
+      format.json do
+        render json: @build.to_json(methods: :trace_html)
+      end
+    end
+  end
+
+  def retry
+    if @build.commands.blank?
+      return page_404
+    end
+
+    build = Ci::Build.retry(@build)
+
+    if params[:return_to]
+      redirect_to URI.parse(params[:return_to]).path
+    else
+      redirect_to build_path(build)
+    end
+  end
+
+  def status
+    render json: @build.to_json(only: [:status, :id, :sha, :coverage], methods: :sha)
+  end
+
+  def cancel
+    @build.cancel
+
+    redirect_to build_path(@build)
+  end
+
+  private
+
+  def build
+    @build ||= ci_project.builds.unscoped.find_by!(id: params[:id])
+  end
+
+  def build_path(build)
+    namespace_project_build_path(build.gl_project.namespace, build.gl_project, build)
+  end
+end
diff --git a/app/controllers/projects/ci_services_controller.rb b/app/controllers/projects/ci_services_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..550a019e8e29037f28a95a75a43585d674e81266
--- /dev/null
+++ b/app/controllers/projects/ci_services_controller.rb
@@ -0,0 +1,49 @@
+class Projects::CiServicesController < Projects::ApplicationController
+  before_action :ci_project
+  before_action :authorize_admin_project!
+
+  layout "project_settings"
+
+  def index
+    @ci_project.build_missing_services
+    @services = @ci_project.services.reload
+  end
+
+  def edit
+    service
+  end
+
+  def update
+    if service.update_attributes(service_params)
+      redirect_to edit_namespace_project_ci_service_path(@project.namespace, @project, service.to_param)
+    else
+      render 'edit'
+    end
+  end
+
+  def test
+    last_build = @project.ci_builds.last
+
+    if service.execute(last_build)
+      message = { notice: 'We successfully tested the service' }
+    else
+      message = { alert: 'We tried to test the service but error occurred' }
+    end
+
+    redirect_back_or_default(options: message)
+  end
+
+  private
+
+  def service
+    @service ||= @ci_project.services.find { |service| service.to_param == params[:id] }
+  end
+
+  def service_params
+    params.require(:service).permit(
+      :type, :active, :webhook, :notify_only_broken_builds,
+      :email_recipients, :email_only_broken_builds, :email_add_pusher,
+      :hipchat_token, :hipchat_room, :hipchat_server
+    )
+  end
+end
diff --git a/app/controllers/projects/ci_settings_controller.rb b/app/controllers/projects/ci_settings_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..a263242a8507daecbcb86932d75b101a48fe2a9c
--- /dev/null
+++ b/app/controllers/projects/ci_settings_controller.rb
@@ -0,0 +1,36 @@
+class Projects::CiSettingsController < Projects::ApplicationController
+  before_action :ci_project
+  before_action :authorize_admin_project!
+
+  layout "project_settings"
+
+  def edit
+  end
+
+  def update
+    if ci_project.update_attributes(project_params)
+      Ci::EventService.new.change_project_settings(current_user, ci_project)
+
+      redirect_to edit_namespace_project_ci_settings_path(project.namespace, project), notice: 'Project was successfully updated.'
+    else
+      render action: "edit"
+    end
+  end
+
+  def destroy
+    ci_project.destroy
+    Ci::EventService.new.remove_project(current_user, ci_project)
+    project.gitlab_ci_service.update_attributes(active: false)
+
+    redirect_to project_path(project), notice: "CI was disabled for this project"
+  end
+
+  protected
+
+  def project_params
+    params.require(:project).permit(:path, :timeout, :timeout_in_minutes, :default_ref, :always_build,
+                                    :polling_interval, :public, :ssh_url_to_repo, :allow_git_fetch, :email_recipients,
+                                    :email_add_pusher, :email_only_broken_builds, :coverage_regex, :shared_runners_enabled, :token,
+                                    { variables_attributes: [:id, :key, :value, :_destroy] })
+  end
+end
diff --git a/app/controllers/projects/ci_web_hooks_controller.rb b/app/controllers/projects/ci_web_hooks_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..a2d470d4a6964143202f620acbf49d8bdb740f52
--- /dev/null
+++ b/app/controllers/projects/ci_web_hooks_controller.rb
@@ -0,0 +1,45 @@
+class Projects::CiWebHooksController < Projects::ApplicationController
+  before_action :ci_project
+  before_action :authorize_admin_project!
+
+  layout "project_settings"
+
+  def index
+    @web_hooks = @ci_project.web_hooks
+    @web_hook = Ci::WebHook.new
+  end
+
+  def create
+    @web_hook = @ci_project.web_hooks.new(web_hook_params)
+    @web_hook.save
+
+    if @web_hook.valid?
+      redirect_to namespace_project_ci_web_hooks_path(@project.namespace, @project)
+    else
+      @web_hooks = @ci_project.web_hooks.select(&:persisted?)
+      render :index
+    end
+  end
+
+  def test
+    Ci::TestHookService.new.execute(hook, current_user)
+
+    redirect_back_or_default(default: { action: 'index' })
+  end
+
+  def destroy
+    hook.destroy
+
+    redirect_to namespace_project_ci_web_hooks_path(@project.namespace, @project)
+  end
+
+  private
+
+  def hook
+    @web_hook ||= @ci_project.web_hooks.find(params[:id])
+  end
+
+  def web_hook_params
+    params.require(:web_hook).permit(:url)
+  end
+end
diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb
index 2fae5057138084f1213497fa262fe71d35db56fa..7886f3c6deb20545a6231c026eb9bbffa64dff5c 100644
--- a/app/controllers/projects/commit_controller.rb
+++ b/app/controllers/projects/commit_controller.rb
@@ -31,6 +31,21 @@ class Projects::CommitController < Projects::ApplicationController
     end
   end
 
+  def ci
+    @ci_commit = @project.ci_commit(@commit.sha)
+    @builds = @ci_commit.builds if @ci_commit
+    @notes_count = @commit.notes.count
+    @ci_project = @project.gitlab_ci_project
+  end
+
+  def cancel_builds
+    @ci_commit = @project.ci_commit(@commit.sha)
+    @ci_commit.builds.running_or_pending.each(&:cancel)
+
+    redirect_to ci_namespace_project_commit_path(project.namespace, project, commit.sha)
+  end
+
+
   def branches
     @branches = @project.repository.branch_names_contains(commit.id)
     @tags = @project.repository.tag_names_contains(commit.id)
diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb
index d15004f93a613ff50a732433278343fa77fd765a..71aaad1fad61d565a67250afd6b55f1ad17bd900 100644
--- a/app/controllers/projects/compare_controller.rb
+++ b/app/controllers/projects/compare_controller.rb
@@ -17,9 +17,10 @@ class Projects::CompareController < Projects::ApplicationController
       execute(@project, head_ref, @project, base_ref)
 
     if compare_result
-      @commits = compare_result.commits
+      @commits = Commit.decorate(compare_result.commits, @project)
       @diffs = compare_result.diffs
       @commit = @commits.last
+      @first_commit = @commits.first
       @line_notes = []
     end
   end
diff --git a/app/controllers/projects/deploy_keys_controller.rb b/app/controllers/projects/deploy_keys_controller.rb
index 40e2b37912bb4dd181cf858e5507f3cb8950dc01..7d09288bc8060a9045472167bc163b6409d5acd4 100644
--- a/app/controllers/projects/deploy_keys_controller.rb
+++ b/app/controllers/projects/deploy_keys_controller.rb
@@ -46,7 +46,7 @@ class Projects::DeployKeysController < Projects::ApplicationController
   def disable
     @project.deploy_keys_projects.find_by(deploy_key_id: params[:id]).destroy
 
-    redirect_to :back
+    redirect_back_or_default(default: { action: 'index' })
   end
 
   protected
diff --git a/app/controllers/projects/hooks_controller.rb b/app/controllers/projects/hooks_controller.rb
index 4e5b4125f5a9cbaa654066ad9e1ae745c7cfeb2e..c7569541899602a7695188b326fd57df9256e102 100644
--- a/app/controllers/projects/hooks_controller.rb
+++ b/app/controllers/projects/hooks_controller.rb
@@ -37,7 +37,7 @@ class Projects::HooksController < Projects::ApplicationController
       flash[:alert] = 'Hook execution failed. Ensure the project has commits.'
     end
 
-    redirect_to :back
+    redirect_back_or_default(default: { action: 'index' })
   end
 
   def destroy
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index 0f89f2e88ccce26ab6b5c225ad0b269993eb82f8..e767efbdc0cfd168c51670ac5b1b6fcad6b7feac 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -14,6 +14,9 @@ class Projects::IssuesController < Projects::ApplicationController
   # Allow issues bulk update
   before_action :authorize_admin_issues!, only: [:bulk_update]
 
+  # Cross-reference merge requests
+  before_action :closed_by_merge_requests, only: [:show]
+
   respond_to :html
 
   def index
@@ -55,9 +58,9 @@ class Projects::IssuesController < Projects::ApplicationController
   end
 
   def show
-    @participants = @issue.participants(current_user, @project)
+    @participants = @issue.participants(current_user)
     @note = @project.notes.new(noteable: @issue)
-    @notes = @issue.notes.inc_author.fresh
+    @notes = @issue.notes.with_associations.fresh
     @noteable = @issue
 
     respond_with(@issue)
@@ -103,7 +106,7 @@ class Projects::IssuesController < Projects::ApplicationController
 
   def bulk_update
     result = Issues::BulkUpdateService.new(project, current_user, bulk_update_params).execute
-    redirect_to :back, notice: "#{result[:count]} issues updated"
+    redirect_back_or_default(default: { action: 'index' }, options: { notice: "#{result[:count]} issues updated" })
   end
 
   def toggle_subscription
@@ -112,6 +115,10 @@ class Projects::IssuesController < Projects::ApplicationController
     render nothing: true
   end
 
+  def closed_by_merge_requests
+    @closed_by_merge_requests ||= @issue.closed_by_merge_requests(current_user)
+  end
+
   protected
 
   def issue
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 7574842cd432d0782e748bf27b8d572de8099b89..16c42386623347e43ec941e93b1ca138b6c7fa0d 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -56,6 +56,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
 
   def diffs
     @commit = @merge_request.last_commit
+    @first_commit = @merge_request.first_commit
+
     @comments_allowed = @reply_allowed = true
     @comments_target = {
       noteable_type: 'MergeRequest',
@@ -89,7 +91,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
     @target_project = merge_request.target_project
     @source_project = merge_request.source_project
     @commits = @merge_request.compare_commits
-    @commit = @merge_request.compare_commits.last
+    @commit = @merge_request.last_commit
+    @first_commit = @merge_request.first_commit
     @diffs = @merge_request.compare_diffs
     @note_counts = Note.where(commit_id: @commits.map(&:id)).
       group(:commit_id).count
@@ -150,6 +153,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
     return access_denied! unless @merge_request.can_be_merged_by?(current_user)
 
     if @merge_request.mergeable?
+      @merge_request.update(merge_error: nil)
       MergeWorker.perform_async(@merge_request.id, current_user.id, params)
       @status = true
     else
@@ -245,7 +249,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
   end
 
   def define_show_vars
-    @participants = @merge_request.participants(current_user, @project)
+    @participants = @merge_request.participants(current_user)
 
     # Build a note object for comment form
     @note = @project.notes.new(noteable: @merge_request)
@@ -258,7 +262,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
     @commits = @merge_request.commits
 
     @merge_request_diff = @merge_request.merge_request_diff
-    
+
     if @merge_request.locked_long_ago?
       @merge_request.unlock_mr
       @merge_request.close
diff --git a/app/controllers/projects/milestones_controller.rb b/app/controllers/projects/milestones_controller.rb
index 86f4a02a6e99ddf98c57ab95be9c02e6d84f53dc..15506bd677ad0200c73cad9127bfdf0b2015ad75 100644
--- a/app/controllers/projects/milestones_controller.rb
+++ b/app/controllers/projects/milestones_controller.rb
@@ -75,11 +75,7 @@ class Projects::MilestonesController < Projects::ApplicationController
   end
 
   def sort_issues
-    @issues = @milestone.issues.where(id: params['sortable_issue'])
-    @issues.each do |issue|
-      issue.position = params['sortable_issue'].index(issue.id.to_s) + 1
-      issue.save
-    end
+    @milestone.sort_issues(params['sortable_issue'].map(&:to_i))
 
     render json: { saved: true }
   end
diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb
index 0f5d82ce133828bfae5b4b6054f3491be41accc0..41cd08c93c60bfed5fa7ac6f0e14c85055f86162 100644
--- a/app/controllers/projects/notes_controller.rb
+++ b/app/controllers/projects/notes_controller.rb
@@ -25,7 +25,7 @@ class Projects::NotesController < Projects::ApplicationController
 
     respond_to do |format|
       format.json { render_note_json(@note) }
-      format.html { redirect_to :back }
+      format.html { redirect_back_or_default }
     end
   end
 
@@ -34,7 +34,7 @@ class Projects::NotesController < Projects::ApplicationController
 
     respond_to do |format|
       format.json { render_note_json(@note) }
-      format.html { redirect_to :back }
+      format.html { redirect_back_or_default }
     end
   end
 
diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb
index cf73bc01c8fb56fd5e074461297712b278196f3c..9de5269cd2520abaea1b308e694dfd3999754f9d 100644
--- a/app/controllers/projects/project_members_controller.rb
+++ b/app/controllers/projects/project_members_controller.rb
@@ -72,7 +72,8 @@ class Projects::ProjectMembersController < Projects::ApplicationController
 
   def leave
     if @project.namespace == current_user.namespace
-      return redirect_to(:back, alert: 'You can not leave your own project. Transfer or delete the project.')
+      message = 'You can not leave your own project. Transfer or delete the project.'
+      return redirect_back_or_default(default: { action: 'index' }, options: { alert: message })
     end
 
     @project.project_members.find_by(user_id: current_user).destroy
diff --git a/app/controllers/projects/raw_controller.rb b/app/controllers/projects/raw_controller.rb
index 5f6fbce795e950d3792d80be348e1ff724779813..d5ee6ac8663b24aadaa88818becf516764454741 100644
--- a/app/controllers/projects/raw_controller.rb
+++ b/app/controllers/projects/raw_controller.rb
@@ -20,7 +20,7 @@ class Projects::RawController < Projects::ApplicationController
         disposition: 'inline'
       )
     else
-      not_found!
+      render_404
     end
   end
 
diff --git a/app/controllers/projects/refs_controller.rb b/app/controllers/projects/refs_controller.rb
index 6080c849c8d30b42a8ca0392d8fa65a9626e2438..c4e18c170777c5f01a8ad846723ebcac45c01ca7 100644
--- a/app/controllers/projects/refs_controller.rb
+++ b/app/controllers/projects/refs_controller.rb
@@ -3,6 +3,7 @@ class Projects::RefsController < Projects::ApplicationController
   include TreeHelper
 
   before_action :require_non_empty_project
+  before_action :validate_ref_id
   before_action :assign_ref_vars
   before_action :authorize_download_code!
 
@@ -71,4 +72,10 @@ class Projects::RefsController < Projects::ApplicationController
       format.js
     end
   end
+
+  private
+
+  def validate_ref_id
+    return not_found! if params[:id].present? && params[:id] !~ Gitlab::Regex.git_reference_regex
+  end
 end
diff --git a/app/controllers/projects/repositories_controller.rb b/app/controllers/projects/repositories_controller.rb
index c4a5e2d63598f624c6a7990cb64913cd65cc769e..ba9aea1c165335c4f1bb898409794e64963500bf 100644
--- a/app/controllers/projects/repositories_controller.rb
+++ b/app/controllers/projects/repositories_controller.rb
@@ -11,18 +11,9 @@ class Projects::RepositoriesController < Projects::ApplicationController
   end
 
   def archive
-    begin
-      file_path = ArchiveRepositoryService.new(@project, params[:ref], params[:format]).execute
-    rescue
-      return head :not_found
-    end
-
-    if file_path
-      # Send file to user
-      response.headers["Content-Length"] = File.open(file_path).size.to_s
-      send_file file_path
-    else
-      redirect_to request.fullpath
-    end
+    render json: ArchiveRepositoryService.new(@project, params[:ref], params[:format]).execute
+  rescue => ex
+    logger.error("#{self.class.name}: #{ex}")
+    return git_not_found!
   end
 end
diff --git a/app/controllers/projects/runners_controller.rb b/app/controllers/projects/runners_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..deb07a214160f396092597b6ae1127c2b4d0ed07
--- /dev/null
+++ b/app/controllers/projects/runners_controller.rb
@@ -0,0 +1,65 @@
+class Projects::RunnersController < Projects::ApplicationController
+  before_action :ci_project
+  before_action :set_runner, only: [:edit, :update, :destroy, :pause, :resume, :show]
+  before_action :authorize_admin_project!
+
+  layout 'project_settings'
+
+  def index
+    @runners = @ci_project.runners.order('id DESC')
+    @specific_runners =
+      Ci::Runner.specific.includes(:runner_projects).
+      where(Ci::RunnerProject.table_name => { project_id: current_user.authorized_projects } ).
+      where.not(id: @runners).order("#{Ci::Runner.table_name}.id DESC").page(params[:page]).per(20)
+    @shared_runners = Ci::Runner.shared.active
+    @shared_runners_count = @shared_runners.count(:all)
+  end
+
+  def edit
+  end
+
+  def update
+    if @runner.update_attributes(runner_params)
+      redirect_to runner_path(@runner), notice: 'Runner was successfully updated.'
+    else
+      redirect_to runner_path(@runner), alert: 'Runner was not updated.'
+    end
+  end
+
+  def destroy
+    if @runner.only_for?(@ci_project)
+      @runner.destroy
+    end
+
+    redirect_to runners_path(@project)
+  end
+
+  def resume
+    if @runner.update_attributes(active: true)
+      redirect_to runner_path(@runner), notice: 'Runner was successfully updated.'
+    else
+      redirect_to runner_path(@runner), alert: 'Runner was not updated.'
+    end
+  end
+
+  def pause
+    if @runner.update_attributes(active: false)
+      redirect_to runner_path(@runner), notice: 'Runner was successfully updated.'
+    else
+      redirect_to runner_path(@runner), alert: 'Runner was not updated.'
+    end
+  end
+
+  def show
+  end
+
+  protected
+
+  def set_runner
+    @runner ||= @ci_project.runners.find(params[:id])
+  end
+
+  def runner_params
+    params.require(:runner).permit(:description, :tag_list, :active)
+  end
+end
diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb
index 3a22ed832ac4fb19bdc5b0913b95f87c3eaf6944..42dbb497e013ace446d1b38e76c37c9e84b35124 100644
--- a/app/controllers/projects/services_controller.rb
+++ b/app/controllers/projects/services_controller.rb
@@ -9,6 +9,10 @@ class Projects::ServicesController < Projects::ApplicationController
                     :note_events, :send_from_committer_email, :disable_diffs, :external_wiki_url,
                     :notify, :color,
                     :server_host, :server_port, :default_irc_uri, :enable_ssl_verification]
+
+  # Parameters to ignore if no value is specified
+  FILTER_BLANK_PARAMS = [:password]
+
   # Authorize
   before_action :authorize_admin_project!
   before_action :service, only: [:edit, :update, :test]
@@ -48,7 +52,7 @@ class Projects::ServicesController < Projects::ApplicationController
       message = { alert: error_message }
     end
 
-    redirect_to :back, message
+    redirect_back_or_default(options: message)
   end
 
   private
@@ -58,6 +62,10 @@ class Projects::ServicesController < Projects::ApplicationController
   end
 
   def service_params
-    params.require(:service).permit(ALLOWED_PARAMS)
+    service_params = params.require(:service).permit(ALLOWED_PARAMS)
+    FILTER_BLANK_PARAMS.each do |param|
+      service_params.delete(param) if service_params[param].blank?
+    end
+    service_params
   end
 end
diff --git a/app/controllers/projects/snippets_controller.rb b/app/controllers/projects/snippets_controller.rb
index b07a2a8db2f7d121a5f8ad50a1c8d1433725d5f3..2104c7a7a718f7f70b07660407b8e7c7865ed7cc 100644
--- a/app/controllers/projects/snippets_controller.rb
+++ b/app/controllers/projects/snippets_controller.rb
@@ -21,6 +21,7 @@ class Projects::SnippetsController < Projects::ApplicationController
       filter: :by_project,
       project: @project
     })
+    @snippets = @snippets.page(params[:page]).per(PER_PAGE)
   end
 
   def new
diff --git a/app/controllers/projects/tree_controller.rb b/app/controllers/projects/tree_controller.rb
index 92e4bc16d9d772e91b33bd76a57e2c854be2e5af..bdcb1a3e297ee178eb58f15157f06f61db037d81 100644
--- a/app/controllers/projects/tree_controller.rb
+++ b/app/controllers/projects/tree_controller.rb
@@ -1,13 +1,16 @@
 # Controller for viewing a repository's file structure
 class Projects::TreeController < Projects::ApplicationController
   include ExtractsPath
+  include ActionView::Helpers::SanitizeHelper
 
   before_action :require_non_empty_project, except: [:new, :create]
   before_action :assign_ref_vars
+  before_action :assign_dir_vars, only: [:create_dir]
   before_action :authorize_download_code!
+  before_action :authorize_push_code!, only: [:create_dir]
 
   def show
-    return not_found! unless @repository.commit(@ref)
+    return render_404 unless @repository.commit(@ref)
 
     if tree.entries.empty?
       if @repository.blob_at(@commit.id, @path)
@@ -16,7 +19,7 @@ class Projects::TreeController < Projects::ApplicationController
                                       File.join(@ref, @path))
         ) and return
       elsif @path.present?
-        return not_found!
+        return render_404
       end
     end
 
@@ -26,4 +29,38 @@ class Projects::TreeController < Projects::ApplicationController
       format.js { no_cache_headers }
     end
   end
+
+  def create_dir
+    return render_404 unless @commit_params.values.all?
+
+    begin
+      result = Files::CreateDirService.new(@project, current_user, @commit_params).execute
+      message = result[:message]
+    rescue => e
+      message = e.to_s
+    end
+
+    if result && result[:status] == :success
+      flash[:notice] = "The directory has been successfully created"
+      respond_to do |format|
+        format.html { redirect_to namespace_project_blob_path(@project.namespace, @project, File.join(@new_branch, @dir_name)) }
+      end
+    else
+      flash[:alert] = message
+      respond_to do |format|
+        format.html { redirect_to namespace_project_blob_path(@project.namespace, @project, @new_branch) }
+      end
+    end
+  end
+
+  def assign_dir_vars
+    @new_branch = params[:new_branch].present? ? sanitize(strip_tags(params[:new_branch])) : @ref
+    @dir_name = File.join(@path, params[:dir_name])
+    @commit_params = {
+      file_path: @dir_name,
+      current_branch: @ref,
+      target_branch: @new_branch,
+      commit_message: params[:commit_message],
+    }
+  end
 end
diff --git a/app/controllers/projects/triggers_controller.rb b/app/controllers/projects/triggers_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..782ebd01b055dc7298ee3fb6a0ddcee81a801529
--- /dev/null
+++ b/app/controllers/projects/triggers_controller.rb
@@ -0,0 +1,35 @@
+class Projects::TriggersController < Projects::ApplicationController
+  before_action :ci_project
+  before_action :authorize_admin_project!
+
+  layout 'project_settings'
+
+  def index
+    @triggers = @ci_project.triggers
+    @trigger = Ci::Trigger.new
+  end
+
+  def create
+    @trigger = @ci_project.triggers.new
+    @trigger.save
+
+    if @trigger.valid?
+      redirect_to namespace_project_triggers_path(@project.namespace, @project)
+    else
+      @triggers = @ci_project.triggers.select(&:persisted?)
+      render :index
+    end
+  end
+
+  def destroy
+    trigger.destroy
+
+    redirect_to namespace_project_triggers_path(@project.namespace, @project)
+  end
+
+  private
+
+  def trigger
+    @trigger ||= @ci_project.triggers.find(params[:id])
+  end
+end
diff --git a/app/controllers/projects/uploads_controller.rb b/app/controllers/projects/uploads_controller.rb
index 71ecc20dd95ea7fe681e5b9ed5ef378974eeb8e6..e1fe7ea21143fcc6d3131cff79026d9f6f2ebafb 100644
--- a/app/controllers/projects/uploads_controller.rb
+++ b/app/controllers/projects/uploads_controller.rb
@@ -20,7 +20,7 @@ class Projects::UploadsController < Projects::ApplicationController
   end
 
   def show
-    return not_found! if uploader.nil? || !uploader.file.exists?
+    return render_404 if uploader.nil? || !uploader.file.exists?
 
     disposition = uploader.image? ? 'inline' : 'attachment'
     send_file uploader.file.path, disposition: disposition
diff --git a/app/controllers/projects/variables_controller.rb b/app/controllers/projects/variables_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..d6561a45a701f52fb616869f0ce0bd92cc256061
--- /dev/null
+++ b/app/controllers/projects/variables_controller.rb
@@ -0,0 +1,25 @@
+class Projects::VariablesController < Projects::ApplicationController
+  before_action :ci_project
+  before_action :authorize_admin_project!
+
+  layout 'project_settings'
+
+  def show
+  end
+
+  def update
+    if ci_project.update_attributes(project_params)
+      Ci::EventService.new.change_project_settings(current_user, ci_project)
+
+      redirect_to namespace_project_variables_path(project.namespace, project), notice: 'Variables were successfully updated.'
+    else
+      render action: 'show'
+    end
+  end
+
+  private
+
+  def project_params
+    params.require(:project).permit({ variables_attributes: [:id, :key, :value, :_destroy] })
+  end
+end
diff --git a/app/controllers/projects/wikis_controller.rb b/app/controllers/projects/wikis_controller.rb
index 51c26a6a4659682528508a6531886cfc127e0331..88fccfed5099e837b026783e8ff1ee25f5fb74c0 100644
--- a/app/controllers/projects/wikis_controller.rb
+++ b/app/controllers/projects/wikis_controller.rb
@@ -98,7 +98,7 @@ class Projects::WikisController < Projects::ApplicationController
 
     # Call #wiki to make sure the Wiki Repo is initialized
     @project_wiki.wiki
-  rescue ProjectWiki::CouldNotCreateWikiError => ex
+  rescue ProjectWiki::CouldNotCreateWikiError
     flash[:notice] = "Could not create Wiki Repository at this time. Please try again later."
     redirect_to project_path(@project)
     return false
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 213c2a7173b4517c1080ed80a0e3e632c4133b10..82119022cf9b249feefb39c04045bd3fa8c30865 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -1,11 +1,14 @@
 class ProjectsController < ApplicationController
+  include ExtractsPath
+
   prepend_before_filter :render_go_import, only: [:show]
   skip_before_action :authenticate_user!, only: [:show, :activity]
   before_action :project, except: [:new, :create]
   before_action :repository, except: [:new, :create]
+  before_action :assign_ref_vars, :tree, only: [:show], if: :repo_exists?
 
   # Authorize
-  before_action :authorize_admin_project!, only: [:edit, :update, :destroy, :transfer, :archive, :unarchive]
+  before_action :authorize_admin_project!, only: [:edit, :update]
   before_action :event_filter, only: [:show, :activity]
 
   layout :determine_layout
@@ -56,6 +59,8 @@ class ProjectsController < ApplicationController
   end
 
   def transfer
+    return access_denied! unless can?(current_user, :change_namespace, @project)
+
     namespace = Namespace.find_by(id: params[:new_namespace_id])
     ::Projects::TransferService.new(project, current_user).execute(namespace)
 
@@ -64,6 +69,15 @@ class ProjectsController < ApplicationController
     end
   end
 
+  def remove_fork
+    return access_denied! unless can?(current_user, :remove_fork_project, @project)
+
+    if @project.forked?
+      @project.forked_project_link.destroy
+      flash[:notice] = 'The fork relationship has been removed.'
+    end
+  end
+
   def activity
     respond_to do |format|
       format.html
@@ -87,7 +101,7 @@ class ProjectsController < ApplicationController
             render 'projects/empty'
           else
             if current_user
-              @membership = @project.project_member_by_id(current_user.id)
+              @membership = @project.team.find_member(current_user.id)
             end
 
             render :show
@@ -139,6 +153,7 @@ class ProjectsController < ApplicationController
 
   def archive
     return access_denied! unless can?(current_user, :archive_project, @project)
+
     @project.archive!
 
     respond_to do |format|
@@ -148,6 +163,7 @@ class ProjectsController < ApplicationController
 
   def unarchive
     return access_denied! unless can?(current_user, :archive_project, @project)
+
     @project.unarchive!
 
     respond_to do |format|
@@ -225,4 +241,14 @@ class ProjectsController < ApplicationController
 
     render "go_import", layout: false
   end
+
+  def repo_exists?
+    project.repository_exists? && !project.empty_repo?
+  end
+
+  # Override get_id from ExtractsPath, which returns the branch and file path 
+  # for the blob/tree, which in this case is just the root of the default branch.
+  def get_id
+    project.repository.root_ref
+  end
 end
diff --git a/app/controllers/root_controller.rb b/app/controllers/root_controller.rb
index 54171ff67c5e4d4b02748f482059ac55ff773372..ad04c646e1b031fe77083f3e725befdc1b536aff 100644
--- a/app/controllers/root_controller.rb
+++ b/app/controllers/root_controller.rb
@@ -22,6 +22,10 @@ class RootController < Dashboard::ProjectsController
     when 'stars'
       flash.keep
       redirect_to starred_dashboard_projects_path
+    when 'project_activity'
+      redirect_to activity_dashboard_path
+    when 'starred_project_activity'
+      redirect_to activity_dashboard_path(filter: 'starred')
     else
       return
     end
diff --git a/app/controllers/uploads_controller.rb b/app/controllers/uploads_controller.rb
index 28536e359e51c538e3bbfc8fe2bedef816eb7a73..868b05929d7404461438e8d321bb3115f3ee7400 100644
--- a/app/controllers/uploads_controller.rb
+++ b/app/controllers/uploads_controller.rb
@@ -10,7 +10,7 @@ class UploadsController < ApplicationController
     end
 
     unless uploader.file && uploader.file.exists?
-      return not_found!
+      return render_404
     end
 
     disposition = uploader.image? ? 'inline' : 'attachment'
@@ -21,7 +21,7 @@ class UploadsController < ApplicationController
 
   def find_model
     unless upload_model && upload_mount
-      return not_found!
+      return render_404
     end
 
     @model = upload_model.find(params[:id])
@@ -44,7 +44,7 @@ class UploadsController < ApplicationController
     return if authorized
 
     if current_user
-      not_found!
+      render_404
     else
       authenticate_user!
     end
diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index ab89aa2c53a5ef5b294ec23ef06e9a614f6de16e..c407dfc163a9bdd1ed50c98b033b44ba65106c4c 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -39,7 +39,7 @@ class IssuableFinder
     items = by_assignee(items)
     items = by_author(items)
     items = by_label(items)
-    items = sort(items)
+    sort(items)
   end
 
   def group
@@ -53,15 +53,36 @@ class IssuableFinder
       end
   end
 
+  def project?
+    params[:project_id].present?
+  end
+
   def project
     return @project if defined?(@project)
 
-    @project =
-      if params[:project_id].present?
-        Project.find(params[:project_id])
-      else
-        nil
-      end
+    if project?
+      @project = Project.find(params[:project_id])
+      
+      unless Ability.abilities.allowed?(current_user, :read_project, @project)
+        @project = nil
+      end 
+    else
+      @project = nil
+    end
+
+    @project
+  end
+
+  def projects
+    return @projects if defined?(@projects)
+
+    if project?
+      project
+    elsif current_user && params[:authorized_only].presence && !current_user_related?
+      current_user.authorized_projects
+    else
+      ProjectsFinder.new.execute(current_user)
+    end
   end
 
   def search
@@ -72,17 +93,31 @@ class IssuableFinder
     params[:milestone_title].present?
   end
 
+  def filter_by_no_milestone?
+    milestones? && params[:milestone_title] == Milestone::None.title
+  end
+
   def milestones
     return @milestones if defined?(@milestones)
 
     @milestones =
-      if milestones? && params[:milestone_title] != Milestone::None.title
-        Milestone.where(title: params[:milestone_title])
+      if milestones?
+        scope = Milestone.where(project_id: projects)
+
+        scope.where(title: params[:milestone_title])
       else
         nil
       end
   end
 
+  def labels?
+    params[:label_name].present?
+  end
+
+  def filter_by_no_label?
+    labels? && params[:label_name] == Label::None.title
+  end
+
   def assignee?
     params[:assignee_id].present?
   end
@@ -116,19 +151,7 @@ class IssuableFinder
   private
 
   def init_collection
-    table_name = klass.table_name
-
-    if project
-      if Ability.abilities.allowed?(current_user, :read_project, project)
-        project.send(table_name)
-      else
-        []
-      end
-    elsif current_user && params[:authorized_only].presence && !current_user_related?
-      klass.of_projects(current_user.authorized_projects).references(:project)
-    else
-      klass.of_projects(ProjectsFinder.new.execute(current_user)).references(:project)
-    end
+    klass.all
   end
 
   def by_scope(items)
@@ -166,7 +189,12 @@ class IssuableFinder
   end
 
   def by_project(items)
-    items = items.of_projects(project.id) if project
+    items =
+      if projects
+        items.of_projects(projects).references(:project)
+      else
+        items.none
+      end
 
     items
   end
@@ -181,14 +209,6 @@ class IssuableFinder
     items.sort(params[:sort])
   end
 
-  def by_milestone(items)
-    if milestones?
-      items = items.where(milestone_id: milestones.try(:pluck, :id))
-    end
-
-    items
-  end
-
   def by_assignee(items)
     if assignee?
       items = items.where(assignee_id: assignee.try(:id))
@@ -205,15 +225,37 @@ class IssuableFinder
     items
   end
 
+  def by_milestone(items)
+    if milestones?
+      if filter_by_no_milestone?
+        items = items.where(milestone_id: [-1, nil])
+      else
+        items = items.joins(:milestone).where(milestones: { title: params[:milestone_title] })
+
+        if projects
+          items = items.where(milestones: { project_id: projects })
+        end
+      end
+    end
+
+    items
+  end
+
   def by_label(items)
-    if params[:label_name].present?
-      label_names = params[:label_name].split(",")
+    if labels?
+      if filter_by_no_label?
+        items = items.
+          joins("LEFT OUTER JOIN label_links ON label_links.target_type = '#{klass.name}' AND label_links.target_id = #{klass.table_name}.id").
+          where(label_links: { id: nil })
+      else
+        label_names = params[:label_name].split(",")
 
-      item_ids = LabelLink.joins(:label).
-        where('labels.title in (?)', label_names).
-        where(target_type: klass.name).pluck(:target_id)
+        items = items.joins(:labels).where(labels: { title: label_names })
 
-      items = items.where(id: item_ids)
+        if projects
+          items = items.where(labels: { project_id: projects })
+        end
+      end
     end
 
     items
diff --git a/app/finders/trending_projects_finder.rb b/app/finders/trending_projects_finder.rb
index 9ea342cb26dc14ce97330ec911d9b975d8854c55..81a12403801a4447a528228d5d204dc109a904b3 100644
--- a/app/finders/trending_projects_finder.rb
+++ b/app/finders/trending_projects_finder.rb
@@ -1,13 +1,6 @@
 class TrendingProjectsFinder
-  def execute(current_user, start_date = nil)
-    start_date ||= Date.today - 1.month
-
-    projects = projects_for(current_user)
-
-    # Determine trending projects based on comments count
-    # for period of time - ex. month
-    projects.joins(:notes).where('notes.created_at > ?', start_date).
-      group("projects.id").reorder("count(notes.id) DESC")
+  def execute(current_user, start_date = 1.month.ago)
+    projects_for(current_user).trending(start_date)
   end
 
   private
diff --git a/app/helpers/appearances_helper.rb b/app/helpers/appearances_helper.rb
index 14df8d4cbd7323dfe54997e0490be24aa0ace65d..c5820bf4c5026137f02662b8982f5b30934d7e08 100644
--- a/app/helpers/appearances_helper.rb
+++ b/app/helpers/appearances_helper.rb
@@ -16,6 +16,6 @@ module AppearancesHelper
   end
 
   def brand_header_logo
-    image_tag 'logo.svg'
+    render 'shared/logo.svg'
   end
 end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 056ffd278f6f11cc29375b426aa4aba708f187a2..596a47938d69302a42d9b29a19d03a54107150a8 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -35,7 +35,7 @@ module ApplicationHelper
   def project_icon(project_id, options = {})
     project =
       if project_id.is_a?(Project)
-        project = project_id
+        project_id
       else
         Project.find_with_namespace(project_id)
       end
@@ -68,13 +68,17 @@ module ApplicationHelper
     end
   end
 
-  def avatar_icon(user_email = '', size = nil, scale = 2)
-    user = User.find_by(email: user_email)
+  def avatar_icon(user_email = nil, size = nil, scale = 2)
+    if user_or_email.is_a?(User)
+      user = user_or_email
+    else
+      user = User.find_by(email: user_or_email)
+    end
 
     if user
       user.avatar_url(size) || default_avatar
     else
-      gravatar_icon(user_email, size, scale)
+      gravatar_icon(user_or_email, size, scales)
     end
   end
 
@@ -314,4 +318,8 @@ module ApplicationHelper
 
     html.html_safe
   end
+
+  def truncate_first_line(message, length = 50)
+    truncate(message.each_line.first.chomp, length: length) if message
+  end
 end
diff --git a/app/helpers/auth_helper.rb b/app/helpers/auth_helper.rb
index ce7e9b1db87a5f28d1bdb09734cc018a4a174f7f..cd99a2324038d4ddb5e277927a6be5589817b3ae 100644
--- a/app/helpers/auth_helper.rb
+++ b/app/helpers/auth_helper.rb
@@ -1,6 +1,6 @@
 module AuthHelper
   PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2).freeze
-  FORM_BASED_PROVIDERS = [/\Aldap/, 'kerberos', 'crowd'].freeze
+  FORM_BASED_PROVIDERS = [/\Aldap/, 'crowd'].freeze
 
   def ldap_enabled?
     Gitlab.config.ldap.enabled
diff --git a/app/helpers/builds_helper.rb b/app/helpers/builds_helper.rb
new file mode 100644
index 0000000000000000000000000000000000000000..1b5a2c31d74660e4fb01931bf5b4aa0135affd23
--- /dev/null
+++ b/app/helpers/builds_helper.rb
@@ -0,0 +1,13 @@
+module BuildsHelper
+  def build_ref_link build
+    gitlab_ref_link build.project, build.ref
+  end
+
+  def build_commit_link build
+    gitlab_commit_link build.project, build.short_sha
+  end
+
+  def build_url(build)
+    namespace_project_build_path(build.gl_project, build.project, build)
+  end
+end
diff --git a/app/helpers/ci/application_helper.rb b/app/helpers/ci/application_helper.rb
deleted file mode 100644
index 9fe6282bb81782cebee9685a7e4a3c8363635b3f..0000000000000000000000000000000000000000
--- a/app/helpers/ci/application_helper.rb
+++ /dev/null
@@ -1,54 +0,0 @@
-module Ci
-  module ApplicationHelper
-    def loader_html
-      image_tag 'ci/loader.gif', alt: 'Loading'
-    end
-
-    def date_from_to(from, to)
-      "#{from.to_s(:short)} - #{to.to_s(:short)}"
-    end
-
-    def duration_in_words(finished_at, started_at)
-      if finished_at && started_at
-        interval_in_seconds = finished_at.to_i - started_at.to_i
-      elsif started_at
-        interval_in_seconds = Time.now.to_i - started_at.to_i
-      end
-
-      time_interval_in_words(interval_in_seconds)
-    end
-
-    def time_interval_in_words(interval_in_seconds)
-      minutes = interval_in_seconds / 60
-      seconds = interval_in_seconds - minutes * 60
-
-      if minutes >= 1
-        "#{pluralize(minutes, "minute")} #{pluralize(seconds, "second")}"
-      else
-        "#{pluralize(seconds, "second")}"
-      end
-    end
-
-    def ci_icon_for_status(status)
-      icon_name =
-        case status
-        when 'success'
-          'check-square'
-        when 'failed'
-          'close'
-        when 'running', 'pending'
-          'clock-o'
-        else
-          'circle'
-        end
-
-      icon(icon_name)
-    end
-
-    def ci_status_with_icon(status)
-      content_tag :span, class: "ci-status ci-#{status}" do
-        ci_icon_for_status(status) + '&nbsp;'.html_safe + status
-      end
-    end
-  end
-end
diff --git a/app/helpers/ci/builds_helper.rb b/app/helpers/ci/builds_helper.rb
deleted file mode 100644
index 5d6e785d951269dea57c34efbf5f5bb3b36ae551..0000000000000000000000000000000000000000
--- a/app/helpers/ci/builds_helper.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-module Ci
-  module BuildsHelper
-    def build_ref_link build
-      gitlab_ref_link build.project, build.ref
-    end
-
-    def build_compare_link build
-      gitlab_compare_link build.project, build.commit.short_before_sha, build.short_sha
-    end
-
-    def build_commit_link build
-      gitlab_commit_link build.project, build.short_sha
-    end
-
-    def build_url(build)
-      ci_project_build_url(build.project, build)
-    end
-  end
-end
diff --git a/app/helpers/ci/commits_helper.rb b/app/helpers/ci/commits_helper.rb
deleted file mode 100644
index 9069aed5b4d3f044d270521115a76784a4e45097..0000000000000000000000000000000000000000
--- a/app/helpers/ci/commits_helper.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-module Ci
-  module CommitsHelper
-    def ci_commit_path(commit)
-      ci_project_ref_commits_path(commit.project, commit.ref, commit.sha)
-    end
-
-    def commit_link(commit)
-      link_to(commit.short_sha, ci_commit_path(commit))
-    end
-
-    def truncate_first_line(message, length = 50)
-      truncate(message.each_line.first.chomp, length: length) if message
-    end
-
-    def ci_commit_title(commit)
-      content_tag :span do
-        link_to(
-          simple_sanitize(commit.project.name), ci_project_path(commit.project)
-        ) + ' @ ' +
-          gitlab_commit_link(@project, @commit.sha)
-      end
-    end
-  end
-end
diff --git a/app/helpers/ci/gitlab_helper.rb b/app/helpers/ci/gitlab_helper.rb
index 2b89a0ce93e42bada415711ef9a7cf94d556bd80..baddbc806f2d386d31ec6e85605ba7af0136a2c4 100644
--- a/app/helpers/ci/gitlab_helper.rb
+++ b/app/helpers/ci/gitlab_helper.rb
@@ -26,10 +26,10 @@ module Ci
     def yaml_web_editor_link(project)
       commits = project.commits
 
-      if commits.any? && commits.last.push_data[:ci_yaml_file]
-        "#{@project.gitlab_url}/edit/master/.gitlab-ci.yml"
+      if commits.any? && commits.last.ci_yaml_file
+        "#{project.gitlab_url}/edit/master/.gitlab-ci.yml"
       else
-        "#{@project.gitlab_url}/new/master"
+        "#{project.gitlab_url}/new/master"
       end
     end
   end
diff --git a/app/helpers/ci/icons_helper.rb b/app/helpers/ci/icons_helper.rb
deleted file mode 100644
index be40f79e880ec04b676dcddc30f10d2f6a608931..0000000000000000000000000000000000000000
--- a/app/helpers/ci/icons_helper.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-module Ci
-  module IconsHelper
-    def boolean_to_icon(value)
-      if value.to_s == "true"
-        content_tag :i, nil, class: 'fa fa-circle cgreen'
-      else
-        content_tag :i, nil, class: 'fa fa-power-off clgray'
-      end
-    end
-  end
-end
diff --git a/app/helpers/ci/runners_helper.rb b/app/helpers/ci/runners_helper.rb
deleted file mode 100644
index 03c9914641e328b789ae24b077f1f9463e963c4f..0000000000000000000000000000000000000000
--- a/app/helpers/ci/runners_helper.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-module Ci
-  module RunnersHelper
-    def runner_status_icon(runner)
-      unless runner.contacted_at
-        return content_tag :i, nil,
-          class: "fa fa-warning-sign",
-          title: "New runner. Has not connected yet"
-      end
-
-      status =
-        if runner.active?
-          runner.contacted_at > 3.hour.ago ? :online : :offline
-        else
-          :paused
-        end
-
-      content_tag :i, nil,
-        class: "fa fa-circle runner-status-#{status}",
-        title: "Runner is #{status}, last contact was #{time_ago_in_words(runner.contacted_at)} ago"
-    end
-  end
-end
diff --git a/app/helpers/ci/triggers_helper.rb b/app/helpers/ci/triggers_helper.rb
deleted file mode 100644
index 0d2438928ceb55c770134be6996cec083918a42c..0000000000000000000000000000000000000000
--- a/app/helpers/ci/triggers_helper.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-module Ci
-  module TriggersHelper
-    def ci_build_trigger_url(project_id, ref_name)
-      "#{Settings.gitlab_ci.url}/ci/api/v1/projects/#{project_id}/refs/#{ref_name}/trigger"
-    end
-  end
-end
diff --git a/app/helpers/ci/user_helper.rb b/app/helpers/ci/user_helper.rb
deleted file mode 100644
index c332d6ed9cf7a06bf61afdbb2d5baa1248854ac6..0000000000000000000000000000000000000000
--- a/app/helpers/ci/user_helper.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-module Ci
-  module UserHelper
-    def user_avatar_url(user = nil, size = nil, default = 'identicon')
-      size = 40 if size.nil? || size <= 0
-
-      if user.blank? || user.avatar_url.blank?
-        'ci/no_avatar.png'
-      elsif /^(http(s?):\/\/(www|secure)\.gravatar\.com\/avatar\/(\w*))/ =~ user.avatar_url
-        Regexp.last_match[0] + "?s=#{size}&d=#{default}"
-      else
-        user.avatar_url
-      end
-    end
-  end
-end
diff --git a/app/helpers/ci_status_helper.rb b/app/helpers/ci_status_helper.rb
index 18c30ddb2810e0a20d89ff907b69bde994a58f14..dbd1e26fa79b924fdb7595ed004cf5aadc243d6b 100644
--- a/app/helpers/ci_status_helper.rb
+++ b/app/helpers/ci_status_helper.rb
@@ -1,22 +1,11 @@
 module CiStatusHelper
   def ci_status_path(ci_commit)
-    ci_project_ref_commits_path(ci_commit.project, ci_commit.ref, ci_commit)
+    project = ci_commit.gl_project
+    ci_namespace_project_commit_path(project.namespace, project, ci_commit.sha)
   end
 
   def ci_status_icon(ci_commit)
-    icon_name =
-      case ci_commit.status
-      when 'success'
-        'check'
-      when 'failed'
-        'close'
-      when 'running', 'pending'
-        'clock-o'
-      else
-        'circle'
-      end
-
-    icon(icon_name)
+    ci_icon_for_status(ci_commit.status)
   end
 
   def ci_status_color(ci_commit)
@@ -31,4 +20,26 @@ module CiStatusHelper
       'gray'
     end
   end
+
+  def ci_status_with_icon(status)
+    content_tag :span, class: "ci-status ci-#{status}" do
+      ci_icon_for_status(status) + '&nbsp;'.html_safe + status
+    end
+  end
+
+  def ci_icon_for_status(status)
+    icon_name =
+      case status
+      when 'success'
+        'check'
+      when 'failed'
+        'close'
+      when 'running', 'pending'
+        'clock-o'
+      else
+        'circle'
+      end
+
+    icon(icon_name)
+  end
 end
diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb
index 6ffa1a7121d7d7b2b4c1a5ddd9334d31da5396a0..e65e37211c4151a80921cfe253d4c26db227eed8 100644
--- a/app/helpers/diff_helper.rb
+++ b/app/helpers/diff_helper.rb
@@ -167,4 +167,24 @@ module DiffHelper
       content_tag(:span, commit_id, class: 'monospace'),
     ].join(' ').html_safe
   end
+
+  def commit_for_diff(diff)
+    if diff.deleted_file
+      first_commit = @first_commit || @commit
+      first_commit.parent
+    else
+      @commit
+    end
+  end
+
+  def diff_file_html_data(project, diff_commit, diff_file)
+    {
+      blob_diff_path: namespace_project_blob_diff_path(project.namespace, project,
+                                                       tree_join(diff_commit.id, diff_file.file_path))
+    }
+  end
+
+  def editable_diff?(diff)
+    !diff.deleted_file && @merge_request && @merge_request.source_project
+  end
 end
diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb
index 153a44870f6649bfb0ba993ca90d82bee3714490..658134821202f227b264514bbb58161128949021 100644
--- a/app/helpers/gitlab_markdown_helper.rb
+++ b/app/helpers/gitlab_markdown_helper.rb
@@ -19,9 +19,10 @@ module GitlabMarkdownHelper
                      escape_once(body)
                    end
 
-    gfm_body = Gitlab::Markdown.gfm(escaped_body, project: @project, current_user: current_user)
+    user = current_user if defined?(current_user)
+    gfm_body = Gitlab::Markdown.gfm(escaped_body, project: @project, current_user: user)
 
-    fragment = Nokogiri::XML::DocumentFragment.parse(gfm_body)
+    fragment = Nokogiri::HTML::DocumentFragment.parse(gfm_body)
     if fragment.children.size == 1 && fragment.children[0].name == 'a'
       # Fragment has only one node, and it's a link generated by `gfm`.
       # Replace it with our requested link.
@@ -45,29 +46,39 @@ module GitlabMarkdownHelper
   end
 
   def markdown(text, context = {})
+    return "" unless text.present?
+
     context.reverse_merge!(
-      current_user: current_user,
       path:         @path,
+      pipeline:     :default,
       project:      @project,
       project_wiki: @project_wiki,
       ref:          @ref
     )
 
-    Gitlab::Markdown.render(text, context)
+    user = current_user if defined?(current_user)
+
+    html = Gitlab::Markdown.render(text, context)
+    Gitlab::Markdown.post_process(html, pipeline: context[:pipeline], project: @project, user: user)
   end
 
   # TODO (rspeicher): Remove all usages of this helper and just call `markdown`
   # with a custom pipeline depending on the content being rendered
   def gfm(text, options = {})
+    return "" unless text.present?
+
     options.reverse_merge!(
-      current_user: current_user,
       path:         @path,
+      pipeline:     :default,
       project:      @project,
       project_wiki: @project_wiki,
       ref:          @ref
     )
 
-    Gitlab::Markdown.gfm(text, options)
+    user = current_user if defined?(current_user)
+
+    html = Gitlab::Markdown.gfm(text, options)
+    Gitlab::Markdown.post_process(html, pipeline: options[:pipeline], project: @project, user: user)
   end
 
   def asciidoc(text)
diff --git a/app/helpers/gitlab_routing_helper.rb b/app/helpers/gitlab_routing_helper.rb
index e0816f4e714a8f8a4ed2ef0938d6697d62941426..b0b536d4649aef959d25a6e9e8e5d330eb18e110 100644
--- a/app/helpers/gitlab_routing_helper.rb
+++ b/app/helpers/gitlab_routing_helper.rb
@@ -25,6 +25,10 @@ module GitlabRoutingHelper
     namespace_project_commits_path(project.namespace, project, @ref || project.repository.root_ref)
   end
 
+  def project_builds_path(project, *args)
+    namespace_project_builds_path(project.namespace, project, *args)
+  end
+
   def activity_project_path(project, *args)
     activity_namespace_project_path(project.namespace, project, *args)
   end
@@ -33,6 +37,14 @@ module GitlabRoutingHelper
     edit_namespace_project_path(project.namespace, project, *args)
   end
 
+  def runners_path(project, *args)
+    namespace_project_runners_path(project.namespace, project, *args)
+  end
+
+  def runner_path(runner, *args)
+    namespace_project_runner_path(@project.namespace, @project, runner, *args)
+  end
+
   def issue_path(entity, *args)
     namespace_project_issue_path(entity.project.namespace, entity.project, entity, *args)
   end
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index 6ddb37cd0dc9e7f4c343fd771210cb123b3cf9c6..fda18e7b316d7c130338ac6e85a47eaf0d17d3bc 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -83,6 +83,10 @@ module IssuesHelper
     end
   end
 
+  def merge_requests_sentence(merge_requests)
+    merge_requests.map(&:to_reference).to_sentence(last_word_connector: ', or ')
+  end
+
   # Required for Gitlab::Markdown::IssueReferenceFilter
   module_function :url_for_issue
 end
diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb
index 8036303851b70aded155f62cfec35415cd0e7a82..ee04ace35d0933e74386739f275c625d4a6ecedb 100644
--- a/app/helpers/labels_helper.rb
+++ b/app/helpers/labels_helper.rb
@@ -92,8 +92,19 @@ module LabelsHelper
     end
   end
 
-  def project_labels_options(project)
-    options_from_collection_for_select(project.labels, 'name', 'name', params[:label_name])
+  def projects_labels_options
+    labels =
+      if @project
+        @project.labels
+      else
+        Label.where(project_id: @projects)
+      end
+
+    grouped_labels = Labels::GroupService.new(labels).execute
+    grouped_labels.unshift(Label::None)
+    grouped_labels.unshift(Label::Any)
+
+    options_from_collection_for_select(grouped_labels, 'name', 'title', params[:label_name])
   end
 
   # Required for Gitlab::Markdown::LabelReferenceFilter
diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb
index f8169b4f2887bffc83ff1ceec919d64a611188e2..728d877ace226e73b574c191fec62875a3f22415 100644
--- a/app/helpers/merge_requests_helper.rb
+++ b/app/helpers/merge_requests_helper.rb
@@ -47,7 +47,7 @@ module MergeRequestsHelper
   end
 
   def issues_sentence(issues)
-    issues.map { |i| "##{i.iid}" }.to_sentence
+    issues.map(&:to_reference).to_sentence
   end
 
   def mr_change_branches_path(merge_request)
@@ -71,4 +71,17 @@ module MergeRequestsHelper
       merge_request.source_branch
     end
   end
+
+  def format_mr_branch_names(merge_request)
+    source_path = merge_request.source_project_path
+    target_path = merge_request.target_project_path
+    source_branch = merge_request.source_branch
+    target_branch = merge_request.target_branch
+
+    if source_path == target_path
+      [source_branch, target_branch]
+    else
+      ["#{source_path}:#{source_branch}", "#{target_path}:#{target_branch}"]
+    end
+  end
 end
diff --git a/app/helpers/milestones_helper.rb b/app/helpers/milestones_helper.rb
index 132a893e532965be442e9f11a4c18cd16a7eb52b..37a5b58cce8be8efd3ad934662b239b529cc02d4 100644
--- a/app/helpers/milestones_helper.rb
+++ b/app/helpers/milestones_helper.rb
@@ -30,7 +30,8 @@ module MilestonesHelper
 
     grouped_milestones = Milestones::GroupService.new(milestones).execute
     grouped_milestones.unshift(Milestone::None)
+    grouped_milestones.unshift(Milestone::Any)
 
-    options_from_collection_for_select(grouped_milestones, 'title', 'title', params[:milestone_title])
+    options_from_collection_for_select(grouped_milestones, 'name', 'title', params[:milestone_title])
   end
 end
diff --git a/app/helpers/page_layout_helper.rb b/app/helpers/page_layout_helper.rb
index df37be51ce9603b70682760baedea04aa8fd7e28..775cf5a3dd4d2dc119bffc629a4c4f988a4605b4 100644
--- a/app/helpers/page_layout_helper.rb
+++ b/app/helpers/page_layout_helper.rb
@@ -26,7 +26,7 @@ module PageLayoutHelper
 
   def fluid_layout(enabled = false)
     if @fluid_layout.nil?
-      @fluid_layout = enabled
+      @fluid_layout = (current_user && current_user.layout == "fluid") || enabled
     else
       @fluid_layout
     end
diff --git a/app/helpers/preferences_helper.rb b/app/helpers/preferences_helper.rb
index 7f1b6a6992676d532bcc9b35b42d1c8234ba392f..c73cb3028eebe65c980c8e7dd9225b2db6cdb20c 100644
--- a/app/helpers/preferences_helper.rb
+++ b/app/helpers/preferences_helper.rb
@@ -1,9 +1,18 @@
 # Helper methods for per-User preferences
 module PreferencesHelper
+  def layout_choices
+    [
+        ['Fixed', :fixed],
+        ['Fluid', :fluid]
+    ]
+  end
+
   # Maps `dashboard` values to more user-friendly option text
   DASHBOARD_CHOICES = {
     projects: 'Your Projects (default)',
-    stars:    'Starred Projects'
+    stars:    'Starred Projects',
+    project_activity: "Your Projects' Activity",
+    starred_project_activity: "Starred Projects' Activity"
   }.with_indifferent_access.freeze
 
   # Returns an Array usable by a select field for more user-friendly option text
@@ -25,7 +34,8 @@ module PreferencesHelper
   def project_view_choices
     [
       ['Readme (default)', :readme],
-      ['Activity view', :activity]
+      ['Activity view', :activity],
+      ['Files view', :files]
     ]
   end
 
@@ -37,8 +47,7 @@ module PreferencesHelper
     Gitlab::ColorSchemes.for_user(current_user).css_class
   end
 
-  def prefer_readme?
-    !current_user ||
-      current_user.project_view == 'readme'
+  def default_project_view
+    current_user ? current_user.project_view : 'readme'
   end
 end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 7b4747ce3d7f93fb3b11cd51d3eed910342b9998..5301c2ccf7688a0b293f28fe27b3577e23cde479 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -29,7 +29,7 @@ module ProjectsHelper
     author_html =  ""
 
     # Build avatar image tag
-    author_html << image_tag(avatar_icon(author.try(:email), opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]}", alt:'') if opts[:avatar]
+    author_html << image_tag(avatar_icon(author, opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]}", alt:'') if opts[:avatar]
 
     # Build name span tag
     author_html << content_tag(:span, sanitize(author.name), class: opts[:author_class]) if opts[:name]
@@ -70,6 +70,10 @@ module ProjectsHelper
     "You are going to transfer #{project.name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
   end
 
+  def remove_fork_project_message(project)
+    "You are going to remove the fork relationship to source project #{@project.forked_from_project.name_with_namespace}.  Are you ABSOLUTELY sure?"
+  end
+
   def project_nav_tabs
     @nav_tabs ||= get_project_nav_tabs(@project, current_user)
   end
@@ -113,6 +117,10 @@ module ProjectsHelper
       nav_tabs << :merge_requests
     end
 
+    if project.gitlab_ci? && can?(current_user, :read_build, project)
+      nav_tabs << :builds
+    end
+
     if can?(current_user, :admin_project, project)
       nav_tabs << :settings
     end
@@ -296,7 +304,7 @@ module ProjectsHelper
 
   def readme_cache_key
     sha = @project.commit.try(:sha) || 'nil'
-    [@project.id, sha, "readme"].join('-')
+    [@project.path_with_namespace, sha, "readme"].join('-')
   end
 
   def round_commit_count(project)
diff --git a/app/helpers/runners_helper.rb b/app/helpers/runners_helper.rb
new file mode 100644
index 0000000000000000000000000000000000000000..46eb82a354ff543ff0e8179f3c2bd561a4fa2424
--- /dev/null
+++ b/app/helpers/runners_helper.rb
@@ -0,0 +1,29 @@
+module RunnersHelper
+  def runner_status_icon(runner)
+    status = runner.status
+    case status
+    when :not_connected
+      content_tag :i, nil,
+                  class: "fa fa-warning",
+                  title: "New runner. Has not connected yet"
+
+    when :online, :offline, :paused
+      content_tag :i, nil,
+                  class: "fa fa-circle runner-status-#{status}",
+                  title: "Runner is #{status}, last contact was #{time_ago_in_words(runner.contacted_at)} ago"
+    end
+  end
+
+  def runner_link(runner)
+    display_name = truncate(runner.display_name, length: 15)
+    id = "\##{runner.id}"
+
+    if current_user && current_user.admin
+      link_to ci_admin_runner_path(runner) do
+        display_name + id
+      end
+    else
+      display_name + id
+    end
+  end
+end
diff --git a/app/helpers/tab_helper.rb b/app/helpers/tab_helper.rb
index 0e7d8065ac799003201fbf78cd125ba38c74b383..04e53fe7c6100baabf913968a5d2bc5192a6ffbe 100644
--- a/app/helpers/tab_helper.rb
+++ b/app/helpers/tab_helper.rb
@@ -110,22 +110,4 @@ module TabHelper
       'active'
     end
   end
-
-  # Use nav_tab for save controller/action  but different params
-  def nav_tab(key, value, &block)
-    o = {}
-    o[:class] = ""
-
-    if value.nil?
-      o[:class] << " active" if params[key].blank?
-    else
-      o[:class] << " active" if params[key] == value
-    end
-
-    if block_given?
-      content_tag(:li, capture(&block), o)
-    else
-      content_tag(:li, nil, o)
-    end
-  end
 end
diff --git a/app/helpers/time_helper.rb b/app/helpers/time_helper.rb
new file mode 100644
index 0000000000000000000000000000000000000000..8142f733e76cd1f6ba4cd0b88afd2171d2eea0f0
--- /dev/null
+++ b/app/helpers/time_helper.rb
@@ -0,0 +1,27 @@
+module TimeHelper
+  def duration_in_words(finished_at, started_at)
+    if finished_at && started_at
+      interval_in_seconds = finished_at.to_i - started_at.to_i
+    elsif started_at
+      interval_in_seconds = Time.now.to_i - started_at.to_i
+    end
+
+    time_interval_in_words(interval_in_seconds)
+  end
+
+  def time_interval_in_words(interval_in_seconds)
+    minutes = interval_in_seconds / 60
+    seconds = interval_in_seconds - minutes * 60
+
+    if minutes >= 1
+      "#{pluralize(minutes, "minute")} #{pluralize(seconds, "second")}"
+    else
+      "#{pluralize(seconds, "second")}"
+    end
+  end
+
+
+  def date_from_to(from, to)
+    "#{from.to_s(:short)} - #{to.to_s(:short)}"
+  end
+end
diff --git a/app/helpers/triggers_helper.rb b/app/helpers/triggers_helper.rb
new file mode 100644
index 0000000000000000000000000000000000000000..2a3a7e80fca1117da4d16020c4454447b85d41d4
--- /dev/null
+++ b/app/helpers/triggers_helper.rb
@@ -0,0 +1,5 @@
+module TriggersHelper
+  def ci_build_trigger_url(project_id, ref_name)
+    "#{Settings.gitlab_ci.url}/ci/api/v1/projects/#{project_id}/refs/#{ref_name}/trigger"
+  end
+end
diff --git a/app/mailers/abuse_report_mailer.rb b/app/mailers/abuse_report_mailer.rb
new file mode 100644
index 0000000000000000000000000000000000000000..f0c41f69a5c5b15eefcd7e107f6faf7fc989a37a
--- /dev/null
+++ b/app/mailers/abuse_report_mailer.rb
@@ -0,0 +1,12 @@
+class AbuseReportMailer < BaseMailer
+  include Gitlab::CurrentSettings
+
+  def notify(abuse_report_id)
+    @abuse_report = AbuseReport.find(abuse_report_id)
+
+    mail(
+      to:       current_application_settings.admin_notification_email, 
+      subject:  "#{@abuse_report.user.name} (#{@abuse_report.user.username}) was reported for abuse"
+    )
+  end
+end
diff --git a/app/mailers/ci/notify.rb b/app/mailers/ci/notify.rb
index 4462da0d7d277155fed847846bf6bfc440f64fd0..404842cf213b4e43201986a0cc565130b3ebddff 100644
--- a/app/mailers/ci/notify.rb
+++ b/app/mailers/ci/notify.rb
@@ -2,7 +2,6 @@ module Ci
   class Notify < ActionMailer::Base
     include Ci::Emails::Builds
 
-    add_template_helper Ci::ApplicationHelper
     add_template_helper Ci::GitlabHelper
 
     default_url_options[:host]     = Gitlab.config.gitlab.host
diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb
index 4a6e18e6a748eac992ddb6e98c79138eb3ac9b34..caba63006da093192fe24305d6a0efb741244372 100644
--- a/app/mailers/emails/projects.rb
+++ b/app/mailers/emails/projects.rb
@@ -50,10 +50,11 @@ module Emails
            subject: subject("Invitation declined"))
     end
 
-    def project_was_moved_email(project_id, user_id)
+    def project_was_moved_email(project_id, user_id, old_path_with_namespace)
       @current_user = @user = User.find user_id
       @project = Project.find project_id
       @target_url = namespace_project_url(@project.namespace, @project)
+      @old_path_with_namespace = old_path_with_namespace
       mail(to: @user.notification_email,
            subject: subject("Project was moved"))
     end
diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb
index db2f9654e1443e28e5f68b4536125bb65be7694d..50a409c375477574aba1804220d651d0f3d2e570 100644
--- a/app/mailers/notify.rb
+++ b/app/mailers/notify.rb
@@ -140,7 +140,7 @@ class Notify < BaseMailer
   #  * have a 'In-Reply-To' or 'References' header that references the original 'Message-ID'
   #
   def mail_answer_thread(model, headers = {})
-    headers['Message-ID'] = SecureRandom.hex
+    headers['Message-ID'] = "<#{SecureRandom.hex}@#{Gitlab.config.gitlab.host}>"
     headers['In-Reply-To'] = message_id(model)
     headers['References'] = message_id(model)
 
diff --git a/app/models/ability.rb b/app/models/ability.rb
index a020b24a550f6fe75f2830b37228666fdafcc1c9..b72178fa12608f84058cb356ee71d7c798e8ebc4 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -41,6 +41,7 @@ class Ability
           :read_project_member,
           :read_merge_request,
           :read_note,
+          :read_build,
           :download_code
         ]
 
@@ -127,6 +128,7 @@ class Ability
         :read_project_member,
         :read_merge_request,
         :read_note,
+        :read_build,
         :create_project,
         :create_issue,
         :create_note
@@ -135,6 +137,8 @@ class Ability
 
     def project_report_rules
       project_guest_rules + [
+        :create_commit_status,
+        :read_commit_statuses,
         :download_code,
         :fork_project,
         :create_project_snippet,
@@ -185,7 +189,8 @@ class Ability
         :change_visibility_level,
         :rename_project,
         :remove_project,
-        :archive_project
+        :archive_project,
+        :remove_fork_project
       ]
     end
 
diff --git a/app/models/abuse_report.rb b/app/models/abuse_report.rb
index 07c87a7fe8756b8fd89476f14a7b601a8e0ef5d4..89b3116b9f2b0372a0e3c6104ba147fb10dc3f86 100644
--- a/app/models/abuse_report.rb
+++ b/app/models/abuse_report.rb
@@ -11,11 +11,11 @@
 #
 
 class AbuseReport < ActiveRecord::Base
-  belongs_to :reporter, class_name: "User"
+  belongs_to :reporter, class_name: 'User'
   belongs_to :user
 
   validates :reporter, presence: true
   validates :user, presence: true
   validates :message, presence: true
-  validates :user_id, uniqueness: { scope: :reporter_id }
+  validates :user_id, uniqueness: true
 end
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index 784f5c96a0a751f1abd4d0f15a55e5faf6c3ba0b..05430c2ee18e106bdfa0f7a34900d518c83a3868 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -44,6 +44,10 @@ class ApplicationSetting < ActiveRecord::Base
     allow_blank: true,
     format: { with: /\A#{URI.regexp(%w(http https))}\z/, message: "should be a valid url" }
 
+  validates :admin_notification_email,
+    allow_blank: true,
+    email: true
+
   validates_each :restricted_visibility_levels do |record, attr, value|
     unless value.nil?
       value.each do |level|
@@ -83,8 +87,7 @@ class ApplicationSetting < ActiveRecord::Base
       default_project_visibility: Settings.gitlab.default_projects_features['visibility_level'],
       default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level'],
       restricted_signup_domains: Settings.gitlab['restricted_signup_domains'],
-      import_sources: ['github','bitbucket','gitlab','gitorious','google_code','fogbugz','git'],
-      ci_enabled: Settings.gitlab_ci['enabled']
+      import_sources: ['github','bitbucket','gitlab','gitorious','google_code','fogbugz','git']
     )
   end
 
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 8096d4fa5ae332410d72a522f1dcb90a7426aab1..b19e2ac13634566ef3f7a9e05bd32f5904c38e3a 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -24,28 +24,20 @@
 #
 
 module Ci
-  class Build < ActiveRecord::Base
-    extend Ci::Model
-    
+  class Build < CommitStatus
     LAZY_ATTRIBUTES = ['trace']
 
-    belongs_to :commit, class_name: 'Ci::Commit'
-    belongs_to :project, class_name: 'Ci::Project'
     belongs_to :runner, class_name: 'Ci::Runner'
     belongs_to :trigger_request, class_name: 'Ci::TriggerRequest'
 
     serialize :options
 
-    validates :commit, presence: true
-    validates :status, presence: true
     validates :coverage, numericality: true, allow_blank: true
+    validates_presence_of :ref
 
-    scope :running, ->() { where(status: "running") }
-    scope :pending, ->() { where(status: "pending") }
-    scope :success, ->() { where(status: "success") }
-    scope :failed, ->() { where(status: "failed")  }
     scope :unstarted, ->() { where(runner_id: nil) }
-    scope :running_or_pending, ->() { where(status:[:running, :pending]) }
+    scope :ignore_failures, ->() { where(allow_failure: false) }
+    scope :similar, ->(build) { where(ref: build.ref, tag: build.tag, trigger_request_id: build.trigger_request_id) }
 
     acts_as_taggable
 
@@ -69,21 +61,24 @@ module Ci
 
       def create_from(build)
         new_build = build.dup
-        new_build.status = :pending
+        new_build.status = 'pending'
         new_build.runner_id = nil
+        new_build.trigger_request_id = nil
         new_build.save
       end
 
       def retry(build)
-        new_build = Ci::Build.new(status: :pending)
+        new_build = Ci::Build.new(status: 'pending')
+        new_build.ref = build.ref
+        new_build.tag = build.tag
         new_build.options = build.options
         new_build.commands = build.commands
         new_build.tag_list = build.tag_list
         new_build.commit_id = build.commit_id
-        new_build.project_id = build.project_id
         new_build.name = build.name
         new_build.allow_failure = build.allow_failure
         new_build.stage = build.stage
+        new_build.stage_idx = build.stage_idx
         new_build.trigger_request = build.trigger_request
         new_build.save
         new_build
@@ -91,80 +86,29 @@ module Ci
     end
 
     state_machine :status, initial: :pending do
-      event :run do
-        transition pending: :running
-      end
-
-      event :drop do
-        transition running: :failed
-      end
-
-      event :success do
-        transition running: :success
-      end
-
-      event :cancel do
-        transition [:pending, :running] => :canceled
-      end
-
-      after_transition pending: :running do |build, transition|
-        build.update_attributes started_at: Time.now
-      end
-
       after_transition any => [:success, :failed, :canceled] do |build, transition|
-        build.update_attributes finished_at: Time.now
         project = build.project
 
         if project.web_hooks?
           Ci::WebHookService.new.build_end(build)
         end
 
-        if build.commit.success?
-          build.commit.create_next_builds(build.trigger_request)
-        end
-
+        build.commit.create_next_builds(build)
         project.execute_services(build)
 
         if project.coverage_enabled?
           build.update_coverage
         end
       end
-
-      state :pending, value: 'pending'
-      state :running, value: 'running'
-      state :failed, value: 'failed'
-      state :success, value: 'success'
-      state :canceled, value: 'canceled'
     end
 
-    delegate :sha, :short_sha, :before_sha, :ref,
-      to: :commit, prefix: false
+    def ignored?
+      failed? && allow_failure?
+    end
 
     def trace_html
       html = Ci::Ansi2html::convert(trace) if trace.present?
-      html ||= ''
-    end
-
-    def trace
-      if project && read_attribute(:trace).present?
-        read_attribute(:trace).gsub(project.token, 'xxxxxx')
-      end
-    end
-
-    def started?
-      !pending? && !canceled? && started_at
-    end
-
-    def active?
-      running? || pending?
-    end
-
-    def complete?
-      canceled? || success? || failed?
-    end
-
-    def ignored?
-      failed? && allow_failure?
+      html || ''
     end
 
     def timeout
@@ -172,15 +116,7 @@ module Ci
     end
 
     def variables
-      yaml_variables + project_variables + trigger_variables
-    end
-
-    def duration
-      if started_at && finished_at
-        finished_at - started_at
-      elsif started_at
-        Time.now - started_at
-      end
+      predefined_variables + yaml_variables + project_variables + trigger_variables
     end
 
     def project
@@ -188,13 +124,23 @@ module Ci
     end
 
     def project_id
-      commit.project_id
+      commit.project.id
     end
 
     def project_name
       project.name
     end
 
+    def project_recipients
+      recipients = project.email_recipients.split(' ')
+
+      if project.email_add_pusher? && user.present? && user.notification_email.present?
+        recipients << user.notification_email
+      end
+
+      recipients.uniq
+    end
+
     def repo_url
       project.repo_url_with_auth
     end
@@ -219,13 +165,13 @@ module Ci
         if coverage.present?
           coverage.to_f
         end
-      rescue => ex
+      rescue
         # if bad regex or something goes wrong we dont want to interrupt transition
         # so we just silentrly ignore error for now
       end
     end
 
-    def trace
+    def raw_trace
       if File.exist?(path_to_trace)
         File.read(path_to_trace)
       else
@@ -234,6 +180,15 @@ module Ci
       end
     end
 
+    def trace
+      trace = raw_trace
+      if project && trace.present?
+        trace.gsub(project.token, 'xxxxxx')
+      else
+        trace
+      end
+    end
+
     def trace=(trace)
       unless Dir.exists? dir_to_trace
         FileUtils.mkdir_p dir_to_trace
@@ -254,6 +209,37 @@ module Ci
       "#{dir_to_trace}/#{id}.log"
     end
 
+    def target_url
+      Gitlab::Application.routes.url_helpers.
+        namespace_project_build_url(gl_project.namespace, gl_project, self)
+    end
+
+    def cancel_url
+      if active?
+        Gitlab::Application.routes.url_helpers.
+          cancel_namespace_project_build_path(gl_project.namespace, gl_project, self)
+      end
+    end
+
+    def retry_url
+      if commands.present?
+        Gitlab::Application.routes.url_helpers.
+          retry_namespace_project_build_path(gl_project.namespace, gl_project, self)
+      end
+    end
+
+    def can_be_served?(runner)
+      (tag_list - runner.tag_list).empty?
+    end
+
+    def any_runners_online?
+      project.any_runners? { |runner| runner.active? && runner.online? && can_be_served?(runner) }
+    end
+
+    def show_warning?
+      pending? && !any_runners_online?
+    end
+
     private
 
     def yaml_variables
@@ -281,5 +267,14 @@ module Ci
         []
       end
     end
+
+    def predefined_variables
+      variables = []
+      variables << { key: :CI_BUILD_TAG, value: ref, public: true } if tag?
+      variables << { key: :CI_BUILD_NAME, value: name, public: true }
+      variables << { key: :CI_BUILD_STAGE, value: stage, public: true }
+      variables << { key: :CI_BUILD_TRIGGERED, value: 'true', public: true } if trigger_request
+      variables
+    end
   end
 end
diff --git a/app/models/ci/commit.rb b/app/models/ci/commit.rb
index f102d0a767913d263df6da29fe933a31abf37c15..13437b2483f1f6a6f9fef45227419c196bd28c75 100644
--- a/app/models/ci/commit.rb
+++ b/app/models/ci/commit.rb
@@ -18,14 +18,15 @@
 module Ci
   class Commit < ActiveRecord::Base
     extend Ci::Model
-    
-    belongs_to :project, class_name: 'Ci::Project'
-    has_many :builds, dependent: :destroy, class_name: 'Ci::Build'
+
+    belongs_to :gl_project, class_name: '::Project', foreign_key: :gl_project_id
+    has_many :statuses, dependent: :destroy, class_name: 'CommitStatus'
+    has_many :builds, class_name: 'Ci::Build'
     has_many :trigger_requests, dependent: :destroy, class_name: 'Ci::TriggerRequest'
 
-    serialize :push_data
+    scope :ordered, -> { order('CASE WHEN ci_commits.committed_at IS NULL THEN 0 ELSE 1 END', :committed_at, :id) }
 
-    validates_presence_of :ref, :sha, :before_sha, :push_data
+    validates_presence_of :sha
     validate :valid_commit_sha
 
     def self.truncate_sha(sha)
@@ -36,12 +37,20 @@ module Ci
       sha
     end
 
+    def project
+      @project ||= gl_project.ensure_gitlab_ci_project
+    end
+
+    def project_id
+      project.id
+    end
+
     def last_build
       builds.order(:id).last
     end
 
     def retry
-      builds_without_retry.each do |build|
+      latest_builds.each do |build|
         Ci::Build.retry(build)
       end
     end
@@ -52,28 +61,16 @@ module Ci
       end
     end
 
-    def new_branch?
-      before_sha == Ci::Git::BLANK_SHA
-    end
-
-    def compare?
-      !new_branch?
-    end
-
     def git_author_name
-      commit_data[:author][:name] if commit_data && commit_data[:author]
+      commit_data.author_name if commit_data
     end
 
     def git_author_email
-      commit_data[:author][:email] if commit_data && commit_data[:author]
+      commit_data.author_email if commit_data
     end
 
     def git_commit_message
-      commit_data[:message] if commit_data && commit_data[:message]
-    end
-
-    def short_before_sha
-      Ci::Commit.truncate_sha(before_sha)
+      commit_data.message if commit_data
     end
 
     def short_sha
@@ -81,127 +78,82 @@ module Ci
     end
 
     def commit_data
-      push_data[:commits].find do |commit|
-        commit[:id] == sha
-      end
+      @commit ||= gl_project.commit(sha)
     rescue
       nil
     end
 
-    def project_recipients
-      recipients = project.email_recipients.split(' ')
-
-      if project.email_add_pusher? && push_data[:user_email].present?
-        recipients << push_data[:user_email]
-      end
-
-      recipients.uniq
-    end
-
     def stage
-      return unless config_processor
-      stages = builds_without_retry.select(&:active?).map(&:stage)
-      config_processor.stages.find { |stage| stages.include? stage }
+      running_or_pending = statuses.latest.running_or_pending.ordered
+      running_or_pending.first.try(:stage)
     end
 
-    def create_builds_for_stage(stage, trigger_request)
-      return if skip_ci? && trigger_request.blank?
+    def create_builds(ref, tag, user, trigger_request = nil)
       return unless config_processor
-
-      builds_attrs = config_processor.builds_for_stage_and_ref(stage, ref, tag)
-      builds_attrs.map do |build_attrs|
-        builds.create!({
-          project: project,
-          name: build_attrs[:name],
-          commands: build_attrs[:script],
-          tag_list: build_attrs[:tags],
-          options: build_attrs[:options],
-          allow_failure: build_attrs[:allow_failure],
-          stage: build_attrs[:stage],
-          trigger_request: trigger_request,
-        })
+      config_processor.stages.any? do |stage|
+        CreateBuildsService.new.execute(self, stage, ref, tag, user, trigger_request, 'success').present?
       end
     end
 
-    def create_next_builds(trigger_request)
-      return if skip_ci? && trigger_request.blank?
+    def create_next_builds(build)
       return unless config_processor
 
-      stages = builds.where(trigger_request: trigger_request).group_by(&:stage)
+      # don't create other builds if this one is retried
+      latest_builds = builds.similar(build).latest
+      return unless latest_builds.exists?(build.id)
 
-      config_processor.stages.any? do |stage|
-        !stages.include?(stage) && create_builds_for_stage(stage, trigger_request).present?
-      end
-    end
+      # get list of stages after this build
+      next_stages = config_processor.stages.drop_while { |stage| stage != build.stage }
+      next_stages.delete(build.stage)
 
-    def create_builds(trigger_request = nil)
-      return if skip_ci? && trigger_request.blank?
-      return unless config_processor
+      # get status for all prior builds
+      prior_builds = latest_builds.reject { |other_build| next_stages.include?(other_build.stage) }
+      status = Ci::Status.get_status(prior_builds)
 
-      config_processor.stages.any? do |stage|
-        create_builds_for_stage(stage, trigger_request).present?
+      # create builds for next stages based
+      next_stages.any? do |stage|
+        CreateBuildsService.new.execute(self, stage, build.ref, build.tag, build.user, build.trigger_request, status).present?
       end
     end
 
-    def builds_without_retry
-      @builds_without_retry ||=
-        begin
-          grouped_builds = builds.group_by(&:name)
-          grouped_builds.map do |name, builds|
-            builds.sort_by(&:id).last
-          end
-        end
+    def refs
+      statuses.order(:ref).pluck(:ref).uniq
     end
 
-    def builds_without_retry_sorted
-      return builds_without_retry unless config_processor
+    def latest_statuses
+      @latest_statuses ||= statuses.latest.to_a
+    end
 
-      stages = config_processor.stages
-      builds_without_retry.sort_by do |build|
-        [stages.index(build.stage) || -1, build.name || ""]
-      end
+    def latest_builds
+      @latest_builds ||= builds.latest.to_a
+    end
+
+    def latest_builds_for_ref(ref)
+      latest_builds.select { |build| build.ref == ref }
     end
 
-    def retried_builds
-      @retried_builds ||= (builds.order(id: :desc) - builds_without_retry)
+    def retried
+      @retried ||= (statuses.order(id: :desc) - statuses.latest)
     end
 
     def status
-      if skip_ci?
-        return 'skipped'
-      elsif yaml_errors.present?
+      if yaml_errors.present?
         return 'failed'
-      elsif builds.none?
-        return 'skipped'
-      elsif success?
-        'success'
-      elsif pending?
-        'pending'
-      elsif running?
-        'running'
-      elsif canceled?
-        'canceled'
-      else
-        'failed'
       end
+
+      @status ||= Ci::Status.get_status(latest_statuses)
     end
 
     def pending?
-      builds_without_retry.all? do |build|
-        build.pending?
-      end
+      status == 'pending'
     end
 
     def running?
-      builds_without_retry.any? do |build|
-        build.running? || build.pending?
-      end
+      status == 'running'
     end
 
     def success?
-      builds_without_retry.all? do |build|
-        build.success? || build.ignored?
-      end
+      status == 'success'
     end
 
     def failed?
@@ -209,34 +161,33 @@ module Ci
     end
 
     def canceled?
-      builds_without_retry.all? do |build|
-        build.canceled?
-      end
+      status == 'canceled'
     end
 
     def duration
-      @duration ||= builds_without_retry.select(&:duration).sum(&:duration).to_i
+      duration_array = latest_statuses.map(&:duration).compact
+      duration_array.reduce(:+).to_i
     end
 
     def finished_at
-      @finished_at ||= builds.order('finished_at DESC').first.try(:finished_at)
+      @finished_at ||= statuses.order('finished_at DESC').first.try(:finished_at)
     end
 
     def coverage
       if project.coverage_enabled?
-        coverage_array = builds_without_retry.map(&:coverage).compact
+        coverage_array = latest_builds.map(&:coverage).compact
         if coverage_array.size >= 1
           '%.2f' % (coverage_array.reduce(:+) / coverage_array.size)
         end
       end
     end
 
-    def matrix?
-      builds_without_retry.size > 1
+    def matrix_for_ref?(ref)
+      latest_builds_for_ref(ref).size > 1
     end
 
     def config_processor
-      @config_processor ||= Ci::GitlabCiYamlProcessor.new(push_data[:ci_yaml_file])
+      @config_processor ||= Ci::GitlabCiYamlProcessor.new(ci_yaml_file)
     rescue Ci::GitlabCiYamlProcessor::ValidationError => e
       save_yaml_error(e.message)
       nil
@@ -246,10 +197,14 @@ module Ci
       nil
     end
 
+    def ci_yaml_file
+      gl_project.repository.blob_at(sha, '.gitlab-ci.yml').data
+    rescue
+      nil
+    end
+
     def skip_ci?
-      return false if builds.any?
-      commits = push_data[:commits]
-      commits.present? && commits.last[:message] =~ /(\[ci skip\])/
+      git_commit_message =~ /(\[ci skip\])/ if git_commit_message
     end
 
     def update_committed!
diff --git a/app/models/ci/project.rb b/app/models/ci/project.rb
index a52e28615f7e5f13237ae941d95911277c646ed2..eb65c773570c4e937205b4071ec7c26ba9462f64 100644
--- a/app/models/ci/project.rb
+++ b/app/models/ci/project.rb
@@ -33,15 +33,12 @@ module Ci
 
     belongs_to :gl_project, class_name: '::Project', foreign_key: :gitlab_id
 
-    has_many :commits, ->() { order('CASE WHEN ci_commits.committed_at IS NULL THEN 0 ELSE 1 END', :committed_at, :id) }, dependent: :destroy, class_name: 'Ci::Commit'
-    has_many :builds, through: :commits, dependent: :destroy, class_name: 'Ci::Build'
     has_many :runner_projects, dependent: :destroy, class_name: 'Ci::RunnerProject'
     has_many :runners, through: :runner_projects, class_name: 'Ci::Runner'
     has_many :web_hooks, dependent: :destroy, class_name: 'Ci::WebHook'
     has_many :events, dependent: :destroy, class_name: 'Ci::Event'
     has_many :variables, dependent: :destroy, class_name: 'Ci::Variable'
     has_many :triggers, dependent: :destroy, class_name: 'Ci::Trigger'
-    has_one :last_commit, -> { order 'ci_commits.created_at DESC' }, class_name: 'Ci::Commit'
 
     # Project services
     has_many :services, dependent: :destroy, class_name: 'Ci::Service'
@@ -51,19 +48,18 @@ module Ci
 
     accepts_nested_attributes_for :variables, allow_destroy: true
 
+    delegate :name_with_namespace, :path_with_namespace, :web_url, :http_url_to_repo, :ssh_url_to_repo, to: :gl_project
+
     #
     # Validations
     #
-    validates_presence_of :name, :timeout, :token, :default_ref,
-      :path, :ssh_url_to_repo, :gitlab_id
+    validates_presence_of :timeout, :token, :default_ref, :gitlab_id
 
     validates_uniqueness_of :gitlab_id
 
     validates :polling_interval,
-      presence: true,
-      if: ->(project) { project.always_build.present? }
-
-    scope :public_only, ->() { where(public: true) }
+              presence: true,
+              if: ->(project) { project.always_build.present? }
 
     before_validation :set_default_values
 
@@ -79,11 +75,8 @@ module Ci
 
       def parse(project)
         params = {
-          name:                     project.name_with_namespace,
           gitlab_id:                project.id,
-          path:                     project.path_with_namespace,
           default_ref:              project.default_branch || 'master',
-          ssh_url_to_repo:          project.ssh_url_to_repo,
           email_add_pusher:         current_application_settings.add_pusher,
           email_only_broken_builds: current_application_settings.all_broken_builds,
         }
@@ -100,35 +93,43 @@ module Ci
       def unassigned(runner)
         joins("LEFT JOIN #{Ci::RunnerProject.table_name} ON #{Ci::RunnerProject.table_name}.project_id = #{Ci::Project.table_name}.id " \
           "AND #{Ci::RunnerProject.table_name}.runner_id = #{runner.id}").
-        where('#{Ci::RunnerProject.table_name}.project_id' => nil)
+        where("#{Ci::RunnerProject.table_name}.project_id" => nil)
       end
 
       def ordered_by_last_commit_date
-        last_commit_subquery = "(SELECT project_id, MAX(committed_at) committed_at FROM #{Ci::Commit.table_name} GROUP BY project_id)"
-        joins("LEFT JOIN #{last_commit_subquery} AS last_commit ON #{Ci::Project.table_name}.id = last_commit.project_id").
+        last_commit_subquery = "(SELECT gl_project_id, MAX(committed_at) committed_at FROM #{Ci::Commit.table_name} GROUP BY gl_project_id)"
+        joins("LEFT JOIN #{last_commit_subquery} AS last_commit ON #{Ci::Project.table_name}.gitlab_id = last_commit.gl_project_id").
           order("CASE WHEN last_commit.committed_at IS NULL THEN 1 ELSE 0 END, last_commit.committed_at DESC")
       end
+    end
 
-      def search(query)
-        where("LOWER(#{Ci::Project.table_name}.name) LIKE :query",
-              query: "%#{query.try(:downcase)}%")
-      end
+    def name
+      name_with_namespace
+    end
+
+    def path
+      path_with_namespace
+    end
+
+    def gitlab_url
+      web_url
     end
 
-    def any_runners?
-      if runners.active.any?
+    def any_runners?(&block)
+      if runners.active.any?(&block)
         return true
       end
 
-      shared_runners_enabled && Ci::Runner.shared.active.any?
+      shared_runners_enabled && Ci::Runner.shared.active.any?(&block)
     end
 
     def set_default_values
       self.token = SecureRandom.hex(15) if self.token.blank?
+      self.default_ref ||= 'master'
     end
 
     def tracked_refs
-      @tracked_refs ||= default_ref.split(",").map{|ref| ref.strip}
+      @tracked_refs ||= default_ref.split(",").map { |ref| ref.strip }
     end
 
     def valid_token? token
@@ -168,8 +169,7 @@ module Ci
     # using http and basic auth
     def repo_url_with_auth
       auth = "gitlab-ci-token:#{token}@"
-      url = gitlab_url + ".git"
-      url.sub(/^https?:\/\//) do |prefix|
+      http_url_to_repo.sub(/^https?:\/\//) do |prefix|
         prefix + auth
       end
     end
@@ -184,7 +184,7 @@ module Ci
 
         # If service is available but missing in db
         # we should create an instance. Ex `create_gitlab_ci_service`
-        service = self.send :"create_#{service_name}_service" if service.nil?
+        self.send :"create_#{service_name}_service" if service.nil?
       end
     end
 
@@ -200,12 +200,16 @@ module Ci
       end
     end
 
-    def gitlab_url
-      File.join(Gitlab.config.gitlab.url, path)
-    end
-
     def setup_finished?
       commits.any?
     end
+
+    def commits
+      gl_project.ci_commits.ordered
+    end
+
+    def builds
+      gl_project.ci_builds
+    end
   end
 end
diff --git a/app/models/ci/project_status.rb b/app/models/ci/project_status.rb
index 6d5cafe81a2f1a44a04f88274c73c7207206b5f5..b66f1212f239da967a16480ac2fe9b5d428edbc9 100644
--- a/app/models/ci/project_status.rb
+++ b/app/models/ci/project_status.rb
@@ -28,18 +28,6 @@ module Ci
       status
     end
 
-    # only check for toggling build status within same ref.
-    def last_commit_changed_status?
-      ref = last_commit.ref
-      last_commits = commits.where(ref: ref).last(2)
-
-      if last_commits.size < 2
-        false
-      else
-        last_commits[0].status != last_commits[1].status
-      end
-    end
-
     def last_commit_for_ref(ref)
       commits.where(ref: ref).last
     end
diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb
index 1e9f78a37482d4ef9456ad77606db038dcade435..1b3669f1b7a7b5ef88b68215f2b6bb364b9aa575 100644
--- a/app/models/ci/runner.rb
+++ b/app/models/ci/runner.rb
@@ -20,6 +20,8 @@
 module Ci
   class Runner < ActiveRecord::Base
     extend Ci::Model
+
+    LAST_CONTACT_TIME = 5.minutes.ago
     
     has_many :builds, class_name: 'Ci::Build'
     has_many :runner_projects, dependent: :destroy, class_name: 'Ci::RunnerProject'
@@ -33,6 +35,7 @@ module Ci
     scope :shared, ->() { where(is_shared: true) }
     scope :active, ->() { where(active: true) }
     scope :paused, ->() { where(active: false) }
+    scope :online, ->() { where('contacted_at > ?', LAST_CONTACT_TIME) }
 
     acts_as_taggable
 
@@ -41,6 +44,10 @@ module Ci
             query: "%#{query.try(:downcase)}%")
     end
 
+    def gl_projects_ids
+      projects.select(:gitlab_id)
+    end
+
     def set_default_values
       self.token = SecureRandom.hex(15) if self.token.blank?
     end
@@ -52,7 +59,7 @@ module Ci
     end
 
     def display_name
-      return token unless !description.blank?
+      return short_sha unless !description.blank?
 
       description
     end
@@ -61,6 +68,20 @@ module Ci
       is_shared
     end
 
+    def online?
+      contacted_at && contacted_at > LAST_CONTACT_TIME
+    end
+
+    def status
+      if contacted_at.nil?
+        :not_connected
+      elsif active?
+        online? ? :online : :offline
+      else
+        :paused
+      end
+    end
+
     def belongs_to_one_project?
       runner_projects.count == 1
     end
@@ -74,7 +95,7 @@ module Ci
     end
 
     def short_sha
-      token[0...10]
+      token[0...8] if token
     end
   end
 end
diff --git a/app/models/commit.rb b/app/models/commit.rb
index aff329d71fa3f29e657597531ea161bfd3c90b68..492f6be1ce39be2995c71c57ec2dfa0f2ce44c98 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -2,13 +2,13 @@ class Commit
   extend ActiveModel::Naming
 
   include ActiveModel::Conversion
-  include Mentionable
   include Participable
+  include Mentionable
   include Referable
   include StaticModel
 
   attr_mentionable :safe_message
-  participant :author, :committer, :notes, :mentioned_users
+  participant :author, :committer, :notes
 
   attr_accessor :project
 
@@ -164,6 +164,14 @@ class Commit
     @committer ||= User.find_by_any_email(committer_email)
   end
 
+  def parents
+    @parents ||= parent_ids.map { |id| project.commit(id) }
+  end
+
+  def parent
+    @parent ||= project.commit(self.parent_id) if self.parent_id
+  end
+
   def notes
     project.notes.for_commit_id(self.id)
   end
@@ -181,7 +189,11 @@ class Commit
     @raw.short_id(7)
   end
 
-  def parents
-    @parents ||= Commit.decorate(super, project)
+  def ci_commit
+    project.ci_commit(sha)
+  end
+
+  def status
+    ci_commit.try(:status) || :not_found
   end
 end
diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb
new file mode 100644
index 0000000000000000000000000000000000000000..8188ba3a28ebf3d2566831db8124d88eedf9cc3e
--- /dev/null
+++ b/app/models/commit_status.rb
@@ -0,0 +1,96 @@
+class CommitStatus < ActiveRecord::Base
+  self.table_name = 'ci_builds'
+
+  belongs_to :commit, class_name: 'Ci::Commit'
+  belongs_to :user
+
+  validates :commit, presence: true
+  validates :status, inclusion: { in: %w(pending running failed success canceled) }
+
+  validates_presence_of :name
+
+  alias_attribute :author, :user
+
+  scope :running, -> { where(status: 'running') }
+  scope :pending, -> { where(status: 'pending') }
+  scope :success, -> { where(status: 'success') }
+  scope :failed, -> { where(status: 'failed')  }
+  scope :running_or_pending, -> { where(status:[:running, :pending]) }
+  scope :finished, -> { where(status:[:success, :failed, :canceled]) }
+  scope :latest, -> { where(id: unscope(:select).select('max(id)').group(:name, :ref)) }
+  scope :ordered, -> { order(:ref, :stage_idx, :name) }
+  scope :for_ref, ->(ref) { where(ref: ref) }
+  scope :running_or_pending, -> { where(status: [:running, :pending]) }
+
+  state_machine :status, initial: :pending do
+    event :run do
+      transition pending: :running
+    end
+
+    event :drop do
+      transition [:pending, :running] => :failed
+    end
+
+    event :success do
+      transition [:pending, :running] => :success
+    end
+
+    event :cancel do
+      transition [:pending, :running] => :canceled
+    end
+
+    after_transition pending: :running do |build, transition|
+      build.update_attributes started_at: Time.now
+    end
+
+    after_transition any => [:success, :failed, :canceled] do |build, transition|
+      build.update_attributes finished_at: Time.now
+    end
+
+    state :pending, value: 'pending'
+    state :running, value: 'running'
+    state :failed, value: 'failed'
+    state :success, value: 'success'
+    state :canceled, value: 'canceled'
+  end
+
+  delegate :sha, :short_sha, :gl_project,
+           to: :commit, prefix: false
+
+  # TODO: this should be removed with all references
+  def before_sha
+    Gitlab::Git::BLANK_SHA
+  end
+
+  def started?
+    !pending? && !canceled? && started_at
+  end
+
+  def active?
+    running? || pending?
+  end
+
+  def complete?
+    canceled? || success? || failed?
+  end
+
+  def duration
+    if started_at && finished_at
+      finished_at - started_at
+    elsif started_at
+      Time.now - started_at
+    end
+  end
+
+  def cancel_url
+    nil
+  end
+
+  def retry_url
+    nil
+  end
+
+  def show_warning?
+    false
+  end
+end
diff --git a/app/models/concerns/case_sensitivity.rb b/app/models/concerns/case_sensitivity.rb
new file mode 100644
index 0000000000000000000000000000000000000000..fe0cea8465f628842bfe311f9bcdcbdce76d93f2
--- /dev/null
+++ b/app/models/concerns/case_sensitivity.rb
@@ -0,0 +1,28 @@
+# Concern for querying columns with specific case sensitivity handling.
+module CaseSensitivity
+  extend ActiveSupport::Concern
+
+  module ClassMethods
+    # Queries the given columns regardless of the casing used.
+    #
+    # Unlike other ActiveRecord methods this method only operates on a Hash.
+    def iwhere(params)
+      criteria   = self
+      cast_lower = Gitlab::Database.postgresql?
+
+      params.each do |key, value|
+        column = ActiveRecord::Base.connection.quote_table_name(key)
+
+        if cast_lower
+          condition = "LOWER(#{column}) = LOWER(:value)"
+        else
+          condition = "#{column} = :value"
+        end
+
+        criteria = criteria.where(condition, value: value)
+      end
+
+      criteria
+    end
+  end
+end
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index 4db4ffb2e79835fb234e53470f32da2c105fad6a..5e964f04ef55a39c45212bbbaa01f9ecd575475a 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -6,8 +6,8 @@
 #
 module Issuable
   extend ActiveSupport::Concern
-  include Mentionable
   include Participable
+  include Mentionable
 
   included do
     belongs_to :author, class_name: "User"
@@ -47,7 +47,7 @@ module Issuable
              prefix: true
 
     attr_mentionable :title, :description
-    participant :author, :assignee, :notes, :mentioned_users
+    participant :author, :assignee, :notes_with_associations
   end
 
   module ClassMethods
@@ -85,6 +85,10 @@ module Issuable
     assignee_id_changed?
   end
 
+  def open?
+    opened? || reopened?
+  end
+
   #
   # Votes
   #
@@ -176,6 +180,10 @@ module Issuable
     self.class.to_s.underscore
   end
 
+  def notes_with_associations
+    notes.includes(:author, :project)
+  end
+
   private
 
   def filter_superceded_votes(votes, notes)
diff --git a/app/models/concerns/mentionable.rb b/app/models/concerns/mentionable.rb
index 5b0ae41164200ed37a0eedfb994cacecdbcd4378..193c91f1742940f4c87c1149ca2dec0d325a1c86 100644
--- a/app/models/concerns/mentionable.rb
+++ b/app/models/concerns/mentionable.rb
@@ -20,6 +20,12 @@ module Mentionable
     end
   end
 
+  included do
+    if self < Participable
+      participant ->(current_user) { mentioned_users(current_user, load_lazy_references: false) }
+    end
+  end
+
   # Returns the text used as the body of a Note when this object is referenced
   #
   # By default this will be the class name and the result of calling
@@ -41,55 +47,49 @@ module Mentionable
     self
   end
 
-  # Determine whether or not a cross-reference Note has already been created between this Mentionable and
-  # the specified target.
-  def has_mentioned?(target)
-    SystemNoteService.cross_reference_exists?(target, local_reference)
+  def all_references(current_user = self.author, text = self.mentionable_text, load_lazy_references: true)
+    ext = Gitlab::ReferenceExtractor.new(self.project, current_user, load_lazy_references: load_lazy_references)
+    ext.analyze(text)
+    ext
   end
 
-  def mentioned_users(current_user = nil)
-    return [] if mentionable_text.blank?
-
-    ext = Gitlab::ReferenceExtractor.new(self.project, current_user)
-    ext.analyze(mentionable_text)
-    ext.users.uniq
+  def mentioned_users(current_user = nil, load_lazy_references: true)
+    all_references(current_user, load_lazy_references: load_lazy_references).users
   end
 
   # Extract GFM references to other Mentionables from this Mentionable. Always excludes its #local_reference.
-  def references(p = project, current_user = self.author, text = mentionable_text)
+  def referenced_mentionables(current_user = self.author, text = self.mentionable_text, load_lazy_references: true)
     return [] if text.blank?
 
-    ext = Gitlab::ReferenceExtractor.new(p, current_user)
-    ext.analyze(text)
-
-    (ext.issues + ext.merge_requests + ext.commits).uniq - [local_reference]
+    refs = all_references(current_user, text, load_lazy_references: load_lazy_references)
+    (refs.issues + refs.merge_requests + refs.commits) - [local_reference]
   end
 
   # Create a cross-reference Note for each GFM reference to another Mentionable found in +mentionable_text+.
-  def create_cross_references!(p = project, a = author, without = [])
-    refs = references(p)
-
+  def create_cross_references!(author = self.author, without = [], text = self.mentionable_text)
+    refs = referenced_mentionables(author, text)
+    
     # We're using this method instead of Array diffing because that requires
     # both of the object's `hash` values to be the same, which may not be the
     # case for otherwise identical Commit objects.
-    refs.reject! { |ref| without.include?(ref) }
+    refs.reject! { |ref| without.include?(ref) || cross_reference_exists?(ref) }
 
     refs.each do |ref|
-      SystemNoteService.cross_reference(ref, local_reference, a)
+      SystemNoteService.cross_reference(ref, local_reference, author)
     end
   end
 
   # When a mentionable field is changed, creates cross-reference notes that
   # don't already exist
-  def create_new_cross_references!(p = project, a = author)
+  def create_new_cross_references!(author = self.author)
     changes = detect_mentionable_changes
 
     return if changes.empty?
 
     original_text = changes.collect { |_, vals| vals.first }.join(' ')
 
-    preexisting = references(p, self.author, original_text)
-    create_cross_references!(p, a, preexisting)
+    preexisting = referenced_mentionables(author, original_text)
+    create_cross_references!(author, preexisting)
   end
 
   private
@@ -111,4 +111,10 @@ module Mentionable
     # Only include changed fields that are mentionable
     source.select { |key, val| mentionable.include?(key) }
   end
+  
+  # Determine whether or not a cross-reference Note has already been created between this Mentionable and
+  # the specified target.
+  def cross_reference_exists?(target)
+    SystemNoteService.cross_reference_exists?(target, local_reference)
+  end
 end
diff --git a/app/models/concerns/participable.rb b/app/models/concerns/participable.rb
index 7c9597333dd943269a8c83b0e4eeb9bd10930555..85367f89f4f381f4f8d46e2266479eacefb86904 100644
--- a/app/models/concerns/participable.rb
+++ b/app/models/concerns/participable.rb
@@ -12,7 +12,7 @@
 #
 #       # ...
 #
-#       participant :author, :assignee, :mentioned_users, :notes
+#       participant :author, :assignee, :notes, ->(current_user) { mentioned_users(current_user) }
 #     end
 #
 #     issue = Issue.last
@@ -27,7 +27,7 @@ module Participable
 
   module ClassMethods
     def participant(*attrs)
-      participant_attrs.concat(attrs.map(&:to_s))
+      participant_attrs.concat(attrs)
     end
 
     def participant_attrs
@@ -37,21 +37,21 @@ module Participable
 
   # Be aware that this method makes a lot of sql queries.
   # Save result into variable if you are going to reuse it inside same request
-  def participants(current_user = self.author, project = self.project)
+  def participants(current_user = self.author, load_lazy_references: true)
     participants = self.class.participant_attrs.flat_map do |attr|
-      meth = method(attr)
-
       value =
-        if meth.arity == 1 || meth.arity == -1
-          meth.call(current_user)
+        if attr.respond_to?(:call)
+          instance_exec(current_user, &attr)
         else
-          meth.call
+          send(attr)
         end
 
-      participants_for(value, current_user, project)
+      participants_for(value, current_user)
     end.compact.uniq
 
-    if project
+    if load_lazy_references
+      participants = Gitlab::Markdown::ReferenceFilter::LazyReference.load(participants).uniq
+
       participants.select! do |user|
         user.can?(:read_project, project)
       end
@@ -62,14 +62,14 @@ module Participable
 
   private
 
-  def participants_for(value, current_user = nil, project = nil)
+  def participants_for(value, current_user = nil)
     case value
-    when User
+    when User, Gitlab::Markdown::ReferenceFilter::LazyReference
       [value]
     when Enumerable, ActiveRecord::Relation
-      value.flat_map { |v| participants_for(v, current_user, project) }
+      value.flat_map { |v| participants_for(v, current_user) }
     when Participable
-      value.participants(current_user, project)
+      value.participants(current_user, load_lazy_references: false)
     end
   end
 end
diff --git a/app/models/generic_commit_status.rb b/app/models/generic_commit_status.rb
new file mode 100644
index 0000000000000000000000000000000000000000..fa54e3540d07bd99637c76b65d7b53ba4acc58c5
--- /dev/null
+++ b/app/models/generic_commit_status.rb
@@ -0,0 +1,15 @@
+class GenericCommitStatus < CommitStatus
+  before_validation :set_default_values
+
+  # GitHub compatible API
+  alias_attribute :context, :name
+
+  def set_default_values
+    self.context ||= 'default'
+    self.stage ||= 'external'
+  end
+
+  def tags
+    [:external]
+  end
+end
diff --git a/app/models/group.rb b/app/models/group.rb
index 9cd146bb73bf18e718beab0f34594b7ca7a50c8c..465c22d23ac85ae8305112bf9f637fac3693f336 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -64,7 +64,7 @@ class Group < Namespace
   end
 
   def owners
-    @owners ||= group_members.owners.map(&:user)
+    @owners ||= group_members.owners.includes(:user).map(&:user)
   end
 
   def add_users(user_ids, access_level, current_user = nil)
diff --git a/app/models/group_label.rb b/app/models/group_label.rb
new file mode 100644
index 0000000000000000000000000000000000000000..0fc39cb87716245bbcd36c658f92b2f0eb5e0e37
--- /dev/null
+++ b/app/models/group_label.rb
@@ -0,0 +1,9 @@
+class GroupLabel
+  attr_accessor :title, :labels
+  alias_attribute :name, :title
+
+  def initialize(title, labels)
+    @title = title
+    @labels = labels
+  end
+end
diff --git a/app/models/group_milestone.rb b/app/models/group_milestone.rb
index ab055f6b80bf785341fae04cc03cb0692c485811..91844da62e22c6c7a2b3cfc1f799e301f899fd9c 100644
--- a/app/models/group_milestone.rb
+++ b/app/models/group_milestone.rb
@@ -1,22 +1,16 @@
 class GroupMilestone
+  attr_accessor :title, :milestones
+  alias_attribute :name, :title
 
   def initialize(title, milestones)
     @title = title
     @milestones = milestones
   end
 
-  def title
-    @title
-  end
-
   def safe_title
     @title.parameterize
   end
-
-  def milestones
-    @milestones
-  end
-
+  
   def projects
     milestones.map { |milestone| milestone.project }
   end
diff --git a/app/models/issue.rb b/app/models/issue.rb
index fc7e9abe29ea2869079432178f64954e7357c5b2..721831080334cefe53755d5df5d130af734a8931 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -95,4 +95,14 @@ class Issue < ActiveRecord::Base
   def source_project
     project
   end
+
+  # From all notes on this issue, we'll select the system notes about linked
+  # merge requests. Of those, the MRs closing `self` are returned.
+  def closed_by_merge_requests(current_user = nil)
+    return [] unless open?
+
+    notes.system.flat_map do |note|
+      note.all_references(current_user).merge_requests
+    end.uniq.select { |mr| mr.open? && mr.closes_issue?(self) }
+  end
 end
diff --git a/app/models/label.rb b/app/models/label.rb
index 4a22bd53400480af0f2e981f06393565c8de2a61..1bb4b5f55cfa6e89f32e3d354e0abd9b3ad6c83a 100644
--- a/app/models/label.rb
+++ b/app/models/label.rb
@@ -12,6 +12,11 @@
 
 class Label < ActiveRecord::Base
   include Referable
+  # Represents a "No Label" state used for filtering Issues and Merge
+  # Requests that have no label assigned.
+  LabelStruct = Struct.new(:title, :name)
+  None = LabelStruct.new('No Label', 'No Label')
+  Any = LabelStruct.new('Any', '')
 
   DEFAULT_COLOR = '#428BCA'
 
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index eb468c6cd53b162140dbd58c987c9cd1740f72be..21861a46a84ddecdecc51145bf167bfae799f0c3 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -40,7 +40,7 @@ class MergeRequest < ActiveRecord::Base
   after_create :create_merge_request_diff
   after_update :update_merge_request_diff
 
-  delegate :commits, :diffs, :last_commit, :last_commit_short_sha, to: :merge_request_diff, prefix: nil
+  delegate :commits, :diffs, to: :merge_request_diff, prefix: nil
 
   # When this attribute is true some MR validation is ignored
   # It allows us to close or modify broken merge requests
@@ -157,6 +157,18 @@ class MergeRequest < ActiveRecord::Base
     reference
   end
 
+  def last_commit
+    merge_request_diff ? merge_request_diff.last_commit : compare_commits.last
+  end 
+
+  def first_commit
+    merge_request_diff ? merge_request_diff.first_commit : compare_commits.first
+  end 
+
+  def last_commit_short_sha
+    last_commit.short_id
+  end
+
   def validate_branches
     if target_project == source_project && target_branch == source_branch
       errors.add :branch_conflict, "You can not use same project/branch for source and target"
@@ -222,12 +234,8 @@ class MergeRequest < ActiveRecord::Base
     self.target_project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::CLOSED).last
   end
 
-  def open?
-    opened? || reopened?
-  end
-
   def work_in_progress?
-    title =~ /\A\[?WIP\]?:? /i
+    !!(title =~ /\A\[?WIP\]?:? /i)
   end
 
   def mergeable?
@@ -275,7 +283,8 @@ class MergeRequest < ActiveRecord::Base
     attrs = {
       source: source_project.hook_attrs,
       target: target_project.hook_attrs,
-      last_commit: nil
+      last_commit: nil,
+      work_in_progress: work_in_progress?
     }
 
     unless last_commit.nil?
@@ -293,6 +302,10 @@ class MergeRequest < ActiveRecord::Base
     target_project
   end
 
+  def closes_issue?(issue)
+    closes_issues.include?(issue)
+  end
+
   # Return the set of issues that will be closed if this merge request is accepted.
   def closes_issues(current_user = self.author)
     if target_branch == project.default_branch
diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb
index f75f999b0d0275048d103a217c1e94319eef036f..6575d0bc81f1ea118a37a2f9c7bc8f4191ef2b98 100644
--- a/app/models/merge_request_diff.rb
+++ b/app/models/merge_request_diff.rb
@@ -55,6 +55,10 @@ class MergeRequestDiff < ActiveRecord::Base
     commits.first
   end
 
+  def first_commit
+    commits.last
+  end
+
   def last_commit_short_sha
     @last_commit_short_sha ||= last_commit.short_id
   end
@@ -144,12 +148,10 @@ class MergeRequestDiff < ActiveRecord::Base
   # Collect array of Git::Diff objects
   # between target and source branches
   def unmerged_diffs
-    diffs = compare_result.diffs
-    diffs ||= []
-    diffs
-  rescue Gitlab::Git::Diff::TimeoutError => ex
+    compare_result.diffs || []
+  rescue Gitlab::Git::Diff::TimeoutError
     self.state = :timeout
-    diffs = []
+    []
   end
 
   def repository
@@ -165,7 +167,8 @@ class MergeRequestDiff < ActiveRecord::Base
         merge_request.fetch_ref
 
         # Get latest sha of branch from source project
-        source_sha = merge_request.source_project.commit(source_branch).sha
+        source_commit = merge_request.source_project.commit(source_branch)
+        source_sha = source_commit.try(:sha)
 
         Gitlab::CompareResult.new(
           Gitlab::Git::Compare.new(
diff --git a/app/models/milestone.rb b/app/models/milestone.rb
index d979a35084b8b1608bbd541c1f4e45c88a76d506..2ff16e2825c71ff7eb89eb905505048ebeedbd08 100644
--- a/app/models/milestone.rb
+++ b/app/models/milestone.rb
@@ -16,7 +16,9 @@
 class Milestone < ActiveRecord::Base
   # Represents a "No Milestone" state used for filtering Issues and Merge
   # Requests that have no milestone assigned.
-  None = Struct.new(:title).new('No Milestone')
+  MilestoneStruct = Struct.new(:title, :name)
+  None = MilestoneStruct.new('No Milestone', 'No Milestone')
+  Any = MilestoneStruct.new('Any', '')
 
   include InternalId
   include Sortable
@@ -47,6 +49,8 @@ class Milestone < ActiveRecord::Base
     state :active
   end
 
+  alias_attribute :name, :title
+
   class << self
     def search(query)
       query = "%#{query}%"
@@ -101,4 +105,36 @@ class Milestone < ActiveRecord::Base
   def author_id
     nil
   end
+
+  # Sorts the issues for the given IDs.
+  #
+  # This method runs a single SQL query using a CASE statement to update the
+  # position of all issues in the current milestone (scoped to the list of IDs).
+  #
+  # Given the ids [10, 20, 30] this method produces a SQL query something like
+  # the following:
+  #
+  #     UPDATE issues
+  #     SET position = CASE
+  #       WHEN id = 10 THEN 1
+  #       WHEN id = 20 THEN 2
+  #       WHEN id = 30 THEN 3
+  #       ELSE position
+  #     END
+  #     WHERE id IN (10, 20, 30);
+  #
+  # This method expects that the IDs given in `ids` are already Fixnums.
+  def sort_issues(ids)
+    pairs = []
+
+    ids.each_with_index do |id, index|
+      pairs << id
+      pairs << index + 1
+    end
+
+    conditions = 'WHEN id = ? THEN ? ' * ids.length
+
+    issues.where(id: ids).
+      update_all(["position = CASE #{conditions} ELSE position END", *pairs])
+  end
 end
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index 161a16ca61c49fa83538291fc03f42ed838f63a0..5782e649f8be15100eadec612886b6ea2f26e5ae 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -118,6 +118,8 @@ class Namespace < ActiveRecord::Base
     gitlab_shell.add_namespace(path_was)
 
     if gitlab_shell.mv_namespace(path_was, path)
+      Gitlab::UploadsTransfer.new.rename_namespace(path_was, path)
+
       # If repositories moved successfully we need to
       # send update instructions to users.
       # However we cannot allow rollback since we moved namespace dir
@@ -137,7 +139,9 @@ class Namespace < ActiveRecord::Base
   end
 
   def send_update_instructions
-    projects.each(&:send_move_instructions)
+    projects.each do |project|
+      project.send_move_instructions("#{path_was}/#{project.path}")
+    end
   end
 
   def kind
diff --git a/app/models/note.rb b/app/models/note.rb
index 89d81ab1de2c77c71442d9bff0f8cef450c64228..0b3aa30abd745187bc656439d4cddac7969a532a 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -22,14 +22,14 @@ require 'carrierwave/orm/activerecord'
 require 'file_size_validator'
 
 class Note < ActiveRecord::Base
-  include Mentionable
   include Gitlab::CurrentSettings
   include Participable
+  include Mentionable
 
   default_value_for :system, false
 
   attr_mentionable :note
-  participant :author, :mentioned_users
+  participant :author
 
   belongs_to :project
   belongs_to :noteable, polymorphic: true
@@ -60,9 +60,13 @@ class Note < ActiveRecord::Base
   scope :inc_author_project, ->{ includes(:project, :author) }
   scope :inc_author, ->{ includes(:author) }
 
+  scope :with_associations, -> do
+    includes(:author, :noteable, :updated_by,
+             project: [:project_members, { group: [:group_members] }])
+  end
+
   serialize :st_diff
   before_create :set_diff, if: ->(n) { n.line_code.present? }
-  after_update :set_references
 
   class << self
     def discussions_from_notes(notes)
@@ -333,15 +337,13 @@ class Note < ActiveRecord::Base
   end
 
   def noteable_type_name
-    if noteable_type.present?
-      noteable_type.downcase
-    end
+    noteable_type.downcase if noteable_type.present?
   end
 
   # FIXME: Hack for polymorphic associations with STI
   #        For more information visit http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#label-Polymorphic+Associations
-  def noteable_type=(sType)
-    super(sType.to_s.classify.constantize.base_class.to_s)
+  def noteable_type=(noteable_type)
+    super(noteable_type.to_s.classify.constantize.base_class.to_s)
   end
 
   # Reset notes events cache
@@ -357,15 +359,11 @@ class Note < ActiveRecord::Base
     Event.reset_event_cache_for(self)
   end
 
-  def set_references
-    create_new_cross_references!(project, author)
-  end
-
   def system?
     read_attribute(:system)
   end
 
   def editable?
-    !read_attribute(:system)
+    !system?
   end
 end
diff --git a/app/models/project.rb b/app/models/project.rb
index e912c48467d1e47259aa11a4e9ac6febb83cdcae..74b89aad49901a4eb274521b116c5149d125487d 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -40,6 +40,7 @@ class Project < ActiveRecord::Base
   include Referable
   include Sortable
   include AfterCommitQueue
+  include CaseSensitivity
 
   extend Gitlab::ConfigHelper
   extend Enumerize
@@ -118,6 +119,8 @@ class Project < ActiveRecord::Base
   has_many :deploy_keys, through: :deploy_keys_projects
   has_many :users_star_projects, dependent: :destroy
   has_many :starrers, through: :users_star_projects, source: :user
+  has_many :ci_commits, dependent: :destroy, class_name: 'Ci::Commit', foreign_key: :gl_project_id
+  has_many :ci_builds, through: :ci_commits, source: :builds, dependent: :destroy, class_name: 'Ci::Build'
 
   has_one :import_data, dependent: :destroy, class_name: "ProjectImportData"
   has_one :gitlab_ci_project, dependent: :destroy, class_name: "Ci::Project", foreign_key: :gitlab_id
@@ -233,13 +236,19 @@ class Project < ActiveRecord::Base
     end
 
     def find_with_namespace(id)
-      return nil unless id.include?('/')
+      namespace_path, project_path = id.split('/')
 
-      id = id.split('/')
-      namespace = Namespace.find_by(path: id.first)
-      return nil unless namespace
+      return nil if !namespace_path || !project_path
 
-      where(namespace_id: namespace.id).find_by(path: id.second)
+      # Use of unscoped ensures we're not secretly adding any ORDER BYs, which
+      # have a negative impact on performance (and aren't needed for this
+      # query).
+      projects = unscoped.
+        joins(:namespace).
+        iwhere('namespaces.path' => namespace_path)
+
+      projects.where('projects.path' => project_path).take || 
+        projects.iwhere('projects.path' => project_path).take
     end
 
     def visibility_levels
@@ -258,6 +267,20 @@ class Project < ActiveRecord::Base
       name_pattern = Gitlab::Regex::NAMESPACE_REGEX_STR
       %r{(?<project>#{name_pattern}/#{name_pattern})}
     end
+
+    def trending(since = 1.month.ago)
+      # By counting in the JOIN we don't expose the GROUP BY to the outer query.
+      # This means that calls such as "any?" and "count" just return a number of
+      # the total count, instead of the counts grouped per project as a Hash.
+      join_body = "INNER JOIN (
+        SELECT project_id, COUNT(*) AS amount
+        FROM notes
+        WHERE created_at >= #{sanitize(since)}
+        GROUP BY project_id
+      ) join_note_counts ON projects.id = join_note_counts.project_id"
+
+      joins(join_body).reorder('join_note_counts.amount DESC')
+    end
   end
 
   def team
@@ -411,7 +434,7 @@ class Project < ActiveRecord::Base
 
         if template.nil?
           # If no template, we should create an instance. Ex `create_gitlab_ci_service`
-          service = self.send :"create_#{service_name}_service"
+          self.send :"create_#{service_name}_service"
         else
           Service.create_from_template(self.id, template)
         end
@@ -479,8 +502,8 @@ class Project < ActiveRecord::Base
     end
   end
 
-  def send_move_instructions
-    NotificationService.new.project_was_moved(self)
+  def send_move_instructions(old_path_with_namespace)
+    NotificationService.new.project_was_moved(self, old_path_with_namespace)
   end
 
   def owner
@@ -545,7 +568,7 @@ class Project < ActiveRecord::Base
   end
 
   def empty_repo?
-    !repository.exists? || repository.empty?
+    !repository.exists? || !repository.has_visible_content?
   end
 
   def repo
@@ -622,7 +645,7 @@ class Project < ActiveRecord::Base
       # So we basically we mute exceptions in next actions
       begin
         gitlab_shell.mv_repository("#{old_path_with_namespace}.wiki", "#{new_path_with_namespace}.wiki")
-        send_move_instructions
+        send_move_instructions(old_path_with_namespace)
         reset_events_cache
       rescue
         # Returning false does not rollback after_* transaction but gives
@@ -634,6 +657,8 @@ class Project < ActiveRecord::Base
       # db changes in order to prevent out of sync between db and fs
       raise Exception.new('repository cannot be renamed')
     end
+
+    Gitlab::UploadsTransfer.new.rename_project(path_was, path, namespace.path)
   end
 
   def hook_attrs
@@ -736,22 +761,26 @@ class Project < ActiveRecord::Base
   def create_wiki
     ProjectWiki.new(self, self.owner).wiki
     true
-  rescue ProjectWiki::CouldNotCreateWikiError => ex
+  rescue ProjectWiki::CouldNotCreateWikiError
     errors.add(:base, 'Failed create wiki')
     false
   end
 
   def ci_commit(sha)
-    gitlab_ci_project.commits.find_by(sha: sha) if gitlab_ci?
+    ci_commits.find_by(sha: sha)
   end
 
-  def enable_ci(user)
-    # Enable service
+  def ensure_ci_commit(sha)
+    ci_commit(sha) || ci_commits.create(sha: sha)
+  end
+
+  def ensure_gitlab_ci_project
+    gitlab_ci_project || create_gitlab_ci_project
+  end
+
+  def enable_ci
     service = gitlab_ci_service || create_gitlab_ci_service
     service.active = true
     service.save
-
-    # Create Ci::Project
-    Ci::CreateProjectService.new.execute(user, self)
   end
 end
diff --git a/app/models/project_services/bamboo_service.rb b/app/models/project_services/bamboo_service.rb
index d8aedbd2ab48c86726ccd7c0e472af2133859971..d31b12f539e9bb9dee0e3903761d418f7d2004e4 100644
--- a/app/models/project_services/bamboo_service.rb
+++ b/app/models/project_services/bamboo_service.rb
@@ -40,12 +40,19 @@ class BambooService < CiService
   attr_accessor :response
 
   after_save :compose_service_hook, if: :activated?
+  before_update :reset_password
 
   def compose_service_hook
     hook = service_hook || build_service_hook
     hook.save
   end
 
+  def reset_password
+    if bamboo_url_changed? && !password_touched?
+      self.password = nil
+    end
+  end
+
   def title
     'Atlassian Bamboo CI'
   end
diff --git a/app/models/project_services/ci/hip_chat_message.rb b/app/models/project_services/ci/hip_chat_message.rb
index 25c72033eacafd948e84dbb77ccfdc0306fa24eb..cbf325cc5255af0193bbb25155db43de7fe91767 100644
--- a/app/models/project_services/ci/hip_chat_message.rb
+++ b/app/models/project_services/ci/hip_chat_message.rb
@@ -11,14 +11,7 @@ module Ci
     def to_s
       lines = Array.new
       lines.push("<a href=\"#{ci_project_url(project)}\">#{project.name}</a> - ")
-      
-      if commit.matrix?
-        lines.push("<a href=\"#{ci_project_ref_commits_url(project, commit.ref, commit.sha)}\">Commit ##{commit.id}</a></br>")
-      else
-        first_build = commit.builds_without_retry.first
-        lines.push("<a href=\"#{ci_project_build_url(project, first_build)}\">Build '#{first_build.name}' ##{first_build.id}</a></br>")
-      end
-      
+      lines.push("<a href=\"#{ci_namespace_project_commit_url(commit.gl_project.namespace, commit.gl_project, commit.sha)}\">Commit ##{commit.id}</a></br>")
       lines.push("#{commit.short_sha} #{commit.git_author_name} - #{commit.git_commit_message}</br>")
       lines.push("#{humanized_status(commit_status)} in #{commit.duration} second(s).")
       lines.join('')
diff --git a/app/models/project_services/ci/hip_chat_service.rb b/app/models/project_services/ci/hip_chat_service.rb
index 0e6e97394bc67c954e2048a1f206cf9fdcf5905e..f17993d9f3bc7df6451f1fd2c3d801cfad4b231e 100644
--- a/app/models/project_services/ci/hip_chat_service.rb
+++ b/app/models/project_services/ci/hip_chat_service.rb
@@ -49,7 +49,7 @@ module Ci
 
       commit = build.commit
       return unless commit
-      return unless commit.builds_without_retry.include? build
+      return unless commit.latest_builds.include? build
 
       case commit.status.to_sym
       when :failed
diff --git a/app/models/project_services/ci/mail_service.rb b/app/models/project_services/ci/mail_service.rb
index 1bd2f33612b5cb196618c2a909e3e0b1c1ae080a..fd1933010015022130be19cefe1a3e36500ea9bf 100644
--- a/app/models/project_services/ci/mail_service.rb
+++ b/app/models/project_services/ci/mail_service.rb
@@ -48,7 +48,7 @@ module Ci
       # it doesn't make sense to send emails for retried builds
       commit = build.commit
       return unless commit
-      return unless commit.builds_without_retry.include?(build)
+      return unless commit.latest_builds.include?(build)
 
       case build.status.to_sym
       when :failed
@@ -61,7 +61,7 @@ module Ci
     end
 
     def execute(build)
-      build.commit.project_recipients.each do |recipient|
+      build.project_recipients.each do |recipient|
         case build.status.to_sym
         when :success
           mailer.build_success_email(build.id, recipient)
diff --git a/app/models/project_services/ci/slack_message.rb b/app/models/project_services/ci/slack_message.rb
index 757b1961143f846f8bedc453ac8dad58814caf1f..dc050a3fc59973a8890e5f6e09daa833af3931e4 100644
--- a/app/models/project_services/ci/slack_message.rb
+++ b/app/models/project_services/ci/slack_message.rb
@@ -23,15 +23,13 @@ module Ci
     def attachments
       fields = []
 
-      if commit.matrix?
-        commit.builds_without_retry.each do |build|
-          next if build.allow_failure?
-          next unless build.failed?
-          fields << {
-            title: build.name,
-            value: "Build <#{ci_project_build_url(project, build)}|\##{build.id}> failed in #{build.duration.to_i} second(s)."
-          }
-        end
+      commit.latest_builds.each do |build|
+        next if build.allow_failure?
+        next unless build.failed?
+        fields << {
+          title: build.name,
+          value: "Build <#{namespace_project_build_url(build.gl_project.namespace, build.gl_project, build)}|\##{build.id}> failed in #{build.duration.to_i} second(s)."
+        }
       end
 
       [{
@@ -47,12 +45,7 @@ module Ci
 
     def attachment_message
       out = "<#{ci_project_url(project)}|#{project_name}>: "
-      if commit.matrix?
-        out << "Commit <#{ci_project_ref_commits_url(project, commit.ref, commit.sha)}|\##{commit.id}> "
-      else
-        build = commit.builds_without_retry.first
-        out << "Build <#{ci_project_build_url(project, build)}|\##{build.id}> "
-      end
+      out << "Commit <#{ci_namespace_project_commit_url(commit.gl_project.namespace, commit.gl_project, commit.sha)}|\##{commit.id}> "
       out << "(<#{commit_sha_link}|#{commit.short_sha}>) "
       out << "of <#{commit_ref_link}|#{commit.ref}> "
       out << "by #{commit.git_author_name} " if commit.git_author_name
diff --git a/app/models/project_services/ci/slack_service.rb b/app/models/project_services/ci/slack_service.rb
index 76db573dc17a52b7e5b0ab63dd58e2b09ba3ee62..ee8e49888263c31d1daa95a07c785feaf587576e 100644
--- a/app/models/project_services/ci/slack_service.rb
+++ b/app/models/project_services/ci/slack_service.rb
@@ -48,7 +48,7 @@ module Ci
 
       commit = build.commit
       return unless commit
-      return unless commit.builds_without_retry.include?(build)
+      return unless commit.latest_builds.include?(build)
 
       case commit.status.to_sym
       when :failed
diff --git a/app/models/project_services/gitlab_ci_service.rb b/app/models/project_services/gitlab_ci_service.rb
index 23ab206efbacd0611328dca71ab5478093259bf9..4dcd16ede3a29d5cb835b51860177747068b316c 100644
--- a/app/models/project_services/gitlab_ci_service.rb
+++ b/app/models/project_services/gitlab_ci_service.rb
@@ -22,12 +22,17 @@ class GitlabCiService < CiService
   include Gitlab::Application.routes.url_helpers
 
   after_save :compose_service_hook, if: :activated?
+  after_save :ensure_gitlab_ci_project, if: :activated?
 
   def compose_service_hook
     hook = service_hook || build_service_hook
     hook.save
   end
 
+  def ensure_gitlab_ci_project
+    project.ensure_gitlab_ci_project
+  end
+
   def supported_events
     %w(push tag_push)
   end
@@ -35,19 +40,10 @@ class GitlabCiService < CiService
   def execute(data)
     return unless supported_events.include?(data[:object_kind])
 
-    sha = data[:checkout_sha]
-
-    if sha.present?
-      file = ci_yaml_file(sha)
-
-      if file && file.data
-        data.merge!(ci_yaml_file: file.data)
-      end
-    end
-
-    ci_project = Ci::Project.find_by(gitlab_id: project.id)
+    ci_project = project.gitlab_ci_project
     if ci_project
-      Ci::CreateCommitService.new.execute(ci_project, data)
+      current_user = User.find_by(id: data[:user_id])
+      Ci::CreateCommitService.new.execute(ci_project, current_user, data)
     end
   end
 
@@ -58,7 +54,7 @@ class GitlabCiService < CiService
   end
 
   def get_ci_commit(sha, ref)
-    Ci::Project.find(project.gitlab_ci_project).commits.find_by_sha_and_ref!(sha, ref)
+    Ci::Project.find(project.gitlab_ci_project).commits.find_by_sha!(sha)
   end
 
   def commit_status(sha, ref)
@@ -67,25 +63,6 @@ class GitlabCiService < CiService
     :error
   end
 
-  def fork_registration(new_project, current_user)
-    params = OpenStruct.new({
-      id:                  new_project.id,
-      name_with_namespace: new_project.name_with_namespace,
-      path_with_namespace: new_project.path_with_namespace,
-      web_url:             new_project.web_url,
-      default_branch:      new_project.default_branch,
-      ssh_url_to_repo:     new_project.ssh_url_to_repo
-    })
-
-    ci_project = Ci::Project.find_by!(gitlab_id: project.id)
-
-    Ci::CreateProjectService.new.execute(
-      current_user,
-      params,
-      ci_project
-    )
-  end
-
   def commit_coverage(sha, ref)
     get_ci_commit(sha, ref).coverage
   rescue ActiveRecord::RecordNotFound
@@ -94,7 +71,7 @@ class GitlabCiService < CiService
 
   def build_page(sha, ref)
     if project.gitlab_ci_project.present?
-      ci_project_ref_commits_url(project.gitlab_ci_project, ref, sha)
+      ci_namespace_project_commit_url(project.namespace, project, sha)
     end
   end
 
@@ -113,14 +90,4 @@ class GitlabCiService < CiService
   def fields
     []
   end
-
-  private
-
-  def ci_yaml_file(sha)
-    repository.blob_at(sha, '.gitlab-ci.yml')
-  end
-
-  def repository
-    project.repository
-  end
 end
diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb
index 7a15a861abc56d539b94e61a81ea5868f0818eac..af2840a57f029dcce74014400767cbf8e6752fab 100644
--- a/app/models/project_services/hipchat_service.rb
+++ b/app/models/project_services/hipchat_service.rb
@@ -85,17 +85,16 @@ class HipchatService < Service
   def create_message(data)
     object_kind = data[:object_kind]
 
-    message = \
-      case object_kind
-      when "push", "tag_push"
-        create_push_message(data)
-      when "issue"
-        create_issue_message(data) unless is_update?(data)
-      when "merge_request"
-        create_merge_request_message(data) unless is_update?(data)
-      when "note"
-        create_note_message(data)
-      end
+    case object_kind
+    when "push", "tag_push"
+      create_push_message(data)
+    when "issue"
+      create_issue_message(data) unless is_update?(data)
+    when "merge_request"
+      create_merge_request_message(data) unless is_update?(data)
+    when "note"
+      create_note_message(data)
+    end
   end
 
   def create_push_message(push)
@@ -167,8 +166,6 @@ class HipchatService < Service
     obj_attr = data[:object_attributes]
     obj_attr = HashWithIndifferentAccess.new(obj_attr)
     merge_request_id = obj_attr[:iid]
-    source_branch = obj_attr[:source_branch]
-    target_branch = obj_attr[:target_branch]
     state = obj_attr[:state]
     description = obj_attr[:description]
     title = obj_attr[:title]
@@ -194,8 +191,6 @@ class HipchatService < Service
     data = HashWithIndifferentAccess.new(data)
     user_name = data[:user][:name]
 
-    repo_attr = HashWithIndifferentAccess.new(data[:repository])
-
     obj_attr = HashWithIndifferentAccess.new(data[:object_attributes])
     note = obj_attr[:note]
     note_url = obj_attr[:url]
diff --git a/app/models/project_services/teamcity_service.rb b/app/models/project_services/teamcity_service.rb
index 3c002a1634b8c9535e577f829145e27f1c224c9b..0b0224612505e18f81386b5442103193865f5d29 100644
--- a/app/models/project_services/teamcity_service.rb
+++ b/app/models/project_services/teamcity_service.rb
@@ -37,12 +37,19 @@ class TeamcityService < CiService
   attr_accessor :response
 
   after_save :compose_service_hook, if: :activated?
+  before_update :reset_password
 
   def compose_service_hook
     hook = service_hook || build_service_hook
     hook.save
   end
 
+  def reset_password
+    if teamcity_url_changed? && !password_touched?
+      self.password = nil
+    end
+  end
+
   def title
     'JetBrains TeamCity CI'
   end
diff --git a/app/models/project_team.rb b/app/models/project_team.rb
index 56e49af23246f79775ae3983c7c806797bd3741e..9f380a382cb40f0acaf855d659ebd034903b26a2 100644
--- a/app/models/project_team.rb
+++ b/app/models/project_team.rb
@@ -135,15 +135,32 @@ class ProjectTeam
     !!find_member(user_id)
   end
 
+  def human_max_access(user_id)
+    Gitlab::Access.options.key max_member_access(user_id)
+  end
+
+  # This method assumes project and group members are eager loaded for optimal
+  # performance.
   def max_member_access(user_id)
     access = []
-    access << project.project_members.find_by(user_id: user_id).try(:access_field)
+
+    project.project_members.each do |member|
+      if member.user_id == user_id
+        access << member.access_field if member.access_field
+        break
+      end
+    end
 
     if group
-      access << group.group_members.find_by(user_id: user_id).try(:access_field)
+      group.group_members.each do |member|
+        if member.user_id == user_id
+          access << member.access_field if member.access_field
+          break
+        end
+      end
     end
 
-    access.compact.max
+    access.max
   end
 
   private
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 79b48ebfedfe6bb833ed85005c6ae84c06646072..88d3d73a40efd5b905ed3050bd0f13f75c883ab5 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -8,6 +8,14 @@ class Repository
 
   attr_accessor :raw_repository, :path_with_namespace, :project
 
+  def self.clean_old_archives
+    repository_downloads_path = Gitlab.config.gitlab.repository_downloads_path
+
+    return unless File.directory?(repository_downloads_path)
+
+    Gitlab::Popen.popen(%W(find #{repository_downloads_path} -not -path #{repository_downloads_path} -mmin +120 -delete))
+  end
+
   def initialize(path_with_namespace, default_branch = nil, project = nil)
     @path_with_namespace = path_with_namespace
     @project = project
@@ -36,6 +44,19 @@ class Repository
     raw_repository.empty?
   end
 
+  #
+  # Git repository can contains some hidden refs like:
+  #   /refs/notes/*
+  #   /refs/git-as-svn/*
+  #   /refs/pulls/*
+  # This refs by default not visible in project page and not cloned to client side.
+  #
+  # This method return true if repository contains some content visible in project page.
+  #
+  def has_visible_content?
+    !raw_repository.branches.empty?
+  end
+
   def commit(id = 'HEAD')
     return nil unless raw_repository
     commit = Gitlab::Git::Commit.find(raw_repository, id)
@@ -269,14 +290,6 @@ class Repository
   end
 
   # Remove archives older than 2 hours
-  def clean_old_archives
-    repository_downloads_path = Gitlab.config.gitlab.repository_downloads_path
-
-    return unless File.directory?(repository_downloads_path)
-
-    Gitlab::Popen.popen(%W(find #{repository_downloads_path} -not -path #{repository_downloads_path} -mmin +120 -delete))
-  end
-
   def branches_sorted_by(value)
     case value
     when 'recently_updated'
@@ -312,13 +325,7 @@ class Repository
   end
 
   def blob_for_diff(commit, diff)
-    file = blob_at(commit.id, diff.new_path)
-
-    unless file
-      file = prev_blob_for_diff(commit, diff)
-    end
-
-    file
+    blob_at(commit.id, diff.file_path)
   end
 
   def prev_blob_for_diff(commit, diff)
@@ -373,11 +380,25 @@ class Repository
     @root_ref ||= raw_repository.root_ref
   end
 
-  def commit_file(user, path, content, message, branch)
+  def commit_dir(user, path, message, branch)
     commit_with_hooks(user, branch) do |ref|
-      path[0] = '' if path[0] == '/'
+      committer = user_to_committer(user)
+      options = {}
+      options[:committer] = committer
+      options[:author] = committer
 
-      committer = user_to_comitter(user)
+      options[:commit] = {
+        message: message,
+        branch: ref,
+      }
+
+      raw_repository.mkdir(path, options)
+    end
+  end
+
+  def commit_file(user, path, content, message, branch, update)
+    commit_with_hooks(user, branch) do |ref|
+      committer = user_to_committer(user)
       options = {}
       options[:committer] = committer
       options[:author] = committer
@@ -388,7 +409,8 @@ class Repository
 
       options[:file] = {
         content: content,
-        path: path
+        path: path,
+        update: update
       }
 
       Gitlab::Git::Blob.commit(raw_repository, options)
@@ -397,9 +419,7 @@ class Repository
 
   def remove_file(user, path, message, branch)
     commit_with_hooks(user, branch) do |ref|
-      path[0] = '' if path[0] == '/'
-
-      committer = user_to_comitter(user)
+      committer = user_to_committer(user)
       options = {}
       options[:committer] = committer
       options[:author] = committer
@@ -416,7 +436,7 @@ class Repository
     end
   end
 
-  def user_to_comitter(user)
+  def user_to_committer(user)
     {
       email: user.email,
       name: user.name,
@@ -467,6 +487,10 @@ class Repository
     end
   end
 
+  def merge_base(first_commit_id, second_commit_id)
+    rugged.merge_base(first_commit_id, second_commit_id)
+  end
+
   def search_files(query, ref)
     offset = 2
     args = %W(git grep -i -n --before-context #{offset} --after-context #{offset} #{query} #{ref || root_ref})
@@ -549,7 +573,7 @@ class Repository
 
       # Run GitLab post receive hook
       post_receive_hook = Gitlab::Git::Hook.new('post-receive', path_to_repo)
-      status = post_receive_hook.trigger(gl_id, oldrev, newrev, ref)
+      post_receive_hook.trigger(gl_id, oldrev, newrev, ref)
     else
       # Remove tmp ref and return error to user
       rugged.references.delete(tmp_ref)
diff --git a/app/models/service.rb b/app/models/service.rb
index 60fcc9d2857a50dfdff4a9cddc51ab62b1d3b3fc..d610abd16837ce1760d2a4585050f2b0b10f0944 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -33,6 +33,8 @@ class Service < ActiveRecord::Base
 
   after_initialize :initialize_properties
 
+  after_commit :reset_updated_properties
+
   belongs_to :project
   has_one :service_hook
 
@@ -103,6 +105,7 @@ class Service < ActiveRecord::Base
 
   # Provide convenient accessor methods
   # for each serialized property.
+  # Also keep track of updated properties in a similar way as ActiveModel::Dirty
   def self.prop_accessor(*args)
     args.each do |arg|
       class_eval %{
@@ -111,12 +114,39 @@ class Service < ActiveRecord::Base
         end
 
         def #{arg}=(value)
+          updated_properties['#{arg}'] = #{arg} unless #{arg}_changed?
           self.properties['#{arg}'] = value
         end
+
+        def #{arg}_changed?
+          #{arg}_touched? && #{arg} != #{arg}_was
+        end
+
+        def #{arg}_touched?
+          updated_properties.include?('#{arg}')
+        end
+
+        def #{arg}_was
+          updated_properties['#{arg}']
+        end
       }
     end
   end
 
+  # Returns a hash of the properties that have been assigned a new value since last save,
+  # indicating their original values (attr => original value).
+  # ActiveRecord does not provide a mechanism to track changes in serialized keys, 
+  # so we need a specific implementation for service properties.
+  # This allows to track changes to properties set with the accessor methods,
+  # but not direct manipulation of properties hash.
+  def updated_properties
+    @updated_properties ||= ActiveSupport::HashWithIndifferentAccess.new
+  end
+
+  def reset_updated_properties
+    @updated_properties = nil
+  end
+  
   def async_execute(data)
     return unless supported_events.include?(data[:object_kind])
 
diff --git a/app/models/user.rb b/app/models/user.rb
index 55c095d7d5798b590e8e1bebaf8e093c2034c9ba..81a47c7bb6bf211f386ec826d463c2b782ce19f4 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -54,6 +54,7 @@
 #  public_email               :string(255)      default(""), not null
 #  dashboard                  :integer          default(0)
 #  project_view               :integer          default(0)
+#  layout                     :integer          default(0)
 #
 
 require 'carrierwave/orm/activerecord'
@@ -67,6 +68,7 @@ class User < ActiveRecord::Base
   include Referable
   include Sortable
   include TokenAuthenticatable
+  include CaseSensitivity
 
   default_value_for :admin, false
   default_value_for :can_create_group, gitlab_config.default_can_create_group
@@ -129,6 +131,8 @@ class User < ActiveRecord::Base
   has_many :assigned_issues,          dependent: :destroy, foreign_key: :assignee_id, class_name: "Issue"
   has_many :assigned_merge_requests,  dependent: :destroy, foreign_key: :assignee_id, class_name: "MergeRequest"
   has_many :oauth_applications, class_name: 'Doorkeeper::Application', as: :owner, dependent: :destroy
+  has_one  :abuse_report,             dependent: :destroy
+  has_many :ci_builds,                dependent: :nullify, class_name: 'Ci::Build'
 
 
   #
@@ -170,13 +174,16 @@ class User < ActiveRecord::Base
   after_create :post_create_hook
   after_destroy :post_destroy_hook
 
+  # User's Layout preference
+  enum layout: [:fixed, :fluid]
+
   # User's Dashboard preference
   # Note: When adding an option, it MUST go on the end of the array.
-  enum dashboard: [:projects, :stars]
+  enum dashboard: [:projects, :stars, :project_activity, :starred_project_activity]
 
   # User's Project preference
   # Note: When adding an option, it MUST go on the end of the array.
-  enum project_view: [:readme, :activity]
+  enum project_view: [:readme, :activity, :files]
 
   alias_attribute :private_token, :authentication_token
 
@@ -267,8 +274,13 @@ class User < ActiveRecord::Base
     end
 
     def by_login(login)
-      where('lower(username) = :value OR lower(email) = :value',
-            value: login.to_s.downcase).first
+      return nil unless login
+
+      if login.include?('@'.freeze)
+        unscoped.iwhere(email: login).take
+      else
+        unscoped.iwhere(username: login).take
+      end
     end
 
     def find_by_username!(username)
@@ -327,6 +339,10 @@ class User < ActiveRecord::Base
     @reset_token
   end
 
+  def recently_sent_password_reset?
+    reset_password_sent_at.present? && reset_password_sent_at >= 1.minute.ago
+  end
+
   def disable_two_factor!
     update_attributes(
       two_factor_enabled:        false,
@@ -690,23 +706,20 @@ class User < ActiveRecord::Base
   end
 
   def toggle_star(project)
-    user_star_project = users_star_projects.
-      where(project: project, user: self).take
-    if user_star_project
-      user_star_project.destroy
-    else
-      UsersStarProject.create!(project: project, user: self)
+    UsersStarProject.transaction do
+      user_star_project = users_star_projects.
+          where(project: project, user: self).lock(true).first
+
+      if user_star_project
+        user_star_project.destroy
+      else
+        UsersStarProject.create!(project: project, user: self)
+      end
     end
   end
 
   def manageable_namespaces
-    @manageable_namespaces ||=
-      begin
-        namespaces = []
-        namespaces << namespace
-        namespaces += owned_groups
-        namespaces += masters_groups
-      end
+    @manageable_namespaces ||= [namespace] + owned_groups + masters_groups
   end
 
   def namespaces
diff --git a/app/services/archive_repository_service.rb b/app/services/archive_repository_service.rb
index e1b41527d8dc5d5efb86d47a1f11186de9845a6c..2160bf13e6d281cbc073e3e827d4bdee8d7558f3 100644
--- a/app/services/archive_repository_service.rb
+++ b/app/services/archive_repository_service.rb
@@ -7,19 +7,12 @@ class ArchiveRepositoryService
   end
 
   def execute(options = {})
-    project.repository.clean_old_archives
+    RepositoryArchiveCacheWorker.perform_async
 
-    raise "No archive file path" unless file_path
+    metadata = project.repository.archive_metadata(ref, storage_path, format)
+    raise "Repository or ref not found" if metadata.empty?
 
-    return file_path if archived?
-
-    unless archiving?
-      RepositoryArchiveWorker.perform_async(project.id, ref, format)
-    end
-
-    archived = wait_until_archived(options[:timeout] || 5.0)
-
-    file_path if archived
+    metadata
   end
 
   private
@@ -27,36 +20,4 @@ class ArchiveRepositoryService
   def storage_path
     Gitlab.config.gitlab.repository_downloads_path
   end
-
-  def file_path
-    @file_path ||= project.repository.archive_file_path(ref, storage_path, format)
-  end
-
-  def pid_file_path
-    @pid_file_path ||= project.repository.archive_pid_file_path(ref, storage_path, format)
-  end
-
-  def archived?
-    File.exist?(file_path)
-  end
-
-  def archiving?
-    File.exist?(pid_file_path)
-  end
-
-  def wait_until_archived(timeout = 5.0)
-    return archived? if timeout == 0.0
-    
-    t1 = Time.now
-
-    begin
-      sleep 0.1
-
-      success = archived?
-
-      t2 = Time.now
-    end until success || t2 - t1 >= timeout
-
-    success
-  end
 end
diff --git a/app/services/ci/create_builds_service.rb b/app/services/ci/create_builds_service.rb
new file mode 100644
index 0000000000000000000000000000000000000000..912eb6258a4aea905ee4b5ff1da73969e7a2a472
--- /dev/null
+++ b/app/services/ci/create_builds_service.rb
@@ -0,0 +1,39 @@
+module Ci
+  class CreateBuildsService
+    def execute(commit, stage, ref, tag, user, trigger_request, status)
+      builds_attrs = commit.config_processor.builds_for_stage_and_ref(stage, ref, tag)
+
+      # check when to create next build
+      builds_attrs = builds_attrs.select do |build_attrs|
+        case build_attrs[:when]
+        when 'on_success'
+          status == 'success'
+        when 'on_failure'
+          status == 'failed'
+        when 'always'
+          %w(success failed).include?(status)
+        end
+      end
+
+      builds_attrs.map do |build_attrs|
+        # don't create the same build twice
+        unless commit.builds.find_by(ref: ref, tag: tag, trigger_request: trigger_request, name: build_attrs[:name])
+          build_attrs.slice!(:name,
+                             :commands,
+                             :tag_list,
+                             :options,
+                             :allow_failure,
+                             :stage,
+                             :stage_idx)
+
+          build_attrs.merge!(ref: ref,
+                             tag: tag,
+                             trigger_request: trigger_request,
+                             user: user)
+
+          commit.builds.create!(build_attrs)
+        end
+      end
+    end
+  end
+end
diff --git a/app/services/ci/create_commit_service.rb b/app/services/ci/create_commit_service.rb
index 0a1abf89a95b14786bd03e10d6715fdf0f9de65a..479a2d6defc5e28b722512d02d9621178f83c8bd 100644
--- a/app/services/ci/create_commit_service.rb
+++ b/app/services/ci/create_commit_service.rb
@@ -1,7 +1,6 @@
 module Ci
   class CreateCommitService
-    def execute(project, params)
-      before_sha = params[:before]
+    def execute(project, user, params)
       sha = params[:checkout_sha] || params[:after]
       origin_ref = params[:ref]
       
@@ -16,34 +15,13 @@ module Ci
         return false
       end
 
-      commit = project.commits.find_by_sha_and_ref(sha, ref)
-
-      # Create commit if not exists yet
-      unless commit
-        data = {
-          ref: ref,
-          sha: sha,
-          tag: origin_ref.start_with?('refs/tags/'),
-          before_sha: before_sha,
-          push_data: {
-            before: before_sha,
-            after: sha,
-            ref: ref,
-            user_name: params[:user_name],
-            user_email: params[:user_email],
-            repository: params[:repository],
-            commits: params[:commits],
-            total_commits_count: params[:total_commits_count],
-            ci_yaml_file: params[:ci_yaml_file]
-          }
-        }
-
-        commit = project.commits.create(data)
+      tag = origin_ref.start_with?('refs/tags/')
+      commit = project.gl_project.ensure_ci_commit(sha)
+      unless commit.skip_ci?
+        commit.update_committed!
+        commit.create_builds(ref, tag, user)
       end
 
-      commit.update_committed!
-      commit.create_builds unless commit.builds.any?
-
       commit
     end
   end
diff --git a/app/services/ci/create_project_service.rb b/app/services/ci/create_project_service.rb
deleted file mode 100644
index f42babd238827bb86aca9fbc84bf334e8d3270e4..0000000000000000000000000000000000000000
--- a/app/services/ci/create_project_service.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-module Ci
-  class CreateProjectService
-    include Gitlab::Application.routes.url_helpers
-
-    def execute(current_user, params, forked_project = nil)
-      @project = Ci::Project.parse(params)
-
-      Ci::Project.transaction do
-        @project.save!
-
-        gl_project = ::Project.find(@project.gitlab_id)
-        gl_project.build_missing_services
-        gl_project.gitlab_ci_service.update_attributes(active: true)
-      end
-
-      if forked_project
-        # Copy settings
-        settings = forked_project.attributes.select do |attr_name, value|
-          ["public", "shared_runners_enabled", "allow_git_fetch"].include? attr_name
-        end
-
-        @project.update(settings)
-      end
-
-      Ci::EventService.new.create_project(current_user, @project)
-
-      @project
-    end
-  end
-end
diff --git a/app/services/ci/create_trigger_request_service.rb b/app/services/ci/create_trigger_request_service.rb
index 9bad09f2f54b35fd4ff1d6b3684621040d4f2e7b..4b86cb0a1f54edb4a6a5f7e235c0c2e728cece39 100644
--- a/app/services/ci/create_trigger_request_service.rb
+++ b/app/services/ci/create_trigger_request_service.rb
@@ -1,15 +1,20 @@
 module Ci
   class CreateTriggerRequestService
     def execute(project, trigger, ref, variables = nil)
-      commit = project.commits.where(ref: ref).last
+      commit = project.gl_project.commit(ref)
       return unless commit
 
+      # check if ref is tag
+      tag = project.gl_project.repository.find_tag(ref).present?
+
+      ci_commit = project.gl_project.ensure_ci_commit(commit.sha)
+
       trigger_request = trigger.trigger_requests.create!(
-        commit: commit,
-        variables: variables
+        variables: variables,
+        commit: ci_commit,
       )
 
-      if commit.create_builds(trigger_request)
+      if ci_commit.create_builds(ref, tag, nil, trigger_request)
         trigger_request
       end
     end
diff --git a/app/services/ci/register_build_service.rb b/app/services/ci/register_build_service.rb
index 33f1c1e918d6e6bd51de95d9f27c7cf97771f47f..7beb098659c44f70a2e865133fa64e7b85832d26 100644
--- a/app/services/ci/register_build_service.rb
+++ b/app/services/ci/register_build_service.rb
@@ -8,18 +8,18 @@ module Ci
       builds =
         if current_runner.shared?
           # don't run projects which have not enables shared runners
-          builds.includes(:project).where(ci_projects: { shared_runners_enabled: true })
+          builds.joins(commit: { gl_project: :gitlab_ci_project }).where(ci_projects: { shared_runners_enabled: true })
         else
           # do run projects which are only assigned to this runner
-          builds.where(project_id: current_runner.projects)
+          builds.joins(:commit).where(ci_commits: { gl_project_id: current_runner.gl_projects_ids })
         end
 
       builds = builds.order('created_at ASC')
 
       build = builds.find do |build|
-        (build.tag_list - current_runner.tag_list).empty?
+        build.can_be_served?(current_runner)
       end
-        
+
 
       if build
         # In case when 2 runners try to assign the same build, second runner will be declined
diff --git a/app/services/ci/web_hook_service.rb b/app/services/ci/web_hook_service.rb
index 87984b20fa16c747bb27fffd0e1b1a8c80ece883..92e6df442b4f3f9ee929077a254c81684ed3571c 100644
--- a/app/services/ci/web_hook_service.rb
+++ b/app/services/ci/web_hook_service.rb
@@ -27,9 +27,8 @@ module Ci
         project_name: project.name,
         gitlab_url: project.gitlab_url,
         ref: build.ref,
-        sha: build.sha,
         before_sha: build.before_sha,
-        push_data: build.commit.push_data
+        sha: build.sha,
       })
     end
   end
diff --git a/app/services/files/base_service.rb b/app/services/files/base_service.rb
index 7aecee217d856f12c967a6826e42bf063a250cd5..008833eed80aa9705256926ac6f07e9c8c0f08df 100644
--- a/app/services/files/base_service.rb
+++ b/app/services/files/base_service.rb
@@ -21,7 +21,7 @@ module Files
         create_target_branch
       end
 
-      if sha = commit
+      if commit
         success
       else
         error("Something went wrong. Your changes were not committed")
diff --git a/app/services/files/create_dir_service.rb b/app/services/files/create_dir_service.rb
new file mode 100644
index 0000000000000000000000000000000000000000..71272fb57075e0be96b0e702585f4564cbcced5a
--- /dev/null
+++ b/app/services/files/create_dir_service.rb
@@ -0,0 +1,9 @@
+require_relative "base_service"
+
+module Files
+  class CreateDirService < Files::BaseService
+    def commit
+      repository.commit_dir(current_user, @file_path, @commit_message, @target_branch)
+    end
+  end
+end
diff --git a/app/services/files/create_service.rb b/app/services/files/create_service.rb
index ffbb59932794d865814ea2afc82d135c6894620c..c8e3a910bbade941f73101bc168579d273c45534 100644
--- a/app/services/files/create_service.rb
+++ b/app/services/files/create_service.rb
@@ -3,7 +3,7 @@ require_relative "base_service"
 module Files
   class CreateService < Files::BaseService
     def commit
-      repository.commit_file(current_user, @file_path, @file_content, @commit_message, @target_branch)
+      repository.commit_file(current_user, @file_path, @file_content, @commit_message, @target_branch, false)
     end
 
     def validate
diff --git a/app/services/files/update_service.rb b/app/services/files/update_service.rb
index a20903c6f02c13e8f4e014a56ce307fe1d829c3d..1960dc7d949c1abb2612d024227da98050a1c5e9 100644
--- a/app/services/files/update_service.rb
+++ b/app/services/files/update_service.rb
@@ -3,7 +3,7 @@ require_relative "base_service"
 module Files
   class UpdateService < Files::BaseService
     def commit
-      repository.commit_file(current_user, @file_path, @file_content, @commit_message, @target_branch)
+      repository.commit_file(current_user, @file_path, @file_content, @commit_message, @target_branch, true)
     end
   end
 end
diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb
index 8193b6e192dfbf841f464533a58d9874bd564092..3de7bb9dcaaa80f2ef3b6f5baf00e10c0f573e0b 100644
--- a/app/services/git_push_service.rb
+++ b/app/services/git_push_service.rb
@@ -49,16 +49,19 @@ class GitPushService
     elsif push_to_existing_branch?(ref, oldrev)
       # Collect data for this git push
       @push_commits = project.repository.commits_between(oldrev, newrev)
-      project.update_merge_requests(oldrev, newrev, ref, @user)
       process_commit_messages(ref)
     end
 
+    # Update merge requests that may be affected by this push. A new branch
+    # could cause the last commit of a merge request to change.
+    project.update_merge_requests(oldrev, newrev, ref, @user)
+
     @push_data = build_push_data(oldrev, newrev, ref)
 
     # If CI was disabled but .gitlab-ci.yml file was pushed
     # we enable CI automatically
     if !project.gitlab_ci? && gitlab_ci_yaml?(newrev)
-      project.enable_ci(user)
+      project.enable_ci
     end
 
     EventCreateService.new.push(project, user, @push_data)
@@ -74,48 +77,30 @@ class GitPushService
   def process_commit_messages(ref)
     is_default_branch = is_default_branch?(ref)
 
-    @push_commits.each do |commit|
-      # Close issues if these commits were pushed to the project's default branch and the commit message matches the
-      # closing regex. Exclude any mentioned Issues from cross-referencing even if the commits are being pushed to
-      # a different branch.
-      issues_to_close = commit.closes_issues(user)
+    authors = Hash.new do |hash, commit|
+      email = commit.author_email
+      next hash[email] if hash.has_key?(email)
 
-      # Load commit author only if needed.
-      # For push with 1k commits it prevents 900+ requests in database
-      author = nil
+      hash[email] = commit_user(commit)
+    end
 
+    @push_commits.each do |commit|
       # Keep track of the issues that will be actually closed because they are on a default branch.
       # Hence, when creating cross-reference notes, the not-closed issues (on non-default branches)
       # will also have cross-reference.
-      actually_closed_issues = []
-
-      if issues_to_close.present? && is_default_branch
-        author ||= commit_user(commit)
-        actually_closed_issues = issues_to_close
-        issues_to_close.each do |issue|
-          Issues::CloseService.new(project, author, {}).execute(issue, commit)
+      closed_issues = []
+
+      if is_default_branch
+        # Close issues if these commits were pushed to the project's default branch and the commit message matches the
+        # closing regex. Exclude any mentioned Issues from cross-referencing even if the commits are being pushed to
+        # a different branch.
+        closed_issues = commit.closes_issues(user)
+        closed_issues.each do |issue|
+          Issues::CloseService.new(project, authors[commit], {}).execute(issue, commit)
         end
       end
 
-      if project.default_issues_tracker?
-        create_cross_reference_notes(commit, actually_closed_issues)
-      end
-    end
-  end
-
-  def create_cross_reference_notes(commit, issues_to_close)
-    # Create cross-reference notes for any other references than those given in issues_to_close.
-    # Omit any issues that were referenced in an issue-closing phrase, or have already been
-    # mentioned from this commit (probably from this commit being pushed to a different branch).
-    refs = commit.references(project, user) - issues_to_close
-    refs.reject! { |r| commit.has_mentioned?(r) }
-
-    if refs.present?
-      author ||= commit_user(commit)
-
-      refs.each do |r|
-        SystemNoteService.cross_reference(r, commit, author)
-      end
+      commit.create_cross_references!(authors[commit], closed_issues)
     end
   end
 
diff --git a/app/services/issues/create_service.rb b/app/services/issues/create_service.rb
index 1ea4b72216c6a2e9edeaa682c43b4da8b1e21686..bcb380d3215da95c3b07a1f38105283a8b620be6 100644
--- a/app/services/issues/create_service.rb
+++ b/app/services/issues/create_service.rb
@@ -10,7 +10,7 @@ module Issues
         issue.update_attributes(label_ids: label_params)
         notification_service.new_issue(issue, current_user)
         event_service.open_issue(issue, current_user)
-        issue.create_cross_references!(issue.project, current_user)
+        issue.create_cross_references!(current_user)
         execute_hooks(issue, 'open')
       end
 
diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb
index 2fc6ef7f35642913776680d7e9283bd1d9a21c65..2b5426ad4528f3d33b503840cc4b9c62c88e21be 100644
--- a/app/services/issues/update_service.rb
+++ b/app/services/issues/update_service.rb
@@ -35,7 +35,7 @@ module Issues
           create_title_change_note(issue, issue.previous_changes['title'].first)
         end
 
-        issue.create_new_cross_references!(issue.project, current_user)
+        issue.create_new_cross_references!
         execute_hooks(issue, 'update')
       end
 
diff --git a/app/services/labels/group_service.rb b/app/services/labels/group_service.rb
new file mode 100644
index 0000000000000000000000000000000000000000..b26cee24d56bbd1ab330744e74cc0b558a2f6fc8
--- /dev/null
+++ b/app/services/labels/group_service.rb
@@ -0,0 +1,26 @@
+module Labels
+  class GroupService < ::BaseService
+    def initialize(project_labels)
+      @project_labels = project_labels.group_by(&:title)
+    end
+
+    def execute
+      build(@project_labels)
+    end
+
+    def label(title)
+      if title
+        group_label = @project_labels[title].group_by(&:title)
+        build(group_label).first
+      else
+        nil
+      end
+    end
+
+    private
+
+    def build(label)
+      label.map { |title, labels| GroupLabel.new(title, labels) }
+    end
+  end
+end
diff --git a/app/services/merge_requests/create_service.rb b/app/services/merge_requests/create_service.rb
index 9651b16462cb61b2225111e1b1c6c6a99ac0b98d..009d5a6867efab83a9065e9fcc062683dfcc446a 100644
--- a/app/services/merge_requests/create_service.rb
+++ b/app/services/merge_requests/create_service.rb
@@ -18,7 +18,7 @@ module MergeRequests
         merge_request.update_attributes(label_ids: label_params)
         event_service.open_mr(merge_request, current_user)
         notification_service.new_merge_request(merge_request, current_user)
-        merge_request.create_cross_references!(merge_request.project, current_user)
+        merge_request.create_cross_references!(current_user)
         execute_hooks(merge_request)
       end
 
diff --git a/app/services/merge_requests/merge_service.rb b/app/services/merge_requests/merge_service.rb
index 98a67c0bc9937a197cf1f92d41e67219c5e6f025..7963af127e1c61c92fc5361518fef0e4dd7c43bb 100644
--- a/app/services/merge_requests/merge_service.rb
+++ b/app/services/merge_requests/merge_service.rb
@@ -29,7 +29,7 @@ module MergeRequests
     private
 
     def commit
-      committer = repository.user_to_comitter(current_user)
+      committer = repository.user_to_committer(current_user)
 
       options = {
         message: commit_message,
@@ -38,6 +38,10 @@ module MergeRequests
       }
 
       repository.merge(current_user, merge_request.source_sha, merge_request.target_branch, options)
+    rescue Exception => e
+      merge_request.update(merge_error: "Something went wrong during merge")
+      Rails.logger.error(e.message)
+      return false
     end
 
     def after_merge
diff --git a/app/services/merge_requests/post_merge_service.rb b/app/services/merge_requests/post_merge_service.rb
index aceb8cb902199cca00d3113fb2210800b2aa17e5..8f25c5e24967dc601fc62f1007fc5ec3296f979a 100644
--- a/app/services/merge_requests/post_merge_service.rb
+++ b/app/services/merge_requests/post_merge_service.rb
@@ -6,6 +6,7 @@ module MergeRequests
   #
   class PostMergeService < MergeRequests::BaseService
     def execute(merge_request)
+      close_issues(merge_request)
       merge_request.mark_as_merged
       create_merge_event(merge_request, current_user)
       create_note(merge_request)
@@ -15,6 +16,15 @@ module MergeRequests
 
     private
 
+    def close_issues(merge_request)
+      return unless merge_request.target_branch == project.default_branch
+
+      closed_issues = merge_request.closes_issues(current_user)
+      closed_issues.each do |issue|
+        Issues::CloseService.new(project, current_user, {}).execute(issue, merge_request)
+      end
+    end
+
     def create_merge_event(merge_request, current_user)
       EventCreateService.new.merge_mr(merge_request, current_user)
     end
diff --git a/app/services/merge_requests/refresh_service.rb b/app/services/merge_requests/refresh_service.rb
index e903e48e3cd26daeb577dc4e5ecb3986dd315515..d68bc79ecc064fe5134aaf5def2ad1e07190df4e 100644
--- a/app/services/merge_requests/refresh_service.rb
+++ b/app/services/merge_requests/refresh_service.rb
@@ -5,13 +5,20 @@ module MergeRequests
 
       @oldrev, @newrev = oldrev, newrev
       @branch_name = Gitlab::Git.ref_name(ref)
-      @fork_merge_requests = @project.fork_merge_requests.opened
-      @commits = @project.repository.commits_between(oldrev, newrev)
 
-      close_merge_requests
+      find_new_commits
       reload_merge_requests
+
+      # Leave a system note if a branch was deleted/added
+      if branch_added? || branch_removed?
+        comment_mr_branch_presence_changed
+        comment_mr_with_commits
+      else
+        comment_mr_with_commits
+        close_merge_requests
+      end
+
       execute_mr_web_hooks
-      comment_mr_with_commits
 
       true
     end
@@ -31,7 +38,6 @@ module MergeRequests
         commit_ids.include?(merge_request.last_commit.id)
       end
 
-
       merge_requests.uniq.select(&:source_project).each do |merge_request|
         MergeRequests::PostMergeService.
           new(merge_request.target_project, @current_user).
@@ -47,7 +53,7 @@ module MergeRequests
     # Note: we should update merge requests from forks too
     def reload_merge_requests
       merge_requests = @project.merge_requests.opened.by_branch(@branch_name).to_a
-      merge_requests += @fork_merge_requests.by_branch(@branch_name).to_a
+      merge_requests += fork_merge_requests.by_branch(@branch_name).to_a
       merge_requests = filter_merge_requests(merge_requests)
 
       merge_requests.each do |merge_request|
@@ -70,13 +76,48 @@ module MergeRequests
       end
     end
 
+    def find_new_commits
+      if branch_added?
+        @commits = []
+
+        merge_request = merge_requests_for_source_branch.first
+        return unless merge_request
+
+        last_commit = merge_request.last_commit
+
+        begin
+          # Since any number of commits could have been made to the restored branch,
+          # find the common root to see what has been added.
+          common_ref = @project.repository.merge_base(last_commit.id, @newrev)
+          # If the a commit no longer exists in this repo, gitlab_git throws
+          # a Rugged::OdbError. This is fixed in https://gitlab.com/gitlab-org/gitlab_git/merge_requests/52
+          @commits = @project.repository.commits_between(common_ref, @newrev) if common_ref
+        rescue
+        end
+      elsif branch_removed?
+        # No commits for a deleted branch.
+        @commits = []
+      else
+        @commits = @project.repository.commits_between(@oldrev, @newrev)
+      end
+    end
+
+    # Add comment about branches being deleted or added to merge requests
+    def comment_mr_branch_presence_changed
+      presence = branch_added? ? :add : :delete
+
+      merge_requests_for_source_branch.each do |merge_request|
+        SystemNoteService.change_branch_presence(
+            merge_request, merge_request.project, @current_user,
+            :source, @branch_name, presence)
+      end
+    end
+
     # Add comment about pushing new commits to merge requests
     def comment_mr_with_commits
-      merge_requests = @project.origin_merge_requests.opened.where(source_branch: @branch_name).to_a
-      merge_requests += @fork_merge_requests.where(source_branch: @branch_name).to_a
-      merge_requests = filter_merge_requests(merge_requests)
+      return unless @commits.present?
 
-      merge_requests.each do |merge_request|
+      merge_requests_for_source_branch.each do |merge_request|
         mr_commit_ids = Set.new(merge_request.commits.map(&:id))
 
         new_commits, existing_commits = @commits.partition do |commit|
@@ -91,14 +132,7 @@ module MergeRequests
 
     # Call merge request webhook with update branches
     def execute_mr_web_hooks
-      merge_requests = @project.origin_merge_requests.opened
-        .where(source_branch: @branch_name)
-        .to_a
-      merge_requests += @fork_merge_requests.where(source_branch: @branch_name)
-        .to_a
-      merge_requests = filter_merge_requests(merge_requests)
-
-      merge_requests.each do |merge_request|
+      merge_requests_for_source_branch.each do |merge_request|
         execute_hooks(merge_request, 'update')
       end
     end
@@ -106,5 +140,25 @@ module MergeRequests
     def filter_merge_requests(merge_requests)
       merge_requests.uniq.select(&:source_project)
     end
+
+    def merge_requests_for_source_branch
+      @source_merge_requests ||= begin
+        merge_requests = @project.origin_merge_requests.opened.where(source_branch: @branch_name).to_a
+        merge_requests += fork_merge_requests.where(source_branch: @branch_name).to_a
+        filter_merge_requests(merge_requests)
+      end
+    end
+
+    def fork_merge_requests
+      @fork_merge_requests ||= @project.fork_merge_requests.opened
+    end
+
+    def branch_added?
+      Gitlab::Git.blank_ref?(@oldrev)
+    end
+
+    def branch_removed?
+      Gitlab::Git.blank_ref?(@newrev)
+    end
   end
 end
diff --git a/app/services/merge_requests/update_service.rb b/app/services/merge_requests/update_service.rb
index 25d79e22e395c9182f508621f7666d05ee63751b..ebbe0af803ba60bc069d7ce10874f18708180ab2 100644
--- a/app/services/merge_requests/update_service.rb
+++ b/app/services/merge_requests/update_service.rb
@@ -59,7 +59,7 @@ module MergeRequests
           merge_request.mark_as_unchecked
         end
 
-        merge_request.create_new_cross_references!(merge_request.project, current_user)
+        merge_request.create_new_cross_references!
         execute_hooks(merge_request, 'update')
       end
 
diff --git a/app/services/notes/create_service.rb b/app/services/notes/create_service.rb
index 482c0444049bdef61d8c8fab5e4b0fac8779a265..2001dc89c3332fbbf91770d2dc31aefb7d244eb9 100644
--- a/app/services/notes/create_service.rb
+++ b/app/services/notes/create_service.rb
@@ -11,13 +11,7 @@ module Notes
         # Skip system notes, like status changes and cross-references.
         unless note.system
           event_service.leave_note(note, note.author)
-
-          # Create a cross-reference note if this Note contains GFM that names an
-          # issue, merge request, or commit.
-          note.references.each do |mentioned|
-            SystemNoteService.cross_reference(mentioned, note.noteable, note.author)
-          end
-
+          note.create_cross_references!
           execute_hooks(note)
         end
       end
diff --git a/app/services/notes/update_service.rb b/app/services/notes/update_service.rb
index c22a9333ef6889d9f36a1992a9b675b5cb7d92da..6c2f08e5963c51e0e2c2f4b44490e7edb638f777 100644
--- a/app/services/notes/update_service.rb
+++ b/app/services/notes/update_service.rb
@@ -4,7 +4,7 @@ module Notes
       return note unless note.editable?
 
       note.update_attributes(params.merge(updated_by: current_user))
-
+      note.create_new_cross_references!
       note.reset_events_cache
 
       note
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb
index e294b23bc23fa7e7e59e2259ef090999253d604d..a6b2234865047a8470101013749730185ad81454 100644
--- a/app/services/notification_service.rb
+++ b/app/services/notification_service.rb
@@ -183,12 +183,12 @@ class NotificationService
     mailer.group_access_granted_email(group_member.id)
   end
 
-  def project_was_moved(project)
+  def project_was_moved(project, old_path_with_namespace)
     recipients = project.team.members
     recipients = reject_muted_users(recipients, project)
 
     recipients.each do |recipient|
-      mailer.project_was_moved_email(project.id, recipient.id)
+      mailer.project_was_moved_email(project.id, recipient.id, old_path_with_namespace)
     end
   end
 
diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb
index e54a13ed6c5dfd051d62cc1c96c8529aad87c3b6..faf1ee008e7e4461fb96eb0055de4f577e7d2bb7 100644
--- a/app/services/projects/create_service.rb
+++ b/app/services/projects/create_service.rb
@@ -62,7 +62,7 @@ module Projects
       after_create_actions if @project.persisted?
 
       @project
-    rescue => ex
+    rescue
       @project.errors.add(:base, "Can't save project. Please try again later")
       @project
     end
diff --git a/app/services/projects/fork_service.rb b/app/services/projects/fork_service.rb
index 2e995d6fd518181e277b73b0348299a91aebb1f0..46374a3909a8bd3e7b3165dcb51ef78b174d3d20 100644
--- a/app/services/projects/fork_service.rb
+++ b/app/services/projects/fork_service.rb
@@ -18,7 +18,13 @@ module Projects
 
       if new_project.persisted?
         if @project.gitlab_ci?
-          @project.gitlab_ci_service.fork_registration(new_project, @current_user)
+          new_project.enable_ci
+
+          settings = @project.gitlab_ci_project.attributes.select do |attr_name, value|
+            ["public", "shared_runners_enabled", "allow_git_fetch"].include? attr_name
+          end
+
+          new_project.gitlab_ci_project.update(settings)
         end
       end
 
diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb
index 550ed6897dd4c7afb857a747aae1b28b2f12def5..64ea6dd42eb8db8a88d90cd045fdd607c14c93d7 100644
--- a/app/services/projects/transfer_service.rb
+++ b/app/services/projects/transfer_service.rb
@@ -27,6 +27,7 @@ module Projects
     def transfer(project, new_namespace)
       Project.transaction do
         old_path = project.path_with_namespace
+        old_namespace = project.namespace
         new_path = File.join(new_namespace.try(:path) || '', project.path)
 
         if Project.where(path: project.path, namespace_id: new_namespace.try(:id)).present?
@@ -38,7 +39,7 @@ module Projects
         project.save!
 
         # Notifications
-        project.send_move_instructions
+        project.send_move_instructions(old_path)
 
         # Move main repository
         unless gitlab_shell.mv_repository(old_path, new_path)
@@ -51,6 +52,9 @@ module Projects
         # clear project cached events
         project.reset_events_cache
 
+        # Move uploads
+        Gitlab::UploadsTransfer.new.move_project(project.path, old_namespace.path, new_namespace.path)
+
         true
       end
     end
diff --git a/app/services/system_hooks_service.rb b/app/services/system_hooks_service.rb
index 60235b6be2ab1abe4e51058d721e02671860f9b6..9a5fe4af9dde7e93b9c298018867b9a52309c15f 100644
--- a/app/services/system_hooks_service.rb
+++ b/app/services/system_hooks_service.rb
@@ -54,6 +54,7 @@ class SystemHooksService
       data.merge!({
         project_name: model.project.name,
         project_path: model.project.path,
+        project_path_with_namespace: model.project.path_with_namespace,
         project_id: model.project.id,
         user_name: model.user.name,
         user_email: model.user.email,
diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb
index 8253c1f780d58ede386bb38623727d9a7bcccfc6..708c2f00486aef8ca0d54aacee44fcc0d166beab 100644
--- a/app/services/system_note_service.rb
+++ b/app/services/system_note_service.rb
@@ -168,6 +168,31 @@ class SystemNoteService
     create_note(noteable: noteable, project: project, author: author, note: body)
   end
 
+  # Called when a branch in Noteable is added or deleted
+  #
+  # noteable    - Noteable object
+  # project     - Project owning noteable
+  # author      - User performing the change
+  # branch_type - :source or :target
+  # branch      - branch name
+  # presence    - :add or :delete
+  #
+  # Example Note text:
+  #
+  #   "Restored target branch `feature`"
+  #
+  # Returns the created Note object
+  def self.change_branch_presence(noteable, project, author, branch_type, branch, presence)
+    verb =
+      if presence == :add
+        'restored'
+      else
+        'deleted'
+      end
+    body = "#{verb} #{branch_type.to_s} branch `#{branch}`".capitalize
+    create_note(noteable: noteable, project: project, author: author, note: body)
+  end
+
   # Called when a Mentionable references a Noteable
   #
   # noteable  - Noteable object being referenced
@@ -302,7 +327,7 @@ class SystemNoteService
     commit_ids = if count == 1
                    existing_commits.first.short_id
                  else
-                   if oldrev
+                   if oldrev && !Gitlab::Git.blank_ref?(oldrev)
                      "#{Commit.truncate_sha(oldrev)}...#{existing_commits.last.short_id}"
                    else
                      "#{existing_commits.first.short_id}..#{existing_commits.last.short_id}"
diff --git a/app/uploaders/file_uploader.rb b/app/uploaders/file_uploader.rb
index f9673abbfe8a5d0f1ea0d4b6a176c2be373a4128..e82115858342f4af270fa2d474753a52ed2f2829 100644
--- a/app/uploaders/file_uploader.rb
+++ b/app/uploaders/file_uploader.rb
@@ -26,7 +26,7 @@ class FileUploader < CarrierWave::Uploader::Base
   end
 
   def secure_url
-    File.join(Gitlab.config.gitlab.url, @project.path_with_namespace, "uploads", @secret, file.filename)
+    File.join("/uploads", @secret, file.filename)
   end
 
   def file_storage?
diff --git a/app/views/abuse_report_mailer/notify.html.haml b/app/views/abuse_report_mailer/notify.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..619533e09a70eea8adfb5e3ab545cdf394dbc6ca
--- /dev/null
+++ b/app/views/abuse_report_mailer/notify.html.haml
@@ -0,0 +1,11 @@
+%p
+  #{link_to @abuse_report.user.name, user_url(@abuse_report.user)} 
+  (@#{@abuse_report.user.username}) was reported for abuse by 
+  #{link_to @abuse_report.reporter.name, user_url(@abuse_report.reporter)} 
+  (@#{@abuse_report.reporter.username}).
+
+%blockquote
+  = @abuse_report.message
+
+%p
+  = link_to "View details", abuse_reports_url
diff --git a/app/views/abuse_report_mailer/notify.text.haml b/app/views/abuse_report_mailer/notify.text.haml
new file mode 100644
index 0000000000000000000000000000000000000000..7dacf857035ba1bd5db53ec4395fb7019178d8ab
--- /dev/null
+++ b/app/views/abuse_report_mailer/notify.text.haml
@@ -0,0 +1,5 @@
+#{@abuse_report.user.name} (@#{@abuse_report.user.username}) was reported for abuse by #{@abuse_report.reporter.name} (@#{@abuse_report.reporter.username}).
+\
+> #{@abuse_report.message}
+\
+View details: #{admin_abuse_reports_url}
diff --git a/app/views/admin/abuse_reports/index.html.haml b/app/views/admin/abuse_reports/index.html.haml
index 2e8746146d15f8b8690b53a6086c602bb8f43ee1..40a5fe4628bf4939812102ee07e0423ab17c1e60 100644
--- a/app/views/admin/abuse_reports/index.html.haml
+++ b/app/views/admin/abuse_reports/index.html.haml
@@ -2,16 +2,17 @@
 %h3.page-title Abuse Reports
 %hr
 - if @abuse_reports.present?
-  %table.table
-    %thead
-      %tr
-        %th Reported by
-        %th Reported at
-        %th Message
-        %th User
-        %th Primary action
-        %th
-    = render @abuse_reports
+  .table-holder
+    %table.table
+      %thead
+        %tr
+          %th Reported by
+          %th Reported at
+          %th Message
+          %th User
+          %th Primary action
+          %th
+      = render @abuse_reports
   = paginate @abuse_reports
 - else
   %h4 There are no abuse reports
diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml
index 143cd10c543862907b8287404b15d5e46558aa08..7a78526e09ac1903279b94ace7e17d0d4d241c8d 100644
--- a/app/views/admin/application_settings/_form.html.haml
+++ b/app/views/admin/application_settings/_form.html.haml
@@ -47,6 +47,12 @@
           = f.label :version_check_enabled do
             = f.check_box :version_check_enabled
             Version check enabled
+    .form-group
+      = f.label :admin_notification_email, class: 'control-label col-sm-2'
+      .col-sm-10
+        = f.text_field :admin_notification_email, class: 'form-control'
+        .help-block
+          Abuse reports will be sent to this address if it is set. Abuse reports are always available in the admin area.
 
   %fieldset
     %legend Account and Limit Settings
@@ -124,14 +130,5 @@
         = f.text_area :help_page_text, class: 'form-control', rows: 4
         .help-block Markdown enabled
 
-  %fieldset
-    %legend Continuous Integration
-    .form-group
-      .col-sm-offset-2.col-sm-10
-        .checkbox
-          = f.label :ci_enabled do
-            = f.check_box :ci_enabled
-            Disable to prevent CI usage until rake ci:migrate is run (8.0 only)
-
   .form-actions
     = f.submit 'Save', class: 'btn btn-primary'
diff --git a/app/views/admin/applications/index.html.haml b/app/views/admin/applications/index.html.haml
index fc921a966f3fe7f139ecfb04c9aaf75c97ce259e..f8cd98f0ec45edd2aa0b93f5f1b8d07b4d93cb78 100644
--- a/app/views/admin/applications/index.html.haml
+++ b/app/views/admin/applications/index.html.haml
@@ -2,7 +2,7 @@
 %h3.page-title
   System OAuth applications
 %p.light
-  System OAuth application does not belong to certain user and can be managed only by admins
+  System OAuth applications don't belong to any user and can only be managed by admins
 %hr
 %p= link_to 'New Application', new_admin_application_path, class: 'btn btn-success'
 %table.table.table-striped
diff --git a/app/views/admin/applications/show.html.haml b/app/views/admin/applications/show.html.haml
index 0ea2ffeda9976b5909d9631b0f397dc1b4b5c9cb..3eb9d61972b314a3fea5e12e7f460b69fbadf933 100644
--- a/app/views/admin/applications/show.html.haml
+++ b/app/views/admin/applications/show.html.haml
@@ -3,25 +3,26 @@
   Application: #{@application.name}
 
 
-%table.table
-  %tr
-    %td
-      Application Id
-    %td
-      %code#application_id= @application.uid
-  %tr
-    %td
-      Secret:
-    %td
-      %code#secret= @application.secret
+.table-holder
+  %table.table
+    %tr
+      %td
+        Application Id
+      %td
+        %code#application_id= @application.uid
+    %tr
+      %td
+        Secret:
+      %td
+        %code#secret= @application.secret
 
-  %tr
-    %td
-      Callback url
-    %td
-      - @application.redirect_uri.split.each do |uri|
-        %div
-          %span.monospace= uri
+    %tr
+      %td
+        Callback url
+      %td
+        - @application.redirect_uri.split.each do |uri|
+          %div
+            %span.monospace= uri
 .form-actions
   = link_to 'Edit', edit_admin_application_path(@application), class: 'btn btn-primary wide pull-left'
   = render 'delete_form', application: @application, submit_btn_css: 'btn btn-danger prepend-left-10'
diff --git a/app/views/admin/background_jobs/show.html.haml b/app/views/admin/background_jobs/show.html.haml
index 3a01e1151098e8bc3d553ae2e6e9f68a74f428b5..de5bc050cf0b409dc8ce203efd3a206a198bc369 100644
--- a/app/views/admin/background_jobs/show.html.haml
+++ b/app/views/admin/background_jobs/show.html.haml
@@ -12,24 +12,25 @@
         %i.fa.fa-exclamation-triangle
         There are no running sidekiq processes. Please restart GitLab
     - else
-      %table.table
-        %thead
-          %th USER
-          %th PID
-          %th CPU
-          %th MEM
-          %th STATE
-          %th START
-          %th COMMAND
-        %tbody
-          - @sidekiq_processes.each do |process|
-            - next unless process.match(/(sidekiq \d+\.\d+\.\d+.+$)/)
-            - data = process.strip.split(' ')
-            %tr
-              %td= gitlab_config.user
-              - 5.times do
-                %td= data.shift
-              %td= data.join(' ')
+      .table-holder
+        %table.table
+          %thead
+            %th USER
+            %th PID
+            %th CPU
+            %th MEM
+            %th STATE
+            %th START
+            %th COMMAND
+          %tbody
+            - @sidekiq_processes.each do |process|
+              - next unless process.match(/(sidekiq \d+\.\d+\.\d+.+$)/)
+              - data = process.strip.split(' ')
+              %tr
+                %td= gitlab_config.user
+                - 5.times do
+                  %td= data.shift
+                %td= data.join(' ')
 
       .clearfix
         %p
diff --git a/app/views/admin/deploy_keys/index.html.haml b/app/views/admin/deploy_keys/index.html.haml
index 2bf1689cbc65ab88a6cc0565c1791e23914fdd34..841e6971fb2dd84c27a8c4cd85faeff71b1d60d7 100644
--- a/app/views/admin/deploy_keys/index.html.haml
+++ b/app/views/admin/deploy_keys/index.html.haml
@@ -5,22 +5,23 @@
     .panel-head-actions
       = link_to 'New Deploy Key', new_admin_deploy_key_path, class: "btn btn-new btn-sm"
   - if @deploy_keys.any?
-    %table.table
-      %thead.panel-heading
-        %tr
-          %th Title
-          %th Fingerprint
-          %th Added at
-          %th
-      %tbody
-        - @deploy_keys.each do |deploy_key|
+    .table-holder
+      %table.table
+        %thead.panel-heading
           %tr
-            %td
-              %strong= deploy_key.title
-            %td
-              %code.key-fingerprint= deploy_key.fingerprint
-            %td
-              %span.cgray
-                added #{time_ago_with_tooltip(deploy_key.created_at)}
-            %td
-              = link_to 'Remove', admin_deploy_key_path(deploy_key), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-sm btn-remove delete-key pull-right"
+            %th Title
+            %th Fingerprint
+            %th Added at
+            %th
+        %tbody
+          - @deploy_keys.each do |deploy_key|
+            %tr
+              %td
+                %strong= deploy_key.title
+              %td
+                %code.key-fingerprint= deploy_key.fingerprint
+              %td
+                %span.cgray
+                  added #{time_ago_with_tooltip(deploy_key.created_at)}
+              %td
+                = link_to 'Remove', admin_deploy_key_path(deploy_key), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-sm btn-remove delete-key pull-right"
diff --git a/app/views/admin/identities/index.html.haml b/app/views/admin/identities/index.html.haml
index ae57e3adc4d412271f1ac33b2abfc7f7b359035d..8358a14445b24c20eaa0e7edc661f42fd1187c32 100644
--- a/app/views/admin/identities/index.html.haml
+++ b/app/views/admin/identities/index.html.haml
@@ -2,12 +2,13 @@
 = render 'admin/users/head'
 
 - if @identities.present?
-  %table.table
-    %thead
-      %tr
-        %th Provider
-        %th Identifier
-        %th
-    = render @identities
+  .table-holder
+    %table.table
+      %thead
+        %tr
+          %th Provider
+          %th Identifier
+          %th
+      = render @identities
 - else
   %h4 This user has no identities
diff --git a/app/views/admin/labels/index.html.haml b/app/views/admin/labels/index.html.haml
index 8b11c28c56e99ca59be8d832f5b5be275a7a2fa9..d67454c03e797b2c5f9c9a8e37863456de92e4d1 100644
--- a/app/views/admin/labels/index.html.haml
+++ b/app/views/admin/labels/index.html.haml
@@ -12,5 +12,5 @@
     = paginate @labels, theme: 'gitlab'
   - else
     .light-well
-      .nothing-here-block There are no any labels yet
-      
\ No newline at end of file
+      .nothing-here-block There are no labels yet
+      
diff --git a/app/views/admin/services/index.html.haml b/app/views/admin/services/index.html.haml
index e2377291142f1273697a258e0e350e621f003543..6a5986f496a9c4b49e5e76e7bf6669dc0cbfe16c 100644
--- a/app/views/admin/services/index.html.haml
+++ b/app/views/admin/services/index.html.haml
@@ -2,22 +2,23 @@
 %h3.page-title Service templates
 %p.light Service template allows you to set default values for project services
 
-%table.table
-  %thead
-    %tr
-      %th
-      %th Service
-      %th Description
-      %th Last edit
-  - @services.sort_by(&:title).each do |service|
-    %tr
-      %td
-        = icon("copy", class: 'clgray')
-      %td
-        = link_to edit_admin_application_settings_service_path(service.id) do
-          %strong= service.title
-      %td
-        = service.description
-      %td.light
-        = time_ago_in_words service.updated_at
-        ago
+.table-holder
+  %table.table
+    %thead
+      %tr
+        %th
+        %th Service
+        %th Description
+        %th Last edit
+    - @services.sort_by(&:title).each do |service|
+      %tr
+        %td
+          = icon("copy", class: 'clgray')
+        %td
+          = link_to edit_admin_application_settings_service_path(service.id) do
+            %strong= service.title
+        %td
+          = service.description
+        %td.light
+          = time_ago_in_words service.updated_at
+          ago
diff --git a/app/views/admin/users/_head.html.haml b/app/views/admin/users/_head.html.haml
index 9d5e934c8bafc622d43df9cb0b34f436975930f6..4245d0f1eda1f52b3c84c7f830493af0acc87775 100644
--- a/app/views/admin/users/_head.html.haml
+++ b/app/views/admin/users/_head.html.haml
@@ -6,6 +6,8 @@
     %span.cred (Admin)
 
   .pull-right
+    - unless @user == current_user
+      = link_to 'Log in as this user', login_as_admin_user_path(@user), method: :post, class: "btn btn-grouped btn-info"
     = link_to edit_admin_user_path(@user), class: "btn btn-grouped" do
       %i.fa.fa-pencil-square-o
       Edit
diff --git a/app/views/users/_profile.html.haml b/app/views/admin/users/_profile.html.haml
similarity index 100%
rename from app/views/users/_profile.html.haml
rename to app/views/admin/users/_profile.html.haml
diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml
index e3698ac1c46cbf50405fcaf51dec9e1001de5e9e..bc08458312c4b74b5ef4c0804d3f97f5ee624be7 100644
--- a/app/views/admin/users/index.html.haml
+++ b/app/views/admin/users/index.html.haml
@@ -32,7 +32,7 @@
       %hr
       = form_tag admin_users_path, method: :get, class: 'form-inline' do
         .form-group
-          = search_field_tag :name, params[:name], placeholder: 'Name, email or username', class: 'form-control'
+          = search_field_tag :name, params[:name], placeholder: 'Name, email or username', class: 'form-control', spellcheck: false
           = hidden_field_tag "filter", params[:filter]
         = button_tag class: 'btn btn-primary' do
           %i.fa.fa-search
@@ -54,19 +54,19 @@
               %b.caret
             %ul.dropdown-menu
               %li
-                = link_to admin_users_path(sort: sort_value_name) do
+                = link_to admin_users_path(sort: sort_value_name, filter: params[:filter]) do
                   = sort_title_name
-                = link_to admin_users_path(sort: sort_value_recently_signin) do
+                = link_to admin_users_path(sort: sort_value_recently_signin, filter: params[:filter]) do
                   = sort_title_recently_signin
-                = link_to admin_users_path(sort: sort_value_oldest_signin) do
+                = link_to admin_users_path(sort: sort_value_oldest_signin, filter: params[:filter]) do
                   = sort_title_oldest_signin
-                = link_to admin_users_path(sort: sort_value_recently_created) do
+                = link_to admin_users_path(sort: sort_value_recently_created, filter: params[:filter]) do
                   = sort_title_recently_created
-                = link_to admin_users_path(sort: sort_value_oldest_created) do
+                = link_to admin_users_path(sort: sort_value_oldest_created, filter: params[:filter]) do
                   = sort_title_oldest_created
-                = link_to admin_users_path(sort: sort_value_recently_updated) do
+                = link_to admin_users_path(sort: sort_value_recently_updated, filter: params[:filter]) do
                   = sort_title_recently_updated
-                = link_to admin_users_path(sort: sort_value_oldest_updated) do
+                = link_to admin_users_path(sort: sort_value_oldest_updated, filter: params[:filter]) do
                   = sort_title_oldest_updated
 
           = link_to 'New User', new_admin_user_path, class: "btn btn-new btn-sm"
diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml
index a383ea573841a5fbcfc9f8fa2d4038f4b2c7ecda..0848504b7a638939cb48f3470374afbfa36099ce 100644
--- a/app/views/admin/users/show.html.haml
+++ b/app/views/admin/users/show.html.haml
@@ -8,13 +8,13 @@
         = @user.name
       %ul.well-list
         %li
-          = image_tag avatar_icon(@user.email, 60), class: "avatar s60"
+          = image_tag avatar_icon(@user, 60), class: "avatar s60"
         %li
           %span.light Profile page:
           %strong
             = link_to user_path(@user) do
               = @user.username
-    = render 'users/profile', user: @user
+    = render 'admin/users/profile', user: @user
 
     .panel.panel-default
       .panel-heading
diff --git a/app/views/ci/admin/builds/_build.html.haml b/app/views/ci/admin/builds/_build.html.haml
index 778d51d03be94e31a7f597e005f79c0fba683fcf..2df5871321404bd3ed5ecb03418e6ef8e2326f7c 100644
--- a/app/views/ci/admin/builds/_build.html.haml
+++ b/app/views/ci/admin/builds/_build.html.haml
@@ -1,14 +1,16 @@
+- gl_project = build.project.gl_project
 - if build.commit && build.project
   %tr.build
     %td.build-link
-      = link_to ci_project_build_url(build.project, build) do
+      = link_to namespace_project_build_path(gl_project.namespace, gl_project, build) do
         %strong #{build.id}
 
     %td.status
       = ci_status_with_icon(build.status)
 
     %td.commit-link
-      = commit_link(build.commit)
+      = link_to ci_status_path(build.commit) do
+        %strong #{build.commit.short_sha}
 
     %td.runner
       - if build.runner
diff --git a/app/views/ci/admin/events/index.html.haml b/app/views/ci/admin/events/index.html.haml
index f9ab09943046b9327c1d4594b2b67e471c841fe3..5a5b4dc7c3571cd2cee561369e3cf0c7ae01b87c 100644
--- a/app/views/ci/admin/events/index.html.haml
+++ b/app/views/ci/admin/events/index.html.haml
@@ -1,17 +1,18 @@
-%table.table
-  %thead
-    %tr
-      %th User ID
-      %th Description
-      %th When
-  - @events.each do |event|
-    %tr
-      %td
-        = event.user_id
-      %td
-        = event.description
-      %td.light
-        = time_ago_in_words event.updated_at
-        ago
+.table-holder
+  %table.table
+    %thead
+      %tr
+        %th User ID
+        %th Description
+        %th When
+    - @events.each do |event|
+      %tr
+        %td
+          = event.user_id
+        %td
+          = event.description
+        %td.light
+          = time_ago_in_words event.updated_at
+          ago
 
-= paginate @events
\ No newline at end of file
+= paginate @events
diff --git a/app/views/ci/admin/projects/_project.html.haml b/app/views/ci/admin/projects/_project.html.haml
index c461206c72a7359e5f64bd8efb6037245893e848..a342d6e1cf0afb126c1f63954e14c75edc48ab6b 100644
--- a/app/views/ci/admin/projects/_project.html.haml
+++ b/app/views/ci/admin/projects/_project.html.haml
@@ -1,4 +1,4 @@
-- last_commit = project.last_commit
+- last_commit = project.commits.last
 %tr
   %td
     = project.id
diff --git a/app/views/ci/admin/projects/index.html.haml b/app/views/ci/admin/projects/index.html.haml
index dc7b041473be1c872521d055e525be4f0e5f3f02..0da8547924bb8c41244245eabbcc0288e14c681a 100644
--- a/app/views/ci/admin/projects/index.html.haml
+++ b/app/views/ci/admin/projects/index.html.haml
@@ -1,15 +1,16 @@
-%table.table
-  %thead
-    %tr
-      %th ID
-      %th Name
-      %th Last build
-      %th Access
-      %th Builds
-      %th
+.table-holder
+  %table.table
+    %thead
+      %tr
+        %th ID
+        %th Name
+        %th Last build
+        %th Access
+        %th Builds
+        %th
 
-  - @projects.each do |project|
-    = render "ci/admin/projects/project", project: project
+    - @projects.each do |project|
+      = render "ci/admin/projects/project", project: project
 
 = paginate @projects
 
diff --git a/app/views/ci/admin/runners/index.html.haml b/app/views/ci/admin/runners/index.html.haml
index b9d6703ff4104d9e5381b87139c1dee98a2781f4..bb213fbffc4e88d1cac84fd7fe619f9537c9fb59 100644
--- a/app/views/ci/admin/runners/index.html.haml
+++ b/app/views/ci/admin/runners/index.html.haml
@@ -27,7 +27,7 @@
   .pull-left
     = form_tag ci_admin_runners_path, id: 'runners-search', class: 'form-inline', method: :get do
       .form-group
-        = search_field_tag :search, params[:search], class: 'form-control', placeholder: 'Runner description or token'
+        = search_field_tag :search, params[:search], class: 'form-control', placeholder: 'Runner description or token', spellcheck: false
       = submit_tag 'Search', class: 'btn'
 
   .pull-right.light
@@ -35,18 +35,19 @@
 
 %br
 
-%table.table
-  %thead
-    %tr
-      %th Type
-      %th Runner token
-      %th Description
-      %th Projects
-      %th Builds
-      %th Tags
-      %th Last contact
-      %th
+.table-holder
+  %table.table
+    %thead
+      %tr
+        %th Type
+        %th Runner token
+        %th Description
+        %th Projects
+        %th Builds
+        %th Tags
+        %th Last contact
+        %th
 
-  - @runners.each do |runner|
-    = render "ci/admin/runners/runner", runner: runner
+    - @runners.each do |runner|
+      = render "ci/admin/runners/runner", runner: runner
 = paginate @runners
diff --git a/app/views/ci/admin/runners/show.html.haml b/app/views/ci/admin/runners/show.html.haml
index 09905e0eb47d02f9d83418f9ffc48c53c5e75080..92787b2e6ac933b0d7dae3f9e2388dde4e068f41 100644
--- a/app/views/ci/admin/runners/show.html.haml
+++ b/app/views/ci/admin/runners/show.html.haml
@@ -76,7 +76,7 @@
         %td
           = form_tag ci_admin_runner_path(@runner), id: 'runner-projects-search', class: 'form-inline', method: :get do
             .form-group
-              = search_field_tag :search, params[:search], class: 'form-control'
+              = search_field_tag :search, params[:search], class: 'form-control', spellcheck: false
             = submit_tag 'Search', class: 'btn'
 
         %td
@@ -96,6 +96,7 @@
     %table.builds.runner-builds
       %thead
         %tr
+          %th Build ID
           %th Status
           %th Project
           %th Commit
@@ -103,6 +104,11 @@
 
       - @builds.each do |build|
         %tr.build
+          %td.id
+            - gl_project = build.project.gl_project
+            = link_to namespace_project_build_path(gl_project.namespace, gl_project, build) do
+              = build.id
+
           %td.status
             = ci_status_with_icon(build.status)
 
@@ -110,8 +116,8 @@
             = build.project.name
 
           %td.build-link
-            = link_to ci_project_build_path(build.project, build) do
-              %strong #{build.short_sha}
+            = link_to ci_status_path(build.commit) do
+              %strong #{build.commit.short_sha}
 
           %td.timestamp
             - if build.finished_at
diff --git a/app/views/ci/builds/_build.html.haml b/app/views/ci/builds/_build.html.haml
deleted file mode 100644
index 515b862e992c11f95d7ea07a2e71691234d95fa1..0000000000000000000000000000000000000000
--- a/app/views/ci/builds/_build.html.haml
+++ /dev/null
@@ -1,45 +0,0 @@
-%tr.build
-  %td.status
-    = ci_status_with_icon(build.status)
-
-  %td.build-link
-    = link_to ci_project_build_path(build.project, build) do
-      %strong Build ##{build.id}
-
-  %td
-    = build.stage
-
-  %td
-    = build.name
-    .pull-right
-      - if build.tags.any?
-        - build.tag_list.each do |tag|
-          %span.label.label-primary
-            = tag
-      - if build.trigger_request
-        %span.label.label-info triggered
-      - if build.allow_failure
-        %span.label.label-danger allowed to fail
-
-  %td.duration
-    - if build.duration
-      #{duration_in_words(build.finished_at, build.started_at)}
-
-  %td.timestamp
-    - if build.finished_at
-      %span #{time_ago_in_words build.finished_at} ago
-
-  - if build.project.coverage_enabled?
-    %td.coverage
-      - if build.coverage
-        #{build.coverage}%
-
-  %td
-    - if defined?(controls) && current_user && can?(current_user, :manage_builds, gl_project)
-      .pull-right
-        - if build.active?
-          = link_to cancel_ci_project_build_path(build.project, build, return_to: request.original_url), title: 'Cancel build' do
-            %i.fa.fa-remove.cred
-        - elsif build.commands.present?
-          = link_to retry_ci_project_build_path(build.project, build, return_to: request.original_url), method: :post, title: 'Retry build' do
-            %i.fa.fa-repeat
diff --git a/app/views/ci/builds/show.html.haml b/app/views/ci/builds/show.html.haml
deleted file mode 100644
index 839dbf5c55444f7772dea4340c118db4e4f1e95f..0000000000000000000000000000000000000000
--- a/app/views/ci/builds/show.html.haml
+++ /dev/null
@@ -1,170 +0,0 @@
-#up-build-trace
-- if @commit.matrix?
-  %ul.center-top-menu
-    - @commit.builds_without_retry_sorted.each do |build|
-      %li{class: ('active' if build == @build) }
-        = link_to ci_project_build_url(@project, build) do
-          = ci_icon_for_status(build.status)
-          %span
-            - if build.name
-              = build.name
-            - else
-              = build.id
-
-
-    - unless @commit.builds_without_retry.include?(@build)
-      %li.active
-        %a
-          Build ##{@build.id}
-          &middot;
-          %i.fa.fa-warning-sign
-          This build was retried.
-
-.gray-content-block
-  .build-head
-    %h4
-      - if @build.commit.tag?
-        Build for tag
-        %code #{@build.ref}
-      - else
-        Build for commit
-        %strong.monospace= commit_link(@build.commit)
-        from
-
-        = link_to ci_project_path(@build.project, ref: @build.ref) do
-          %strong.monospace= "#{@build.ref}"
-
-      - if @build.duration
-        .pull-right
-          %span
-            %i.fa.fa-time
-            #{duration_in_words(@build.finished_at, @build.started_at)}
-
-    .clearfix
-      = ci_status_with_icon(@build.status)
-      .pull-right
-        = @build.updated_at.stamp('19:00 Aug 27')
-
-.row.prepend-top-default
-  .col-md-9
-    .clearfix
-      - if @build.active?
-        .autoscroll-container
-          %button.btn.btn-success.btn-sm#autoscroll-button{:type => "button", :data => {:state => 'disabled'}} enable autoscroll
-        .clearfix
-    .scroll-controls
-      = link_to '#up-build-trace', class: 'btn' do
-        %i.fa.fa-angle-up
-      = link_to '#down-build-trace', class: 'btn' do
-        %i.fa.fa-angle-down
-
-    %pre.trace#build-trace
-      %code.bash
-        = preserve do
-          = raw @build.trace_html
-    %div#down-build-trace
-
-  .col-md-3
-    - if @build.coverage
-      .build-widget
-        %h4.title
-          Test coverage
-        %h1 #{@build.coverage}%
-
-
-    .build-widget
-      %h4.title
-        Build
-        - if current_user && can?(current_user, :manage_builds, gl_project)
-          .pull-right
-            - if @build.active?
-              = link_to "Cancel", cancel_ci_project_build_path(@project, @build), class: 'btn btn-sm btn-danger'
-            - elsif @build.commands.present?
-              = link_to "Retry", retry_ci_project_build_path(@project, @build), class: 'btn btn-sm btn-primary', method: :post
-
-      - if @build.duration
-        %p
-          %span.attr-name Duration:
-          #{duration_in_words(@build.finished_at, @build.started_at)}
-      %p
-        %span.attr-name Created:
-        #{time_ago_in_words(@build.created_at)} ago
-      - if @build.finished_at
-        %p
-          %span.attr-name Finished:
-          #{time_ago_in_words(@build.finished_at)} ago
-      %p
-        %span.attr-name Runner:
-        - if @build.runner && current_user && current_user.admin
-          \#{link_to "##{@build.runner.id}", ci_admin_runner_path(@build.runner.id)}
-        - elsif @build.runner
-          \##{@build.runner.id}
-
-    - if @build.trigger_request
-      .build-widget
-        %h4.title
-          Trigger
-
-        %p
-          %span.attr-name Token:
-          #{@build.trigger_request.trigger.short_token}
-
-        - if @build.trigger_request.variables
-          %p
-            %span.attr-name Variables:
-
-          %code
-            - @build.trigger_request.variables.each do |key, value|
-              #{key}=#{value}
-
-    .build-widget
-      %h4.title
-        Commit
-        .pull-right
-          %small #{build_commit_link @build}
-
-      - if @build.commit.compare?
-        %p
-          %span.attr-name Compare:
-          #{build_compare_link @build}
-      %p
-        %span.attr-name Branch:
-        #{build_ref_link @build}
-      %p
-        %span.attr-name Author:
-        #{@build.commit.git_author_name}
-      %p
-        %span.attr-name Message:
-        #{@build.commit.git_commit_message}
-
-    - if @build.tags.any?
-      .build-widget
-        %h4.title
-          Tags
-        - @build.tag_list.each do |tag|
-          %span.label.label-primary
-            = tag
-
-    - if @builds.present?
-      .build-widget
-        %h4.title #{pluralize(@builds.count, "other build")} for #{@build.short_sha}:
-        %table.builds
-          - @builds.each_with_index do |build, i|
-            %tr.build
-              %td
-                = ci_icon_for_status(build.status)
-              %td
-                = link_to ci_project_build_url(@project, build) do
-                  - if build.name
-                    = build.name
-                  - else
-                    %span ##{build.id}
-
-              %td.status= build.status
-
-
-        = paginate @builds
-
-
-:javascript
-  new CiBuild("#{ci_project_build_url(@project, @build)}", "#{@build.status}")
diff --git a/app/views/ci/commits/_commit.html.haml b/app/views/ci/commits/_commit.html.haml
index 1eacfca944fce44254928c5d5a87b5fa558ad83e..b24a3b826cfb52a0a8a36144d45ccf5d31111763 100644
--- a/app/views/ci/commits/_commit.html.haml
+++ b/app/views/ci/commits/_commit.html.haml
@@ -7,7 +7,7 @@
 
 
   %td.build-link
-    = link_to ci_project_ref_commits_path(commit.project, commit.ref, commit.sha) do
+    = link_to ci_status_path(commit) do
       %strong #{commit.short_sha}
 
   %td.build-message
@@ -16,7 +16,8 @@
   %td.build-branch
     - unless @ref
       %span
-        = link_to truncate(commit.ref, length: 25), ci_project_path(@project, ref: commit.ref)
+        - commit.refs.each do |ref|
+          = link_to truncate(ref, length: 25), ci_project_path(@project, ref: ref)
 
   %td.duration
     - if commit.duration > 0
diff --git a/app/views/ci/commits/show.html.haml b/app/views/ci/commits/show.html.haml
deleted file mode 100644
index 8f38aa84676a6c39b0ef05aa2418de2d19958648..0000000000000000000000000000000000000000
--- a/app/views/ci/commits/show.html.haml
+++ /dev/null
@@ -1,87 +0,0 @@
-.commit-info
-  .append-bottom-20
-    = ci_status_with_icon(@commit.status)
-
-  .gray-content-block.middle-block
-    %pre.commit-message
-      #{@commit.git_commit_message}
-
-  .gray-content-block.second-block
-    .row
-      .col-sm-6
-        - if @commit.compare?
-          %p
-            %span.attr-name Compare:
-            #{gitlab_compare_link(@project, @commit.short_before_sha, @commit.short_sha)}
-        - else
-          %p
-            %span.attr-name Commit:
-            #{gitlab_commit_link(@project, @commit.sha)}
-
-        %p
-          %span.attr-name Branch:
-          #{gitlab_ref_link(@project, @commit.ref)}
-      .col-sm-6
-        %p
-          %span.attr-name Author:
-          #{@commit.git_author_name} (#{@commit.git_author_email})
-        - if @commit.created_at
-          %p
-            %span.attr-name Created at:
-            #{@commit.created_at.to_s(:short)}
-
-- if current_user && can?(current_user, :manage_builds, gl_project)
-  .pull-right
-    - if @commit.builds.running_or_pending.any?
-      = link_to "Cancel", cancel_ci_project_ref_commits_path(@project, @commit.ref, @commit.sha), class: 'btn btn-sm btn-danger'
-
-
-- if @commit.yaml_errors.present?
-  .bs-callout.bs-callout-danger
-    %h4 Found errors in your .gitlab-ci.yml:
-    %ul
-      - @commit.yaml_errors.split(",").each do |error|
-        %li= error
-
-- unless @commit.push_data[:ci_yaml_file]
-  .bs-callout.bs-callout-warning
-    \.gitlab-ci.yml not found in this commit
-
-%h3
-  Builds
-  - if @commit.duration > 0
-    %small.pull-right
-      %i.fa.fa-time
-      #{time_interval_in_words @commit.duration}
-
-%table.table.builds
-  %thead
-    %tr
-      %th Status
-      %th Build ID
-      %th Stage
-      %th Name
-      %th Duration
-      %th Finished at
-      - if @project.coverage_enabled?
-        %th Coverage
-      %th
-  = render @commit.builds_without_retry_sorted, controls: true
-
-- if @commit.retried_builds.any?
-  %h3
-    Retried builds
-
-  %table.table.builds
-    %thead
-      %tr
-        %th Status
-        %th Build ID
-        %th Stage
-        %th Name
-        %th Duration
-        %th Finished at
-        - if @project.coverage_enabled?
-          %th Coverage
-        %th
-    = render @commit.retried_builds
diff --git a/app/views/ci/events/index.html.haml b/app/views/ci/events/index.html.haml
index 779f49b3d3a761c50f7e62e925f62087e494ca7f..9824e85b1afe883f66946d8f58270734e343ff9b 100644
--- a/app/views/ci/events/index.html.haml
+++ b/app/views/ci/events/index.html.haml
@@ -1,19 +1,20 @@
 %h3.page-title Events
 
-%table.table
-  %thead
-    %tr
-      %th User ID
-      %th Description
-      %th When
-  - @events.each do |event|
-    %tr
-      %td
-        = event.user_id
-      %td
-        = event.description
-      %td.light
-        = time_ago_in_words event.updated_at
-        ago
+.table-holder
+  %table.table
+    %thead
+      %tr
+        %th User ID
+        %th Description
+        %th When
+    - @events.each do |event|
+      %tr
+        %td
+          = event.user_id
+        %td
+          = event.description
+        %td.light
+          = time_ago_in_words event.updated_at
+          ago
 
-= paginate @events
\ No newline at end of file
+= paginate @events
diff --git a/app/views/ci/lints/_create.html.haml b/app/views/ci/lints/_create.html.haml
index e2179e60f3ec886029ff5bac0cd8a8096148af29..f45cd05aec0573494c9c4582becea960f569242b 100644
--- a/app/views/ci/lints/_create.html.haml
+++ b/app/views/ci/lints/_create.html.haml
@@ -4,29 +4,30 @@
     syntax is correct
     %i.fa.fa-ok.correct-syntax
 
-  %table.table.table-bordered
-    %thead
-      %tr
-        %th Parameter
-        %th Value
-    %tbody
-      - @stages.each do |stage|
-        - @builds.select { |build| build[:stage] == stage }.each do |build|
-          %tr
-            %td #{stage.capitalize} Job - #{build[:name]}
-            %td
-              %pre
-                = simple_format build[:script]
+  .table-holder
+    %table.table.table-bordered
+      %thead
+        %tr
+          %th Parameter
+          %th Value
+      %tbody
+        - @stages.each do |stage|
+          - @builds.select { |build| build[:stage] == stage }.each do |build|
+            %tr
+              %td #{stage.capitalize} Job - #{build[:name]}
+              %td
+                %pre
+                  = simple_format build[:script]
 
-              %br
-              %b Tag list:
-              = build[:tags]
-              %br
-              %b Refs only:
-              = build[:only] && build[:only].join(", ")
-              %br
-              %b Refs except:
-              = build[:except] && build[:except].join(", ")
+                %br
+                %b Tag list:
+                = build[:tags]
+                %br
+                %b Refs only:
+                = build[:only] && build[:only].join(", ")
+                %br
+                %b Refs except:
+                = build[:except] && build[:except].join(", ")
 
 -else
   %p
diff --git a/app/views/ci/notify/build_fail_email.html.haml b/app/views/ci/notify/build_fail_email.html.haml
index d818e8b6756aaca8c8100ce8752d48c053c76b00..69689a75022fcb6146f40d45ec0d773de49aa207 100644
--- a/app/views/ci/notify/build_fail_email.html.haml
+++ b/app/views/ci/notify/build_fail_email.html.haml
@@ -11,9 +11,9 @@
 %p
   Author: #{@build.commit.git_author_name}
 %p
-  Branch: #{@build.commit.ref}
+  Branch: #{@build.ref}
 %p
   Message: #{@build.commit.git_commit_message}
 
 %p
-  Url: #{link_to @build.short_sha, ci_project_build_url(@project, @build)}
+  Url: #{link_to @build.short_sha, namespace_project_build_url(@build.gl_project.namespace, @build.gl_project, @build)}
diff --git a/app/views/ci/notify/build_fail_email.text.erb b/app/views/ci/notify/build_fail_email.text.erb
index 1add215a1c8ab5c0ffda424632ebd2ec6f48ed0c..6de5dc10f179184ffdbf0591ff0380a42739ae0e 100644
--- a/app/views/ci/notify/build_fail_email.text.erb
+++ b/app/views/ci/notify/build_fail_email.text.erb
@@ -3,7 +3,7 @@ Build failed for <%= @project.name %>
 Status:   <%= @build.status %>
 Commit:   <%= @build.commit.short_sha %>
 Author:   <%= @build.commit.git_author_name %>
-Branch:   <%= @build.commit.ref %>
+Branch:   <%= @build.ref %>
 Message:  <%= @build.commit.git_commit_message %>
 
-Url:      <%= ci_project_build_url(@build.project, @build) %>
+Url:      <%= namespace_project_build_url(@build.gl_project.namespace, @build.gl_project, @build) %>
diff --git a/app/views/ci/notify/build_success_email.html.haml b/app/views/ci/notify/build_success_email.html.haml
index a20dcaee24e4f0d7f437e047d0188907741bdc01..4e3015a356bea801bea8087a7fe051445167b8be 100644
--- a/app/views/ci/notify/build_success_email.html.haml
+++ b/app/views/ci/notify/build_success_email.html.haml
@@ -12,9 +12,9 @@
 %p
   Author: #{@build.commit.git_author_name}
 %p
-  Branch: #{@build.commit.ref}
+  Branch: #{@build.ref}
 %p
   Message: #{@build.commit.git_commit_message}
 
 %p
-  Url: #{link_to @build.short_sha, ci_project_build_url(@project, @build)}
+  Url: #{link_to @build.short_sha, namespace_project_build_url(@build.gl_project.namespace, @build.gl_project, @build)}
diff --git a/app/views/ci/notify/build_success_email.text.erb b/app/views/ci/notify/build_success_email.text.erb
index 7ebd17e7270495bc56b06f3d2c2c99692dfc3af0..d0a43ae1c12915fd47fd85b6d0b14eb25a9b1c70 100644
--- a/app/views/ci/notify/build_success_email.text.erb
+++ b/app/views/ci/notify/build_success_email.text.erb
@@ -3,7 +3,7 @@ Build successful for <%= @project.name %>
 Status:   <%= @build.status %>
 Commit:   <%= @build.commit.short_sha %>
 Author:   <%= @build.commit.git_author_name %>
-Branch:   <%= @build.commit.ref %>
+Branch:   <%= @build.ref %>
 Message:  <%= @build.commit.git_commit_message %>
 
-Url:      <%= ci_project_build_url(@build.project, @build) %>
+Url:      <%= namespace_project_build_url(@build.gl_project.namespace, @build.gl_project, @build) %>
diff --git a/app/views/ci/projects/_info.html.haml b/app/views/ci/projects/_info.html.haml
deleted file mode 100644
index 1888e1bde93166b9a800869243fadf53a1e857ae..0000000000000000000000000000000000000000
--- a/app/views/ci/projects/_info.html.haml
+++ /dev/null
@@ -1,2 +0,0 @@
-- if no_runners_for_project?(@project)
-  = render 'no_runners'
diff --git a/app/views/ci/projects/disabled.html.haml b/app/views/ci/projects/disabled.html.haml
deleted file mode 100644
index 83b0d8329e18ee6efa855c8a5330e6d70f68521b..0000000000000000000000000000000000000000
--- a/app/views/ci/projects/disabled.html.haml
+++ /dev/null
@@ -1 +0,0 @@
-Continuous Integration has been disabled for time of the migration.
diff --git a/app/views/ci/projects/index.html.haml b/app/views/ci/projects/index.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..9c2290bc4a5cf778865e6c800eece3ab78b7de14
--- /dev/null
+++ b/app/views/ci/projects/index.html.haml
@@ -0,0 +1,20 @@
+.wiki
+  %h1
+    GitLab CI is now integrated in GitLab UI
+  %h2 For existing projects
+
+  %p
+    Check the following pages to find the CI status you're looking for:
+
+  %ul
+    %li Projects page - shows CI status for each project.
+    %li Project commits page - show CI status for each commit.
+
+
+
+  %h2 For new projects
+
+  %p
+    If you want to enable CI for a new project it is easy as adding
+    = link_to ".gitlab-ci.yml", "http://doc.gitlab.com/ce/ci/yaml/README.html"
+    file to your repository
diff --git a/app/views/ci/projects/show.html.haml b/app/views/ci/projects/show.html.haml
deleted file mode 100644
index 6443378af99b2385c98901f24769c25705d79c8b..0000000000000000000000000000000000000000
--- a/app/views/ci/projects/show.html.haml
+++ /dev/null
@@ -1,60 +0,0 @@
-= render 'ci/shared/guide' unless @project.setup_finished?
-
-- if current_user && can?(current_user, :manage_project, gl_project) && !@project.any_runners?
-  .alert.alert-danger
-    Builds for this project wont be served unless you configure runners on
-    = link_to "Runners page", ci_project_runners_path(@project)
-
-%ul.nav.nav-tabs.append-bottom-20
-  %li{class: ref_tab_class}
-    = link_to 'All commits', ci_project_path(@project)
-  - @project.tracked_refs.each do |ref|
-    %li{class: ref_tab_class(ref)}
-      = link_to ref, ci_project_path(@project, ref: ref)
-
-  - if @ref && !@project.tracked_refs.include?(@ref)
-    %li{class: 'active'}
-      = link_to @ref, ci_project_path(@project, ref: @ref)
-
-  %li.pull-right
-    = link_to 'View on GitLab', @project.gitlab_url, no_turbolink.merge( class: 'btn btn-sm' )
-
-- if @ref
-  %p
-    Paste build status image for #{@ref} with next link
-    = link_to '#', class: 'badge-codes-toggle btn btn-default btn-xs' do
-      Status Badge
-    .badge-codes-block.bs-callout.bs-callout-info.hide
-      %p
-        Status badge for
-        %span.label.label-info #{@ref}
-        branch
-      %div
-        %label Markdown:
-        = text_field_tag 'badge_md', markdown_badge_code(@project, @ref), readonly: true, class: 'form-control'
-        %label Html:
-        = text_field_tag 'badge_html', html_badge_code(@project, @ref), readonly: true, class: 'form-control'
-
-
-
-
-%table.table.builds
-  %thead
-    %tr
-      %th Status
-      %th Commit
-      %th Message
-      %th Branch
-      %th Total duration
-      %th Finished at
-      - if @project.coverage_enabled?
-        %th Coverage
-
-  = render @commits
-
-= paginate @commits
-
-- if @commits.empty?
-  .bs-callout
-    %h4 No commits yet
-
diff --git a/app/views/ci/runners/show.html.haml b/app/views/ci/runners/show.html.haml
deleted file mode 100644
index ffec495f85a132a0a9d69463bb7690fe97e0f49e..0000000000000000000000000000000000000000
--- a/app/views/ci/runners/show.html.haml
+++ /dev/null
@@ -1,64 +0,0 @@
-= content_for :title do
-  %h3.project-title
-    Runner ##{@runner.id}
-    .pull-right
-      - if @runner.shared?
-        %span.runner-state.runner-state-shared
-          Shared
-      - else
-        %span.runner-state.runner-state-specific
-          Specific
-
-%table.table
-  %thead
-    %tr
-      %th Property Name
-      %th Value
-  %tr
-    %td
-      Tags
-    %td
-      - @runner.tag_list.each do |tag|
-        %span.label.label-primary
-          = tag
-  %tr
-    %td
-      Name
-    %td
-      = @runner.name
-  %tr
-    %td
-      Version
-    %td
-      = @runner.version
-  %tr
-    %td
-      Revision
-    %td
-      = @runner.revision
-  %tr
-    %td
-      Platform
-    %td
-      = @runner.platform
-  %tr
-    %td
-      Architecture
-    %td
-      = @runner.architecture
-  %tr
-    %td
-      Description
-    %td
-      = @runner.description
-  %tr
-    %td
-      Last contact
-    %td
-      - if @runner.contacted_at
-        #{time_ago_in_words(@runner.contacted_at)} ago
-      - else
-        Never
-
-
-      
diff --git a/app/views/ci/shared/_guide.html.haml b/app/views/ci/shared/_guide.html.haml
index 8a42f29b77cb73547d9ebee320e318b381b7e5ef..db2d7f2f4b650c675d67c964cd5bc9bbaf26bf83 100644
--- a/app/views/ci/shared/_guide.html.haml
+++ b/app/views/ci/shared/_guide.html.haml
@@ -4,7 +4,7 @@
   %ol
     %li
       Add at least one runner to the project.
-      Go to #{link_to 'Runners page', ci_project_runners_path(@project), target: :blank} for instructions.
+      Go to #{link_to 'Runners page', runners_path(@project.gl_project), target: :blank} for instructions.
     %li
       Put the .gitlab-ci.yml in the root of your repository. Examples can be found in #{link_to "Configuring project (.gitlab-ci.yml)", "http://doc.gitlab.com/ci/yaml/README.html", target: :blank}.
       You can also test your .gitlab-ci.yml in the #{link_to "Lint", ci_lint_path}
diff --git a/app/views/dashboard/_activities.html.haml b/app/views/dashboard/_activities.html.haml
index 19d919f9b6a99a456d12452899d0a3ada744d448..f98fd9f06ba707c49ae8325da944e1a54198c500 100644
--- a/app/views/dashboard/_activities.html.haml
+++ b/app/views/dashboard/_activities.html.haml
@@ -3,10 +3,9 @@
 
 .gray-content-block
   - if current_user
-    %ul.nav.nav-pills.event_filter.pull-right
-      %li.pull-right
-        = link_to dashboard_projects_path(:atom, { private_token: current_user.private_token }), class: 'rss-btn' do
-          %i.fa.fa-rss
+    .pull-right
+      = link_to dashboard_projects_path(:atom, { private_token: current_user.private_token }), class: 'btn rss-btn' do
+        %i.fa.fa-rss
   = render 'shared/event_filter'
 
 .content_list
diff --git a/app/views/dashboard/milestones/_issue.html.haml b/app/views/dashboard/milestones/_issue.html.haml
index f689b9698eb76806e1f50a6fdaa1e1eb9e9058bd..1408ebdd5dcf6953a63ae06a96ab531118871524 100644
--- a/app/views/dashboard/milestones/_issue.html.haml
+++ b/app/views/dashboard/milestones/_issue.html.haml
@@ -7,4 +7,4 @@
     = link_to_gfm issue.title, [project.namespace.becomes(Namespace), project, issue], title: issue.title
   .pull-right.assignee-icon
     - if issue.assignee
-      = image_tag avatar_icon(issue.assignee.email, 16), class: "avatar s16"
+      = image_tag avatar_icon(issue.assignee, 16), class: "avatar s16"
diff --git a/app/views/dashboard/milestones/_merge_request.html.haml b/app/views/dashboard/milestones/_merge_request.html.haml
index 8f5c4cce529b601421a4cb813422e6b86cb99a87..77c46de030b1b3bd56121581f9457828a9e68588 100644
--- a/app/views/dashboard/milestones/_merge_request.html.haml
+++ b/app/views/dashboard/milestones/_merge_request.html.haml
@@ -7,4 +7,4 @@
     = link_to_gfm merge_request.title, [project.namespace.becomes(Namespace), project, merge_request], title: merge_request.title
   .pull-right.assignee-icon
     - if merge_request.assignee
-      = image_tag avatar_icon(merge_request.assignee.email, 16), class: "avatar s16"
+      = image_tag avatar_icon(merge_request.assignee, 16), class: "avatar s16"
diff --git a/app/views/dashboard/milestones/show.html.haml b/app/views/dashboard/milestones/show.html.haml
index 0d204ced7ea339ac57d4f88aad22d19713f832b9..2fe14c6388c3255b6e014400d45ddbb1f75d65ad 100644
--- a/app/views/dashboard/milestones/show.html.haml
+++ b/app/views/dashboard/milestones/show.html.haml
@@ -13,26 +13,28 @@
     %span All issues for this milestone are closed. You may close the milestone now.
 
 .description
-%table.table
-  %thead
-    %tr
-      %th Project
-      %th Open issues
-      %th State
-      %th Due date
-  - @dashboard_milestone.milestones.each do |milestone|
-    %tr
-      %td
-        = link_to "#{milestone.project.name_with_namespace}", namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone)
-      %td
-        = milestone.issues.opened.count
-      %td
-        - if milestone.closed?
-          Closed
-        - else
-          Open
-      %td
-        = milestone.expires_at
+
+.table-holder
+  %table.table
+    %thead
+      %tr
+        %th Project
+        %th Open issues
+        %th State
+        %th Due date
+    - @dashboard_milestone.milestones.each do |milestone|
+      %tr
+        %td
+          = link_to "#{milestone.project.name_with_namespace}", namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone)
+        %td
+          = milestone.issues.opened.count
+        %td
+          - if milestone.closed?
+            Closed
+          - else
+            Open
+        %td
+          = milestone.expires_at
 
 .context
   %p.lead
@@ -79,7 +81,7 @@
       - @dashboard_milestone.participants.each do |user|
         %li
           = link_to user, title: user.name, class: "darken" do
-            = image_tag avatar_icon(user.email, 32), class: "avatar s32"
+            = image_tag avatar_icon(user, 32), class: "avatar s32"
             %strong= truncate(user.name, lenght: 40)
             %br
             %small.cgray= user.username
diff --git a/app/views/dashboard/projects/_projects.html.haml b/app/views/dashboard/projects/_projects.html.haml
index c8c315c73d8121aba322f8a0d3a2d09049cdafa0..81a5909e2d2ac5f01430f000bf0512306320cedd 100644
--- a/app/views/dashboard/projects/_projects.html.haml
+++ b/app/views/dashboard/projects/_projects.html.haml
@@ -1,10 +1,11 @@
 .projects-list-holder
   .projects-search-form
     .input-group
-      = search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control'
+      = search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control', spellcheck: false
       - if current_user.can_create_project?
         %span.input-group-btn
-          = link_to new_project_path, class: 'btn btn-success' do
-            New project
+          = link_to new_project_path, class: 'btn btn-green' do
+            %i.fa.fa-plus
+            New Project
 
   = render 'shared/projects/list', projects: @projects, ci: true
diff --git a/app/views/dashboard/projects/starred.html.haml b/app/views/dashboard/projects/starred.html.haml
index 339362701d439bcf484d40ff8ab4ff9ec6c6a695..f75f2e0a32a61d232ae7f6142f740089582ec077 100644
--- a/app/views/dashboard/projects/starred.html.haml
+++ b/app/views/dashboard/projects/starred.html.haml
@@ -3,6 +3,9 @@
 
 = render 'dashboard/projects_head'
 
+- if @last_push
+  = render "events/event_last_push", event: @last_push
+
 - if @projects.any?
   = render 'projects'
 - else
diff --git a/app/views/dashboard/snippets/index.html.haml b/app/views/dashboard/snippets/index.html.haml
index d3908062f43e5cdccb0f57694f98fcf187aaa1b4..07b6d57932ea70a3bef91bcc2a52131ed8899812 100644
--- a/app/views/dashboard/snippets/index.html.haml
+++ b/app/views/dashboard/snippets/index.html.haml
@@ -6,33 +6,29 @@
 .gray-content-block
   .pull-right
     = link_to new_snippet_path, class: "btn btn-new", title: "New Snippet" do
-      Add new snippet
+      = icon('plus')
+      New Snippet
 
-  .oneline
-    Share code pastes with others out of git repository
-
-%ul.nav.nav-tabs.prepend-top-20
-  = nav_tab :scope, nil do
-    = link_to dashboard_snippets_path do
+  .btn-group.btn-group-next.snippet-scope-menu
+    = link_to dashboard_snippets_path, class: "btn btn-default #{"active" unless params[:scope]}" do
       All
       %span.badge
         = current_user.snippets.count
-  = nav_tab :scope, 'are_private' do
-    = link_to dashboard_snippets_path(scope: 'are_private') do
+
+    = link_to dashboard_snippets_path(scope: 'are_private'), class: "btn btn-default #{"active" if params[:scope] == "are_private"}" do
       Private
       %span.badge
         = current_user.snippets.are_private.count
-  = nav_tab :scope, 'are_internal' do
-    = link_to dashboard_snippets_path(scope: 'are_internal') do
+
+    = link_to dashboard_snippets_path(scope: 'are_internal'), class: "btn btn-default #{"active" if params[:scope] == "are_internal"}" do
       Internal
       %span.badge
         = current_user.snippets.are_internal.count
-  = nav_tab :scope, 'are_public' do
-    = link_to dashboard_snippets_path(scope: 'are_public') do
+
+    = link_to dashboard_snippets_path(scope: 'are_public'), class: "btn btn-default #{"active" if params[:scope] == "are_public"}" do
       Public
       %span.badge
         = current_user.snippets.are_public.count
 
-.my-snippets
-  = render 'snippets/snippets'
+= render 'snippets/snippets'
 
diff --git a/app/views/devise/passwords/new.html.haml b/app/views/devise/passwords/new.html.haml
index 29ffe8a8be30d20e8e888db71e2d2b880a80916d..535e85869e54564a5b08eb24c7b836521405873a 100644
--- a/app/views/devise/passwords/new.html.haml
+++ b/app/views/devise/passwords/new.html.haml
@@ -6,7 +6,7 @@
       .devise-errors
         = devise_error_messages!
       .clearfix.append-bottom-20
-        = f.email_field :email, placeholder: "Email",  class: "form-control", required: true, value: params[:user_email]
+        = f.email_field :email, placeholder: "Email",  class: "form-control", required: true, value: params[:user_email], autofocus: true
       .clearfix
         = f.submit "Reset password", class: "btn-primary btn"
 
diff --git a/app/views/doorkeeper/applications/index.html.haml b/app/views/doorkeeper/applications/index.html.haml
index 3b0b19107ca53612bb61fced036d43bea48b1b4f..ba4c5b86efbcce2dc13a69d6f9ea3fce75b4895b 100644
--- a/app/views/doorkeeper/applications/index.html.haml
+++ b/app/views/doorkeeper/applications/index.html.haml
@@ -1,17 +1,19 @@
 - page_title "Applications"
 %h3.page-title Your applications
 %p= link_to 'New Application', new_oauth_application_path, class: 'btn btn-success'
-%table.table.table-striped
-  %thead
-    %tr
-      %th Name
-      %th Callback URL
-      %th
-      %th
-  %tbody
-    - @applications.each do |application|
-      %tr{:id => "application_#{application.id}"}
-        %td= link_to application.name, oauth_application_path(application)
-        %td= application.redirect_uri
-        %td= link_to 'Edit', edit_oauth_application_path(application), class: 'btn btn-link'
-        %td= render 'delete_form', application: application
+
+.table-holder
+  %table.table.table-striped
+    %thead
+      %tr
+        %th Name
+        %th Callback URL
+        %th
+        %th
+    %tbody
+      - @applications.each do |application|
+        %tr{:id => "application_#{application.id}"}
+          %td= link_to application.name, oauth_application_path(application)
+          %td= application.redirect_uri
+          %td= link_to 'Edit', edit_oauth_application_path(application), class: 'btn btn-link'
+          %td= render 'delete_form', application: application
diff --git a/app/views/doorkeeper/applications/show.html.haml b/app/views/doorkeeper/applications/show.html.haml
index 80340aca54cecfd832202359055c59ad7821a680..47442b78d48e4972b4f87e59070e83502ac4a7ea 100644
--- a/app/views/doorkeeper/applications/show.html.haml
+++ b/app/views/doorkeeper/applications/show.html.haml
@@ -2,26 +2,26 @@
 %h3.page-title
   Application: #{@application.name}
 
+.table-holder
+  %table.table
+    %tr
+      %td
+        Application Id
+      %td
+        %code#application_id= @application.uid
+    %tr
+      %td
+        Secret:
+      %td
+        %code#secret= @application.secret
 
-%table.table
-  %tr
-    %td
-      Application Id
-    %td
-      %code#application_id= @application.uid
-  %tr
-    %td
-      Secret:
-    %td
-      %code#secret= @application.secret
-
-  %tr
-    %td
-      Callback url
-    %td
-      - @application.redirect_uri.split.each do |uri|
-        %div
-          %span.monospace= uri
+    %tr
+      %td
+        Callback url
+      %td
+        - @application.redirect_uri.split.each do |uri|
+          %div
+            %span.monospace= uri
 .form-actions
   = link_to 'Edit', edit_oauth_application_path(@application), class: 'btn btn-primary wide pull-left'
   = render 'delete_form', application: @application, submit_btn_css: 'btn btn-danger prepend-left-10'
diff --git a/app/views/doorkeeper/authorized_applications/index.html.haml b/app/views/doorkeeper/authorized_applications/index.html.haml
index 814cdc987ef7c466f4dbccab541d16be2845947b..b184b9c01d4e8c8c4ab1b07efbcb611c887ba740 100644
--- a/app/views/doorkeeper/authorized_applications/index.html.haml
+++ b/app/views/doorkeeper/authorized_applications/index.html.haml
@@ -1,16 +1,17 @@
 %header.page-header
   %h1 Your authorized applications
 %main{:role => "main"}
-  %table.table.table-striped
-    %thead
-      %tr
-        %th Application
-        %th Created At
-        %th
-        %th
-    %tbody
-      - @applications.each do |application|
+  .table-holder
+    %table.table.table-striped
+      %thead
         %tr
-          %td= application.name
-          %td= application.created_at.strftime('%Y-%m-%d %H:%M:%S')
-          %td= render 'delete_form', application: application
\ No newline at end of file
+          %th Application
+          %th Created At
+          %th
+          %th
+      %tbody
+        - @applications.each do |application|
+          %tr
+            %td= application.name
+            %td= application.created_at.strftime('%Y-%m-%d %H:%M:%S')
+            %td= render 'delete_form', application: application
diff --git a/app/views/events/_event_issue.atom.haml b/app/views/events/_event_issue.atom.haml
index 4259f64c19102a11f7543903e53ce20e1ec6ef9f..fad65310021542a8603f16bed8f320960fa2b2af 100644
--- a/app/views/events/_event_issue.atom.haml
+++ b/app/views/events/_event_issue.atom.haml
@@ -1,3 +1,2 @@
 %div{xmlns: "http://www.w3.org/1999/xhtml"}
-  - if issue.description.present?
-    = markdown(issue.description, xhtml: true, reference_only_path: false, project: issue.project)
+  = markdown(issue.description, pipeline: :atom, project: issue.project)
diff --git a/app/views/events/_event_merge_request.atom.haml b/app/views/events/_event_merge_request.atom.haml
index e8ed13df783952f4a0b10d3ecd73b86c915eabab..19bdc7b9ca540f9de4607f90e64901f55aac4411 100644
--- a/app/views/events/_event_merge_request.atom.haml
+++ b/app/views/events/_event_merge_request.atom.haml
@@ -1,3 +1,2 @@
 %div{xmlns: "http://www.w3.org/1999/xhtml"}
-  - if merge_request.description.present?
-    = markdown(merge_request.description, xhtml: true, reference_only_path: false, project: merge_request.project)
+  = markdown(merge_request.description, pipeline: :atom, project: merge_request.project)
diff --git a/app/views/events/_event_note.atom.haml b/app/views/events/_event_note.atom.haml
index cfbfba502027f1a65cbb892f0955db56ca052a05..b730ebbd5f9f5052b272d89939b0e2f6540580d4 100644
--- a/app/views/events/_event_note.atom.haml
+++ b/app/views/events/_event_note.atom.haml
@@ -1,2 +1,2 @@
 %div{xmlns: "http://www.w3.org/1999/xhtml"}
-  = markdown(note.note, xhtml: true, reference_only_path: false, project: note.project)
+  = markdown(note.note, pipeline: :atom, project: note.project)
diff --git a/app/views/events/_event_push.atom.haml b/app/views/events/_event_push.atom.haml
index 3625cb49d8b6b459219fae6edf6d55d80990c93d..b271b9daff1160fba791da0c669b81188ade9f8a 100644
--- a/app/views/events/_event_push.atom.haml
+++ b/app/views/events/_event_push.atom.haml
@@ -6,7 +6,7 @@
       %i
         at
         = commit[:timestamp].to_time.to_s(:short)
-    %blockquote= markdown(escape_once(commit[:message]), xhtml: true, reference_only_path: false, project: event.project)
+    %blockquote= markdown(escape_once(commit[:message]), pipeline: :atom, project: event.project)
   - if event.commits_count > 15
     %p
       %i
diff --git a/app/views/explore/groups/index.html.haml b/app/views/explore/groups/index.html.haml
index 83d4d321c8311bdd0fac3ba20524f27cb7de5da9..fcb07b04083ae03470f5f608e267b66a74426484 100644
--- a/app/views/explore/groups/index.html.haml
+++ b/app/views/explore/groups/index.html.haml
@@ -11,7 +11,7 @@
     = form_tag explore_groups_path, method: :get, class: 'form-inline form-tiny' do |f|
       = hidden_field_tag :sort, @sort
       .form-group
-        = search_field_tag :search, params[:search], placeholder: "Filter by name", class: "form-control search-text-input", id: "groups_search"
+        = search_field_tag :search, params[:search], placeholder: "Filter by name", class: "form-control search-text-input", id: "groups_search", spellcheck: false
       .form-group
         = button_tag 'Search', class: "btn btn-default"
 
diff --git a/app/views/explore/projects/_filter.html.haml b/app/views/explore/projects/_filter.html.haml
index 5a3d689d1e5ce42887a7639b38d2ef4b4d411605..2761272aa8ab15d40a2d575da4f2da92bbf391e6 100644
--- a/app/views/explore/projects/_filter.html.haml
+++ b/app/views/explore/projects/_filter.html.haml
@@ -1,7 +1,7 @@
 .pull-left
   = form_tag explore_projects_filter_path, method: :get, class: 'form-inline form-tiny' do |f|
     .form-group
-      = search_field_tag :search, params[:search], placeholder: "Filter by name", class: "form-control search-text-input", id: "projects_search"
+      = search_field_tag :search, params[:search], placeholder: "Filter by name", class: "form-control search-text-input", id: "projects_search", spellcheck: false
     .form-group
       = button_tag 'Search', class: "btn btn-success"
 
diff --git a/app/views/explore/snippets/index.html.haml b/app/views/explore/snippets/index.html.haml
index 7e4fa7d48734cde7c9ab85bf58eb255d0d852b65..0f100c39ffb8f1c5cd42ad9a0411b5efa456d74a 100644
--- a/app/views/explore/snippets/index.html.haml
+++ b/app/views/explore/snippets/index.html.haml
@@ -10,7 +10,8 @@
   - if current_user
     .pull-right
       = link_to new_snippet_path, class: "btn btn-new", title: "New Snippet" do
-        Add new snippet
+        = icon('plus')
+        New Snippet
 
   .oneline
     Public snippets created by you and other users are listed here
diff --git a/app/views/groups/_projects.html.haml b/app/views/groups/_projects.html.haml
index 9ac56b1e5fe0bfd406ecaaf6e6505cacda92b0dc..11d69977ef9e03b87fd2c5bb113cd131651fb1d7 100644
--- a/app/views/groups/_projects.html.haml
+++ b/app/views/groups/_projects.html.haml
@@ -1,10 +1,11 @@
 .panel.panel-default.projects-list-holder
   .panel-heading.clearfix
     .input-group
-      = search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control'
+      = search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control', spellcheck: false
       - if can? current_user, :create_projects, @group
         %span.input-group-btn
-          = link_to new_project_path(namespace_id: @group.id), class: 'btn btn-success' do
-            New project
+          = link_to new_project_path(namespace_id: @group.id), class: 'btn btn-green' do
+            %i.fa.fa-plus
+            New Project
 
-  = render 'shared/projects/list', projects: @projects, projects_limit: 20, stars: false
+  = render 'shared/projects/list', projects: @projects, projects_limit: 20, stars: false, skip_namespace: true
diff --git a/app/views/groups/group_members/_group_member.html.haml b/app/views/groups/group_members/_group_member.html.haml
index b5f359279d579847ac43223569204543958f9f3a..3c19381321aec37e36924f7c34635726ea265fde 100644
--- a/app/views/groups/group_members/_group_member.html.haml
+++ b/app/views/groups/group_members/_group_member.html.haml
@@ -5,7 +5,7 @@
 %li{class: "#{dom_class(member)} js-toggle-container", id: dom_id(member)}
   %span{class: ("list-item-name" if show_controls)}
     - if member.user
-      = image_tag avatar_icon(user.email, 16), class: "avatar s16", alt: ''
+      = image_tag avatar_icon(user, 16), class: "avatar s16", alt: ''
       %strong
         = link_to user.name, user_path(user)
       %span.cgray= user.username
diff --git a/app/views/groups/group_members/index.html.haml b/app/views/groups/group_members/index.html.haml
index 3a6d07ebddf956a3ea051334396d458e8a898d9a..fee4b0052b590af4f5c3f62d65717275c7e120eb 100644
--- a/app/views/groups/group_members/index.html.haml
+++ b/app/views/groups/group_members/index.html.haml
@@ -12,7 +12,7 @@
 .clearfix.js-toggle-container
   = form_tag group_group_members_path(@group), method: :get, class: 'form-inline member-search-form'  do
     .form-group
-      = search_field_tag :search, params[:search], { placeholder: 'Find existing member by name', class: 'form-control search-text-input' }
+      = search_field_tag :search, params[:search], { placeholder: 'Find existing member by name', class: 'form-control search-text-input', spellcheck: false }
     = button_tag 'Search', class: 'btn'
 
   - if current_user && current_user.can?(:admin_group_member, @group)
diff --git a/app/views/groups/milestones/_issue.html.haml b/app/views/groups/milestones/_issue.html.haml
index 09f9b4b896906d07db480142df62bbbe6b241174..9b85d83d6d854cc8e0f48ed78bfd39c3b7edfeb9 100644
--- a/app/views/groups/milestones/_issue.html.haml
+++ b/app/views/groups/milestones/_issue.html.haml
@@ -7,4 +7,4 @@
     = link_to_gfm issue.title, [project.namespace.becomes(Namespace), project, issue], title: issue.title
   .pull-right.assignee-icon
     - if issue.assignee
-      = image_tag avatar_icon(issue.assignee.email, 16), class: "avatar s16", alt: ''
+      = image_tag avatar_icon(issue.assignee, 16), class: "avatar s16", alt: ''
diff --git a/app/views/groups/milestones/_merge_request.html.haml b/app/views/groups/milestones/_merge_request.html.haml
index d0d1426762b5fb41840f4004bf5b0582150b3a21..e3aa4aad198f558929077e653dd482339f81fd29 100644
--- a/app/views/groups/milestones/_merge_request.html.haml
+++ b/app/views/groups/milestones/_merge_request.html.haml
@@ -7,4 +7,4 @@
     = link_to_gfm merge_request.title, [project.namespace.becomes(Namespace), project, merge_request], title: merge_request.title
   .pull-right.assignee-icon
     - if merge_request.assignee
-      = image_tag avatar_icon(merge_request.assignee.email, 16), class: "avatar s16", alt: ''
+      = image_tag avatar_icon(merge_request.assignee, 16), class: "avatar s16", alt: ''
diff --git a/app/views/groups/milestones/show.html.haml b/app/views/groups/milestones/show.html.haml
index 0c213f421869190ad434643947ea71cb005d9baf..a92ad5d751b985815ddcf3dadae39dacb1caea5c 100644
--- a/app/views/groups/milestones/show.html.haml
+++ b/app/views/groups/milestones/show.html.haml
@@ -21,26 +21,28 @@
     %span All issues for this milestone are closed. You may close the milestone now.
 
 .description
-%table.table
-  %thead
-    %tr
-      %th Project
-      %th Open issues
-      %th State
-      %th Due date
-  - @group_milestone.milestones.each do |milestone|
-    %tr
-      %td
-        = link_to "#{milestone.project.name}", namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone)
-      %td
-        = milestone.issues.opened.count
-      %td
-        - if milestone.closed?
-          Closed
-        - else
-          Open
-      %td
-        = milestone.expires_at
+
+.table-holder
+  %table.table
+    %thead
+      %tr
+        %th Project
+        %th Open issues
+        %th State
+        %th Due date
+    - @group_milestone.milestones.each do |milestone|
+      %tr
+        %td
+          = link_to "#{milestone.project.name}", namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone)
+        %td
+          = milestone.issues.opened.count
+        %td
+          - if milestone.closed?
+            Closed
+          - else
+            Open
+        %td
+          = milestone.expires_at
 
 .context
   %p.lead
@@ -87,7 +89,7 @@
       - @group_milestone.participants.each do |user|
         %li
           = link_to user, title: user.name, class: "darken" do
-            = image_tag avatar_icon(user.email, 32), class: "avatar s32"
+            = image_tag avatar_icon(user, 32), class: "avatar s32"
             %strong= truncate(user.name, lenght: 40)
             %br
             %small.cgray= user.username
diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml
index a9ba9d2ba101a31bf1ad716ec1586d314aa8281a..dc8e81323a63daf43f7e527162142042b3a37111 100644
--- a/app/views/groups/show.html.haml
+++ b/app/views/groups/show.html.haml
@@ -25,11 +25,9 @@
         .hidden-xs
           - if current_user
             = render "events/event_last_push", event: @last_push
-
-            %ul.nav.nav-pills.event_filter.pull-right
-              %li
-                = link_to group_path(@group, { format: :atom, private_token: current_user.private_token }), title: "Feed", class: 'rss-btn' do
-                  %i.fa.fa-rss
+            .pull-right
+              = link_to group_path(@group, { format: :atom, private_token: current_user.private_token }), title: "Feed", class: 'btn rss-btn' do
+                %i.fa.fa-rss
 
             = render 'shared/event_filter'
             %hr
diff --git a/app/views/help/_shortcuts.html.haml b/app/views/help/_shortcuts.html.haml
index e809d99ba71ffb20a69dbe30e9e97f05dc508760..67349fcbd787bf437315ba88e83cb55138c06d47 100644
--- a/app/views/help/_shortcuts.html.haml
+++ b/app/views/help/_shortcuts.html.haml
@@ -99,6 +99,12 @@
                   .key c
                 %td
                   Go to commits
+              %tr
+                %td.shortcut
+                  .key g
+                  .key b
+                %td
+                  Go to builds
               %tr
                 %td.shortcut
                   .key g
diff --git a/app/views/help/ui.html.haml b/app/views/help/ui.html.haml
index 7c89457ace3885129eaea47487e560ead6dec74a..2169a821fb24c6fc22c7c6a01224430d82726610 100644
--- a/app/views/help/ui.html.haml
+++ b/app/views/help/ui.html.haml
@@ -14,6 +14,8 @@
       = link_to 'Lists', '#lists'
     %li
       = link_to 'Tables', '#tables'
+    %li
+      = link_to 'Nav', '#nav'
     %li
       = link_to 'Buttons', '#buttons'
     %li
@@ -30,16 +32,31 @@
   %h2#blocks Blocks
 
   %h3
-    %code .well
+    %code .gray-content-block
+
 
 
-  .well
-    %h4 Something
+  .gray-content-block.middle-block
+    %h4 Normal block inside content
+    = lorem
+
+  .gray-content-block.second-block
+    %h4 Second block
     = lorem
 
 
   %h2#lists Lists
 
+  %h3
+    %code .content-list
+  %ul.content-list
+    %li
+      One item
+    %li
+      One item
+    %li
+      One item
+
   %h3
     %code .well-list
   %ul.well-list
@@ -102,11 +119,40 @@
           %td the Bird
           %td @twitter
 
+  %h2#navs Navigation
+
+  %h3
+    %code .center-top-menu
+  .example
+    %ul.center-top-menu
+      %li.active
+        %a Open
+      %li
+        %a Closed
+
+  %h3
+    %code .btn-group.btn-group-next
+  .example
+    %div.btn-group.btn-group-next
+      %a.btn.active Open
+      %a.btn Closed
+
+
+  %h3
+    %code .nav.nav-tabs
+  .example
+    %ul.nav.nav-tabs
+      %li.active
+        %a Open
+      %li
+        %a Closed
+
 
   %h2#buttons Buttons
 
   .example
     %button.btn.btn-default{:type => "button"} Default
+    %button.btn.btn-gray{:type => "button"} Gray
     %button.btn.btn-primary{:type => "button"} Primary
     %button.btn.btn-success{:type => "button"} Success
     %button.btn.btn-info{:type => "button"} Info
diff --git a/app/views/import/bitbucket/status.html.haml b/app/views/import/bitbucket/status.html.haml
index 777eb482714b37730689522e973e4f4d1a0ef448..30bcdb8682775708840fc86826021e32b3808985 100644
--- a/app/views/import/bitbucket/status.html.haml
+++ b/app/views/import/bitbucket/status.html.haml
@@ -14,45 +14,46 @@
     = button_tag 'Import all projects', class: "btn btn-success js-import-all"
 
 
-%table.table.import-jobs
-  %thead
-    %tr
-      %th From Bitbucket
-      %th To GitLab
-      %th Status
-  %tbody
-    - @already_added_projects.each do |project|
-      %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
-        %td
-          = link_to project.import_source, "https://bitbucket.org/#{project.import_source}", target: "_blank"
-        %td
-          %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
-        %td.job-status
-          - if project.import_status == 'finished'
-            %span
-              %i.fa.fa-check
-              done
-          - elsif project.import_status == 'started'
-            %i.fa.fa-spinner.fa-spin
-            started
-          - else
-            = project.human_import_status_name
+.table-holder
+  %table.table.import-jobs
+    %thead
+      %tr
+        %th From Bitbucket
+        %th To GitLab
+        %th Status
+    %tbody
+      - @already_added_projects.each do |project|
+        %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
+          %td
+            = link_to project.import_source, "https://bitbucket.org/#{project.import_source}", target: "_blank"
+          %td
+            %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
+          %td.job-status
+            - if project.import_status == 'finished'
+              %span
+                %i.fa.fa-check
+                done
+            - elsif project.import_status == 'started'
+              %i.fa.fa-spinner.fa-spin
+              started
+            - else
+              = project.human_import_status_name
 
-    - @repos.each do |repo|
-      %tr{id: "repo_#{repo["owner"]}___#{repo["slug"]}"}
-        %td
-          = link_to "#{repo["owner"]}/#{repo["slug"]}", "https://bitbucket.org/#{repo["owner"]}/#{repo["slug"]}", target: "_blank"
-        %td.import-target
-          = "#{repo["owner"]}/#{repo["slug"]}"
-        %td.import-actions.job-status
-          = button_tag "Import", class: "btn js-add-to-import"
-    - @incompatible_repos.each do |repo|
-      %tr{id: "repo_#{repo["owner"]}___#{repo["slug"]}"}
-        %td
-          = link_to "#{repo["owner"]}/#{repo["slug"]}", "https://bitbucket.org/#{repo["owner"]}/#{repo["slug"]}", target: "_blank"
-        %td.import-target
-        %td.import-actions-job-status
-          = label_tag "Incompatible Project", nil, class: "label label-danger"
+      - @repos.each do |repo|
+        %tr{id: "repo_#{repo["owner"]}___#{repo["slug"]}"}
+          %td
+            = link_to "#{repo["owner"]}/#{repo["slug"]}", "https://bitbucket.org/#{repo["owner"]}/#{repo["slug"]}", target: "_blank"
+          %td.import-target
+            = "#{repo["owner"]}/#{repo["slug"]}"
+          %td.import-actions.job-status
+            = button_tag "Import", class: "btn js-add-to-import"
+      - @incompatible_repos.each do |repo|
+        %tr{id: "repo_#{repo["owner"]}___#{repo["slug"]}"}
+          %td
+            = link_to "#{repo["owner"]}/#{repo["slug"]}", "https://bitbucket.org/#{repo["owner"]}/#{repo["slug"]}", target: "_blank"
+          %td.import-target
+          %td.import-actions-job-status
+            = label_tag "Incompatible Project", nil, class: "label label-danger"
 
 - if @incompatible_repos.any?
   %p
diff --git a/app/views/import/fogbugz/new_user_map.html.haml b/app/views/import/fogbugz/new_user_map.html.haml
index 25cebfb36650b49137f5ce6818d882691afe72ba..a701e49ac56ea178be31daab235dfce6094a661f 100644
--- a/app/views/import/fogbugz/new_user_map.html.haml
+++ b/app/views/import/fogbugz/new_user_map.html.haml
@@ -25,22 +25,23 @@
         of issues and comments (e.g. "By <a href="#">@johnsmith</a>"). It will also 
         associate and/or assign these issues and comments with the selected user.
 
-  %table.table
-    %thead
-      %tr
-        %th ID
-        %th Name
-        %th Email
-        %th GitLab User
-    %tbody
-      - @user_map.each do |id, user|
+  .table-holder
+    %table.table
+      %thead
         %tr
-          %td= id
-          %td= text_field_tag "users[#{id}][name]", user[:name], class: 'form-control'
-          %td= text_field_tag "users[#{id}][email]", user[:email], class: 'form-control'
-          %td
-            = users_select_tag("users[#{id}][gitlab_user]", class: 'custom-form-control',
-              scope: :all, email_user: true, selected: user[:gitlab_user])
+          %th ID
+          %th Name
+          %th Email
+          %th GitLab User
+      %tbody
+        - @user_map.each do |id, user|
+          %tr
+            %td= id
+            %td= text_field_tag "users[#{id}][name]", user[:name], class: 'form-control'
+            %td= text_field_tag "users[#{id}][email]", user[:email], class: 'form-control'
+            %td
+              = users_select_tag("users[#{id}][gitlab_user]", class: 'custom-form-control',
+                scope: :all, email_user: true, selected: user[:gitlab_user])
 
   .form-actions
     = submit_tag 'Continue to the next step', class: 'btn btn-create'
diff --git a/app/views/import/fogbugz/status.html.haml b/app/views/import/fogbugz/status.html.haml
index f179ece402d1f81c88308e4a4e63b0ed7154d7e5..beca6ab14232bc59d55569643bf35e8a58edb857 100644
--- a/app/views/import/fogbugz/status.html.haml
+++ b/app/views/import/fogbugz/status.html.haml
@@ -14,38 +14,39 @@
   %p
   = button_tag 'Import all projects', class: 'btn btn-success js-import-all'
 
-%table.table.import-jobs
-  %thead
-    %tr
-      %th From FogBugz
-      %th To GitLab
-      %th Status
-  %tbody
-    - @already_added_projects.each do |project|
-      %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
-        %td
-          = project.import_source
-        %td
-          %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
-        %td.job-status
-          - if project.import_status == 'finished'
-            %span
-              %i.fa.fa-check
-              done
-          - elsif project.import_status == 'started'
-            %i.fa.fa-spinner.fa-spin
-            started
-          - else
-            = project.human_import_status_name
+.table-holder
+  %table.table.import-jobs
+    %thead
+      %tr
+        %th From FogBugz
+        %th To GitLab
+        %th Status
+    %tbody
+      - @already_added_projects.each do |project|
+        %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
+          %td
+            = project.import_source
+          %td
+            %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
+          %td.job-status
+            - if project.import_status == 'finished'
+              %span
+                %i.fa.fa-check
+                done
+            - elsif project.import_status == 'started'
+              %i.fa.fa-spinner.fa-spin
+              started
+            - else
+              = project.human_import_status_name
 
-    - @repos.each do |repo|
-      %tr{id: "repo_#{repo.id}"}
-        %td
-          = repo.name
-        %td.import-target
-          = "#{current_user.username}/#{repo.name}"
-        %td.import-actions.job-status
-          = button_tag "Import", class: "btn js-add-to-import"
+      - @repos.each do |repo|
+        %tr{id: "repo_#{repo.id}"}
+          %td
+            = repo.name
+          %td.import-target
+            = "#{current_user.username}/#{repo.name}"
+          %td.import-actions.job-status
+            = button_tag "Import", class: "btn js-add-to-import"
 
 :coffeescript
   new ImporterStatus("#{jobs_import_fogbugz_path}", "#{import_fogbugz_path}")
diff --git a/app/views/import/github/status.html.haml b/app/views/import/github/status.html.haml
index ef5524982390fe4817753d043bb934157cd39601..0669b05adca9da10e1ffd49fbfc6cae15e147c11 100644
--- a/app/views/import/github/status.html.haml
+++ b/app/views/import/github/status.html.haml
@@ -9,38 +9,39 @@
 %p
   = button_tag 'Import all projects', class: "btn btn-success js-import-all"
 
-%table.table.import-jobs
-  %thead
-    %tr
-      %th From GitHub
-      %th To GitLab
-      %th Status
-  %tbody
-    - @already_added_projects.each do |project|
-      %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
-        %td
-          = link_to project.import_source, "https://github.com/#{project.import_source}", target: "_blank"
-        %td
-          %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
-        %td.job-status
-          - if project.import_status == 'finished'
-            %span
-              %i.fa.fa-check
-              done
-          - elsif project.import_status == 'started'
-            %i.fa.fa-spinner.fa-spin
-            started
-          - else
-            = project.human_import_status_name
+.table-holder
+  %table.table.import-jobs
+    %thead
+      %tr
+        %th From GitHub
+        %th To GitLab
+        %th Status
+    %tbody
+      - @already_added_projects.each do |project|
+        %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
+          %td
+            = link_to project.import_source, "https://github.com/#{project.import_source}", target: "_blank"
+          %td
+            %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
+          %td.job-status
+            - if project.import_status == 'finished'
+              %span
+                %i.fa.fa-check
+                done
+            - elsif project.import_status == 'started'
+              %i.fa.fa-spinner.fa-spin
+              started
+            - else
+              = project.human_import_status_name
 
-    - @repos.each do |repo|
-      %tr{id: "repo_#{repo.id}"}
-        %td
-          = link_to repo.full_name, "https://github.com/#{repo.full_name}", target: "_blank"
-        %td.import-target
-          = repo.full_name
-        %td.import-actions.job-status
-          = button_tag "Import", class: "btn js-add-to-import"
+      - @repos.each do |repo|
+        %tr{id: "repo_#{repo.id}"}
+          %td
+            = link_to repo.full_name, "https://github.com/#{repo.full_name}", target: "_blank"
+          %td.import-target
+            = repo.full_name
+          %td.import-actions.job-status
+            = button_tag "Import", class: "btn js-add-to-import"
 
 :coffeescript
   new ImporterStatus("#{jobs_import_github_path}", "#{import_github_path}")
diff --git a/app/views/import/gitlab/status.html.haml b/app/views/import/gitlab/status.html.haml
index 727f3c7e7fa69b1ace9ff715880c72d012d7f4d4..3bc85059e7d926a5375cee54a7d1fbb5659c1988 100644
--- a/app/views/import/gitlab/status.html.haml
+++ b/app/views/import/gitlab/status.html.haml
@@ -9,38 +9,39 @@
 %p
   = button_tag 'Import all projects', class: "btn btn-success js-import-all"
 
-%table.table.import-jobs
-  %thead
-    %tr
-      %th From GitLab.com
-      %th To this GitLab instance
-      %th Status
-  %tbody
-    - @already_added_projects.each do |project|
-      %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
-        %td
-          = link_to project.import_source, "https://gitlab.com/#{project.import_source}", target: "_blank"
-        %td
-          %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
-        %td.job-status
-          - if project.import_status == 'finished'
-            %span
-              %i.fa.fa-check
-              done
-          - elsif project.import_status == 'started'
-            %i.fa.fa-spinner.fa-spin
-            started
-          - else
-            = project.human_import_status_name
+.table-holder
+  %table.table.import-jobs
+    %thead
+      %tr
+        %th From GitLab.com
+        %th To this GitLab instance
+        %th Status
+    %tbody
+      - @already_added_projects.each do |project|
+        %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
+          %td
+            = link_to project.import_source, "https://gitlab.com/#{project.import_source}", target: "_blank"
+          %td
+            %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
+          %td.job-status
+            - if project.import_status == 'finished'
+              %span
+                %i.fa.fa-check
+                done
+            - elsif project.import_status == 'started'
+              %i.fa.fa-spinner.fa-spin
+              started
+            - else
+              = project.human_import_status_name
 
-    - @repos.each do |repo|
-      %tr{id: "repo_#{repo["id"]}"}
-        %td
-          = link_to repo["path_with_namespace"], "https://gitlab.com/#{repo["path_with_namespace"]}", target: "_blank"
-        %td.import-target
-          = repo["path_with_namespace"]
-        %td.import-actions.job-status
-          = button_tag "Import", class: "btn js-add-to-import"
+      - @repos.each do |repo|
+        %tr{id: "repo_#{repo["id"]}"}
+          %td
+            = link_to repo["path_with_namespace"], "https://gitlab.com/#{repo["path_with_namespace"]}", target: "_blank"
+          %td.import-target
+            = repo["path_with_namespace"]
+          %td.import-actions.job-status
+            = button_tag "Import", class: "btn js-add-to-import"
 
 :coffeescript
   new ImporterStatus("#{jobs_import_gitlab_path}", "#{import_gitlab_path}")
diff --git a/app/views/import/gitorious/status.html.haml b/app/views/import/gitorious/status.html.haml
index bff7ee7c85d657e532cb754f5a9cb4de1953fd52..2e3a535737f0172e0c75694fa59873aceeff964b 100644
--- a/app/views/import/gitorious/status.html.haml
+++ b/app/views/import/gitorious/status.html.haml
@@ -9,38 +9,39 @@
 %p
   = button_tag 'Import all projects', class: "btn btn-success js-import-all"
 
-%table.table.import-jobs
-  %thead
-    %tr
-      %th From Gitorious.org
-      %th To GitLab
-      %th Status
-  %tbody
-    - @already_added_projects.each do |project|
-      %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
-        %td
-          = link_to project.import_source, "https://gitorious.org/#{project.import_source}", target: "_blank"
-        %td
-          %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
-        %td.job-status
-          - if project.import_status == 'finished'
-            %span
-              %i.fa.fa-check
-              done
-          - elsif project.import_status == 'started'
-            %i.fa.fa-spinner.fa-spin
-            started
-          - else
-            = project.human_import_status_name
+.table-holder
+  %table.table.import-jobs
+    %thead
+      %tr
+        %th From Gitorious.org
+        %th To GitLab
+        %th Status
+    %tbody
+      - @already_added_projects.each do |project|
+        %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
+          %td
+            = link_to project.import_source, "https://gitorious.org/#{project.import_source}", target: "_blank"
+          %td
+            %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
+          %td.job-status
+            - if project.import_status == 'finished'
+              %span
+                %i.fa.fa-check
+                done
+            - elsif project.import_status == 'started'
+              %i.fa.fa-spinner.fa-spin
+              started
+            - else
+              = project.human_import_status_name
 
-    - @repos.each do |repo|
-      %tr{id: "repo_#{repo.id}"}
-        %td
-          = link_to repo.full_name, "https://gitorious.org/#{repo.full_name}", target: "_blank"
-        %td.import-target
-          = repo.full_name
-        %td.import-actions.job-status
-          = button_tag "Import", class: "btn js-add-to-import"
+      - @repos.each do |repo|
+        %tr{id: "repo_#{repo.id}"}
+          %td
+            = link_to repo.full_name, "https://gitorious.org/#{repo.full_name}", target: "_blank"
+          %td.import-target
+            = repo.full_name
+          %td.import-actions.job-status
+            = button_tag "Import", class: "btn js-add-to-import"
 
 :coffeescript
   new ImporterStatus("#{jobs_import_gitorious_path}", "#{import_gitorious_path}")
diff --git a/app/views/import/google_code/status.html.haml b/app/views/import/google_code/status.html.haml
index e8ec79e72f7fed286f5c4bfa171f48cfa418a02a..c5af06edf8705bc382f0dc0814574c7d02bc834d 100644
--- a/app/views/import/google_code/status.html.haml
+++ b/app/views/import/google_code/status.html.haml
@@ -17,45 +17,46 @@
   - else
     = button_tag 'Import all projects', class: "btn btn-success js-import-all"
 
-%table.table.import-jobs
-  %thead
-    %tr
-      %th From Google Code
-      %th To GitLab
-      %th Status
-  %tbody
-    - @already_added_projects.each do |project|
-      %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
-        %td
-          = link_to project.import_source, "https://code.google.com/p/#{project.import_source}", target: "_blank"
-        %td
-          %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
-        %td.job-status
-          - if project.import_status == 'finished'
-            %span
-              %i.fa.fa-check
-              done
-          - elsif project.import_status == 'started'
-            %i.fa.fa-spinner.fa-spin
-            started
-          - else
-            = project.human_import_status_name
+.table-holder
+  %table.table.import-jobs
+    %thead
+      %tr
+        %th From Google Code
+        %th To GitLab
+        %th Status
+    %tbody
+      - @already_added_projects.each do |project|
+        %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
+          %td
+            = link_to project.import_source, "https://code.google.com/p/#{project.import_source}", target: "_blank"
+          %td
+            %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
+          %td.job-status
+            - if project.import_status == 'finished'
+              %span
+                %i.fa.fa-check
+                done
+            - elsif project.import_status == 'started'
+              %i.fa.fa-spinner.fa-spin
+              started
+            - else
+              = project.human_import_status_name
 
-    - @repos.each do |repo|
-      %tr{id: "repo_#{repo.id}"}
-        %td
-          = link_to repo.name, "https://code.google.com/p/#{repo.name}", target: "_blank"
-        %td.import-target
-          = "#{current_user.username}/#{repo.name}"
-        %td.import-actions.job-status
-          = button_tag "Import", class: "btn js-add-to-import"
-    - @incompatible_repos.each do |repo|
-      %tr{id: "repo_#{repo.id}"}
-        %td
-          = link_to repo.name, "https://code.google.com/p/#{repo.name}", target: "_blank"
-        %td.import-target
-        %td.import-actions-job-status
-          = label_tag "Incompatible Project", nil, class: "label label-danger"
+      - @repos.each do |repo|
+        %tr{id: "repo_#{repo.id}"}
+          %td
+            = link_to repo.name, "https://code.google.com/p/#{repo.name}", target: "_blank"
+          %td.import-target
+            = "#{current_user.username}/#{repo.name}"
+          %td.import-actions.job-status
+            = button_tag "Import", class: "btn js-add-to-import"
+      - @incompatible_repos.each do |repo|
+        %tr{id: "repo_#{repo.id}"}
+          %td
+            = link_to repo.name, "https://code.google.com/p/#{repo.name}", target: "_blank"
+          %td.import-target
+          %td.import-actions-job-status
+            = label_tag "Incompatible Project", nil, class: "label label-danger"
 
 - if @incompatible_repos.any?
   %p
diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml
index c3b137e3ddf6b607d53e9b66cbb3699a3f6a9d65..74174a72f5a8c39d972e339c02d61f528063e8bf 100644
--- a/app/views/layouts/_head.html.haml
+++ b/app/views/layouts/_head.html.haml
@@ -3,7 +3,7 @@
   %meta{charset: "utf-8"}
   %meta{'http-equiv' => 'X-UA-Compatible', content: 'IE=edge'}
   %meta{content: "GitLab Community Edition", name: "description"}
-  %meta{name: 'referrer', content: 'origin'}
+  %meta{name: 'referrer', content: 'origin-when-cross-origin'}
 
   %title= page_title
 
diff --git a/app/views/layouts/_init_auto_complete.html.haml b/app/views/layouts/_init_auto_complete.html.haml
index 3c58f10e759f30200430684c241545265cbe1e97..035fe0056d352bc301b5eb8615c8a61042639a0f 100644
--- a/app/views/layouts/_init_auto_complete.html.haml
+++ b/app/views/layouts/_init_auto_complete.html.haml
@@ -1,3 +1,4 @@
+- project = @target_project || @project
 :javascript
-  GitLab.GfmAutoComplete.dataSource = "#{autocomplete_sources_namespace_project_path(@project.namespace, @project, type: @noteable.class, type_id: params[:id])}"
+  GitLab.GfmAutoComplete.dataSource = "#{autocomplete_sources_namespace_project_path(project.namespace, project, type: @noteable.class, type_id: params[:id])}"
   GitLab.GfmAutoComplete.setup();
diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml
index 2468687b56d8c26894e9bc91b749b0b3a3a30f6d..352b8040cf4aa871649584aed4d018a273d8461b 100644
--- a/app/views/layouts/_page.html.haml
+++ b/app/views/layouts/_page.html.haml
@@ -6,7 +6,7 @@
         = brand_header_logo
         .gitlab-text-container
           %h3 GitLab
-          
+
     - if defined?(sidebar) && sidebar
       = render "layouts/nav/#{sidebar}"
     - elsif current_user
@@ -18,11 +18,12 @@
       = render partial: 'layouts/collapse_button'
     - if current_user
       = link_to current_user, class: 'sidebar-user' do
-        = image_tag avatar_icon(current_user.email, 60), alt: 'User activity', class: 'avatar avatar s36'
+        = image_tag avatar_icon(current_user, 60), alt: 'User activity', class: 'avatar avatar s36'
         .username
           = current_user.username
   .content-wrapper
     = render "layouts/flash"
+    = yield :flash_message
     %div{ class: container_class }
       .content
         .clearfix
diff --git a/app/views/layouts/_search.html.haml b/app/views/layouts/_search.html.haml
index e2d2dec7ab814d3d98df01734db0e8bb998e9dd8..ceb64ce3157f69fd054ece96b2fcfac9f66ea4fc 100644
--- a/app/views/layouts/_search.html.haml
+++ b/app/views/layouts/_search.html.haml
@@ -1,6 +1,6 @@
 .search
   = form_tag search_path, method: :get, class: 'navbar-form pull-left' do |f|
-    = search_field_tag "search", nil, placeholder: search_placeholder, class: "search-input form-control"
+    = search_field_tag "search", nil, placeholder: search_placeholder, class: "search-input form-control", spellcheck: false
     = hidden_field_tag :group_id, @group.try(:id)
     - if @project && @project.persisted?
       = hidden_field_tag :project_id, @project.id
diff --git a/app/views/layouts/ci/_nav_project.html.haml b/app/views/layouts/ci/_nav_project.html.haml
index 7daf9342e42a5f2d56a0e2ab59bba96574f2ecb2..f094edbfa87cac6accd2c5e2380a45225f5176fe 100644
--- a/app/views/layouts/ci/_nav_project.html.haml
+++ b/app/views/layouts/ci/_nav_project.html.haml
@@ -5,45 +5,8 @@
       %span
         Back to project
   %li.separate-item
-  = nav_link path: ['projects#show', 'commits#show', 'builds#show'] do
-    = link_to ci_project_path(@project) do
-      = icon('list-alt fw')
-      %span
-        Commits
-        %span.count= @project.commits.count
-    = nav_link path: ['runners#index', 'runners#show', 'runners#edit'] do
-      = link_to ci_project_runners_path(@project) do
-        = icon('cog fw')
-        %span
-          Runners
-    = nav_link path: 'variables#show' do
-      = link_to ci_project_variables_path(@project) do
-        = icon('code fw')
-        %span
-          Variables
-    = nav_link path: 'web_hooks#index' do
-      = link_to ci_project_web_hooks_path(@project) do
-        = icon('link fw')
-        %span
-          Web Hooks
-    = nav_link path: 'triggers#index' do
-      = link_to ci_project_triggers_path(@project) do
-        = icon('retweet fw')
-        %span
-          Triggers
-    = nav_link path: ['services#index', 'services#edit'] do
-      = link_to ci_project_services_path(@project) do
-        = icon('share fw')
-        %span
-          Services
     = nav_link path: 'events#index' do
       = link_to ci_project_events_path(@project) do
         = icon('book fw')
         %span
           Events
-    %li.separate-item
-    = nav_link path: 'projects#edit' do
-      = link_to edit_ci_project_path(@project) do
-        = icon('cogs fw')
-        %span
-          Settings
diff --git a/app/views/layouts/ci/_page.html.haml b/app/views/layouts/ci/_page.html.haml
index bb5ec727bffbcf55f08f1802b9fd2aa35b26ef3f..ab3e29c3f424c63f106f62c28ddf0fb88cb75a3d 100644
--- a/app/views/layouts/ci/_page.html.haml
+++ b/app/views/layouts/ci/_page.html.haml
@@ -15,7 +15,7 @@
       = render partial: 'layouts/collapse_button'
     - if current_user
       = link_to current_user, class: 'sidebar-user' do
-        = image_tag avatar_icon(current_user.email, 60), alt: 'User activity', class: 'avatar avatar s36'
+        = image_tag avatar_icon(current_user, 60), alt: 'User activity', class: 'avatar avatar s36'
         .username
           = current_user.username
   .content-wrapper
diff --git a/app/views/layouts/ci/build.html.haml b/app/views/layouts/ci/build.html.haml
deleted file mode 100644
index a1356f0dc2ea2b802c5c7be62e681769951dba82..0000000000000000000000000000000000000000
--- a/app/views/layouts/ci/build.html.haml
+++ /dev/null
@@ -1,11 +0,0 @@
-!!! 5
-%html{ lang: "en"}
-  = render 'layouts/head'
-  %body{class: "ci-body #{user_application_theme}", 'data-page' => body_data_page}
-    - header_title ci_commit_title(@commit)
-    - if current_user
-      = render "layouts/header/default", title: header_title
-    - else
-      = render "layouts/header/public", title: header_title
-
-    = render 'layouts/ci/page', sidebar: 'nav_project'
diff --git a/app/views/layouts/ci/commit.html.haml b/app/views/layouts/ci/commit.html.haml
deleted file mode 100644
index a1356f0dc2ea2b802c5c7be62e681769951dba82..0000000000000000000000000000000000000000
--- a/app/views/layouts/ci/commit.html.haml
+++ /dev/null
@@ -1,11 +0,0 @@
-!!! 5
-%html{ lang: "en"}
-  = render 'layouts/head'
-  %body{class: "ci-body #{user_application_theme}", 'data-page' => body_data_page}
-    - header_title ci_commit_title(@commit)
-    - if current_user
-      = render "layouts/header/default", title: header_title
-    - else
-      = render "layouts/header/public", title: header_title
-
-    = render 'layouts/ci/page', sidebar: 'nav_project'
diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml
index 21d8655131f9650c33c789c32984e18906054460..b1a1d53184678bcb83ca59473b1169ca11e032ec 100644
--- a/app/views/layouts/nav/_dashboard.html.haml
+++ b/app/views/layouts/nav/_dashboard.html.haml
@@ -1,6 +1,6 @@
 %ul.nav.nav-sidebar
   = nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: {class: 'home'}) do
-    = link_to root_path, title: 'Projects', data: {placement: 'right'} do
+    = link_to dashboard_projects_path, title: 'Projects', data: {placement: 'right'} do
       = icon('home fw')
       %span
         Projects
diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml
index a218ec7486cf9fe649e08ec4c92bfa3bcd1e7220..53a913fe8f379e696555e05a8ef75d8febf0f8cc 100644
--- a/app/views/layouts/nav/_project.html.haml
+++ b/app/views/layouts/nav/_project.html.haml
@@ -38,6 +38,14 @@
         %span
           Commits
 
+  - if project_nav_tab? :builds
+    = nav_link(controller: %w(builds)) do
+      = link_to project_builds_path(@project), title: 'Builds', class: 'shortcuts-builds', data: {placement: 'right'} do
+        = icon('cubes fw')
+        %span
+          Builds
+          %span.count.builds_counter= @project.ci_builds.running_or_pending.count(:all)
+
   - if project_nav_tab? :network
     = nav_link(controller: %w(network)) do
       = link_to namespace_project_network_path(@project.namespace, @project, current_ref), title: 'Network', class: 'shortcuts-network', data: {placement: 'right'} do
@@ -76,13 +84,6 @@
           Merge Requests
           %span.count.merge_counter= @project.merge_requests.opened.count
 
-  - if @project.gitlab_ci?
-    = nav_link(controller: [:ci, :project]) do
-      = link_to ci_project_path(@project.gitlab_ci_project), title: 'Continuous Integration', data: {placement: 'right'} do
-        = icon('building fw')
-        %span
-          Continuous Integration
-
   - if project_nav_tab? :settings
     = nav_link(controller: [:project_members, :teams]) do
       = link_to namespace_project_project_members_path(@project.namespace, @project), title: 'Members', class: 'team-tab tab', data: {placement: 'right'} do
diff --git a/app/views/layouts/nav/_project_settings.html.haml b/app/views/layouts/nav/_project_settings.html.haml
index 857fb199957c41c37ff3794895e448b9b9d87f47..954dbe5d2b9079c39f6fd76c1ee8bf8545e9c6b0 100644
--- a/app/views/layouts/nav/_project_settings.html.haml
+++ b/app/views/layouts/nav/_project_settings.html.haml
@@ -34,3 +34,39 @@
         %span
           Protected Branches
 
+    - if @project.gitlab_ci?
+      = nav_link(controller: :runners) do
+        = link_to namespace_project_runners_path(@project.namespace, @project), title: 'Runners', data: {placement: 'right'} do
+          = icon('cog fw')
+          %span
+            Runners
+      = nav_link(controller: :variables) do
+        = link_to namespace_project_variables_path(@project.namespace, @project) do
+          = icon('code fw')
+          %span
+            Variables
+      = nav_link path: 'triggers#index' do
+        = link_to namespace_project_triggers_path(@project.namespace, @project) do
+          = icon('retweet fw')
+          %span
+            Triggers
+      = nav_link path: 'ci_web_hooks#index' do
+        = link_to namespace_project_ci_web_hooks_path(@project.namespace, @project) do
+          = icon('link fw')
+          %span
+            CI Web Hooks
+      = nav_link path: 'ci_settings#edit' do
+        = link_to edit_namespace_project_ci_settings_path(@project.namespace, @project) do
+          = icon('building fw')
+          %span
+            CI Settings
+      = nav_link controller: 'ci_services' do
+        = link_to namespace_project_ci_services_path(@project.namespace, @project) do
+          = icon('share fw')
+          %span
+            CI Services
+      = nav_link path: 'events#index' do
+        = link_to ci_project_events_path(@project.gitlab_ci_project) do
+          = icon('book fw')
+          %span
+            CI Events
diff --git a/app/views/layouts/notify.html.haml b/app/views/layouts/notify.html.haml
index ec209c38eeddbeea91628f00a5f642d0cf26dff1..854cda57c39638646c04059d57b133cb020be69e 100644
--- a/app/views/layouts/notify.html.haml
+++ b/app/views/layouts/notify.html.haml
@@ -41,6 +41,8 @@
             #{link_to "view it on GitLab", @target_url}.
           - else
             #{link_to "View it on GitLab", @target_url}
+          %br
+          You're receiving this email because of your account on #{link_to Gitlab.config.gitlab.host, root_url}. 
+          If you'd like to receive fewer emails, you can adjust your notification settings.
+
           = email_action @target_url
-        - if @project && !@disable_footer
-          You're receiving this notification because you are a member of the #{link_to_unless @target_url, @project.name_with_namespace, namespace_project_url(@project.namespace, @project)} project team.
diff --git a/app/views/layouts/project.html.haml b/app/views/layouts/project.html.haml
index 78dafcd8bfaff4e41e61f622c8bc55f653003596..abf73bcc70957c4509687ead96de4ffb826a107e 100644
--- a/app/views/layouts/project.html.haml
+++ b/app/views/layouts/project.html.haml
@@ -3,10 +3,11 @@
 - sidebar       "project"               unless sidebar
 
 - content_for :scripts_body_top do
+  - project = @target_project || @project
   - if current_user
     :javascript
-      window.project_uploads_path = "#{namespace_project_uploads_path @project.namespace, @project}";
-      window.markdown_preview_path = "#{markdown_preview_namespace_project_path(@project.namespace, @project)}";
+      window.project_uploads_path = "#{namespace_project_uploads_path project.namespace,project}";
+      window.markdown_preview_path = "#{markdown_preview_namespace_project_path(project.namespace, project)}";
 
 - content_for :scripts_body do
   = render "layouts/init_auto_complete" if current_user
diff --git a/app/views/notify/_note_message.html.haml b/app/views/notify/_note_message.html.haml
index 3fd4b04ac8456a42f591a3f77fa197866e873c72..00cb4aa24cc28b60b4e1c2c98efc7eff2050a1b6 100644
--- a/app/views/notify/_note_message.html.haml
+++ b/app/views/notify/_note_message.html.haml
@@ -1,2 +1,2 @@
 %div
-  = markdown(@note.note, reference_only_path: false)
+  = markdown(@note.note, pipeline: :email)
diff --git a/app/views/notify/merged_merge_request_email.text.haml b/app/views/notify/merged_merge_request_email.text.haml
index 9db75bdb19e48aff9b07415aedda6b07429fefcb..34dbc60e19b5fbbfa2b8026e3f758036798d4cdb 100644
--- a/app/views/notify/merged_merge_request_email.text.haml
+++ b/app/views/notify/merged_merge_request_email.text.haml
@@ -1,6 +1,6 @@
 = "Merge Request ##{@merge_request.iid} was merged"
 
-Merge Request Url: #{namespace_project_merge_request_url(@merge_request.target_project.namespace, @merge_request.target_project, @merge_request)}
+Merge Request url: #{namespace_project_merge_request_url(@merge_request.target_project.namespace, @merge_request.target_project, @merge_request)}
 
 = merge_path_description(@merge_request, 'to')
 
diff --git a/app/views/notify/new_issue_email.html.haml b/app/views/notify/new_issue_email.html.haml
index 53a068be52e5b1c53a380f32a9bcf91cc480638e..d3b799fca23840696c50e71d536b4545f73aa13b 100644
--- a/app/views/notify/new_issue_email.html.haml
+++ b/app/views/notify/new_issue_email.html.haml
@@ -1,5 +1,5 @@
 -if @issue.description
-  = markdown(@issue.description, reference_only_path: false)
+  = markdown(@issue.description, pipeline: :email)
 
 - if @issue.assignee_id.present?
   %p
diff --git a/app/views/notify/new_merge_request_email.html.haml b/app/views/notify/new_merge_request_email.html.haml
index 5b7dd117c16afd159c0a427bc7022dc2a83e04e3..90ebdfc3fe278db5e06c928f12fb62e04787ce6e 100644
--- a/app/views/notify/new_merge_request_email.html.haml
+++ b/app/views/notify/new_merge_request_email.html.haml
@@ -6,4 +6,4 @@
     Assignee: #{@merge_request.author_name} &rarr; #{@merge_request.assignee_name}
 
 -if @merge_request.description
-  = markdown(@merge_request.description, reference_only_path: false)
+  = markdown(@merge_request.description, pipeline: :email)
diff --git a/app/views/notify/project_was_moved_email.html.haml b/app/views/notify/project_was_moved_email.html.haml
index 3cd759f1f5766f91cc0f08414640bc767dcd59dc..87b3ff7f0b323f07cf42be52d564519ebec73aa1 100644
--- a/app/views/notify/project_was_moved_email.html.haml
+++ b/app/views/notify/project_was_moved_email.html.haml
@@ -1,5 +1,5 @@
 %p
-  Project was moved to another location
+  Project #{@old_path_with_namespace} was moved to another location
 %p
   The project is now located under
   = link_to namespace_project_url(@project.namespace, @project) do
diff --git a/app/views/notify/project_was_moved_email.text.erb b/app/views/notify/project_was_moved_email.text.erb
index b3f18b35a4d606a0b46dcddc9ffe3faafef02576..d8a23dabf499789a10a626814d047c9a7cf9e68c 100644
--- a/app/views/notify/project_was_moved_email.text.erb
+++ b/app/views/notify/project_was_moved_email.text.erb
@@ -1,4 +1,4 @@
-Project was moved to another location
+Project #{@old_path_with_namespace} was moved to another location
 
 The project is now located under 
 <%= namespace_project_url(@project.namespace, @project) %>
diff --git a/app/views/profiles/_event_table.html.haml b/app/views/profiles/_event_table.html.haml
index c19ac429d52da7943f6197cce52f4c8e8b38002e..58af79716a75d4b1e014930a0a4165eeb48c58c1 100644
--- a/app/views/profiles/_event_table.html.haml
+++ b/app/views/profiles/_event_table.html.haml
@@ -1,16 +1,17 @@
-%table.table#audits
-  %thead
-    %tr
-      %th Action
-      %th When
-
-  %tbody
-    - events.each do |event|
+.table-holder
+  %table.table#audits
+    %thead
       %tr
-        %td
-          %span
-            Signed in with 
-            %b= event.details[:with]
-            authentication
-        %td #{time_ago_in_words event.created_at} ago
+        %th Action
+        %th When
+
+    %tbody
+      - events.each do |event|
+        %tr
+          %td
+            %span
+              Signed in with 
+              %b= event.details[:with]
+              authentication
+          %td #{time_ago_in_words event.created_at} ago
 = paginate events, theme: "gitlab"
diff --git a/app/views/profiles/keys/_key_details.html.haml b/app/views/profiles/keys/_key_details.html.haml
index e0ae4d9720fdb54a2aa110ba58427b5212c8c9b5..0ca8bd95157a3f12d1238d1cf34f24a769735d7b 100644
--- a/app/views/profiles/keys/_key_details.html.haml
+++ b/app/views/profiles/keys/_key_details.html.haml
@@ -18,5 +18,6 @@
       %code.key-fingerprint= @key.fingerprint
     %pre.well-pre
       = @key.key
-  .pull-right
-    = link_to 'Remove', path_to_key(@key, is_admin), data: {confirm: 'Are you sure?'}, method: :delete, class: "btn btn-remove delete-key"
+  .col-md-12
+    .pull-right
+      = link_to 'Remove', path_to_key(@key, is_admin), data: {confirm: 'Are you sure?'}, method: :delete, class: "btn btn-remove delete-key"
diff --git a/app/views/profiles/preferences/show.html.haml b/app/views/profiles/preferences/show.html.haml
index 60289bfe7cd88b2bbc1224dbe6ebde23c33ac53c..cc41d7dd8130ab787d023d41bf01d32e1529bc9c 100644
--- a/app/views/profiles/preferences/show.html.haml
+++ b/app/views/profiles/preferences/show.html.haml
@@ -32,6 +32,13 @@
     .panel-heading
       Behavior
     .panel-body
+      .form-group
+        = f.label :layout, class: 'control-label' do
+          Layout width
+        .col-sm-10
+          = f.select :layout, layout_choices, {}, class: 'form-control'
+          .help-block
+            Choose between fixed (max. 1200px) and fluid (100%) application layout.
       .form-group
         = f.label :dashboard, class: 'control-label' do
           Default Dashboard
@@ -45,6 +52,6 @@
         .col-sm-10
           = f.select :project_view, project_view_choices, {}, class: 'form-control'
           .help-block
-            Choose what content you want to see when visit project page
+            Choose what content you want to see on a project's home page.
     .panel-footer
       = f.submit 'Save', class: 'btn btn-save'
diff --git a/app/views/profiles/preferences/update.js.erb b/app/views/profiles/preferences/update.js.erb
index 6c4b0ce757dbe447191d02e722391b4bd36b9e6d..4433cab7782f5ea3a0be4e3f386da29562cd675c 100644
--- a/app/views/profiles/preferences/update.js.erb
+++ b/app/views/profiles/preferences/update.js.erb
@@ -2,6 +2,13 @@
 $('body').removeClass('<%= Gitlab::Themes.body_classes %>')
 $('body').addClass('<%= user_application_theme %>')
 
+// Toggle container-fluid class
+if ('<%= current_user.layout %>' === 'fluid') {
+  $('.content-wrapper').find('.container-fluid').removeClass('container-limited')
+} else {
+  $('.content-wrapper').find('.container-fluid').addClass('container-limited')
+}
+
 // Re-enable the "Save" button
 $('input[type=submit]').enable()
 
diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml
index 47412e2ef0c2cd9652389da2fc4bdc7deb900537..ac7355dde1fc1f6a112638ff5ed62dc2d4148e5f 100644
--- a/app/views/profiles/show.html.haml
+++ b/app/views/profiles/show.html.haml
@@ -68,7 +68,7 @@
 
     .col-md-5
       .light-well
-        = image_tag avatar_icon(@user.email, 160), alt: '', class: 'avatar s160'
+        = image_tag avatar_icon(@user, 160), alt: '', class: 'avatar s160'
 
         .clearfix
           .profile-avatar-form-option
diff --git a/app/views/projects/_activity.html.haml b/app/views/projects/_activity.html.haml
index 1261f6254d7a016b69ef1bc447245c4ef2a1c0f9..012858f70b4fae6b403c020c3497ce1cdc934136 100644
--- a/app/views/projects/_activity.html.haml
+++ b/app/views/projects/_activity.html.haml
@@ -1,10 +1,8 @@
-= render 'projects/last_push'
 .gray-content-block.activity-filter-block
   - if current_user
-    %ul.nav.nav-pills.event_filter.pull-right
-      %li
-        = link_to namespace_project_path(@project.namespace, @project, format: :atom, private_token: current_user.private_token), title: "Feed", class: 'rss-btn' do
-          %i.fa.fa-rss
+    .pull-right
+      = link_to namespace_project_path(@project.namespace, @project, format: :atom, private_token: current_user.private_token), title: "Feed", class: 'btn rss-btn' do
+        %i.fa.fa-rss
 
   = render 'shared/event_filter'
 .content_list{:"data-href" => activity_project_path(@project)}
diff --git a/app/views/projects/_files.html.haml b/app/views/projects/_files.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..fa978325ddd5923f65020d669bb1418041fa3d86
--- /dev/null
+++ b/app/views/projects/_files.html.haml
@@ -0,0 +1,6 @@
+#tree-holder.tree-holder.clearfix
+  .gray-content-block.second-block
+    = render 'projects/tree/tree_header', tree: @tree
+
+  = render 'projects/tree/tree_content', tree: @tree
+
diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml
index 6e53f55b0abb5db4910ca66e51471761addb480e..8c0980369fd867d700b331efa7fc3ed5cc9a3340 100644
--- a/app/views/projects/_home_panel.html.haml
+++ b/app/views/projects/_home_panel.html.haml
@@ -16,18 +16,19 @@
 
 
   .project-repo-buttons
-    = render 'projects/buttons/star'
-
-    - unless empty_repo
-      = render 'projects/buttons/fork'
-
-      - if can? current_user, :download_code, @project
-        = link_to archive_namespace_project_repository_path(@project.namespace, @project, ref: @ref, format: 'zip'), class: 'btn', rel: 'nofollow' do
-          = icon('download fw')
-          Download
-
+    .split-one
+      = render 'projects/buttons/star'
+
+      - unless empty_repo
+        = render 'projects/buttons/fork'
+    
+    = render "shared/clone_panel"
+    .split-repo-buttons 
+      - unless empty_repo
+        - if can? current_user, :download_code, @project
+          = link_to archive_namespace_project_repository_path(@project.namespace, @project, ref: @ref, format: 'zip'), class: 'btn', rel: 'nofollow' do
+            = icon('download fw')
+            
+      = render 'projects/buttons/dropdown'
     = render 'projects/buttons/notifications'
-
-    = render 'projects/buttons/dropdown'
-
-  = render "shared/clone_panel"
+    
diff --git a/app/views/projects/_last_commit.html.haml b/app/views/projects/_last_commit.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..d7b20bfc6b113d75ce1cccd8dd2df7e4f0fa489c
--- /dev/null
+++ b/app/views/projects/_last_commit.html.haml
@@ -0,0 +1,12 @@
+.project-last-commit
+  - ci_commit = project.ci_commit(commit.sha)
+  - if ci_commit
+    = link_to ci_status_path(ci_commit), class: "ci-status ci-#{ci_commit.status}" do
+      = ci_status_icon(ci_commit)
+      = ci_commit.status
+
+  = link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit_short_id"
+  = link_to_gfm commit.title, namespace_project_commit_path(project.namespace, project, commit.id), class: "commit-row-message"
+  &middot;
+  #{time_ago_with_tooltip(commit.committed_date, skip_js: true)} by
+  = commit_author_link(commit, avatar: true, size: 24)
diff --git a/app/views/projects/_md_preview.html.haml b/app/views/projects/_md_preview.html.haml
index 507757f6a2bb5b1121047ac9fe827d4e52089811..7b21095ea3e8637688f32cbf4ef94bf2e6f4379b 100644
--- a/app/views/projects/_md_preview.html.haml
+++ b/app/views/projects/_md_preview.html.haml
@@ -2,10 +2,10 @@
   .md-header.clearfix
     %ul.center-top-menu
       %li.active
-        = link_to '#md-write-holder', class: 'js-md-write-button', tabindex: '-1' do
+        %a.js-md-write-button(href="#md-write-holder" tabindex="-1")
           Write
       %li
-        = link_to '#md-preview-holder', class: 'js-md-preview-button', tabindex: '-1' do
+        %a.js-md-preview-button(href="md-preview-holder" tabindex="-1")
           Preview
 
     - if defined?(referenced_users) && referenced_users
diff --git a/app/views/projects/_readme.html.haml b/app/views/projects/_readme.html.haml
index 5038edb95edc01348275b669a7df85481fa553db..b5ef0aca54035a77f2e684506350124d77561b99 100644
--- a/app/views/projects/_readme.html.haml
+++ b/app/views/projects/_readme.html.haml
@@ -1,12 +1,9 @@
 - if readme = @repository.readme
-  %article.readme-holder#README
-    .clearfix
-      .pull-right
-        &nbsp;
-        - if can?(current_user, :push_code, @project)
-          = link_to namespace_project_edit_blob_path(@project.namespace, @project, tree_join(@repository.root_ref, readme.name)), class: 'light' do
-            %i.fa.fa-pencil
-    .wiki
+  %article.readme-holder
+    .pull-right
+      - if can?(current_user, :push_code, @project)
+        = link_to icon('pencil'), namespace_project_edit_blob_path(@project.namespace, @project, tree_join(@repository.root_ref, readme.name)), class: 'light edit-project-readme'
+    .file-content.wiki
       = cache(readme_cache_key) do
         = render_readme(readme)
 - else
diff --git a/app/views/projects/_zen.html.haml b/app/views/projects/_zen.html.haml
index 6a41cdbc907a433e216494e1910a4a7c9e897201..63ebfc9381f25bf82a40e5a9fe24904fe8d2cc99 100644
--- a/app/views/projects/_zen.html.haml
+++ b/app/views/projects/_zen.html.haml
@@ -1,10 +1,10 @@
 .zennable
-  %input#zen-toggle-comment.zen-toggle-comment{ tabindex: '-1', type: 'checkbox' }
+  %input#zen-toggle-comment.zen-toggle-comment(tabindex="-1" type="checkbox")
   .zen-backdrop
     - classes << ' js-gfm-input markdown-area'
     = f.text_area attr, class: classes, placeholder: ''
-    = link_to nil, class: 'zen-enter-link', tabindex: '-1' do
+    %a.zen-enter-link(tabindex="-1" href="#")
       %i.fa.fa-expand
       Edit in fullscreen
-    = link_to nil, class: 'zen-leave-link' do
+    %a.zen-leave-link(href="#")
       %i.fa.fa-compress
diff --git a/app/views/projects/activity.html.haml b/app/views/projects/activity.html.haml
index 555ed76426dd07de53c2222a3486949f4d1e061e..69fa4ad37c4bba65f5d3c93d38e9a1fce62a2e2f 100644
--- a/app/views/projects/activity.html.haml
+++ b/app/views/projects/activity.html.haml
@@ -1,4 +1,6 @@
 - page_title "Activity"
 - header_title project_title(@project, "Activity", activity_project_path(@project))
 
+= render 'projects/last_push'
+
 = render 'projects/activity'
diff --git a/app/views/projects/blob/_blob.html.haml b/app/views/projects/blob/_blob.html.haml
index b4c7d8b9b71112435caefe74b49a388c3a5c9628..42f632b38efea9748a4cf361a96750bab1a46fab 100644
--- a/app/views/projects/blob/_blob.html.haml
+++ b/app/views/projects/blob/_blob.html.haml
@@ -1,25 +1,28 @@
-%ul.breadcrumb.repo-breadcrumb
-  %li
-    %i.fa.fa-angle-right
-    = link_to namespace_project_tree_path(@project.namespace, @project, @ref) do
-      = @project.path
-  - tree_breadcrumbs(@tree, 6) do |title, path|
+.gray-content-block.top-block
+  .tree-ref-holder
+    = render 'shared/ref_switcher', destination: 'blob', path: @path
+
+  %ul.breadcrumb.repo-breadcrumb
     %li
-      - if path
-        - if path.end_with?(@path)
-          = link_to namespace_project_blob_path(@project.namespace, @project, path) do
-            %strong
-              = truncate(title, length: 40)
+      = link_to namespace_project_tree_path(@project.namespace, @project, @ref) do
+        = @project.path
+    - tree_breadcrumbs(@tree, 6) do |title, path|
+      %li
+        - if path
+          - if path.end_with?(@path)
+            = link_to namespace_project_blob_path(@project.namespace, @project, path) do
+              %strong
+                = truncate(title, length: 40)
+          - else
+            = link_to truncate(title, length: 40), namespace_project_tree_path(@project.namespace, @project, path)
         - else
-          = link_to truncate(title, length: 40), namespace_project_tree_path(@project.namespace, @project, path)
-      - else
-        = link_to title, '#'
+          = link_to title, '#'
 
 %ul.blob-commit-info.hidden-xs
   - blob_commit = @repository.last_commit_for_path(@commit.id, blob.path)
   = render blob_commit, project: @project
 
-%div#tree-content-holder.tree-content-holder
+%div#blob-content-holder.blob-content-holder
   %article.file-holder
     .file-title
       = blob_icon blob.mode, blob.name
diff --git a/app/views/projects/blob/_editor.html.haml b/app/views/projects/blob/_editor.html.haml
index 9c3e1703c893148dc66df5cf6e31ccaa684104c8..f1ad0c3c403ca45338dcace3d94e2fe0dfda7230 100644
--- a/app/views/projects/blob/_editor.html.haml
+++ b/app/views/projects/blob/_editor.html.haml
@@ -11,7 +11,7 @@
       - if current_action?(:new) || current_action?(:create)
         \/
         = text_field_tag 'file_name', params[:file_name], placeholder: "File name",
-          required: true, class: 'form-control new-file-name'
+          required: true, class: 'form-control new-file-name js-quick-submit'
       .pull-right
         = select_tag :encoding, options_for_select([ "base64", "text" ], "text"), class: 'form-control'
 
diff --git a/app/views/projects/blob/_new_dir.html.haml b/app/views/projects/blob/_new_dir.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..cb1567a2e68b527a5235f30328f5ceea65e13496
--- /dev/null
+++ b/app/views/projects/blob/_new_dir.html.haml
@@ -0,0 +1,25 @@
+#modal-create-new-dir.modal
+  .modal-dialog
+    .modal-content
+      .modal-header
+        %a.close{href: "#", "data-dismiss" => "modal"} ×
+        %h3.page-title Create New Directory
+      .modal-body
+        = form_tag namespace_project_create_dir_path(@project.namespace, @project, @id), method: :post, remote: false, id: 'dir-create-form', class: 'form-horizontal' do
+          .form-group
+            = label_tag :dir_name, 'Directory Name', class: 'control-label'
+            .col-sm-10
+              = text_field_tag :dir_name, params[:dir_name], placeholder: "Directory name", required: true, class: 'form-control'
+          = render 'shared/commit_message_container', params: params, placeholder: ''
+          - unless @project.empty_repo?
+            .form-group
+              = label_tag :branch_name, 'Branch', class: 'control-label'
+              .col-sm-10
+                = text_field_tag 'new_branch', @ref, class: "form-control"
+          .form-group
+            .col-sm-offset-2.col-sm-10
+              = submit_tag "Create directory", class: 'btn btn-primary btn-create'
+              = link_to "Cancel", '#', class: "btn btn-cancel", "data-dismiss" => "modal"
+
+:coffeescript
+  disableButtonIfAnyEmptyField($("#dir-create-form"), ".form-control", ".btn-create");
diff --git a/app/views/projects/blob/_upload.html.haml b/app/views/projects/blob/_upload.html.haml
index 1a1df12770324e7408e9509c09b8a685f143e3c8..e27f17075273670bae618d1498232fff394678ad 100644
--- a/app/views/projects/blob/_upload.html.haml
+++ b/app/views/projects/blob/_upload.html.haml
@@ -4,9 +4,6 @@
       .modal-header
         %a.close{href: "#", "data-dismiss" => "modal"} ×
         %h3.page-title #{title}
-        %p.light
-          From branch
-          %strong= @ref
       .modal-body
         = form_tag form_path, method: method, class: 'blob-file-upload-form-js form-horizontal' do
           .dropzone
@@ -18,6 +15,12 @@
           .dropzone-alerts{class: "alert alert-danger data", style: "display:none"}
           = render 'shared/commit_message_container', params: params,
             placeholder: placeholder
+          - unless @project.empty_repo?
+            .form-group.branch
+              = label_tag 'branch', class: 'control-label' do
+                Branch
+              .col-sm-10
+                = text_field_tag 'new_branch', @ref, class: "form-control"
           .form-group
             .col-sm-offset-2.col-sm-10
               = button_tag button_title, class: 'btn btn-small btn-primary btn-upload-file', id: 'submit-all'
diff --git a/app/views/projects/blob/new.html.haml b/app/views/projects/blob/new.html.haml
index 1950586b11280357e6a29df530ef74a1fecebc16..7975137c37f018f20911f5c9370c474cd3deb303 100644
--- a/app/views/projects/blob/new.html.haml
+++ b/app/views/projects/blob/new.html.haml
@@ -2,12 +2,7 @@
 = render "header_title"
 
 .gray-content-block.top-block
-  Create a new file or
-  = link_to 'upload', '#modal-upload-blob',
-    { class: 'upload-link', 'data-target' => '#modal-upload-blob', 'data-toggle' => 'modal'}
-  an existing one
-
-= render 'projects/blob/upload', title: 'Upload', placeholder: 'Upload new file', button_title: 'Upload file', form_path: namespace_project_create_blob_path(@project.namespace, @project, @id), method: :post
+  Create a new file
 
 .file-editor
   = form_tag(namespace_project_create_blob_path(@project.namespace, @project, @id), method: :post, class: 'form-horizontal form-new-file js-requires-input') do
@@ -20,7 +15,7 @@
         = label_tag 'branch', class: 'control-label' do
           Branch
         .col-sm-10
-          = text_field_tag 'new_branch', @ref, class: "form-control"
+          = text_field_tag 'new_branch', @ref, class: "form-control js-quick-submit"
 
     = hidden_field_tag 'content', '', id: 'file-content'
     = render 'projects/commit_button', ref: @ref,
diff --git a/app/views/projects/blob/show.html.haml b/app/views/projects/blob/show.html.haml
index fa4be4a1bc43ed30d772306f074c44ad7c1b48a4..f52b89f69210f1aff6ded38209e88dd99f782ae5 100644
--- a/app/views/projects/blob/show.html.haml
+++ b/app/views/projects/blob/show.html.haml
@@ -3,9 +3,6 @@
 
 = render 'projects/last_push'
 
-%div.tree-ref-holder
-  = render 'shared/ref_switcher', destination: 'blob', path: @path
-
 %div#tree-holder.tree-holder
   = render 'blob', blob: @blob
 
diff --git a/app/views/projects/builds/_build.html.haml b/app/views/projects/builds/_build.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..4ce4ed63b401d6410cb21c181019a383cee0989a
--- /dev/null
+++ b/app/views/projects/builds/_build.html.haml
@@ -0,0 +1,53 @@
+%tr.build
+  %td.status
+    = ci_status_with_icon(build.status)
+
+  %td.commit_status-link
+    - if build.target_url
+      = link_to build.target_url do
+        %strong Build ##{build.id}
+    - else
+      %strong Build ##{build.id}
+
+    - if build.show_warning?
+      %i.fa.fa-warning.text-warning
+
+  %td
+    = link_to build.short_sha, namespace_project_commit_path(@project.namespace, @project, build.sha)
+
+  %td
+    = link_to build.ref, namespace_project_commits_path(@project.namespace, @project, build.ref)
+
+  %td
+    - if build.runner
+      = runner_link(build.runner)
+    - else
+      .light none
+
+  %td
+    = build.name
+
+    .pull-right
+      - if build.tags.any?
+        - build.tags.each do |tag|
+          %span.label.label-primary
+            = tag
+      - if build.trigger_request
+        %span.label.label-info triggered
+      - if build.allow_failure
+        %span.label.label-danger allowed to fail
+
+  %td.duration
+    - if build.duration
+      #{duration_in_words(build.finished_at, build.started_at)}
+
+  %td.timestamp
+    - if build.finished_at
+      %span #{time_ago_in_words build.finished_at} ago
+
+  %td
+    .pull-right
+      - if current_user && can?(current_user, :manage_builds, @project)
+        - if build.cancel_url
+          = link_to build.cancel_url, title: 'Cancel' do
+            %i.fa.fa-remove.cred
diff --git a/app/views/projects/builds/index.html.haml b/app/views/projects/builds/index.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..e08556673ed6eac3c370502d99113756732dcc19
--- /dev/null
+++ b/app/views/projects/builds/index.html.haml
@@ -0,0 +1,53 @@
+- page_title "Builds"
+- header_title project_title(@project, "Builds", project_builds_path(@project))
+
+.project-issuable-filter
+  .controls
+    - if @ci_project && current_user && can?(current_user, :manage_builds, @project)
+      .pull-left.hidden-xs
+        - if @all_builds.running_or_pending.any?
+          = link_to 'Cancel all', cancel_all_namespace_project_builds_path(@project.namespace, @project), data: { confirm: 'Are you sure?' }, class: 'btn btn-danger'
+
+  %ul.center-top-menu
+    %li{class: ('active' if @scope.nil?)}
+      = link_to project_builds_path(@project) do
+        Running
+        %span.badge.js-running-count= @all_builds.running_or_pending.count(:id)
+
+    %li{class: ('active' if @scope == 'finished')}
+      = link_to project_builds_path(@project, scope: :finished) do
+        Finished
+        %span.badge.js-running-count= @all_builds.finished.count(:id)
+
+    %li{class: ('active' if @scope == 'all')}
+      = link_to project_builds_path(@project, scope: :all) do
+        All
+        %span.badge.js-totalbuilds-count= @all_builds.count(:id)
+
+.gray-content-block
+  List of #{@scope || 'running'} builds from this project
+
+%ul.content-list
+  - if @builds.blank?
+    %li
+      .nothing-here-block No builds to show
+  - else
+    .table-holder
+      %table.table.builds
+        %thead
+          %tr
+            %th Status
+            %th Build ID
+            %th Commit
+            %th Ref
+            %th Runner
+            %th Name
+            %th Duration
+            %th Finished at
+            %th
+
+        - @builds.each do |build|
+          = render 'projects/builds/build', build: build
+
+    = paginate @builds
+
diff --git a/app/views/projects/builds/show.html.haml b/app/views/projects/builds/show.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..3a8172dc8e67c9319de5dc18605d7fdac318de8f
--- /dev/null
+++ b/app/views/projects/builds/show.html.haml
@@ -0,0 +1,178 @@
+.build-page
+  .gray-content-block
+    Build for commit
+    %strong.monospace
+      = link_to @build.commit.short_sha, ci_status_path(@build.commit)
+    from
+    %code #{@build.ref}
+
+  #up-build-trace
+  - if @commit.matrix_for_ref?(@build.ref)
+    %ul.center-top-menu.build-top-menu
+      - @commit.latest_builds_for_ref(@build.ref).each do |build|
+        %li{class: ('active' if build == @build) }
+          = link_to namespace_project_build_path(@project.namespace, @project, build) do
+            = ci_icon_for_status(build.status)
+            %span
+              - if build.name
+                = build.name
+              - else
+                = build.id
+
+
+      - unless @commit.latest_builds_for_ref(@build.ref).include?(@build)
+        %li.active
+          %a
+            Build ##{@build.id}
+            &middot;
+            %i.fa.fa-warning
+            This build was retried.
+
+  .gray-content-block.second-block
+    .build-head
+      .clearfix
+        = ci_status_with_icon(@build.status)
+        - if @build.duration
+          %span
+            %i.fa.fa-time
+            #{duration_in_words(@build.finished_at, @build.started_at)}
+        .pull-right
+          = @build.updated_at.stamp('19:00 Aug 27')
+
+  - if @build.show_warning?
+    - unless @build.any_runners_online?
+      .bs-callout.bs-callout-warning
+        %p
+          - if no_runners_for_project?(@build.project)
+            This build is stuck, because the project doesn't have any runners online assigned to it.
+          - elsif @build.tags.any?
+            This build is stuck, because you don't have any active runners online with any of these tags assigned to them:
+            - @build.tags.each do |tag|
+              %span.label.label-primary
+                = tag
+          - else
+            This build is stuck, because you don't have any active runners that can run this build.
+
+          %br
+          Go to
+          = link_to namespace_project_runners_path(@build.gl_project.namespace, @build.gl_project) do
+            Runners page
+
+  .row.prepend-top-default
+    .col-md-9
+      .clearfix
+        - if @build.active?
+          .autoscroll-container
+            %button.btn.btn-success.btn-sm#autoscroll-button{:type => "button", :data => {:state => 'disabled'}} enable autoscroll
+          .clearfix
+      .scroll-controls
+        = link_to '#up-build-trace', class: 'btn' do
+          %i.fa.fa-angle-up
+        = link_to '#down-build-trace', class: 'btn' do
+          %i.fa.fa-angle-down
+
+      %pre.trace#build-trace
+        %code.bash
+          = preserve do
+            = raw @build.trace_html
+      %div#down-build-trace
+
+    .col-md-3
+      - if @build.coverage
+        .build-widget
+          %h4.title
+            Test coverage
+          %h1 #{@build.coverage}%
+
+
+      .build-widget
+        %h4.title
+          Build
+          - if current_user && can?(current_user, :manage_builds, @project)
+            .pull-right
+              - if @build.active?
+                = link_to "Cancel", cancel_namespace_project_build_path(@project.namespace, @project, @build), class: 'btn btn-sm btn-danger'
+              - elsif @build.commands.present?
+                = link_to "Retry", retry_namespace_project_build_path(@project.namespace, @project, @build), class: 'btn btn-sm btn-primary', method: :post
+
+        - if @build.duration
+          %p
+            %span.attr-name Duration:
+            #{duration_in_words(@build.finished_at, @build.started_at)}
+        %p
+          %span.attr-name Created:
+          #{time_ago_in_words(@build.created_at)} ago
+        - if @build.finished_at
+          %p
+            %span.attr-name Finished:
+            #{time_ago_in_words(@build.finished_at)} ago
+        %p
+          %span.attr-name Runner:
+          - if @build.runner && current_user && current_user.admin
+            \#{link_to "##{@build.runner.id}", ci_admin_runner_path(@build.runner.id)}
+          - elsif @build.runner
+            \##{@build.runner.id}
+
+      - if @build.trigger_request
+        .build-widget
+          %h4.title
+            Trigger
+
+          %p
+            %span.attr-name Token:
+            #{@build.trigger_request.trigger.short_token}
+
+          - if @build.trigger_request.variables
+            %p
+              %span.attr-name Variables:
+
+            %code
+              - @build.trigger_request.variables.each do |key, value|
+                #{key}=#{value}
+
+      .build-widget
+        %h4.title
+          Commit
+          .pull-right
+            %small #{build_commit_link @build}
+        %p
+          %span.attr-name Branch:
+          #{build_ref_link @build}
+        %p
+          %span.attr-name Author:
+          #{@build.commit.git_author_name}
+        %p
+          %span.attr-name Message:
+          #{@build.commit.git_commit_message}
+
+      - if @build.tags.any?
+        .build-widget
+          %h4.title
+            Tags
+          - @build.tag_list.each do |tag|
+            %span.label.label-primary
+              = tag
+
+      - if @builds.present?
+        .build-widget
+          %h4.title #{pluralize(@builds.count, "other build")} for #{@build.short_sha}:
+          %table.table.builds
+            - @builds.each_with_index do |build, i|
+              %tr.build
+                %td
+                  = ci_icon_for_status(build.status)
+                %td
+                  = link_to namespace_project_build_path(@project.namespace, @project, @build) do
+                    - if build.name
+                      = build.name
+                    - else
+                      %span ##{build.id}
+
+                %td.status= build.status
+
+
+          = paginate @builds
+
+
+  :javascript
+    new CiBuild("#{namespace_project_build_url(@project.namespace, @project, @build)}", "#{@build.status}")
diff --git a/app/views/projects/buttons/_dropdown.html.haml b/app/views/projects/buttons/_dropdown.html.haml
index bc7625e8989dc6bb52517ea7173862966f6e47a0..4580c912692e79e4a0d34f762e3eb80a95785086 100644
--- a/app/views/projects/buttons/_dropdown.html.haml
+++ b/app/views/projects/buttons/_dropdown.html.haml
@@ -1,6 +1,6 @@
 - if current_user
   %span.dropdown
-    %a.dropdown-toggle.btn.btn-new{href: '#', "data-toggle" => "dropdown"}
+    %a.dropdown-new.btn.btn-new{href: '#', "data-toggle" => "dropdown"}
       = icon('plus')
     %ul.dropdown-menu.dropdown-menu-right.project-home-dropdown
       - if can?(current_user, :create_issue, @project)
diff --git a/app/views/projects/buttons/_fork.html.haml b/app/views/projects/buttons/_fork.html.haml
index 854c154824dd72e4d17455039728886f98ff61c5..8f2f631eb7d24eeb1ea50f87672ae5d2da46efc9 100644
--- a/app/views/projects/buttons/_fork.html.haml
+++ b/app/views/projects/buttons/_fork.html.haml
@@ -8,6 +8,5 @@
   - else
     = link_to new_namespace_project_fork_path(@project.namespace, @project), title: "Fork project", class: 'btn' do
       = icon('code-fork fw')
-      Fork
       %span.count
         = @project.forks_count
diff --git a/app/views/projects/buttons/_notifications.html.haml b/app/views/projects/buttons/_notifications.html.haml
index 57f764178d5e3ddc2632e508d9f6a01765e64923..3e83ec3912f6728996d70611e8d0da2b6cdc8f02 100644
--- a/app/views/projects/buttons/_notifications.html.haml
+++ b/app/views/projects/buttons/_notifications.html.haml
@@ -1,14 +1,20 @@
-- return unless @membership
+- case @membership
+- when ProjectMember
+  = form_tag profile_notifications_path, method: :put, remote: true, class: 'inline', id: 'notification-form' do
+    = hidden_field_tag :notification_type, 'project'
+    = hidden_field_tag :notification_id, @membership.id
+    = hidden_field_tag :notification_level
+    %span.dropdown
+      %a.dropdown-new.btn.notifications-btn#notifications-button{href: '#', "data-toggle" => "dropdown"}
+        = icon('bell')
+        = notification_label(@membership)
+        = icon('angle-down')
+      %ul.dropdown-menu.dropdown-menu-right.project-home-dropdown
+        - Notification.project_notification_levels.each do |level|
+          = notification_list_item(level, @membership)
 
-= form_tag profile_notifications_path, method: :put, remote: true, class: 'inline-form', id: 'notification-form' do
-  = hidden_field_tag :notification_type, 'project'
-  = hidden_field_tag :notification_id, @membership.id
-  = hidden_field_tag :notification_level
-  %span.dropdown
-    %a.dropdown-toggle.btn.btn-new#notifications-button{href: '#', "data-toggle" => "dropdown"}
-      = icon('bell')
-      = notification_label(@membership)
-      = icon('angle-down')
-    %ul.dropdown-menu.dropdown-menu-right.project-home-dropdown
-      - Notification.project_notification_levels.each do |level|
-        = notification_list_item(level, @membership)
+- when GroupMember
+  .btn.disabled.notifications-btn.has_tooltip{title: "To change the notification level, you need to be a member of the project itself, not only its group."}
+    = icon('bell')
+    = notification_label(@membership)
+    = icon('angle-down')
diff --git a/app/views/projects/buttons/_star.html.haml b/app/views/projects/buttons/_star.html.haml
index 5d7df5ae09993f0877d54b431ea093882c350eb9..3501dddefbe3a6c6f714ffa02d933ec0ce909f1d 100644
--- a/app/views/projects/buttons/_star.html.haml
+++ b/app/views/projects/buttons/_star.html.haml
@@ -1,10 +1,6 @@
 - if current_user
   = link_to toggle_star_namespace_project_path(@project.namespace, @project), class: 'btn star-btn toggle-star', method: :post, remote: true do
     = icon('star fw')
-    - if current_user.starred?(@project)
-      Unstar
-    - else
-      Star
     %span.count
       = @project.star_count
 
@@ -17,6 +13,5 @@
 - else
   = link_to new_user_session_path, class: 'btn has_tooltip star-btn', title: 'You must sign in to star a project' do
     = icon('star fw')
-    Star
     %span.count
       = @project.star_count
diff --git a/app/views/ci/services/_form.html.haml b/app/views/projects/ci_services/_form.html.haml
similarity index 80%
rename from app/views/ci/services/_form.html.haml
rename to app/views/projects/ci_services/_form.html.haml
index 9110aaa0528fe3c93da1a3097aaee280e8f181a9..397832e56dbe8f7768578a17cde73f04a3251317 100644
--- a/app/views/ci/services/_form.html.haml
+++ b/app/views/projects/ci_services/_form.html.haml
@@ -4,13 +4,10 @@
 
 %p= @service.description
 
-.back-link
-  = link_to ci_project_services_path(@project) do
-    &larr; to services
 
 %hr
 
-= form_for(@service, as: :service, url: ci_project_service_path(@project, @service.to_param), method: :put, html: { class: 'form-horizontal' }) do |f|
+= form_for(@service, as: :service, url: namespace_project_ci_service_path(@project.namespace, @project, @service.to_param), method: :put, html: { class: 'form-horizontal' }) do |f|
   - if @service.errors.any?
     .alert.alert-danger
       %ul
@@ -54,4 +51,4 @@
     = f.submit 'Save', class: 'btn btn-save'
     &nbsp;
     - if @service.valid? && @service.activated? && @service.can_test?
-      = link_to 'Test settings', test_ci_project_service_path(@project, @service.to_param), class: 'btn'
+      = link_to 'Test settings', test_namespace_project_ci_service_path(@project.namespace, @project, @service.to_param), class: 'btn'
diff --git a/app/views/ci/services/edit.html.haml b/app/views/projects/ci_services/edit.html.haml
similarity index 100%
rename from app/views/ci/services/edit.html.haml
rename to app/views/projects/ci_services/edit.html.haml
diff --git a/app/views/ci/services/index.html.haml b/app/views/projects/ci_services/index.html.haml
similarity index 78%
rename from app/views/ci/services/index.html.haml
rename to app/views/projects/ci_services/index.html.haml
index 37e5723b54139cd585df24b8eba55618cc12afd7..c164b2d4bc03836586769a3286b74cd1ba1904a1 100644
--- a/app/views/ci/services/index.html.haml
+++ b/app/views/projects/ci_services/index.html.haml
@@ -6,14 +6,14 @@
     %tr
       %th
       %th Service
-      %th Desription
+      %th Description
       %th Last edit
   - @services.sort_by(&:title).each do |service|
     %tr
       %td
         = boolean_to_icon service.activated?
       %td
-        = link_to edit_ci_project_service_path(@project, service.to_param) do
+        = link_to edit_namespace_project_ci_service_path(@project.namespace, @project, service.to_param) do
           %strong= service.title
       %td
         = service.description
diff --git a/app/views/ci/projects/_form.html.haml b/app/views/projects/ci_settings/_form.html.haml
similarity index 71%
rename from app/views/ci/projects/_form.html.haml
rename to app/views/projects/ci_settings/_form.html.haml
index e782fd8a0f7d7a66f903d37aab9b9713d606affa..d711413c6b956b147c9ddc3a7226e7a84fa6c8e8 100644
--- a/app/views/ci/projects/_form.html.haml
+++ b/app/views/projects/ci_settings/_form.html.haml
@@ -1,17 +1,36 @@
+%h3.page-title
+  CI settings
+%hr
 .bs-callout.help-callout
   %p
     If you want to test your .gitlab-ci.yml, you can use special tool - #{link_to "Lint", ci_lint_path}
   %p
-    Edit your 
-    #{link_to ".gitlab-ci.yml using web-editor", yaml_web_editor_link(@project)}
+    Edit your
+    #{link_to ".gitlab-ci.yml using web-editor", yaml_web_editor_link(@ci_project)}
 
-= nested_form_for [:ci, @project], html: { class: 'form-horizontal' } do |f|
-  - if @project.errors.any?
+- unless @project.empty_repo?
+  %p
+    Paste build status image for #{@repository.root_ref} with next link
+    = link_to '#', class: 'badge-codes-toggle btn btn-default btn-xs' do
+      Status Badge
+    .badge-codes-block.bs-callout.bs-callout-info.hide
+      %p
+        Status badge for
+        %span.label.label-info #{@ref}
+        branch
+      %div
+        %label Markdown:
+        = text_field_tag 'badge_md', markdown_badge_code(@ci_project, @repository.root_ref), readonly: true, class: 'form-control'
+        %label Html:
+        = text_field_tag 'badge_html', html_badge_code(@ci_project, @repository.root_ref), readonly: true, class: 'form-control'
+
+= nested_form_for @ci_project, url: namespace_project_ci_settings_path(@project.namespace, @project), html: { class: 'form-horizontal' } do |f|
+  - if @ci_project.errors.any?
     #error_explanation
-      %p.lead= "#{pluralize(@project.errors.count, "error")} prohibited this project from being saved:"
+      %p.lead= "#{pluralize(@ci_project.errors.count, "error")} prohibited this project from being saved:"
       .alert.alert-error
         %ul
-          - @project.errors.full_messages.each do |msg|
+          - @ci_project.errors.full_messages.each do |msg|
             %li= msg
 
   %fieldset
@@ -93,8 +112,8 @@
       = f.label :token, "CI token", class: 'control-label'
       .col-sm-10
         = f.text_field :token, class: 'form-control', placeholder: 'xEeFCaDAB89'
-    
+
   .form-actions
     = f.submit 'Save changes', class: 'btn btn-save'
-    - unless @project.new_record?
-      = link_to 'Remove Project', ci_project_path(@project), method: :delete, data: { confirm: 'Project will be removed. Are you sure?' }, class: 'btn btn-danger pull-right'
+    - unless @ci_project.new_record?
+      = link_to 'Remove Project', ci_project_path(@ci_project), method: :delete, data: { confirm: 'Project will be removed. Are you sure?' }, class: 'btn btn-danger pull-right'
diff --git a/app/views/ci/projects/_no_runners.html.haml b/app/views/projects/ci_settings/_no_runners.html.haml
similarity index 87%
rename from app/views/ci/projects/_no_runners.html.haml
rename to app/views/projects/ci_settings/_no_runners.html.haml
index c0a296fb17d72e8614e9656f2a47be689e809b14..33038c529780ed45aeba6ccbd2a4a2576aa33faf 100644
--- a/app/views/ci/projects/_no_runners.html.haml
+++ b/app/views/projects/ci_settings/_no_runners.html.haml
@@ -4,5 +4,5 @@
     %br
     You can add Specific runner for this project on Runners page
 
-    - if current_user.is_admin
+    - if current_user.admin
       or add Shared runner for whole application in admin are.
diff --git a/app/views/ci/projects/edit.html.haml b/app/views/projects/ci_settings/edit.html.haml
similarity index 72%
rename from app/views/ci/projects/edit.html.haml
rename to app/views/projects/ci_settings/edit.html.haml
index 876ae5182d4a5629c9b668d68bf08a8bc74e37aa..eedf484bf00f2105548175ba9d749e878a76e8d8 100644
--- a/app/views/ci/projects/edit.html.haml
+++ b/app/views/projects/ci_settings/edit.html.haml
@@ -1,14 +1,17 @@
-- if @project.generated_yaml_config
+- if @ci_project.generated_yaml_config
   %p.alert.alert-danger
-    CI Jobs are deprecated now, you can #{link_to "download", dumped_yaml_ci_project_path(@project)}
+    CI Jobs are deprecated now, you can #{link_to "download", dumped_yaml_ci_project_path(@ci_project)}
     or
     %a.preview-yml{:href => "#yaml-content", "data-toggle" => "modal"} preview
     yaml file which is based on your old jobs.
     Put this file to the root of your project and name it .gitlab-ci.yml
 
+- if no_runners_for_project?(@ci_project)
+  = render 'no_runners'
+
 = render 'form'
 
-- if @project.generated_yaml_config
+- if @ci_project.generated_yaml_config
   #yaml-content.modal.fade{"aria-hidden" => "true", "aria-labelledby" => ".gitlab-ci.yml", :role => "dialog", :tabindex => "-1"}
     .modal-dialog
       .modal-content
@@ -16,6 +19,6 @@
           %button.close{"aria-hidden" => "true", "data-dismiss" => "modal", :type => "button"} ×
           %h4.modal-title Content of .gitlab-ci.yml
         .modal-body
-          = text_area_tag :yaml, @project.generated_yaml_config, size: "70x25", class: "form-control"
+          = text_area_tag :yaml, @ci_project.generated_yaml_config, size: "70x25", class: "form-control"
         .modal-footer
           %button.btn.btn-default{"data-dismiss" => "modal", :type => "button"} Close
diff --git a/app/views/ci/web_hooks/index.html.haml b/app/views/projects/ci_web_hooks/index.html.haml
similarity index 79%
rename from app/views/ci/web_hooks/index.html.haml
rename to app/views/projects/ci_web_hooks/index.html.haml
index 78e8203b25e30ceac1ef9951ba9c70d747aef1c7..369086b39ed0d59d393c93602258bd8e8178e307 100644
--- a/app/views/ci/web_hooks/index.html.haml
+++ b/app/views/projects/ci_web_hooks/index.html.haml
@@ -1,12 +1,12 @@
 %h3.page-title
-  Web hooks
+  CI Web hooks
 
 %p.light
   Web Hooks can be used for binding events when build completed.
 
 %hr.clearfix
 
-= form_for [:ci, @project, @web_hook], html: { class: 'form-horizontal' } do |f|
+= form_for @web_hook, url: namespace_project_ci_web_hooks_path(@project.namespace, @project), html: { class: 'form-horizontal' } do |f|
   -if @web_hook.errors.any?
     .alert.alert-danger
       - @web_hook.errors.full_messages.each do |msg|
@@ -20,17 +20,18 @@
 
 -if @web_hooks.any?
   %h4 Activated web hooks (#{@web_hooks.count})
-  %table.table
-    - @web_hooks.each do |hook|
-      %tr
-        %td
-          .clearfix
-            %span.monospace= hook.url
-        %td
-          .pull-right
-            - if @project.commits.any?
-              = link_to 'Test Hook', test_ci_project_web_hook_path(@project, hook), class: "btn btn-sm btn-grouped"
-            = link_to 'Remove', ci_project_web_hook_path(@project, hook), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-remove btn-sm btn-grouped"
+  .table-holder
+    %table.table
+      - @web_hooks.each do |hook|
+        %tr
+          %td
+            .clearfix
+              %span.monospace= hook.url
+          %td
+            .pull-right
+              - if @ci_project.commits.any?
+                = link_to 'Test Hook', test_namespace_project_ci_web_hook_path(@project.namespace, @project, hook), class: "btn btn-sm btn-grouped"
+              = link_to 'Remove', namespace_project_ci_web_hook_path(@project.namespace, @project, hook), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-remove btn-sm btn-grouped"
 
 %h4 Web Hook data example
 
diff --git a/app/views/projects/commit/_ci_menu.html.haml b/app/views/projects/commit/_ci_menu.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..a634ae5dfda5e623178a5d34399e55b7465ce608
--- /dev/null
+++ b/app/views/projects/commit/_ci_menu.html.haml
@@ -0,0 +1,7 @@
+%ul.center-top-menu.commit-ci-menu
+  = nav_link(path: 'commit#show') do
+    = link_to namespace_project_commit_path(@project.namespace, @project, @commit.id) do
+      Changes
+  = nav_link(path: 'commit#ci') do
+    = link_to ci_namespace_project_commit_path(@project.namespace, @project, @commit.id) do
+      Builds
diff --git a/app/views/projects/commit/ci.html.haml b/app/views/projects/commit/ci.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..43033cad24c97ef4150273faae4caea68b021b07
--- /dev/null
+++ b/app/views/projects/commit/ci.html.haml
@@ -0,0 +1,69 @@
+- page_title "#{@commit.title} (#{@commit.short_id})", "Commits"
+= render "projects/commits/header_title"
+= render "commit_box"
+= render "ci_menu"
+
+
+- if @ci_commit.yaml_errors.present?
+  .bs-callout.bs-callout-danger
+    %h4 Found errors in your .gitlab-ci.yml:
+    %ul
+      - @ci_commit.yaml_errors.split(",").each do |error|
+        %li= error
+
+- unless @ci_commit.ci_yaml_file
+  .bs-callout.bs-callout-warning
+    \.gitlab-ci.yml not found in this commit
+
+.gray-content-block.second-block
+  Latest builds
+
+  .pull-right
+    - if @ci_commit.duration > 0
+      %i.fa.fa-time
+      #{time_interval_in_words @ci_commit.duration}
+
+    &nbsp;
+
+    - if @ci_project && current_user && can?(current_user, :manage_builds, @project)
+      - if @ci_commit.builds.running_or_pending.any?
+        = link_to "Cancel all", cancel_builds_namespace_project_commit_path(@project.namespace, @project, @commit.sha), class: 'btn btn-xs btn-danger'
+
+.table-holder
+  %table.table.builds
+    %thead
+      %tr
+        %th Status
+        %th Build ID
+        %th Ref
+        %th Stage
+        %th Name
+        %th Duration
+        %th Finished at
+        - if @ci_project && @ci_project.coverage_enabled?
+          %th Coverage
+        %th
+    - @ci_commit.refs.each do |ref|
+      = render partial: "projects/commit_statuses/commit_status", collection: @ci_commit.statuses.for_ref(ref).latest.ordered,
+               locals: { coverage: @ci_project.try(:coverage_enabled?), allow_retry: true }
+
+- if @ci_commit.retried.any?
+  .gray-content-block.second-block
+    Retried builds
+
+  .table-holder
+    %table.table.builds
+      %thead
+        %tr
+          %th Status
+          %th Build ID
+          %th Ref
+          %th Stage
+          %th Name
+          %th Duration
+          %th Finished at
+          - if @ci_project && @ci_project.coverage_enabled?
+            %th Coverage
+          %th
+      = render partial: "projects/commit_statuses/commit_status", collection: @ci_commit.retried,
+               locals: { coverage: @ci_project.try(:coverage_enabled?) }
diff --git a/app/views/projects/commit/show.html.haml b/app/views/projects/commit/show.html.haml
index f8681024d1be73fb35b8af3ab0c837c069b8b075..30a3973828ff39cfd7139a8ab5f3899c539d5c64 100644
--- a/app/views/projects/commit/show.html.haml
+++ b/app/views/projects/commit/show.html.haml
@@ -1,5 +1,6 @@
 - page_title "#{@commit.title} (#{@commit.short_id})", "Commits"
 = render "projects/commits/header_title"
 = render "commit_box"
+= render "ci_menu" if @ci_commit
 = render "projects/diffs/diffs", diffs: @diffs, project: @project
 = render "projects/notes/notes_with_form", view: params[:view]
diff --git a/app/views/projects/commit_statuses/_commit_status.html.haml b/app/views/projects/commit_statuses/_commit_status.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..637154f56aa1d00c6562e99a9c1f811312bf940a
--- /dev/null
+++ b/app/views/projects/commit_statuses/_commit_status.html.haml
@@ -0,0 +1,54 @@
+%tr.commit_status
+  %td.status
+    = ci_status_with_icon(commit_status.status)
+
+  %td.commit_status-link
+    - if commit_status.target_url
+      = link_to commit_status.target_url do
+        %strong Build ##{commit_status.id}
+    - else
+      %strong Build ##{commit_status.id}
+
+    - if commit_status.show_warning?
+      %i.fa.fa-warning.text-warning
+
+  %td
+    = commit_status.ref
+
+  %td
+    = commit_status.stage
+
+  %td
+    = commit_status.name
+    .pull-right
+      - if commit_status.tags.any?
+        - commit_status.tags.each do |tag|
+          %span.label.label-primary
+            = tag
+      - if commit_status.try(:trigger_request)
+        %span.label.label-info triggered
+      - if commit_status.try(:allow_failure)
+        %span.label.label-danger allowed to fail
+
+  %td.duration
+    - if commit_status.duration
+      #{duration_in_words(commit_status.finished_at, commit_status.started_at)}
+
+  %td.timestamp
+    - if commit_status.finished_at
+      %span #{time_ago_in_words commit_status.finished_at} ago
+
+  - if defined?(coverage) && coverage
+    %td.coverage
+      - if commit_status.try(:coverage)
+        #{commit_status.coverage}%
+
+  %td
+    .pull-right
+      - if current_user && can?(current_user, :manage_builds, commit_status.gl_project)
+        - if commit_status.cancel_url
+          = link_to commit_status.cancel_url, title: 'Cancel' do
+            %i.fa.fa-remove.cred
+        - elsif defined?(allow_retry) && allow_retry && commit_status.retry_url
+          = link_to commit_status.retry_url, method: :post, title: 'Retry' do
+            %i.fa.fa-repeat
diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml
index efad4cb14733ac93d21ac40bd0bad7e319bc73c1..cddd5aa3a83ce29ca27091d82e829f4539110788 100644
--- a/app/views/projects/commits/_commit.html.haml
+++ b/app/views/projects/commits/_commit.html.haml
@@ -5,7 +5,7 @@
   - note_count = notes.user.count
 
 - ci_commit = project.ci_commit(commit.sha)
-- cache_key = [project.id, commit.id, note_count]
+- cache_key = [project.path_with_namespace, commit.id, note_count]
 - cache_key.push(ci_commit.status) if ci_commit
 
 = cache(cache_key) do
diff --git a/app/views/projects/diffs/_diffs.html.haml b/app/views/projects/diffs/_diffs.html.haml
index 2f24dc7c909e3734dcbfde8e472d9ec79cd6a5ae..56b51f038bab268dcb51df6d3055a536a227e2f7 100644
--- a/app/views/projects/diffs/_diffs.html.haml
+++ b/app/views/projects/diffs/_diffs.html.haml
@@ -1,21 +1,26 @@
 - if params[:view] == 'parallel'
   - fluid_layout true
 
+- diff_files = safe_diff_files(diffs)
+
 .gray-content-block.second-block
   .inline-parallel-buttons
     .btn-group
       = inline_diff_btn
       = parallel_diff_btn
-  = render 'projects/diffs/stats', diffs: diffs
-
-- diff_files = safe_diff_files(diffs)
+  = render 'projects/diffs/stats', diff_files: diff_files
 
 - if diff_files.count < diffs.size
   = render 'projects/diffs/warning', diffs: diffs, shown_files_count: diff_files.count
 
 .files
   - diff_files.each_with_index do |diff_file, index|
-    = render 'projects/diffs/file', diff_file: diff_file, i: index, project: project
+    - diff_commit = commit_for_diff(diff_file)
+    - blob = project.repository.blob_for_diff(diff_commit, diff_file)
+    - next unless blob
+
+    = render 'projects/diffs/file', i: index, project: project,
+      diff_file: diff_file, diff_commit: diff_commit, blob: blob
 
 - if @diff_timeout
   .alert.alert-danger
diff --git a/app/views/projects/diffs/_file.html.haml b/app/views/projects/diffs/_file.html.haml
index 99ee23a1ddc8a2cb9cd7b746bb544f670516be55..410ff6abb43f1f892f1560ed853a8ed65f88efe7 100644
--- a/app/views/projects/diffs/_file.html.haml
+++ b/app/views/projects/diffs/_file.html.haml
@@ -1,39 +1,33 @@
-- blob = project.repository.blob_for_diff(@commit, diff_file.diff)
-- return unless blob
-- blob_diff_path = namespace_project_blob_diff_path(project.namespace, project, tree_join(@commit.id, diff_file.file_path))
-.diff-file{id: "diff-#{i}", data: {blob_diff_path: blob_diff_path }}
-  .diff-header{id: "file-path-#{hexdigest(diff_file.new_path || diff_file.old_path)}"}
-    - if diff_file.deleted_file
-      %span="#{diff_file.old_path} deleted"
-
-      .diff-btn-group
-        - if @commit.parent_ids.present?
-          = view_file_btn(@commit.parent_id, diff_file, project)
-    - elsif diff_file.diff.submodule?
+.diff-file{id: "diff-#{i}", data: diff_file_html_data(project, diff_commit, diff_file)}
+  .diff-header{id: "file-path-#{hexdigest(diff_file.file_path)}"}
+    - if diff_file.diff.submodule?
       %span
         - submodule_item = project.repository.blob_at(@commit.id, diff_file.file_path)
         = submodule_link(submodule_item, @commit.id, project.repository)
     - else
       %span
-        - if diff_file.renamed_file
+        - if diff_file.deleted_file
+          = "#{diff_file.old_path} deleted"
+        - elsif diff_file.renamed_file
           = "#{diff_file.old_path} renamed to #{diff_file.new_path}"
         - else
           = diff_file.new_path
+
         - if diff_file.mode_changed?
           %span.file-mode= "#{diff_file.diff.a_mode} → #{diff_file.diff.b_mode}"
 
-      .diff-btn-group
+      .diff-controls
         - if blob.text?
           = link_to '#', class: 'js-toggle-diff-comments btn btn-sm active has_tooltip', title: "Toggle comments for this file" do
             %i.fa.fa-comments
           &nbsp;
 
-        - if @merge_request && @merge_request.source_project
+        - if editable_diff?(diff_file)
           = edit_blob_link(@merge_request.source_project,
               @merge_request.source_branch, diff_file.new_path,
               after: '&nbsp;', from_merge_request_id: @merge_request.id)
 
-        = view_file_btn(@commit.id, diff_file, project)
+        = view_file_btn(diff_commit.id, diff_file, project)
 
   .diff-content.diff-wrap-lines
     -# Skipp all non non-supported blobs
@@ -44,7 +38,7 @@
       - else
         = render "projects/diffs/text_file", diff_file: diff_file, index: i
     - elsif blob.image?
-      - old_file = project.repository.prev_blob_for_diff(@commit, diff_file)
+      - old_file = project.repository.prev_blob_for_diff(diff_commit, diff_file)
       = render "projects/diffs/image", diff_file: diff_file, old_file: old_file, file: blob, index: i
     - else
       .nothing-here-block No preview for this file type
diff --git a/app/views/projects/diffs/_stats.html.haml b/app/views/projects/diffs/_stats.html.haml
index c4d7f26430bda8255608740252a4dd9faadc3302..ea2a3e01277543aababa899dc2c73357954aa14a 100644
--- a/app/views/projects/diffs/_stats.html.haml
+++ b/app/views/projects/diffs/_stats.html.haml
@@ -2,37 +2,35 @@
   .commit-stat-summary
     Showing
     = link_to '#', class: 'js-toggle-button' do
-      %strong #{pluralize(diffs.count, "changed file")}
-    - if current_controller?(:commit)
-      - unless @commit.has_zero_stats?
-        with
-        %strong.cgreen #{@commit.stats.additions} additions
-        and
-        %strong.cred #{@commit.stats.deletions} deletions
+      %strong #{pluralize(diff_files.count, "changed file")}
+    with
+    %strong.cgreen #{diff_files.sum(&:added_lines)} additions
+    and
+    %strong.cred #{diff_files.sum(&:removed_lines)} deletions
   .file-stats.js-toggle-content.hide
     %ul
-      - diffs.each_with_index do |diff, i|
+      - diff_files.each_with_index do |diff_file, i|
         %li
-          - if diff.deleted_file
+          - if diff_file.deleted_file
             %span.deleted-file
               %a{href: "#diff-#{i}"}
                 %i.fa.fa-minus
-                = diff.old_path
-          - elsif diff.renamed_file
+                = diff_file.old_path
+          - elsif diff_file.renamed_file
             %span.renamed-file
               %a{href: "#diff-#{i}"}
                 %i.fa.fa-minus
-                = diff.old_path
+                = diff_file.old_path
                 &rarr;
-                = diff.new_path
-          - elsif diff.new_file
+                = diff_file.new_path
+          - elsif diff_file.new_file
             %span.new-file
               %a{href: "#diff-#{i}"}
                 %i.fa.fa-plus
-                = diff.new_path
+                = diff_file.new_path
           - else
             %span.edit-file
               %a{href: "#diff-#{i}"}
                 %i.fa.fa-adjust
-                = diff.new_path
+                = diff_file.new_path
 
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index 90dce739992a8817667dd503c22254773c2c0acc..afbf88b55073ed9bdcb37b348c3d345e5b18aa80 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -189,19 +189,35 @@
       - else
         .nothing-here-block Only the project owner can transfer a project
 
+      - if @project.forked?
+        - if can?(current_user, :remove_fork_project, @project)
+          = form_for([@project.namespace.becomes(Namespace), @project], url: remove_fork_namespace_project_path(@project.namespace, @project), method: :delete, remote: true, html: { class: 'transfer-project form-horizontal' }) do |f|
+            .panel.panel-default.panel.panel-danger
+              .panel-heading Remove fork relationship
+              .panel-body
+                %p
+                  This will remove the fork relationship to source project
+                  #{link_to @project.forked_from_project.name_with_namespace, project_path(@project.forked_from_project)}.
+                  %br
+                  %strong Once removed, the fork relationship cannot be restored and you will no longer be able to send merge requests to the source.
+                = button_to 'Remove fork relationship', '#', class: "btn btn-remove js-confirm-danger", data: { "confirm-danger-message" => remove_fork_project_message(@project) }
+        - else
+          .nothing-here-block Only the project owner can remove the fork relationship.
+
       - if can?(current_user, :remove_project, @project)
         .panel.panel-default.panel.panel-danger
           .panel-heading Remove project
           .panel-body
-            = form_tag(namespace_project_path(@project.namespace, @project), method: :delete, html: { class: 'form-horizontal'}) do
+            = form_tag(namespace_project_path(@project.namespace, @project), method: :delete, class: 'form-horizontal') do
               %p
                 Removing the project will delete its repository and all related resources including issues, merge requests etc.
                 %br
                 %strong Removed projects cannot be restored!
 
-              = link_to 'Remove project', '#', class: "btn btn-remove js-confirm-danger", data: { "confirm-danger-message" => remove_project_message(@project) }
+              = button_to 'Remove project', '#', class: "btn btn-remove js-confirm-danger", data: { "confirm-danger-message" => remove_project_message(@project) }
       - else
-        .nothing-here-block Only project owner can remove a project
+        .nothing-here-block Only the project owner can remove a project.
+
 
 .save-project-loader.hide
   .center
diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml
index 185ebf2393440c558928cd5adb7a977de80846ec..c3858e78caddf4e44fc1e79a837bad28b4029e33 100644
--- a/app/views/projects/empty.html.haml
+++ b/app/views/projects/empty.html.haml
@@ -1,52 +1,57 @@
-- if current_user && can?(current_user, :download_code, @project)
-  = render 'shared/no_ssh'
-  = render 'shared/no_password'
+.alert_holder
+  - if current_user && can?(current_user, :download_code, @project)
+    = render 'shared/no_ssh'
+    = render 'shared/no_password'
 
 = render "home_panel"
 
 .gray-content-block.center
   %h3.page-title
     The repository for this project is empty
-  %p
-    If you already have files you can push them using command line instructions below.
-    %br
-    Otherwise you can start with
-    = link_to "adding README", new_readme_path, class: 'underlined-link'
-    file to this project.
+  - if can?(current_user, :download_code, @project)
+    %p
+      If you already have files you can push them using command line instructions below.
+      %br
+      - if can?(current_user, :push_code, @project)
+        Otherwise you can start with
+        = link_to "adding README", new_readme_path, class: 'underlined-link'
+        file to this project.
 
-.prepend-top-20
-%h3.page-title
-  Command line instructions
-%div.git-empty
-  %fieldset
-    %h5 Git global setup
-    %pre.light-well
-      :preserve
-        git config --global user.name "#{h git_user_name}"
-        git config --global user.email "#{h git_user_email}"
+- if can?(current_user, :download_code, @project)
+  .prepend-top-20
+  .empty_wrapper
+    %h3.page-title-empty
+      Command line instructions
+    %div.git-empty
+      %fieldset
+        %h5 Git global setup
+        %pre.light-well
+          :preserve
+            git config --global user.name "#{h git_user_name}"
+            git config --global user.email "#{h git_user_email}"
 
-  %fieldset
-    %h5 Create a new repository
-    %pre.light-well
-      :preserve
-        git clone #{ content_tag(:span, default_url_to_repo, class: 'clone')}
-        cd #{h @project.path}
-        touch README.md
-        git add README.md
-        git commit -m "add README"
-        git push -u origin master
+      %fieldset
+        %h5 Create a new repository
+        %pre.light-well
+          :preserve
+            git clone #{ content_tag(:span, default_url_to_repo, class: 'clone')}
+            cd #{h @project.path}
+            touch README.md
+            git add README.md
+            git commit -m "add README"
+            git push -u origin master
 
-  %fieldset
-    %h5 Existing folder or Git repository
-    %pre.light-well
-      :preserve
-        cd existing_folder
-        git init
-        git remote add origin #{ content_tag(:span, default_url_to_repo, class: 'clone')}
-        git add .
-        git commit
-        git push -u origin master
+      %fieldset
+        %h5 Existing folder or Git repository
+        %pre.light-well
+          :preserve
+            cd existing_folder
+            git init
+            git remote add origin #{ content_tag(:span, default_url_to_repo, class: 'clone')}
+            git add .
+            git commit
+            git push -u origin master
 
-- if can? current_user, :remove_project, @project
-  .prepend-top-20
-    = link_to 'Remove project', [@project.namespace.becomes(Namespace), @project], data: { confirm: remove_project_message(@project)}, method: :delete, class: "btn btn-remove pull-right"
+        - if can? current_user, :remove_project, @project
+          .prepend-top-20
+            = link_to 'Remove project', [@project.namespace.becomes(Namespace), @project], data: { confirm: remove_project_message(@project)}, method: :delete, class: "btn btn-remove pull-right"
diff --git a/app/views/projects/forks/new.html.haml b/app/views/projects/forks/new.html.haml
index cd5f3a5d39e4b7777b5bb8486f92f101f4461db3..f0b0a11c04a30de76383dd410d22bac157c3d580 100644
--- a/app/views/projects/forks/new.html.haml
+++ b/app/views/projects/forks/new.html.haml
@@ -1,36 +1,41 @@
 - page_title "Fork project"
-%h3.page-title Fork project
-%p.lead
-  Click to fork the project to a user or group
-%hr
+- if @namespaces.present?
+  %h3.page-title Fork project
+  %p.lead
+    Click to fork the project to a user or group
+  %hr
 
-.fork-namespaces
-  - @namespaces.in_groups_of(6, false) do |group|
-    .row
-      - group.each do |namespace|
-        .col-md-2.col-sm-3
-          - if fork = namespace.find_fork_of(@project)
-            .fork-thumbnail
-              = link_to project_path(fork), title: "Visit project fork", class: 'has_tooltip' do
-                = image_tag namespace_icon(namespace, 100)
-                .caption
-                  %strong
-                    = namespace.human_name
-                  %div.text-primary
-                    Already forked
+  .fork-namespaces
+    - @namespaces.in_groups_of(6, false) do |group|
+      .row
+        - group.each do |namespace|
+          .col-md-2.col-sm-3
+            - if fork = namespace.find_fork_of(@project)
+              .fork-thumbnail
+                = link_to project_path(fork), title: "Visit project fork", class: 'has_tooltip' do
+                  = image_tag namespace_icon(namespace, 100)
+                  .caption
+                    %strong
+                      = namespace.human_name
+                    %div.text-primary
+                      Already forked
 
-          - else
-            .fork-thumbnail
-              = link_to namespace_project_fork_path(@project.namespace, @project, namespace_key: namespace.id), title: "Fork here", method: "POST", class: 'has_tooltip' do
-                = image_tag namespace_icon(namespace, 100)
-                .caption
-                  %strong
-                    = namespace.human_name
+            - else
+              .fork-thumbnail
+                = link_to namespace_project_fork_path(@project.namespace, @project, namespace_key: namespace.id), title: "Fork here", method: "POST", class: 'has_tooltip' do
+                  = image_tag namespace_icon(namespace, 100)
+                  .caption
+                    %strong
+                      = namespace.human_name
 
-  %p.light
-    Fork is a copy of a project repository.
-    %br
-    Forking a repository allows you to do changes without affecting the original project.
+    %p.light
+      Fork is a copy of a project repository.
+      %br
+      Forking a repository allows you to do changes without affecting the original project.
+- else
+  %h3 No available namespaces to fork the project
+  %p.slead
+    You must have permission to create a project in a namespace before forking.
 
 .save-project-loader.hide
   .center
diff --git a/app/views/projects/imports/new.html.haml b/app/views/projects/imports/new.html.haml
index f8f2e192e291f20a8960862def746e375953f2c4..92a87690c54992961bdb9bc97b72d39ff97d998b 100644
--- a/app/views/projects/imports/new.html.haml
+++ b/app/views/projects/imports/new.html.haml
@@ -17,6 +17,6 @@
         This URL must be publicly accessible or you can add a username and password like this: https://username:password@gitlab.com/company/project.git.
         %br
         The import will time out after 4 minutes. For big repositories, use a clone/push combination.
-        For SVN repositories, check #{link_to "this migrating from SVN doc.", "http://doc.gitlab.com/ce/workflow/migrating_from_svn.html"}
+        For SVN repositories, check #{link_to "this migrating from SVN doc.", "http://doc.gitlab.com/ce/workflow/importing/migrating_from_svn.html"}
   .form-actions
     = f.submit 'Start import', class: "btn btn-create", tabindex: 4
diff --git a/app/views/projects/issues/_closed_by_box.html.haml b/app/views/projects/issues/_closed_by_box.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..aef352029d06d5425d2bee39b108af321c49dfb5
--- /dev/null
+++ b/app/views/projects/issues/_closed_by_box.html.haml
@@ -0,0 +1,3 @@
+.issue-closed-by-widget
+  = icon('check')
+  This issue will be closed automatically when merge request #{gfm(merge_requests_sentence(@closed_by_merge_requests.sort))} is accepted.
diff --git a/app/views/projects/issues/_issues.html.haml b/app/views/projects/issues/_issues.html.haml
index a3399c57aa2af2dc889a3daa7a45f4297b214dda..ca5b1a8386d63497f2a8018a216c6069001ac0cb 100644
--- a/app/views/projects/issues/_issues.html.haml
+++ b/app/views/projects/issues/_issues.html.haml
@@ -5,8 +5,9 @@
       .nothing-here-block No issues to show
 
 - if @issues.present?
-  .pull-right
-    %span.issue_counter #{@issues.total_count}
-    issues for this filter
+  .issuable-filter-count
+    %span.pull-right
+      = @issues.total_count
+      issues for this filter
 
   = paginate @issues, theme: "gitlab"
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index 5cb814c9ea84cb29579c6479e9d1b8f8010c2e1e..f01bf2505dad68e7e8b91463af86244f1b5a5bba 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -46,6 +46,7 @@
                 = markdown(@issue.description)
             %textarea.hidden.js-task-list-field
               = @issue.description
-
+  - if @closed_by_merge_requests.present?
+    = render 'projects/issues/closed_by_box'
   .issue-discussion
     = render 'projects/issues/discussion'
diff --git a/app/views/projects/labels/_form.html.haml b/app/views/projects/labels/_form.html.haml
index 534c545329b0a85f01bb45dc942020ab7915bc08..4cf13492e99cd4cfe0a67b3a2b0a4f69f9c4b93f 100644
--- a/app/views/projects/labels/_form.html.haml
+++ b/app/views/projects/labels/_form.html.haml
@@ -10,7 +10,7 @@
   .form-group
     = f.label :title, class: 'control-label'
     .col-sm-10
-      = f.text_field :title, class: "form-control", required: true
+      = f.text_field :title, class: "form-control js-quick-submit", required: true
   .form-group
     = f.label :color, "Background Color", class: 'control-label'
     .col-sm-10
diff --git a/app/views/projects/merge_requests/_merge_requests.html.haml b/app/views/projects/merge_requests/_merge_requests.html.haml
index d86707b3d97eaa12b2edc10ad4fa35b96acba366..0af970e4b922ecc3d78ce4683c55f087afe42f1c 100644
--- a/app/views/projects/merge_requests/_merge_requests.html.haml
+++ b/app/views/projects/merge_requests/_merge_requests.html.haml
@@ -5,8 +5,10 @@
       .nothing-here-block No merge requests to show
 
 - if @merge_requests.present?
-  .pull-right
-    %span.cgray.pull-right #{@merge_requests.total_count} merge requests for this filter
+  .issuable-filter-count
+    %span.pull-right
+      = @merge_requests.total_count
+      merge requests for this filter
 
   = paginate @merge_requests, theme: "gitlab"
 
diff --git a/app/views/projects/merge_requests/_new_submit.html.haml b/app/views/projects/merge_requests/_new_submit.html.haml
index 46aeecd87336365dde4934a640b4ae9293aed869..6244d3ba0b440c52d943a2cb7d1175d34deb9011 100644
--- a/app/views/projects/merge_requests/_new_submit.html.haml
+++ b/app/views/projects/merge_requests/_new_submit.html.haml
@@ -1,10 +1,11 @@
 %h3.page-title
   New merge request
 %p.slead
+  - source_title, target_title = format_mr_branch_names(@merge_request)
   From
-  %strong.label-branch #{@merge_request.source_project_namespace}:#{@merge_request.source_branch}
+  %strong.label-branch #{source_title}
   %span into
-  %strong.label-branch #{@merge_request.target_project_namespace}:#{@merge_request.target_branch}
+  %strong.label-branch #{target_title}
 
   %span.pull-right
     = link_to 'Change branches', mr_change_branches_path(@merge_request)
diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml
index 0b0f52c653cf184dad3e6a0c31cfc43dad17d1e0..eeaa72ed21bebf3e15a4dc7ea50d3abbcfec3e02 100644
--- a/app/views/projects/merge_requests/_show.html.haml
+++ b/app/views/projects/merge_requests/_show.html.haml
@@ -24,7 +24,7 @@
             %ul.dropdown-menu
               %li= link_to "Email Patches", merge_request_path(@merge_request, format: :patch)
               %li= link_to "Plain Diff",    merge_request_path(@merge_request, format: :diff)
-      .light
+      .normal
         %span Request to merge
         %span.label-branch #{source_branch_with_namespace(@merge_request)}
         %span into
@@ -34,9 +34,10 @@
     = render "projects/merge_requests/widget/show.html.haml"
 
     - if @merge_request.open? && @merge_request.can_be_merged?
-      .light
+      .light.append-bottom-20
         You can also accept this merge request manually using the
-        = link_to "command line", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal"
+        = succeed '.' do
+          = link_to "command line", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal"
 
   - if @commits.present?
     %ul.merge-request-tabs
diff --git a/app/views/projects/merge_requests/widget/_heading.html.haml b/app/views/projects/merge_requests/widget/_heading.html.haml
index 10640f746f01f61f92d3087dd001b18038c484d3..10efb811939a025dcf31ac522f093563b1e9094e 100644
--- a/app/views/projects/merge_requests/widget/_heading.html.haml
+++ b/app/views/projects/merge_requests/widget/_heading.html.haml
@@ -1,4 +1,17 @@
-- if @merge_request.has_ci?
+- ci_commit = @merge_request.source_project.ci_commit(@merge_request.source_sha)
+- if ci_commit
+  - status = ci_commit.status
+  .mr-widget-heading
+    .ci_widget{class: "ci-#{status}"}
+      = ci_status_icon(ci_commit)
+      %span CI build #{status}
+      for #{@merge_request.last_commit_short_sha}.
+      %span.ci-coverage
+      = link_to "View build details", ci_status_path(ci_commit)
+
+- elsif @merge_request.has_ci?
+  - # Compatibility with old CI integrations (ex jenkins) when you request status from CI server via AJAX
+  - # Remove in later versions when services like Jenkins will set CI status via Commit status API
   .mr-widget-heading
     - [:success, :skipped, :canceled, :failed, :running, :pending].each do |status|
       .ci_widget{class: "ci-#{status}", style: "display:none"}
diff --git a/app/views/projects/milestones/_form.html.haml b/app/views/projects/milestones/_form.html.haml
index 74e9668052d60354ce8d66f0f4e40df2fef3c10b..255ddab479f4b3765eb37d15930540c8e35d2c20 100644
--- a/app/views/projects/milestones/_form.html.haml
+++ b/app/views/projects/milestones/_form.html.haml
@@ -16,13 +16,13 @@
       .form-group
         = f.label :title, "Title", class: "control-label"
         .col-sm-10
-          = f.text_field :title, maxlength: 255, class: "form-control", required: true
+          = f.text_field :title, maxlength: 255, class: "form-control js-quick-submit", required: true
           %p.hint Required
       .form-group.milestone-description
         = f.label :description, "Description", class: "control-label"
         .col-sm-10
           = render layout: 'projects/md_preview', locals: { preview_class: "md-preview" } do
-            = render 'projects/zen', f: f, attr: :description, classes: 'description form-control'
+            = render 'projects/zen', f: f, attr: :description, classes: 'description form-control js-quick-submit'
             .hint
               .pull-left Milestones are parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"), target: '_blank'}.
               .pull-left Attach files by dragging & dropping or #{link_to "selecting them", '#', class: 'markdown-selector' }.
diff --git a/app/views/projects/milestones/_issue.html.haml b/app/views/projects/milestones/_issue.html.haml
index 88fccfe4981c4e665c299729080f7b37fa2a85ab..133d802aaca1646f60211d3843fa0491b950f7d6 100644
--- a/app/views/projects/milestones/_issue.html.haml
+++ b/app/views/projects/milestones/_issue.html.haml
@@ -1,7 +1,7 @@
 %li{ id: dom_id(issue, 'sortable'), class: 'issue-row', 'data-iid' => issue.iid, 'data-url' => issue_path(issue) }
   .pull-right.assignee-icon
     - if issue.assignee
-      = image_tag avatar_icon(issue.assignee.email, 16), class: "avatar s16", alt: ''
+      = image_tag avatar_icon(issue.assignee, 16), class: "avatar s16", alt: ''
   %span
     = link_to [@project.namespace.becomes(Namespace), @project, issue] do
       %span.cgray ##{issue.iid}
diff --git a/app/views/projects/milestones/_merge_request.html.haml b/app/views/projects/milestones/_merge_request.html.haml
index 0d7a118569a8943037af86bbadf8dd745cb799e8..a1033607c5de0fb94ede75943e56b1a09b452e57 100644
--- a/app/views/projects/milestones/_merge_request.html.haml
+++ b/app/views/projects/milestones/_merge_request.html.haml
@@ -5,4 +5,4 @@
     = link_to_gfm merge_request.title, [@project.namespace.becomes(Namespace), @project, merge_request], title: merge_request.title
   .pull-right.assignee-icon
     - if merge_request.assignee
-      = image_tag avatar_icon(merge_request.assignee.email, 16), class: "avatar s16", alt: ''
+      = image_tag avatar_icon(merge_request.assignee, 16), class: "avatar s16", alt: ''
diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml
index 4eeb0621e526c32f1d824679c9ae115982760b88..3a898dfbcfd1f2406da96d2afc8e7c71e4cfd77d 100644
--- a/app/views/projects/milestones/show.html.haml
+++ b/app/views/projects/milestones/show.html.haml
@@ -104,7 +104,7 @@
       - @users.each do |user|
         %li
           = link_to user, title: user.name, class: "darken" do
-            = image_tag avatar_icon(user.email, 32), class: "avatar s32"
+            = image_tag avatar_icon(user, 32), class: "avatar s32"
             %strong= truncate(user.name, lenght: 40)
             %br
             %small.cgray= user.username
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index bccea21e7a82794f69880f112c44e4991de11031..daab2326bc7615d88c6a43ed6ae4b8f5fac58397 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -8,7 +8,7 @@
     = form_for @project, html: { class: 'new_project form-horizontal js-requires-input' } do |f|
       .form-group.project-name-holder
         = f.label :path, class: 'control-label' do
-          %strong Project path
+          Project path
         .col-sm-10
           .input-group
             = f.text_field :path, placeholder: "my-awesome-project", class: "form-control", tabindex: 1, autofocus: true, required: true
@@ -23,7 +23,6 @@
             = f.select :namespace_id, namespaces_options(params[:namespace_id] || :current_user), {}, {class: 'select2', tabindex: 2}
 
       - if import_sources_enabled?
-        %hr
 
         .project-import.js-toggle-container
           .form-group
@@ -35,7 +34,7 @@
                     %i.fa.fa-github
                     GitHub
                 - else
-                  = link_to '#', class: 'how_to_import_link light btn import_github' do
+                  = link_to '#', class: 'how_to_import_link btn import_github' do
                     %i.fa.fa-github
                     GitHub
                   = render 'github_import_modal'
@@ -46,7 +45,7 @@
                     %i.fa.fa-bitbucket
                     Bitbucket
                 - else
-                  = link_to status_import_bitbucket_path, class: 'how_to_import_link light btn import_bitbucket', "data-no-turbolink" => "true" do
+                  = link_to status_import_bitbucket_path, class: 'how_to_import_link btn import_bitbucket', "data-no-turbolink" => "true" do
                     %i.fa.fa-bitbucket
                     Bitbucket
                   = render 'bitbucket_import_modal'
@@ -57,7 +56,7 @@
                     %i.fa.fa-heart
                     GitLab.com
                 - else
-                  = link_to status_import_gitlab_path, class: 'how_to_import_link light btn import_gitlab' do
+                  = link_to status_import_gitlab_path, class: 'how_to_import_link btn import_gitlab' do
                     %i.fa.fa-heart
                     GitLab.com
                   = render 'gitlab_import_modal'
@@ -97,7 +96,7 @@
                     %li
                       To migrate an SVN repository, check out #{link_to "this document", "http://doc.gitlab.com/ce/workflow/importing/migrating_from_svn.html"}.
 
-      %hr.prepend-botton-10
+      .prepend-botton-10
 
       .form-group
         = f.label :description, class: 'control-label' do
@@ -112,10 +111,11 @@
 
         - if current_user.can_create_group?
           .pull-right
-            .light
-              Need a group for several dependent projects?
-              = link_to new_group_path, class: "btn btn-xs" do
-                Create a group
+            .light.inline
+              .space-right
+                Need a group for several dependent projects?
+            = link_to new_group_path, class: "btn" do
+              Create a group
 
 .save-project-loader.hide
   .center
diff --git a/app/views/projects/notes/_edit_form.html.haml b/app/views/projects/notes/_edit_form.html.haml
index a0e26f9827e5e86d24079a23160dd79295b404b3..a21c019986a99a9316b8c12fb474a57895824630 100644
--- a/app/views/projects/notes/_edit_form.html.haml
+++ b/app/views/projects/notes/_edit_form.html.haml
@@ -2,7 +2,7 @@
   = form_for note, url: namespace_project_note_path(@project.namespace, @project, note), method: :put, remote: true, authenticity_token: true do |f|
     = note_target_fields(note)
     = render layout: 'projects/md_preview', locals: { preview_class: 'md-preview' } do
-      = render 'projects/zen', f: f, attr: :note, classes: 'note_text js-note-text js-task-list-field'
+      = render 'projects/zen', f: f, attr: :note, classes: 'note_text js-note-text js-task-list-field js-quick-submit'
       = render 'projects/notes/hints'
 
     .note-form-actions
diff --git a/app/views/projects/notes/_form.html.haml b/app/views/projects/notes/_form.html.haml
index d99445da59ac5977711278a13cea860308c49367..13dfa0a1bb33fc48bda63410892bfb1fa2b998cb 100644
--- a/app/views/projects/notes/_form.html.haml
+++ b/app/views/projects/notes/_form.html.haml
@@ -8,12 +8,12 @@
   = f.hidden_field :noteable_type
 
   = render layout: 'projects/md_preview', locals: { preview_class: "md-preview", referenced_users: true } do
-    = render 'projects/zen', f: f, attr: :note, classes: 'note_text js-note-text'
+    = render 'projects/zen', f: f, attr: :note, classes: 'note_text js-note-text js-quick-submit'
     = render 'projects/notes/hints'
     .error-alert
 
   .note-form-actions
     .buttons.clearfix
-      = f.submit 'Add Comment', class: "btn comment-btn btn-grouped js-comment-button"
+      = f.submit 'Add Comment', class: "btn btn-green comment-btn btn-grouped js-comment-button"
       = yield(:note_actions)
       %a.btn.grouped.js-close-discussion-note-form Cancel
diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml
index 9bfbde02ca206ec43506a135b746e2f2068b9bba..5d184730796f9112b6f4db44967b0aa934a089ba 100644
--- a/app/views/projects/notes/_note.html.haml
+++ b/app/views/projects/notes/_note.html.haml
@@ -1,8 +1,8 @@
 %li.timeline-entry{ id: dom_id(note), class: [dom_class(note), "note-row-#{note.id}", ('system-note' if note.system)], data: { discussion: note.discussion_id } }
   .timeline-entry-inner
     .timeline-icon
-      = link_to user_path(note.author) do
-        = image_tag avatar_icon(note.author_email), class: 'avatar s40', alt: ''
+      %a{href: user_path(note.author)}
+        %img.avatar.s40{src: avatar_icon(note.author), alt: ''}
     .timeline-content
       .note-header
         - if note_editable?(note)
@@ -14,10 +14,10 @@
               = icon('trash-o')
 
         - unless note.system
-          - member = note.project.team.find_member(note.author.id)
-          - if member
+          - access = note.project.team.human_max_access(note.author.id)
+          - if access
             %span.note-role.label
-              = member.human_access
+              = access
 
         = link_to_member(note.project, note.author, avatar: false)
 
@@ -25,7 +25,7 @@
           = '@' + note.author.username
 
         %span.note-last-update
-          = link_to "##{dom_id(note)}", name: dom_id(note), title: "Link here" do
+          %a{name: dom_id(note), href: "##{dom_id(note)}", title: 'Link here'}
             = time_ago_with_tooltip(note.created_at, placement: 'bottom', html_class: 'note_created_ago')
           - if note.updated_at != note.created_at
             %span
@@ -59,7 +59,9 @@
         .note-text
           = preserve do
             = markdown(note.note, {no_header_anchors: true})
-        = render 'projects/notes/edit_form', note: note
+        - unless note.system?
+          -# System notes can't be edited
+          = render 'projects/notes/edit_form', note: note
 
       - if note.attachment.url
         .note-attachment
diff --git a/app/views/projects/project_members/_project_member.html.haml b/app/views/projects/project_members/_project_member.html.haml
index 860a997cff84c6f7fb10c69a6f8e3caa06face39..76c46d1d8067a7fe7dc855fa09a342c40260dbc6 100644
--- a/app/views/projects/project_members/_project_member.html.haml
+++ b/app/views/projects/project_members/_project_member.html.haml
@@ -4,7 +4,7 @@
 %li{class: "#{dom_class(member)} js-toggle-container project_member_row access-#{member.human_access.downcase}", id: dom_id(member)}
   %span.list-item-name
     - if member.user
-      = image_tag avatar_icon(user.email, 16), class: "avatar s16", alt: ''
+      = image_tag avatar_icon(user, 16), class: "avatar s16", alt: ''
       %strong
         = link_to user.name, user_path(user)
       %span.cgray= user.username
diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml
index 9a0a824b811ab3a01a094b769e56401fe6ce7d06..82809bec5b81f49754c11d384e0e26e491b96e34 100644
--- a/app/views/projects/project_members/index.html.haml
+++ b/app/views/projects/project_members/index.html.haml
@@ -5,7 +5,7 @@
   .clearfix.js-toggle-container
     = form_tag namespace_project_project_members_path(@project.namespace, @project), method: :get, class: 'form-inline member-search-form'  do
       .form-group
-        = search_field_tag :search, params[:search], { placeholder: 'Find existing member by name', class: 'form-control search-text-input' }
+        = search_field_tag :search, params[:search], { placeholder: 'Find existing member by name', class: 'form-control search-text-input', spellcheck: false }
       = button_tag 'Search', class: 'btn'
 
     - if can?(current_user, :admin_project_member, @project)
diff --git a/app/views/projects/protected_branches/_branches_list.html.haml b/app/views/projects/protected_branches/_branches_list.html.haml
index bb49f4de8736ce2422f605b09c67824ac4ef0040..f68449b186394b54ec952aff3f492c06680621cf 100644
--- a/app/views/projects/protected_branches/_branches_list.html.haml
+++ b/app/views/projects/protected_branches/_branches_list.html.haml
@@ -1,34 +1,35 @@
 - unless @branches.empty?
   %br
   %h4 Already Protected:
-  %table.table.protected-branches-list
-    %thead
-      %tr.no-border
-        %th Branch
-        %th Developers can push
-        %th Last commit
-        %th
+  .table-holder
+    %table.table.protected-branches-list
+      %thead
+        %tr.no-border
+          %th Branch
+          %th Developers can push
+          %th Last commit
+          %th
 
-    %tbody
-      - @branches.each do |branch|
-        - @url = namespace_project_protected_branch_path(@project.namespace, @project, branch)
-        %tr
-          %td
-            = link_to namespace_project_commits_path(@project.namespace, @project, branch.name) do
-              %strong= branch.name
-              - if @project.root_ref?(branch.name)
-                %span.label.label-info default
+      %tbody
+        - @branches.each do |branch|
+          - @url = namespace_project_protected_branch_path(@project.namespace, @project, branch)
+          %tr
             %td
-              = check_box_tag "developers_can_push", branch.id, branch.developers_can_push, "data-url" => @url
-            %td
-              - if commit = branch.commit
-                = link_to namespace_project_commit_path(@project.namespace, @project, commit.id), class: 'commit_short_id' do
-                  = commit.short_id
-                &middot;
-                #{time_ago_with_tooltip(commit.committed_date)}
-              - else
-                (branch was removed from repository)
-            %td
-              .pull-right
-                - if can? current_user, :admin_project, @project
-                  = link_to 'Unprotect', [@project.namespace.becomes(Namespace), @project, branch], data: { confirm: 'Branch will be writable for developers. Are you sure?' }, method: :delete, class: "btn btn-remove btn-sm"
+              = link_to namespace_project_commits_path(@project.namespace, @project, branch.name) do
+                %strong= branch.name
+                - if @project.root_ref?(branch.name)
+                  %span.label.label-info default
+              %td
+                = check_box_tag "developers_can_push", branch.id, branch.developers_can_push, "data-url" => @url
+              %td
+                - if commit = branch.commit
+                  = link_to namespace_project_commit_path(@project.namespace, @project, commit.id), class: 'commit_short_id' do
+                    = commit.short_id
+                  &middot;
+                  #{time_ago_with_tooltip(commit.committed_date)}
+                - else
+                  (branch was removed from repository)
+              %td
+                .pull-right
+                  - if can? current_user, :admin_project, @project
+                    = link_to 'Unprotect', [@project.namespace.becomes(Namespace), @project, branch], data: { confirm: 'Branch will be writable for developers. Are you sure?' }, method: :delete, class: "btn btn-remove btn-sm"
diff --git a/app/views/projects/remove_fork.js.haml b/app/views/projects/remove_fork.js.haml
new file mode 100644
index 0000000000000000000000000000000000000000..17b9fecfeb162f8f3ac88523a7fbe336c4d46516
--- /dev/null
+++ b/app/views/projects/remove_fork.js.haml
@@ -0,0 +1,2 @@
+:plain
+    location.href = "#{edit_namespace_project_path(@project.namespace, @project)}";
diff --git a/app/views/projects/repositories/_download_archive.html.haml b/app/views/projects/repositories/_download_archive.html.haml
index b9486a9b49265c92771b58c529b26fd9f51cb4de..07c24950ee238e89c7d5744d79ea54bd79d5db6d 100644
--- a/app/views/projects/repositories/_download_archive.html.haml
+++ b/app/views/projects/repositories/_download_archive.html.haml
@@ -3,10 +3,10 @@
 - split_button = split_button || false
 - if split_button == true
   %span.btn-group{class: btn_class}
-    = link_to archive_namespace_project_repository_path(@project.namespace, @project, ref: ref, format: 'zip'), class: 'btn col-xs-10', rel: 'nofollow' do
+    = link_to archive_namespace_project_repository_path(@project.namespace, @project, ref: ref, format: 'zip'), class: 'btn btn-success col-xs-10', rel: 'nofollow' do
       %i.fa.fa-download
       %span Download zip
-    %a.col-xs-2.btn.dropdown-toggle{ 'data-toggle' => 'dropdown' }
+    %a.col-xs-2.btn.btn-success.dropdown-toggle{ 'data-toggle' => 'dropdown' }
       %span.caret
       %span.sr-only
         Select Archive Format
diff --git a/app/views/ci/runners/_runner.html.haml b/app/views/projects/runners/_runner.html.haml
similarity index 54%
rename from app/views/ci/runners/_runner.html.haml
rename to app/views/projects/runners/_runner.html.haml
index ef8622e28070dc89fcb4cf3caefe513950e15ae1..e6b8a2e6fe76b77cd62056e70ea0ad2c6c5ec858 100644
--- a/app/views/ci/runners/_runner.html.haml
+++ b/app/views/projects/runners/_runner.html.haml
@@ -3,9 +3,9 @@
     = runner_status_icon(runner)
     %span.monospace
       - if @runners.include?(runner)
-        = link_to runner.short_sha, ci_project_runner_path(@project, runner)
+        = link_to runner.short_sha, runner_path(runner)
         %small
-          =link_to edit_ci_project_runner_path(@project, runner) do
+          =link_to edit_namespace_project_runner_path(@project.namespace, @project, runner) do
             %i.fa.fa-edit.btn
       - else
         = runner.short_sha
@@ -13,12 +13,12 @@
     .pull-right
       - if @runners.include?(runner)
         - if runner.belongs_to_one_project?
-          = link_to 'Remove runner', [:ci, @project, runner], data: { confirm: "Are you sure?" }, method: :delete, class: 'btn btn-danger btn-sm'
+          = link_to 'Remove runner', runner_path(runner), data: { confirm: "Are you sure?" }, method: :delete, class: 'btn btn-danger btn-sm'
         - else
-          - runner_project = @project.runner_projects.find_by(runner_id: runner)
-          = link_to 'Disable for this project', [:ci, @project, runner_project], data: { confirm: "Are you sure?" }, method: :delete, class: 'btn btn-danger btn-sm'
+          - runner_project = @ci_project.runner_projects.find_by(runner_id: runner)
+          = link_to 'Disable for this project', [:ci, @ci_project, runner_project], data: { confirm: "Are you sure?" }, method: :delete, class: 'btn btn-danger btn-sm'
       - elsif runner.specific?
-        = form_for [:ci, @project, @project.runner_projects.new] do |f|
+        = form_for [:ci, @ci_project, @ci_project.runner_projects.new] do |f|
           = f.hidden_field :runner_id, value: runner.id
           = f.submit 'Enable for this project', class: 'btn btn-sm'
   .pull-right
@@ -32,4 +32,3 @@
       - runner.tag_list.each do |tag|
         %span.label.label-primary
           = tag
-
diff --git a/app/views/ci/runners/_shared_runners.html.haml b/app/views/projects/runners/_shared_runners.html.haml
similarity index 68%
rename from app/views/ci/runners/_shared_runners.html.haml
rename to app/views/projects/runners/_shared_runners.html.haml
index 944b3fd930d954e4fdd243317dfaff64c4cdddfa..316ea747b147211dbb59281f7bac65d197514707 100644
--- a/app/views/ci/runners/_shared_runners.html.haml
+++ b/app/views/projects/runners/_shared_runners.html.haml
@@ -3,11 +3,11 @@
 .bs-callout.bs-callout-warning
   GitLab Runners do not offer secure isolation between projects that they do builds for. You are TRUSTING all GitLab users who can push code to project A, B or C to run shell scripts on the machine hosting runner X.
   %hr
-  - if @project.shared_runners_enabled
-    = link_to toggle_shared_runners_ci_project_path(@project), class: 'btn btn-warning', method: :post do
+  - if @ci_project.shared_runners_enabled
+    = link_to toggle_shared_runners_ci_project_path(@ci_project), class: 'btn btn-warning', method: :post do
       Disable shared runners
   - else
-    = link_to toggle_shared_runners_ci_project_path(@project), class: 'btn btn-success', method: :post do
+    = link_to toggle_shared_runners_ci_project_path(@ci_project), class: 'btn btn-success', method: :post do
       Enable shared runners
   &nbsp; for this project
 
@@ -17,7 +17,7 @@
 - else
   %h4.underlined-title Available shared runners - #{@shared_runners_count}
   %ul.bordered-list.available-shared-runners
-    = render @shared_runners.first(10)
+    = render partial: 'runner', collection: @shared_runners, as: :runner
   - if @shared_runners_count > 10
     .light
       and #{@shared_runners_count - 10} more...
diff --git a/app/views/ci/runners/_specific_runners.html.haml b/app/views/projects/runners/_specific_runners.html.haml
similarity index 81%
rename from app/views/ci/runners/_specific_runners.html.haml
rename to app/views/projects/runners/_specific_runners.html.haml
index 0604e7a46c581f8dae36367ee3bc00b720338c38..c13625c7e49abadf337d39ca5a0ecf96fba7940c 100644
--- a/app/views/ci/runners/_specific_runners.html.haml
+++ b/app/views/projects/runners/_specific_runners.html.haml
@@ -12,7 +12,7 @@
       %code #{ci_root_url(only_path: false)}
     %li
       Use the following registration token during setup:
-      %code #{@project.token}
+      %code #{@ci_project.token}
     %li
       Start runner!
 
@@ -20,10 +20,10 @@
 - if @runners.any?
   %h4.underlined-title Runners activated for this project
   %ul.bordered-list.activated-specific-runners
-    = render @runners
+    = render partial: 'runner', collection: @runners, as: :runner
 
 - if @specific_runners.any?
   %h4.underlined-title Available specific runners
   %ul.bordered-list.available-specific-runners
-    = render @specific_runners
+    = render partial: 'runner', collection: @specific_runners, as: :runner
   = paginate @specific_runners
diff --git a/app/views/ci/runners/edit.html.haml b/app/views/projects/runners/edit.html.haml
similarity index 90%
rename from app/views/ci/runners/edit.html.haml
rename to app/views/projects/runners/edit.html.haml
index 81c8e58ae2b2de79b171f589f7acea05fc89c03a..66851d3831638654fdb8a74a29ad6e251b5b5217 100644
--- a/app/views/ci/runners/edit.html.haml
+++ b/app/views/projects/runners/edit.html.haml
@@ -1,6 +1,6 @@
 %h4 Runner ##{@runner.id}
 %hr
-= form_for [:ci, @project, @runner], html: { class: 'form-horizontal' } do |f|
+= form_for @runner, url: runner_path(@runner), html: { class: 'form-horizontal' } do |f|
   .form-group
     = label :active, "Active", class: 'control-label'
     .col-sm-10
diff --git a/app/views/ci/runners/index.html.haml b/app/views/projects/runners/index.html.haml
similarity index 100%
rename from app/views/ci/runners/index.html.haml
rename to app/views/projects/runners/index.html.haml
diff --git a/app/views/projects/runners/show.html.haml b/app/views/projects/runners/show.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..c255cd51bd2969e01d30472c5d89350861e12405
--- /dev/null
+++ b/app/views/projects/runners/show.html.haml
@@ -0,0 +1,65 @@
+= content_for :title do
+  %h3.project-title
+    Runner ##{@runner.id}
+    .pull-right
+      - if @runner.shared?
+        %span.runner-state.runner-state-shared
+          Shared
+      - else
+        %span.runner-state.runner-state-specific
+          Specific
+
+.table-holder
+  %table.table
+    %thead
+      %tr
+        %th Property Name
+        %th Value
+    %tr
+      %td
+        Tags
+      %td
+        - @runner.tag_list.each do |tag|
+          %span.label.label-primary
+            = tag
+    %tr
+      %td
+        Name
+      %td
+        = @runner.name
+    %tr
+      %td
+        Version
+      %td
+        = @runner.version
+    %tr
+      %td
+        Revision
+      %td
+        = @runner.revision
+    %tr
+      %td
+        Platform
+      %td
+        = @runner.platform
+    %tr
+      %td
+        Architecture
+      %td
+        = @runner.architecture
+    %tr
+      %td
+        Description
+      %td
+        = @runner.description
+    %tr
+      %td
+        Last contact
+      %td
+        - if @runner.contacted_at
+          #{time_ago_in_words(@runner.contacted_at)} ago
+        - else
+          Never
+
+
+        
diff --git a/app/views/projects/services/index.html.haml b/app/views/projects/services/index.html.haml
index 1065def693bbbecf3a8846b054a6735f9cda7d9a..c1356f6db02dafca076fc28956a982e22dfdb1e7 100644
--- a/app/views/projects/services/index.html.haml
+++ b/app/views/projects/services/index.html.haml
@@ -2,22 +2,23 @@
 %h3.page-title Project services
 %p.light Project services allow you to integrate GitLab with other applications
 
-%table.table
-  %thead
-    %tr
-      %th
-      %th Service
-      %th Description
-      %th Last edit
-  - @services.sort_by(&:title).each do |service|
-    %tr
-      %td
-        = boolean_to_icon service.activated?
-      %td
-        = link_to edit_namespace_project_service_path(@project.namespace, @project, service.to_param) do
-          %strong= service.title
-      %td
-        = service.description
-      %td.light
-        = time_ago_in_words service.updated_at
-        ago
+.table-holder
+  %table.table
+    %thead
+      %tr
+        %th
+        %th Service
+        %th Description
+        %th Last edit
+    - @services.sort_by(&:title).each do |service|
+      %tr
+        %td
+          = boolean_to_icon service.activated?
+        %td
+          = link_to edit_namespace_project_service_path(@project.namespace, @project, service.to_param) do
+            %strong= service.title
+        %td
+          = service.description
+        %td.light
+          = time_ago_in_words service.updated_at
+          ago
diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml
index 6a5fc689803ff17d0a422f6406d284188aaec342..585caf674c961982e849ec5fad5dd7bf4e27529b 100644
--- a/app/views/projects/show.html.haml
+++ b/app/views/projects/show.html.haml
@@ -2,12 +2,12 @@
   - if current_user
     = auto_discovery_link_tag(:atom, namespace_project_path(@project.namespace, @project, format: :atom, private_token: current_user.private_token), title: "#{@project.name} activity")
 
-- if current_user && can?(current_user, :download_code, @project)
-  = render 'shared/no_ssh'
-  = render 'shared/no_password'
+= content_for :flash_message do
+  - if current_user && can?(current_user, :download_code, @project)
+    = render 'shared/no_ssh'
+    = render 'shared/no_password'
 
-- if prefer_readme?
-  = render 'projects/last_push'
+= render 'projects/last_push'
 
 = render "home_panel"
 
@@ -27,7 +27,7 @@
       = link_to project_files_path(@project) do
         = repository_size
 
-    - if !prefer_readme? && @repository.readme
+    - if default_project_view != 'readme' && @repository.readme
       %li
         = link_to 'Readme', readme_path(@project)
 
@@ -63,19 +63,17 @@
       = icon("exclamation-triangle fw")
       Archived project! Repository is read-only
 
-%section
-  - if prefer_readme?
-    .project-show-readme
-      = render 'projects/readme'
-  - else
-    .project-show-activity
-      = render 'projects/activity'
+- if @repository.commit
+  .content-block.second-block.white
+    = render 'projects/last_commit', commit: @repository.commit, project: @project
 
+%div{class: "project-show-#{default_project_view}"}
+  = render default_project_view
 
 - if current_user
   - access = user_max_access_in_project(current_user, @project)
   - if access
-    .prepend-top-20
+    .prepend-top-20.project-footer
       .gray-content-block.footer-block.center
         You have #{access} access to this project.
         - if @project.project_member_by_id(current_user)
diff --git a/app/views/projects/snippets/_actions.html.haml b/app/views/projects/snippets/_actions.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..4a51546942204346dc8d591ba3bf4c1ade0b7b8b
--- /dev/null
+++ b/app/views/projects/snippets/_actions.html.haml
@@ -0,0 +1,11 @@
+= link_to new_namespace_project_snippet_path(@project.namespace, @project), class: 'btn btn-grouped new-snippet-link', title: "New Snippet" do
+  = icon('plus')
+  New Snippet
+- if can?(current_user, :admin_project_snippet, @snippet)
+  = link_to namespace_project_snippet_path(@project.namespace, @project, @snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-grouped btn-remove", title: 'Delete Snippet' do
+    = icon('trash-o')
+    Delete
+- if can?(current_user, :update_project_snippet, @snippet)
+  = link_to edit_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-grouped snippable-edit" do
+    = icon('pencil-square-o')
+    Edit
diff --git a/app/views/projects/snippets/index.html.haml b/app/views/projects/snippets/index.html.haml
index 3fed2c9949d4ad9953de9f98c32f485393b49fc9..4af963e14da55f6ad7952dbebfc02f571309b180 100644
--- a/app/views/projects/snippets/index.html.haml
+++ b/app/views/projects/snippets/index.html.haml
@@ -1,17 +1,13 @@
 - page_title "Snippets"
 = render "header_title"
 
-%h3.page-title
-  Snippets
-  - if can? current_user, :create_project_snippet, @project
-    = link_to new_namespace_project_snippet_path(@project.namespace, @project), class: "btn btn-new pull-right", title: "New Snippet" do
-      Add new snippet
+.gray-content-block.top-block
+  .pull-right
+    = link_to new_namespace_project_snippet_path(@project.namespace, @project), class: "btn btn-new", title: "New Snippet" do
+      = icon('plus')
+      New Snippet
 
-%p.light
-  Share code pastes with others out of git repository
+  .oneline
+    Share code pastes with others out of git repository
 
-%ul.bordered-list
-  = render partial: "shared/snippets/snippet", collection: @snippets
-  - if @snippets.empty?
-    %li
-      .nothing-here-block Nothing here.
+= render 'snippets/snippets'
diff --git a/app/views/projects/snippets/show.html.haml b/app/views/projects/snippets/show.html.haml
index be7d4d486fa383cdc476bbe42e31de27aeaa7a92..5d706942f2d4cd57080a1067975c39aad0fa9b66 100644
--- a/app/views/projects/snippets/show.html.haml
+++ b/app/views/projects/snippets/show.html.haml
@@ -1,40 +1,18 @@
 - page_title @snippet.title, "Snippets"
 = render "header_title"
 
-%h3.page-title
-  = @snippet.title
+.snippet-holder
+  = render 'shared/snippets/header'
 
-  .pull-right
-    = link_to new_namespace_project_snippet_path(@project.namespace, @project), class: "btn btn-new", title: "New Snippet" do
-      Add new snippet
+  %article.file-holder
+    .file-title
+      = blob_icon 0, @snippet.file_name
+      %strong
+        = @snippet.file_name
+      .file-actions.hidden-xs
+        .btn-group.tree-btn-group
+          = link_to 'Raw', raw_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-sm", target: "_blank"
 
-%hr
+    = render 'shared/snippets/blob'
 
-.append-bottom-20
-  .pull-right
-    = "##{@snippet.id}"
-    %span.light
-      by
-      = link_to user_path(@snippet.author) do
-        = image_tag avatar_icon(@snippet.author_email), class: "avatar avatar-inline s16"
-        = @snippet.author_name
-
-  .back-link
-    = link_to namespace_project_snippets_path(@project.namespace, @project) do
-      &larr; project snippets
-
-.file-holder
-  .file-title
-    %i.fa.fa-file
-    %strong
-      = @snippet.file_name
-    .file-actions
-      .btn-group
-        - if can?(current_user, :update_project_snippet, @snippet)
-          = link_to "edit", edit_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-sm", title: 'Edit Snippet'
-        = link_to "raw", raw_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-sm", target: "_blank"
-      - if can?(current_user, :admin_project_snippet, @snippet)
-        = link_to "remove", namespace_project_snippet_path(@project.namespace, @project, @snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-sm btn-remove", title: 'Delete Snippet'
-  = render 'shared/snippets/blob'
-
-%div#notes= render "projects/notes/notes_with_form"
+  %div#notes= render "projects/notes/notes_with_form"
diff --git a/app/views/projects/tree/_blob_item.html.haml b/app/views/projects/tree/_blob_item.html.haml
index 02ecbade219250ceaf038830c7f9da2361a5baba..2ddc5d504fa14f98f06d6b2bbefe1abe13a22003 100644
--- a/app/views/projects/tree/_blob_item.html.haml
+++ b/app/views/projects/tree/_blob_item.html.haml
@@ -4,5 +4,5 @@
     %span.str-truncated
       = link_to blob_item.name, namespace_project_blob_path(@project.namespace, @project, tree_join(@id || @commit.id, blob_item.name))
   %td.tree_time_ago.cgray
-    = render 'spinner'
+    = render 'projects/tree/spinner'
   %td.hidden-xs.tree_commit
diff --git a/app/views/projects/tree/_readme.html.haml b/app/views/projects/tree/_readme.html.haml
index f082d71186558744fc0eba13427e81659c39c845..3c5edf4b033f1a472953fa081343e70486175b1c 100644
--- a/app/views/projects/tree/_readme.html.haml
+++ b/app/views/projects/tree/_readme.html.haml
@@ -1,7 +1,8 @@
-%article.readme-holder#README
-  = link_to '#README' do
-    %h4.readme-file-title
-      %i.fa.fa-file
-      = readme.name
-  .wiki
+%article.file-holder.readme-holder
+  .file-title
+    = blob_icon readme.mode, readme.name
+    = link_to namespace_project_blob_path(@project.namespace, @project, tree_join(@repository.root_ref, readme.name)) do
+      %strong
+        = readme.name
+  .file-content.wiki
     = render_readme(readme)
diff --git a/app/views/projects/tree/_tree.html.haml b/app/views/projects/tree/_tree.html.haml
deleted file mode 100644
index 367a87927d7910662801a2351d9c0b170ae6f0cb..0000000000000000000000000000000000000000
--- a/app/views/projects/tree/_tree.html.haml
+++ /dev/null
@@ -1,53 +0,0 @@
-%ul.breadcrumb.repo-breadcrumb
-  %li
-    = link_to namespace_project_tree_path(@project.namespace, @project, @ref) do
-      = @project.path
-  - tree_breadcrumbs(tree, 6) do |title, path|
-    %li
-      - if path
-        = link_to truncate(title, length: 40), namespace_project_tree_path(@project.namespace, @project, path)
-      - else
-        = link_to title, '#'
-  - if current_user && can_push_branch?(@project, @ref)
-    %li
-      = link_to namespace_project_new_blob_path(@project.namespace, @project, @id), title: 'New file', id: 'new-file-link' do
-        %small
-          %i.fa.fa-plus
-
-%div#tree-content-holder.tree-content-holder.prepend-top-20
-  %table#tree-slider{class: "table_#{@hex_path} tree-table" }
-    %thead
-      %tr
-        %th Name
-        %th Last Update
-        %th.hidden-xs
-          .pull-left Last Commit
-          .last-commit.hidden-sm.pull-left
-            &nbsp;
-            %i.fa.fa-angle-right
-            &nbsp;
-            %small.light
-              = link_to @commit.short_id, namespace_project_commit_path(@project.namespace, @project, @commit)
-              &ndash;
-              = truncate(@commit.title, length: 50)
-          = link_to 'History', namespace_project_commits_path(@project.namespace, @project, @id), class: 'pull-right'
-
-    - if @path.present?
-      %tr.tree-item
-        %td.tree-item-file-name
-          = link_to "..", namespace_project_tree_path(@project.namespace, @project, up_dir_path), class: 'prepend-left-10'
-        %td
-        %td.hidden-xs
-
-    = render_tree(tree)
-
-  - if tree.readme
-    = render "projects/tree/readme", readme: tree.readme
-
-%div.tree_progress
-
-:javascript
-  // Load last commit log for each file in tree
-  $('#tree-slider').waitForImages(function() {
-    ajaxGet("#{escape_javascript(@logs_path)}");
-  });
diff --git a/app/views/projects/tree/_tree_content.html.haml b/app/views/projects/tree/_tree_content.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..ee4c9d1693d1c7ded187ef654ea979e090e7fe55
--- /dev/null
+++ b/app/views/projects/tree/_tree_content.html.haml
@@ -0,0 +1,40 @@
+%div.tree-content-holder
+  .table-holder
+    %table.table#tree-slider{class: "table_#{@hex_path} tree-table table-striped" }
+      %thead
+        %tr
+          %th Name
+          %th Last Update
+          %th.hidden-xs
+            .pull-left Last Commit
+            .last-commit.hidden-sm.pull-left
+              &nbsp;
+              %i.fa.fa-angle-right
+              &nbsp;
+              %small.light
+                = link_to @commit.short_id, namespace_project_commit_path(@project.namespace, @project, @commit)
+                &ndash;
+                = truncate(@commit.title, length: 50)
+            = link_to 'History', namespace_project_commits_path(@project.namespace, @project, @id), class: 'pull-right'
+
+      - if @path.present?
+        %tr.tree-item
+          %td.tree-item-file-name
+            = link_to "..", namespace_project_tree_path(@project.namespace, @project, up_dir_path), class: 'prepend-left-10'
+          %td
+          %td.hidden-xs
+
+      = render_tree(tree)
+
+  - if tree.readme
+    = render "projects/tree/readme", readme: tree.readme
+
+- if allowed_tree_edit?
+  = render 'projects/blob/upload', title: 'Upload', placeholder: 'Upload new file', button_title: 'Upload file', form_path: namespace_project_create_blob_path(@project.namespace, @project, @id), method: :post
+  = render 'projects/blob/new_dir'
+
+:javascript
+  // Load last commit log for each file in tree
+  $('#tree-slider').waitForImages(function() {
+    ajaxGet("#{escape_javascript(@logs_path)}");
+  });
diff --git a/app/views/projects/tree/_tree_header.html.haml b/app/views/projects/tree/_tree_header.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..1115ca6b4caaf333d997f4eff4efea2243fc218c
--- /dev/null
+++ b/app/views/projects/tree/_tree_header.html.haml
@@ -0,0 +1,32 @@
+.tree-ref-holder
+  = render 'shared/ref_switcher', destination: 'tree', path: @path
+
+%ul.breadcrumb.repo-breadcrumb
+  %li
+    = link_to namespace_project_tree_path(@project.namespace, @project, @ref) do
+      = @project.path
+  - tree_breadcrumbs(tree, 6) do |title, path|
+    %li
+      - if path
+        = link_to truncate(title, length: 40), namespace_project_tree_path(@project.namespace, @project, path)
+      - else
+        = link_to title, '#'
+  - if allowed_tree_edit?
+    %li
+      %span.dropdown
+        %a.dropdown-toggle.btn.add-to-tree{href: '#', "data-toggle" => "dropdown"}
+          = icon('plus')
+        %ul.dropdown-menu
+          %li
+            = link_to namespace_project_new_blob_path(@project.namespace, @project, @id), title: 'Create file', id: 'new-file-link' do
+              = icon('pencil fw')
+              Create file
+          %li
+            = link_to '#modal-upload-blob', { 'data-target' => '#modal-upload-blob', 'data-toggle' => 'modal'} do
+              = icon('file fw')
+              Upload file
+          %li.divider
+          %li
+            = link_to '#modal-create-new-dir', { 'data-target' => '#modal-create-new-dir', 'data-toggle' => 'modal'} do
+              = icon('folder fw')
+              New directory
diff --git a/app/views/projects/tree/_tree_item.html.haml b/app/views/projects/tree/_tree_item.html.haml
index e87138bf9800bd7d4349d4b450a6dfb3af741353..cf65057e70458e5e9e15b8d1e8d9aacdb1fc20ef 100644
--- a/app/views/projects/tree/_tree_item.html.haml
+++ b/app/views/projects/tree/_tree_item.html.haml
@@ -5,5 +5,5 @@
       - path = flatten_tree(tree_item)
       = link_to path, namespace_project_tree_path(@project.namespace, @project, tree_join(@id || @commit.id, path))
   %td.tree_time_ago.cgray
-    = render 'spinner'
+    = render 'projects/tree/spinner'
   %td.hidden-xs.tree_commit
diff --git a/app/views/projects/tree/show.html.haml b/app/views/projects/tree/show.html.haml
index dec4677f83031be6a8d958761139271a1a6cc417..ec14bd7f65a0093caf55e2ca7176a0deb657c9af 100644
--- a/app/views/projects/tree/show.html.haml
+++ b/app/views/projects/tree/show.html.haml
@@ -6,12 +6,12 @@
 
 = render 'projects/last_push'
 
-.tree-ref-holder
-  = render 'shared/ref_switcher', destination: 'tree', path: @path
-
 - if can? current_user, :download_code, @project
   .tree-download-holder
     = render 'projects/repositories/download_archive', ref: @ref, btn_class: 'btn-group pull-right hidden-xs hidden-sm', split_button: true
 
 #tree-holder.tree-holder.clearfix
-  = render "tree", tree: @tree
+  .gray-content-block.top-block
+    = render 'projects/tree/tree_header', tree: @tree
+
+  = render 'projects/tree/tree_content', tree: @tree
diff --git a/app/views/ci/triggers/_trigger.html.haml b/app/views/projects/triggers/_trigger.html.haml
similarity index 53%
rename from app/views/ci/triggers/_trigger.html.haml
rename to app/views/projects/triggers/_trigger.html.haml
index addfbfcb0d438e3667b7e98314a2b6aa2d96dafa..48b3b5c992001d565c8fec791e13d8e9a7dc2b9c 100644
--- a/app/views/ci/triggers/_trigger.html.haml
+++ b/app/views/projects/triggers/_trigger.html.haml
@@ -11,4 +11,4 @@
 
   %td
     .pull-right
-      = link_to 'Revoke', ci_project_trigger_path(@project, trigger), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-danger btn-sm btn-grouped"
+      = link_to 'Revoke', namespace_project_trigger_path(@project.namespace, @project, trigger), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-danger btn-sm btn-grouped"
diff --git a/app/views/ci/triggers/index.html.haml b/app/views/projects/triggers/index.html.haml
similarity index 71%
rename from app/views/ci/triggers/index.html.haml
rename to app/views/projects/triggers/index.html.haml
index 44374a1a4d5080f5f6dcc2ae26c3ada5b2fa4195..18a37302c3e5b254fb99ba31a3b74cbdb774d5bf 100644
--- a/app/views/ci/triggers/index.html.haml
+++ b/app/views/projects/triggers/index.html.haml
@@ -7,16 +7,17 @@
 %hr.clearfix
 
 -if @triggers.any?
-  %table.table
-    %thead
-      %th Token
-      %th Last used
-      %th
-    = render @triggers
+  .table-holder
+    %table.table
+      %thead
+        %th Token
+        %th Last used
+        %th
+      = render partial: 'trigger', collection: @triggers, as: :trigger
 - else
   %h4 No triggers
 
-= form_for [:ci, @project, @trigger], html: { class: 'form-horizontal' } do |f|
+= form_for @trigger, url: url_for(controller: 'projects/triggers', action: 'create'), html: { class: 'form-horizontal' } do |f|
   .clearfix
     = f.submit "Add Trigger", class: 'btn btn-success pull-right'
 
@@ -34,7 +35,7 @@
     :plain
       curl -X POST \
            -F token=TOKEN \
-           #{ci_build_trigger_url(@project.id, 'REF_NAME')}
+           #{ci_build_trigger_url(@ci_project.id, 'REF_NAME')}
   %h3
     Use .gitlab-ci.yml
 
@@ -49,7 +50,7 @@
       trigger:
         type: deploy
         script:
-          - "curl -X POST -F token=TOKEN #{ci_build_trigger_url(@project.id, 'REF_NAME')}"
+          - "curl -X POST -F token=TOKEN #{ci_build_trigger_url(@ci_project.id, 'REF_NAME')}"
   %h3
     Pass build variables
 
@@ -64,4 +65,4 @@
       curl -X POST \
            -F token=TOKEN \
            -F "variables[RUN_NIGHTLY_BUILD]=true" \
-           #{ci_build_trigger_url(@project.id, 'REF_NAME')}
+           #{ci_build_trigger_url(@ci_project.id, 'REF_NAME')}
diff --git a/app/views/ci/variables/show.html.haml b/app/views/projects/variables/show.html.haml
similarity index 77%
rename from app/views/ci/variables/show.html.haml
rename to app/views/projects/variables/show.html.haml
index ebf68341e08851e3cce6b890d6cc4c40a7926bbb..29416a94ff6869a692fc63f101c950f33922d7d1 100644
--- a/app/views/ci/variables/show.html.haml
+++ b/app/views/projects/variables/show.html.haml
@@ -1,21 +1,21 @@
 %h3.page-title
   Secret Variables
 
-%p.light 
+%p.light
   These variables will be set to environment by the runner and will be hidden in the build log.
   %br
-  So you can use them for passwords, secret keys or whatever you want.  
+  So you can use them for passwords, secret keys or whatever you want.
 
 %hr
 
 
-= nested_form_for @project, url: url_for(controller: 'ci/variables', action: 'update'), html: { class: 'form-horizontal' }  do |f|
+= nested_form_for @ci_project, url: url_for(controller: 'projects/variables', action: 'update'), html: { class: 'form-horizontal' }  do |f|
   - if @project.errors.any?
     #error_explanation
-      %p.lead= "#{pluralize(@project.errors.count, "error")} prohibited this project from being saved:"
+      %p.lead= "#{pluralize(@ci_project.errors.count, "error")} prohibited this project from being saved:"
       .alert.alert-error
         %ul
-          - @project.errors.full_messages.each do |msg|
+          - @ci_project.errors.full_messages.each do |msg|
             %li= msg
 
   = f.fields_for :variables do |variable_form|
diff --git a/app/views/projects/wikis/_form.html.haml b/app/views/projects/wikis/_form.html.haml
index 05d754adbe5a8f58b75977c0eabd6a8f64bcd5ff..261d4a92d7d8006a32a0d80f23194a7e7b32d815 100644
--- a/app/views/projects/wikis/_form.html.haml
+++ b/app/views/projects/wikis/_form.html.haml
@@ -22,7 +22,7 @@
     = f.label :content, class: 'control-label'
     .col-sm-10
       = render layout: 'projects/md_preview', locals: { preview_class: "md-preview" } do
-        = render 'projects/zen', f: f, attr: :content, classes: 'description form-control'
+        = render 'projects/zen', f: f, attr: :content, classes: 'description form-control js-quick-submit'
         .col-sm-12.hint
           .pull-left Wiki content is parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"), target: '_blank'}
           .pull-right Attach files by dragging &amp; dropping or #{link_to "selecting them", '#', class: 'markdown-selector' }.
diff --git a/app/views/projects/wikis/history.html.haml b/app/views/projects/wikis/history.html.haml
index bfbef823b35d3d821851565081369feca47a3719..4322146ce340ecbb438f09539ce585d8219353fa 100644
--- a/app/views/projects/wikis/history.html.haml
+++ b/app/views/projects/wikis/history.html.haml
@@ -7,28 +7,29 @@
     %span.light History for
     = link_to @page.title, namespace_project_wiki_path(@project.namespace, @project, @page)
 
-%table.table
-  %thead
-    %tr
-      %th Page version
-      %th Author
-      %th Commit Message
-      %th Last updated
-      %th Format
-  %tbody
-    - @page.versions.each_with_index do |version, index|
-      - commit = version
+.table-holder
+  %table.table
+    %thead
       %tr
-        %td
-          = link_to project_wiki_path_with_version(@project, @page,
-                                                   commit.id, index == 0) do
-            = truncate_sha(commit.id)
-        %td
-          = commit.author.name
-        %td
-          = commit.message
-        %td
-          #{time_ago_with_tooltip(version.authored_date)}
-        %td
-          %strong
-            = @page.page.wiki.page(@page.page.name, commit.id).try(:format)
+        %th Page version
+        %th Author
+        %th Commit Message
+        %th Last updated
+        %th Format
+    %tbody
+      - @page.versions.each_with_index do |version, index|
+        - commit = version
+        %tr
+          %td
+            = link_to project_wiki_path_with_version(@project, @page,
+                                                     commit.id, index == 0) do
+              = truncate_sha(commit.id)
+          %td
+            = commit.author.name
+          %td
+            = commit.message
+          %td
+            #{time_ago_with_tooltip(version.authored_date)}
+          %td
+            %strong
+              = @page.page.wiki.page(@page.page.name, commit.id).try(:format)
diff --git a/app/views/projects/wikis/pages.html.haml b/app/views/projects/wikis/pages.html.haml
index 03e6a522b251ae1b422f1bcc2b4d5d504d74af04..d179a1abec1323380c4de50cc3cdb40f7a1f46da 100644
--- a/app/views/projects/wikis/pages.html.haml
+++ b/app/views/projects/wikis/pages.html.haml
@@ -3,6 +3,7 @@
 
 = render 'nav'
 .gray-content-block
+  = render 'main_links'
   %h3.page-title
     All Pages
 %ul.content-list
diff --git a/app/views/search/_form.html.haml b/app/views/search/_form.html.haml
index 3938c545caddd0bbbc7948b22026c83fbc3fc835..17b0981f073917fb08e66a8b8260d0f72d9ca41f 100644
--- a/app/views/search/_form.html.haml
+++ b/app/views/search/_form.html.haml
@@ -6,7 +6,7 @@
 
   .search-holder.clearfix
     .input-group
-      = search_field_tag :search, params[:search], placeholder: "Search for projects, issues etc", class: "form-control search-text-input", id: "dashboard_search", autofocus: true
+      = search_field_tag :search, params[:search], placeholder: "Search for projects, issues etc", class: "form-control search-text-input", id: "dashboard_search", autofocus: true, spellcheck: false
       %span.input-group-btn
         = button_tag 'Search', class: "btn btn-primary"
     - unless params[:snippets].eql? 'true'
diff --git a/app/views/shared/_clone_panel.html.haml b/app/views/shared/_clone_panel.html.haml
index 2cd422e772a102c61959d4dcae0f6d137f33b468..2e4aab36301833c1fa63becd42024df25f5dd7f1 100644
--- a/app/views/shared/_clone_panel.html.haml
+++ b/app/views/shared/_clone_panel.html.haml
@@ -6,7 +6,7 @@
         type: 'button', |
         class: "btn #{ 'active' if default_clone_protocol == 'ssh' }#{ ' has_tooltip' if current_user && current_user.require_ssh_key? }", |
         :"data-clone" => project.ssh_url_to_repo, |
-        :"data-title" => "Add an SSH key to your profile<br> to pull or push via SSH",
+        :"data-title" => "Add an SSH key to your profile<br> to pull or push via SSH.",
         :"data-html" => "true",
         :"data-container" => "body"}
         SSH
@@ -15,7 +15,7 @@
         type: 'button', |
         class: "btn #{ 'active' if default_clone_protocol == 'http' }#{ ' has_tooltip' if current_user && current_user.require_password? }", |
         :"data-clone" => project.http_url_to_repo, |
-        :"data-title" => "Set a password on your account<br> to pull or push via #{gitlab_config.protocol.upcase}",
+        :"data-title" => "Set a password on your account<br> to pull or push via #{gitlab_config.protocol.upcase}.",
         :"data-html" => "true",
         :"data-container" => "body"}
         = gitlab_config.protocol.upcase
@@ -24,4 +24,4 @@
     .input-group-addon
       .visibility-level-label.has_tooltip{'data-title' => "#{visibility_level_label(project.visibility_level)} project" }
         = visibility_level_icon(project.visibility_level)
-        = visibility_level_label(project.visibility_level).downcase
+   
diff --git a/app/views/shared/_commit_message_container.html.haml b/app/views/shared/_commit_message_container.html.haml
index 5071ff640f18c08bbe3d0bf0e565defe32221b38..cc3f1268f8b9fb8d01dcc87ecc3dcee30c51646b 100644
--- a/app/views/shared/_commit_message_container.html.haml
+++ b/app/views/shared/_commit_message_container.html.haml
@@ -6,7 +6,7 @@
       .max-width-marker
       = text_area_tag 'commit_message',
           (params[:commit_message] || local_assigns[:text]),
-          class: 'form-control', placeholder: local_assigns[:placeholder],
+          class: 'form-control js-quick-submit', placeholder: local_assigns[:placeholder],
           required: true, rows: (local_assigns[:rows] || 3)
     - if local_assigns[:hint]
       %p.hint
diff --git a/app/views/shared/_field.html.haml b/app/views/shared/_field.html.haml
index 45ec49280d2db96474fe2ffc3d52e05a32783743..8d6e16f74c3aa0357568c50925c4c89c6e9f410c 100644
--- a/app/views/shared/_field.html.haml
+++ b/app/views/shared/_field.html.haml
@@ -8,7 +8,10 @@
 - help = field[:help]
 
 .form-group
-  = form.label name, title, class: "control-label"
+  - if type == "password" && value.present?
+    = form.label name, "Change #{title}", class: "control-label"
+  - else
+    = form.label name, title, class: "control-label"
   .col-sm-10
     - if type == 'text'
       = form.text_field name, class: "form-control", placeholder: placeholder
@@ -19,6 +22,6 @@
     - elsif type == 'select'
       = form.select name, options_for_select(choices, value ? value : default_choice), {}, { class: "form-control" }
     - elsif type == 'password'
-      = form.password_field name, value: value, class: 'form-control'
+      = form.password_field name, autocomplete: "new-password", class: 'form-control'
     - if help
       %span.help-block= help
diff --git a/app/views/shared/_logo.svg b/app/views/shared/_logo.svg
new file mode 100644
index 0000000000000000000000000000000000000000..da49c48acd3f54b15148477140c9d82e9b79fd33
--- /dev/null
+++ b/app/views/shared/_logo.svg
@@ -0,0 +1,21 @@
+<svg width="36px" height="36px" viewBox="0 0 210 210" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="tanuki-logo">
+    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
+        <g id="logo" sketch:type="MSLayerGroup" transform="translate(0.000000, 10.000000)">
+            <g id="Page-1" sketch:type="MSShapeGroup">
+                <g id="Fill-1-+-Group-24">
+                    <g id="Group-24">
+                        <g id="Group">
+                            <path d="M105.0614,193.655 L105.0614,193.655 L143.7014,74.734 L66.4214,74.734 L105.0614,193.655 L105.0614,193.655 Z" id="Fill-4" fill="#E24329" class="tanuki-shape"></path>
+                            <path d="M105.0614,193.6548 L66.4214,74.7338 L12.2684,74.7338 L105.0614,193.6548 L105.0614,193.6548 Z" id="Fill-8" fill="#FC6D26" class="tanuki-shape"></path>
+                            <path d="M12.2685,74.7341 L12.2685,74.7341 L0.5265,110.8731 C-0.5445,114.1691 0.6285,117.7801 3.4325,119.8171 L105.0615,193.6551 L12.2685,74.7341 L12.2685,74.7341 Z" id="Fill-12" fill="#FCA326" class="tanuki-shape"></path>
+                            <path d="M12.2685,74.7342 L66.4215,74.7342 L43.1485,3.1092 C41.9515,-0.5768 36.7375,-0.5758 35.5405,3.1092 L12.2685,74.7342 L12.2685,74.7342 Z" id="Fill-16" fill="#E24329" class="tanuki-shape"></path>
+                            <path d="M105.0614,193.6548 L143.7014,74.7338 L197.8544,74.7338 L105.0614,193.6548 L105.0614,193.6548 Z" id="Fill-18" fill="#FC6D26" class="tanuki-shape"></path>
+                            <path d="M197.8544,74.7341 L197.8544,74.7341 L209.5964,110.8731 C210.6674,114.1691 209.4944,117.7801 206.6904,119.8171 L105.0614,193.6551 L197.8544,74.7341 L197.8544,74.7341 Z" id="Fill-20" fill="#FCA326" class="tanuki-shape"></path>
+                            <path d="M197.8544,74.7342 L143.7014,74.7342 L166.9744,3.1092 C168.1714,-0.5768 173.3854,-0.5758 174.5824,3.1092 L197.8544,74.7342 L197.8544,74.7342 Z" id="Fill-22" fill="#E24329" class="tanuki-shape"></path>
+                        </g>
+                    </g>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>
diff --git a/app/views/shared/issuable/_filter.html.haml b/app/views/shared/issuable/_filter.html.haml
index 8f16773077e9d658c86338927b3b5adff1ed7920..0e4e9c0987afaac9dc331a176145a15f7590a648 100644
--- a/app/views/shared/issuable/_filter.html.haml
+++ b/app/views/shared/issuable/_filter.html.haml
@@ -42,11 +42,10 @@
             class: 'select2 trigger-submit', include_blank: true,
             data: {placeholder: 'Milestone'})
 
-        - if @project
-          .filter-item.inline.labels-filter
-            = select_tag('label_name', project_labels_options(@project),
-              class: 'select2 trigger-submit', include_blank: true,
-              data: {placeholder: 'Label'})
+        .filter-item.inline.labels-filter
+          = select_tag('label_name', projects_labels_options,
+            class: 'select2 trigger-submit', include_blank: true,
+            data: {placeholder: 'Label'})
 
         .pull-right
           = render 'shared/sort_dropdown'
diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml
index 33ec726e93c9687ab98c037c490901ab8a46d91a..594e54f404c155ac0767780e4968dece3a9c4900 100644
--- a/app/views/shared/issuable/_form.html.haml
+++ b/app/views/shared/issuable/_form.html.haml
@@ -10,7 +10,7 @@
     %strong= 'Title *'
   .col-sm-10
     = f.text_field :title, maxlength: 255, autofocus: true, autocomplete: 'off',
-        class: 'form-control pad js-gfm-input', required: true
+        class: 'form-control pad js-gfm-input js-quick-submit', required: true
 
     - if issuable.is_a?(MergeRequest)
       %p.help-block
@@ -26,7 +26,7 @@
 
     = render layout: 'projects/md_preview', locals: { preview_class: "md-preview", referenced_users: true } do
       = render 'projects/zen', f: f, attr: :description,
-                               classes: 'description form-control'
+                               classes: 'description form-control js-quick-submit'
       .col-sm-12.hint
         .pull-left
           Parsed with
diff --git a/app/views/shared/issuable/_search_form.html.haml b/app/views/shared/issuable/_search_form.html.haml
index 58c3de64b77727b4a6fe2d1d494e2e01f39535b3..3a5ad00aa91a7c63b045bab87a6b292a5f296ea9 100644
--- a/app/views/shared/issuable/_search_form.html.haml
+++ b/app/views/shared/issuable/_search_form.html.haml
@@ -1,6 +1,6 @@
 = form_tag(path, method: :get, id: "issue_search_form", class: 'pull-left issue-search-form') do
   .append-right-10.hidden-xs.hidden-sm
-    = search_field_tag :issue_search, params[:issue_search], { placeholder: 'Filter by title or description', class: 'form-control issue_search search-text-input' }
+    = search_field_tag :issue_search, params[:issue_search], { placeholder: 'Filter by title or description', class: 'form-control issue_search search-text-input', spellcheck: false }
     = hidden_field_tag :state, params['state']
     = hidden_field_tag :scope, params['scope']
     = hidden_field_tag :assignee_id, params['assignee_id']
diff --git a/app/views/shared/projects/_list.html.haml b/app/views/shared/projects/_list.html.haml
index 16e1d8421ded3c7fcb7d5fa406e3014481f2d880..357cfd6a37007542ca262155848ece0f66d85b06 100644
--- a/app/views/shared/projects/_list.html.haml
+++ b/app/views/shared/projects/_list.html.haml
@@ -2,11 +2,12 @@
 - avatar = true unless local_assigns[:avatar] == false
 - stars = true unless local_assigns[:stars] == false
 - ci = false unless local_assigns[:ci] == true
+- skip_namespace = false unless local_assigns[:skip_namespace] == true
 
 %ul.projects-list
   - projects.each_with_index do |project, i|
     - css_class = (i >= projects_limit) ? 'hide' : nil
-    = render "shared/projects/project", project: project,
+    = render "shared/projects/project", project: project, skip_namespace: skip_namespace,
       avatar: avatar, stars: stars, css_class: css_class, ci: ci
 
   - if projects.size > projects_limit
diff --git a/app/views/shared/projects/_project.html.haml b/app/views/shared/projects/_project.html.haml
index e67e5a8a6387c21381e86d60a8498b0de703ecd3..aee839b44e7ee43d15749ec3215142c606f56a4b 100644
--- a/app/views/shared/projects/_project.html.haml
+++ b/app/views/shared/projects/_project.html.haml
@@ -1,6 +1,7 @@
 - avatar = true unless local_assigns[:avatar] == false
 - stars = true unless local_assigns[:stars] == false
 - ci = false unless local_assigns[:ci] == true
+- skip_namespace = false unless local_assigns[:skip_namespace] == true
 - css_class = '' unless local_assigns[:css_class]
 - css_class += " no-description" unless project.description.present?
 %li.project-row{ class: css_class }
@@ -11,7 +12,7 @@
           = project_icon(project, alt: '', class: 'avatar project-avatar s46')
       %span.project-full-name
         %span.namespace-name
-          - if project.namespace
+          - if project.namespace && !skip_namespace
             = project.namespace.human_name
             \/
         %span.project-name.filter-title
diff --git a/app/views/shared/snippets/_header.html.haml b/app/views/shared/snippets/_header.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..0a4a790ec5ee182b5ad0e5a62178dd0636246e45
--- /dev/null
+++ b/app/views/shared/snippets/_header.html.haml
@@ -0,0 +1,24 @@
+.snippet-details
+  .page-title
+    .snippet-box{class: visibility_level_color(@snippet.visibility_level)}
+      = visibility_level_icon(@snippet.visibility_level)
+      = visibility_level_label(@snippet.visibility_level)
+    %span.snippet-id Snippet ##{@snippet.id}
+    %span.creator
+      &middot; created by #{link_to_member(@project, @snippet.author, size: 24)}
+      &middot;
+      = time_ago_with_tooltip(@snippet.created_at, placement: 'bottom', html_class: 'snippet_updated_ago')
+      - if @snippet.updated_at != @snippet.created_at
+        %span
+          &middot;
+          = icon('edit', title: 'edited')
+          = time_ago_with_tooltip(@snippet.updated_at, placement: 'bottom', html_class: 'snippet_edited_ago')
+
+    .pull-right
+      - if @snippet.project_id?
+        = render "projects/snippets/actions"
+      - else
+        = render "snippets/actions"
+  .gray-content-block.middle-block
+    %h2.snippet-title
+      = gfm escape_once(@snippet.title)
diff --git a/app/views/shared/snippets/_snippet.html.haml b/app/views/shared/snippets/_snippet.html.haml
index 69a713ad9aacf4b20cae64fbfaca0bbc10e09779..c6294caddc7f7d26d8d9fc2d002f5a3d3e9b38bd 100644
--- a/app/views/shared/snippets/_snippet.html.haml
+++ b/app/views/shared/snippets/_snippet.html.haml
@@ -18,4 +18,3 @@
       = image_tag avatar_icon(snippet.author_email), class: "avatar s24", alt: ''
       = snippet.author_name
     authored #{time_ago_with_tooltip(snippet.created_at)}
-
diff --git a/app/views/snippets/_actions.html.haml b/app/views/snippets/_actions.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..751fafa8942c080af20974b4b3f720dc0aa358a5
--- /dev/null
+++ b/app/views/snippets/_actions.html.haml
@@ -0,0 +1,11 @@
+= link_to new_snippet_path, class: 'btn btn-grouped new-snippet-link', title: "New Snippet" do
+  = icon('plus')
+  New Snippet
+- if can?(current_user, :admin_personal_snippet, @snippet)
+  = link_to snippet_path(@snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-grouped btn-remove", title: 'Delete Snippet' do
+    = icon('trash-o')
+    Delete
+- if can?(current_user, :update_personal_snippet, @snippet)
+  = link_to edit_snippet_path(@snippet), class: "btn btn-grouped snippable-edit" do
+    = icon('pencil-square-o')
+    Edit
diff --git a/app/views/snippets/show.html.haml b/app/views/snippets/show.html.haml
index 97374e073dc2447b1f06c7bdf850b33f896f36f2..69d8899d4c1d1467b2cb1e8f44261f62de2449f4 100644
--- a/app/views/snippets/show.html.haml
+++ b/app/views/snippets/show.html.haml
@@ -1,41 +1,14 @@
 - page_title @snippet.title, "Snippets"
-%h4.page-title
-  = @snippet.title
 
-  - if @snippet.private?
-    %span.label.label-success
-      %i.fa.fa-lock
-      private
-
-  .pull-right
-    = link_to new_snippet_path, class: "btn btn-new btn-sm", title: "New Snippet" do
-      Add new snippet
-
-.append-bottom-10.prepend-top-10
-  .pull-right
-    %span.light
-      created by
-      = link_to user_snippets_path(@snippet.author) do
-        = @snippet.author_name
-
-  .back-link
-    - if @snippet.author == current_user
-      = link_to dashboard_snippets_path do
-        &larr; your snippets
-    - else
-      = link_to explore_snippets_path do
-        &larr; explore snippets
-
-.file-holder
-  .file-title
-    %i.fa.fa-file
-    %strong
-      = @snippet.file_name
-    .file-actions
-      .btn-group
-        - if can?(current_user, :update_personal_snippet, @snippet)
-          = link_to "edit", edit_snippet_path(@snippet), class: "btn btn-sm", title: 'Edit Snippet'
-        = link_to "raw", raw_snippet_path(@snippet), class: "btn btn-sm", target: "_blank"
-      - if can?(current_user, :admin_personal_snippet, @snippet)
-        = link_to "remove", snippet_path(@snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-sm btn-remove", title: 'Delete Snippet'
-  = render 'shared/snippets/blob'
+.snippet-holder
+  = render 'shared/snippets/header'
+
+  %article.file-holder
+    .file-title
+      = blob_icon 0, @snippet.file_name
+      %strong
+        = @snippet.file_name
+      .file-actions.hidden-xs
+        .btn-group.tree-btn-group
+          = link_to 'Raw', raw_snippet_path(@snippet), class: "btn btn-sm", target: "_blank"
+    = render 'shared/snippets/blob'
diff --git a/app/views/users/calendar.html.haml b/app/views/users/calendar.html.haml
index 922b0c6cebf1cb1425ec056195bc15025cf434d2..7f29918dba371da38fb3950388f9fed69d0d7ae2 100644
--- a/app/views/users/calendar.html.haml
+++ b/app/views/users/calendar.html.haml
@@ -1,7 +1,3 @@
-%h4
-  Contributions calendar
-  .pull-right
-    %small Issues, merge requests and push events
 #cal-heatmap.calendar
   :javascript
     new Calendar(
@@ -10,3 +6,5 @@
       #{@starting_month},
       '#{user_calendar_activities_path}'
     );
+
+.calendar-hint Summary of issues, merge requests and push events
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index 37d5dba03306fc713bb1cc6f7dd257bab96f5d2a..4ea4a1f92c2ddfb188f3c1a918549d1a60fd9eaa 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -6,48 +6,72 @@
 
 = render 'shared/show_aside'
 
-.row
-  %section.col-md-7
-    .header-with-avatar
-      = link_to avatar_icon(@user.email, 400), target: '_blank' do
-        = image_tag avatar_icon(@user.email, 90), class: "avatar avatar-tile s90", alt: ''
-      %h3
-        = @user.name
-        - if @user == current_user
-          .pull-right.hidden-xs
-            = link_to profile_path, class: 'btn btn-sm' do
-              = icon('user')
-              Profile settings
-        - elsif current_user
-          .pull-right
-            %span.dropdown
-              %a.light.dropdown-toggle.btn.btn-sm{href: '#', "data-toggle" => "dropdown"}
-                = icon('exclamation-circle')
-              %ul.dropdown-menu.dropdown-menu-right
-                %li
-                  = link_to new_abuse_report_path(user_id: @user.id) do
-                    Report abuse
+.cover-block
+  .avatar-holder
+    = link_to avatar_icon(@user, 400), target: '_blank' do
+      = image_tag avatar_icon(@user, 90), class: "avatar s90", alt: ''
+  .cover-title
+    = @user.name
+
+  .cover-desc
+    %span
+      @#{@user.username}.
+    - if @user.bio.present?
+      %span
+        #{@user.bio}.
+    %span
+      Member since #{@user.created_at.stamp("Aug 21, 2011")}
+
+  .cover-desc
+    - unless @user.public_email.blank?
+      = link_to @user.public_email, "mailto:#{@user.public_email}"
+    - unless @user.skype.blank?
+      &middot;
+      = link_to "Skype", "skype:#{@user.skype}"
+    - unless @user.linkedin.blank?
+      &middot;
+      = link_to "LinkedIn", "http://www.linkedin.com/in/#{@user.linkedin}"
+    - unless @user.twitter.blank?
+      &middot;
+      = link_to "Twitter", "http://www.twitter.com/#{@user.twitter}"
+    - unless @user.website_url.blank?
+      &middot;
+      = link_to @user.short_website_url, @user.full_website_url
+    - unless @user.location.blank?
+      &middot;
+      = @user.location
 
-      .username
-        @#{@user.username}
-      .description
-        - if @user.bio.present?
-          = @user.bio
 
-    .clearfix
+  .cover-controls
+    - if @user == current_user
+      = link_to profile_path, class: 'btn btn-gray' do
+        = icon('pencil')
+    - elsif current_user
+      .report-abuse
+        - if @user.abuse_report
+          %button.btn.btn-danger{ title: 'Already reported for abuse',
+            data: { toggle: 'tooltip', placement: 'left', container: 'body' }}
+            = icon('exclamation-circle')
+        - else
+          = link_to new_abuse_report_path(user_id: @user.id), class: 'btn btn-gray',
+            title: 'Report abuse', data: {toggle: 'tooltip', placement: 'left', container: 'body'} do
+            = icon('exclamation-circle')
 
+.gray-content-block.second-block
+  .user-calendar
+    %h4.center.light
+      %i.fa.fa-spinner.fa-spin
+  .user-calendar-activities
+
+
+.row.prepend-top-20
+  %section.col-md-7
     - if @groups.any?
       .prepend-top-20
         %h4 Groups
         = render 'groups', groups: @groups
         %hr
 
-    .hidden-xs
-      .user-calendar
-        %h4.center.light
-          %i.fa.fa-spinner.fa-spin
-      .user-calendar-activities
-      %hr
     %h4
       User Activity
 
@@ -60,7 +84,6 @@
     .content_list
     = spinner
   %aside.col-md-5
-    = render 'profile', user: @user
     = render 'projects', projects: @projects, contributed_projects: @contributed_projects
 
 :coffeescript
diff --git a/app/workers/repository_archive_cache_worker.rb b/app/workers/repository_archive_cache_worker.rb
new file mode 100644
index 0000000000000000000000000000000000000000..47c5a670ed4d17eb00a71ef7c4ccd542577c859e
--- /dev/null
+++ b/app/workers/repository_archive_cache_worker.rb
@@ -0,0 +1,9 @@
+class RepositoryArchiveCacheWorker
+  include Sidekiq::Worker
+
+  sidekiq_options queue: :default
+
+  def perform
+    Repository.clean_old_archives
+  end
+end
diff --git a/app/workers/repository_archive_worker.rb b/app/workers/repository_archive_worker.rb
deleted file mode 100644
index 021c1139568b8bfc5ca6b259d57bb16bbaab5d7f..0000000000000000000000000000000000000000
--- a/app/workers/repository_archive_worker.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-class RepositoryArchiveWorker
-  include Sidekiq::Worker
-
-  sidekiq_options queue: :archive_repo
-
-  attr_accessor :project, :ref, :format
-
-  def perform(project_id, ref, format)
-    @project = Project.find(project_id)
-    @ref, @format = ref, format.downcase
-
-    repository = project.repository
-
-    repository.clean_old_archives
-
-    return unless file_path
-    return if archived? || archiving?
-
-    repository.archive_repo(ref, storage_path, format)
-  end
-
-  private
-
-  def storage_path
-    Gitlab.config.gitlab.repository_downloads_path
-  end
-
-  def file_path
-    @file_path ||= project.repository.archive_file_path(ref, storage_path, format)
-  end
-
-  def pid_file_path
-    @pid_file_path ||= project.repository.archive_pid_file_path(ref, storage_path, format)
-  end
-
-  def archived?
-    File.exist?(file_path)
-  end
-
-  def archiving?
-    File.exist?(pid_file_path)
-  end
-end
diff --git a/config/application.rb b/config/application.rb
index a96e22211e640a4b826552cd9ce4d61a46ff4885..bfa2a809dd7d7fd472990b00d6f38c8948fd36ce 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -74,7 +74,7 @@ module Gitlab
         origins '*'
         resource '/api/*',
           headers: :any,
-          methods: [:get, :post, :options, :put, :delete],
+          methods: :any,
           expose: ['Link']
       end
     end
diff --git a/config/environments/development.rb b/config/environments/development.rb
index d7d6aed1602ca498a7666504b932bbe420c9eedd..827a110c2492ac5349277065d2a992243760bc75 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -24,7 +24,7 @@ Gitlab::Application.configure do
 
   # Expands the lines which load the assets
   # config.assets.debug = true
-  
+
   # Adds additional error checking when serving assets at runtime.
   # Checks for improperly declared sprockets dependencies.
   # Raises helpful error messages.
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index 15930fc90791e283eff0ff9f312aee5e3da1cd5f..8b85981497adecbb42f56c4277f92297f10fc3ea 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -99,7 +99,29 @@ production: &base
   # For documentation on how to set this up, see http://doc.gitlab.com/ce/incoming_email/README.html
   incoming_email:
     enabled: false
-    address: "incoming+%{key}@gitlab.example.com"
+
+    # The email address including the `%{key}` placeholder that will be replaced to reference the item being replied to.
+    # The `%{key}` placeholder is added after the user part, after a `+` character, before the `@`.
+    address: "gitlab-incoming+%{key}@gmail.com"
+
+    # Email account username
+    # With third party providers, this is usually the full email address.
+    # With self-hosted email servers, this is usually the user part of the email address.
+    user: "gitlab-incoming@gmail.com"
+    # Email account password
+    password: "[REDACTED]"
+
+    # IMAP server host
+    host: "imap.gmail.com"
+    # IMAP server port
+    port: 993
+    # Whether the IMAP server uses SSL
+    ssl: true
+    # Whether the IMAP server uses StartTLS
+    start_tls: false
+
+    # The mailbox where incoming mail will end up. Usually "inbox".
+    mailbox: "inbox"
 
   ## Gravatar
   ## For Libravatar see: http://doc.gitlab.com/ce/customization/libravatar.html
@@ -159,7 +181,7 @@ production: &base
         method: 'plain' # "tls" or "ssl" or "plain"
         bind_dn: '_the_full_dn_of_the_user_you_will_bind_with'
         password: '_the_password_of_the_bind_user'
-          
+
         # This setting specifies if LDAP server is Active Directory LDAP server.
         # For non AD servers it skips the AD specific queries.
         # If your LDAP server is not AD, set this to false.
@@ -204,13 +226,13 @@ production: &base
           # The username will be used in paths for the user's own projects
           # (like `gitlab.example.com/username/project`) and when mentioning
           # them in issues, merge request and comments (like `@username`).
-          # If the attribute specified for `username` contains an email address, 
+          # If the attribute specified for `username` contains an email address,
           # the GitLab username will be the part of the email address before the '@'.
           username: ['uid', 'userid', 'sAMAccountName']
           email:    ['mail', 'email', 'userPrincipalName']
 
           # If no full name could be found at the attribute specified for `name`,
-          # the full name is determined using the attributes specified for 
+          # the full name is determined using the attributes specified for
           # `first_name` and `last_name`.
           name:       'cn'
           first_name: 'givenName'
@@ -252,28 +274,28 @@ production: &base
     # arguments, followed by optional 'args' which can be either a hash or an array.
     # Documentation for this is available at http://doc.gitlab.com/ce/integration/omniauth.html
     providers:
-      # - { name: 'google_oauth2', 
+      # - { name: 'google_oauth2',
       #     label: 'Google',
-      #     app_id: 'YOUR_APP_ID', 
+      #     app_id: 'YOUR_APP_ID',
       #     app_secret: 'YOUR_APP_SECRET',
       #     args: { access_type: 'offline', approval_prompt: '' } }
-      # - { name: 'twitter', 
-      #     app_id: 'YOUR_APP_ID', 
+      # - { name: 'twitter',
+      #     app_id: 'YOUR_APP_ID',
       #     app_secret: 'YOUR_APP_SECRET' }
-      # - { name: 'github', 
+      # - { name: 'github',
       #     label: 'GitHub',
-      #     app_id: 'YOUR_APP_ID', 
+      #     app_id: 'YOUR_APP_ID',
       #     app_secret: 'YOUR_APP_SECRET',
       #     args: { scope: 'user:email' } }
-      # - { name: 'gitlab', 
+      # - { name: 'gitlab',
       #     label: 'GitLab.com',
-      #     app_id: 'YOUR_APP_ID', 
+      #     app_id: 'YOUR_APP_ID',
       #     app_secret: 'YOUR_APP_SECRET',
       #     args: { scope: 'api' } }
-      # - { name: 'bitbucket', 
-      #     app_id: 'YOUR_APP_ID', 
+      # - { name: 'bitbucket',
+      #     app_id: 'YOUR_APP_ID',
       #     app_secret: 'YOUR_APP_SECRET' }
-      # - { name: 'saml', 
+      # - { name: 'saml',
       #     label: 'Our SAML Provider',
       #     args: {
       #             assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
@@ -319,6 +341,8 @@ production: &base
     #   # Use multipart uploads when file size reaches 100MB, see
     #   #  http://docs.aws.amazon.com/AmazonS3/latest/dev/uploadobjusingmpu.html
     #   multipart_chunk_size: 104857600
+    #   # Turns on AWS Server-Side Encryption with Amazon S3-Managed Keys for backups, this is optional
+    #   # encryption: 'AES256'
 
   ## GitLab Shell settings
   gitlab_shell:
@@ -422,7 +446,6 @@ test:
         user_filter: ''
         group_base: 'ou=groups,dc=example,dc=com'
         admin_group: ''
-        sync_ssh_keys: false
 
 staging:
   <<: *base
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 48601b67335c630556a21dc93657b31d2d41c6e6..d5493ca038d0399671bdffbf62f8c6bb600b010c 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -178,7 +178,6 @@ Settings.gitlab['import_sources'] ||= ['github','bitbucket','gitlab','gitorious'
 # CI
 #
 Settings['gitlab_ci'] ||= Settingslogic.new({})
-Settings.gitlab_ci['enabled']             = true if Settings.gitlab_ci['enabled'].nil?
 Settings.gitlab_ci['all_broken_builds']   = true if Settings.gitlab_ci['all_broken_builds'].nil?
 Settings.gitlab_ci['add_pusher']          = false if Settings.gitlab_ci['add_pusher'].nil?
 Settings.gitlab_ci['url']                 ||= Settings.send(:build_gitlab_ci_url)
@@ -188,7 +187,11 @@ Settings.gitlab_ci['builds_path']         = File.expand_path(Settings.gitlab_ci[
 # Reply by email
 #
 Settings['incoming_email'] ||= Settingslogic.new({})
-Settings.incoming_email['enabled'] = false if Settings.incoming_email['enabled'].nil?
+Settings.incoming_email['enabled']    = false if Settings.incoming_email['enabled'].nil?
+Settings.incoming_email['port']       = 143 if Settings.incoming_email['port'].nil?
+Settings.incoming_email['ssl']        = 143 if Settings.incoming_email['ssl'].nil?
+Settings.incoming_email['start_tls']  = 143 if Settings.incoming_email['start_tls'].nil?
+Settings.incoming_email['mailbox']    = "inbox" if Settings.incoming_email['mailbox'].nil?
 
 #
 # Gravatar
@@ -229,6 +232,7 @@ if Settings.backup['upload']['connection']
   Settings.backup['upload']['connection'] = Hash[Settings.backup['upload']['connection'].map { |k, v| [k.to_sym, v] }]
 end
 Settings.backup['upload']['multipart_chunk_size'] ||= 104857600
+Settings.backup['upload']['encryption'] ||= nil
 
 #
 # Git
diff --git a/config/initializers/active_record_query_trace.rb b/config/initializers/active_record_query_trace.rb
new file mode 100644
index 0000000000000000000000000000000000000000..4b3c2803b3b36bc31df1b12500b8bc0bdad0288b
--- /dev/null
+++ b/config/initializers/active_record_query_trace.rb
@@ -0,0 +1,5 @@
+if ENV['ENABLE_QUERY_TRACE']
+  require 'active_record_query_trace'
+
+  ActiveRecordQueryTrace.enabled = 'true'
+end
diff --git a/config/initializers/bullet.rb b/config/initializers/bullet.rb
new file mode 100644
index 0000000000000000000000000000000000000000..95e82966c7ae15536f2b7dc6932f9dc45dc1d6b8
--- /dev/null
+++ b/config/initializers/bullet.rb
@@ -0,0 +1,6 @@
+if ENV['ENABLE_BULLET']
+  require 'bullet'
+
+  Bullet.enable  = true
+  Bullet.console = true
+end
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
index 2ce24592f8b9edecfc672238207a39eb3bac950b..29506970af24bfb5c4494d705e847fa7580e746a 100644
--- a/config/initializers/devise.rb
+++ b/config/initializers/devise.rb
@@ -148,6 +148,10 @@ Devise.setup do |config|
   # When someone else invites you to GitLab this time is also used so it should be pretty long.
   config.reset_password_within = 2.days
 
+  # When set to false, does not sign a user in automatically after their password is
+  # reset. Defaults to true, so a user is signed in automatically after a reset.
+  config.sign_in_after_reset_password = false
+
   # ==> Configuration for :encryptable
   # Allow you to use another encryption algorithm besides bcrypt (default). You can use
   # :sha1, :sha512 or encryptors from others authentication tools as :clearance_sha1,
diff --git a/config/initializers/rack_lineprof.rb b/config/initializers/rack_lineprof.rb
new file mode 100644
index 0000000000000000000000000000000000000000..f0c006d811bffe04c02572441f7d5cc329ba0255
--- /dev/null
+++ b/config/initializers/rack_lineprof.rb
@@ -0,0 +1,31 @@
+# The default colors of rack-lineprof can be very hard to look at in terminals
+# with darker backgrounds. This patch tweaks the colors a bit so the output is
+# actually readable.
+if Rails.env.development? and RUBY_ENGINE == 'ruby' and ENV['ENABLE_LINEPROF']
+  Gitlab::Application.config.middleware.use(Rack::Lineprof)
+
+  module Rack
+    class Lineprof
+      class Sample < Rack::Lineprof::Sample.superclass
+        def format(*)
+          formatted = if level == CONTEXT
+                        sprintf "                 | % 3i  %s", line, code
+                      else
+                        sprintf "% 8.1fms %5i | % 3i  %s", ms, calls, line, code
+                      end
+
+          case level
+          when CRITICAL
+            color.red formatted
+          when WARNING
+            color.yellow formatted
+          when NOMINAL
+            color.white formatted
+          else # CONTEXT
+            formatted
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/config/locales/devise.en.yml b/config/locales/devise.en.yml
index d8bf0878a3d7381c8de2e932b5b8598e5f4cac77..22070e37f07f3b1d76df813784e2474fffbf06c8 100644
--- a/config/locales/devise.en.yml
+++ b/config/locales/devise.en.yml
@@ -1,61 +1,63 @@
-# Additional translations at http://github.com/plataformatec/devise/wiki/I18n
+# Additional translations at https://github.com/plataformatec/devise/wiki/I18n
 
 en:
+  devise:
+    confirmations:
+      confirmed: "Your email address has been successfully confirmed."
+      send_instructions: "You will receive an email with instructions for how to confirm your email address in a few minutes."
+      send_paranoid_instructions: "If your email address exists in our database, you will receive an email with instructions for how to confirm your email address in a few minutes."
+    failure:
+      already_authenticated: "You are already signed in."
+      inactive: "Your account is not activated yet."
+      invalid: "Invalid %{authentication_keys} or password."
+      locked: "Your account is locked."
+      last_attempt: "You have one more attempt before your account is locked."
+      not_found_in_database: "Invalid %{authentication_keys} or password."
+      timeout: "Your session expired. Please sign in again to continue."
+      unauthenticated: "You need to sign in or sign up before continuing."
+      unconfirmed: "You have to confirm your email address before continuing."
+    mailer:
+      confirmation_instructions:
+        subject: "Confirmation instructions"
+      reset_password_instructions:
+        subject: "Reset password instructions"
+      unlock_instructions:
+        subject: "Unlock instructions"
+      password_change:
+        subject: "Password Changed"
+    omniauth_callbacks:
+      failure: "Could not authenticate you from %{kind} because \"%{reason}\"."
+      success: "Successfully authenticated from %{kind} account."
+    passwords:
+      no_token: "You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided."
+      recently_reset: "Instructions about how to reset your password have already been sent recently. Please wait a few minutes to try again."
+      send_instructions: "You will receive an email with instructions on how to reset your password in a few minutes."
+      send_paranoid_instructions: "If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes."
+      updated: "Your password has been changed successfully. You are now signed in."
+      updated_not_active: "Your password has been changed successfully."
+    registrations:
+      destroyed: "Bye! Your account has been successfully cancelled. We hope to see you again soon."
+      signed_up: "Welcome! You have signed up successfully."
+      signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated."
+      signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked."
+      signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please follow the link to activate your account."
+      update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirm link to confirm your new email address."
+      updated: "Your account has been updated successfully."
+    sessions:
+      signed_in: "Signed in successfully."
+      signed_out: "Signed out successfully."
+      already_signed_out: "Signed out successfully."
+    unlocks:
+      send_instructions: "You will receive an email with instructions for how to unlock your account in a few minutes."
+      send_paranoid_instructions: "If your account exists, you will receive an email with instructions for how to unlock it in a few minutes."
+      unlocked: "Your account has been unlocked successfully. Please sign in to continue."
   errors:
     messages:
+      already_confirmed: "was already confirmed, please try signing in"
+      confirmation_period_expired: "needs to be confirmed within %{period}, please request a new one"
       expired: "has expired, please request a new one"
       not_found: "not found"
-      already_confirmed: "was already confirmed, please try signing in"
       not_locked: "was not locked"
       not_saved:
         one: "1 error prohibited this %{resource} from being saved:"
         other: "%{count} errors prohibited this %{resource} from being saved:"
-
-  devise:
-    failure:
-      already_authenticated: 'You are already signed in.'
-      unauthenticated: 'You need to sign in before continuing.'
-      unconfirmed: 'You have to confirm your account before continuing.'
-      locked: 'Your account is locked.'
-      not_found_in_database: 'Invalid email or password.'
-      invalid: 'Invalid email or password.'
-      invalid_token: 'Invalid authentication token.'
-      timeout: 'Your session expired, please sign in again to continue.'
-      inactive: 'Your account was not activated yet.'
-    sessions:
-      signed_in: ''
-      signed_out: ''
-    users_sessions:
-      user:
-        signed_in: 'Signed in successfully.'
-    passwords:
-      send_instructions: 'You will receive an email with instructions about how to reset your password in a few minutes.'
-      updated: 'Your password was changed successfully. You are now signed in.'
-      updated_not_active: 'Your password was changed successfully.'
-      send_paranoid_instructions: "If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes."
-      no_token: "You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided."
-    confirmations:
-      send_instructions: 'You will receive an email with instructions about how to confirm your account in a few minutes.'
-      send_paranoid_instructions: 'If your email address exists in our database, you will receive an email with instructions about how to confirm your account in a few minutes.'
-      confirmed: 'Your account was successfully confirmed. You are now signed in.'
-    registrations:
-      signed_up: 'Welcome! You have signed up successfully.'
-      updated: 'You updated your account successfully.'
-      destroyed: 'Bye! Your account was successfully cancelled. We hope to see you again soon.'
-      signed_up_but_unconfirmed: 'A message with a confirmation link has been sent to your email address. Please open the link to activate your account.'
-      signed_up_but_inactive: 'You have signed up successfully. However, we could not sign you in because your account is not yet activated.'
-      signed_up_but_locked: 'You have signed up successfully. However, we could not sign you in because your account is locked.'
-    unlocks:
-      send_instructions: 'You will receive an email with instructions about how to unlock your account in a few minutes.'
-      unlocked: 'Your account was successfully unlocked. You are now signed in.'
-      send_paranoid_instructions: 'If your account exists, you will receive an email with instructions about how to unlock it in a few minutes.'
-    omniauth_callbacks:
-      success: 'Successfully authorized from %{kind} account.'
-      failure: 'Could not authorize you from %{kind} because "%{reason}".'
-    mailer:
-      confirmation_instructions:
-        subject: 'Confirmation instructions'
-      reset_password_instructions:
-        subject: 'Reset password instructions'
-      unlock_instructions:
-        subject: 'Unlock Instructions'
diff --git a/config/mail_room.yml b/config/mail_room.yml
new file mode 100644
index 0000000000000000000000000000000000000000..42f6f74c465b8f1b3830b9a0e31320fc4e9ae179
--- /dev/null
+++ b/config/mail_room.yml
@@ -0,0 +1,39 @@
+:mailboxes:
+<%
+require_relative 'config/environment.rb'
+
+if Gitlab::IncomingEmail.enabled? 
+  config = Gitlab::IncomingEmail.config
+
+  redis_config_file = "config/resque.yml"
+  redis_url = 
+    if File.exists?(redis_config_file)
+      YAML.load_file(redis_config_file)[Rails.env]
+    else
+      "redis://localhost:6379"
+    end
+  %>
+  -
+    :host: <%= config.host.to_json %>
+    :port: <%= config.port.to_json %>
+    :ssl: <%= config.ssl.to_json %>
+    :start_tls: <%= config.start_tls.to_json %>
+    :email: <%= config.user.to_json %>
+    :password: <%= config.password.to_json %>
+
+    :name: <%= config.mailbox.to_json %>
+
+    :delete_after_delivery: true
+
+    :delivery_method: sidekiq
+    :delivery_options:
+      :redis_url: <%= redis_url.to_json %>
+      :namespace: resque:gitlab
+      :queue: incoming_email
+      :worker: EmailReceiverWorker
+
+    :arbitration_method: redis
+    :arbitration_options:
+      :redis_url: <%= redis_url.to_json %>
+      :namespace: mail_room:gitlab
+<% end %>
diff --git a/config/mail_room.yml.example b/config/mail_room.yml.example
deleted file mode 100644
index 82e1a42058e1e9d7a23155449a82b63ce421d02c..0000000000000000000000000000000000000000
--- a/config/mail_room.yml.example
+++ /dev/null
@@ -1,29 +0,0 @@
-:mailboxes:
-  -
-    # # IMAP server host
-    # :host: "imap.gmail.com"
-    # # IMAP server port
-    # :port: 993
-    # # Whether the IMAP server uses SSL
-    # :ssl: true
-    # # Whether the IMAP server uses StartTLS
-    # :start_tls: false
-    # # Email account username. Usually the full email address.
-    # :email: "replies@gitlab.example.com"
-    # # Email account password
-    # :password: "password"
-    # # The name of the mailbox where incoming mail will end up. Usually "inbox".
-    # :name: "inbox"
-    # # Always "sidekiq".
-    # :delivery_method: sidekiq
-    # # Always true.
-    # :delete_after_delivery: true
-    # :delivery_options:
-    #   # The URL to the Redis server used by Sidekiq. Should match the URL in config/resque.yml.
-    #   :redis_url: redis://localhost:6379
-    #   # Always "resque:gitlab".
-    #   :namespace: resque:gitlab
-    #   # Always "incoming_email".
-    #   :queue: incoming_email
-    #   # Always "EmailReceiverWorker"
-    #   :worker: EmailReceiverWorker
diff --git a/config/routes.rb b/config/routes.rb
index 4a07c449b4e9f708f26756e6b83429039a9fabb7..f6812c9280a8819ed7e022904626ab1d7a4c75cc 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -22,50 +22,9 @@ Gitlab::Application.routes.draw do
         get :dumped_yaml
       end
 
-      resources :services, only: [:index, :edit, :update] do
-        member do
-          get :test
-        end
-      end
-
-      resource :charts, only: [:show]
-
-      resources :refs, constraints: { ref_id: /.*/ }, only: [] do
-        resources :commits, only: [:show] do
-          member do
-            get :status
-            get :cancel
-          end
-        end
-      end
-
-      resources :builds, only: [:show] do
-        member do
-          get :cancel
-          get :status
-          post :retry
-        end
-      end
-
-      resources :web_hooks, only: [:index, :create, :destroy] do
-        member do
-          get :test
-        end
-      end
-
-      resources :triggers, only: [:index, :create, :destroy]
-
-      resources :runners, only: [:index, :edit, :update, :destroy, :show] do
-        member do
-          get :resume
-          get :pause
-        end
-      end
-
       resources :runner_projects, only: [:create, :destroy]
 
       resources :events, only: [:index]
-      resource :variables, only: [:show, :update]
     end
 
     resource :user_sessions do
@@ -262,6 +221,7 @@ Gitlab::Application.routes.draw do
         put :unblock
         put :unlock
         put :confirm
+        post :login_as
         patch :disable_two_factor
         delete 'remove/:email_id', action: 'remove_email', as: 'remove_email'
       end
@@ -418,6 +378,7 @@ Gitlab::Application.routes.draw do
               [:new, :create, :index], path: "/") do
       member do
         put :transfer
+        delete :remove_fork
         post :archive
         post :unarchive
         post :toggle_star
@@ -482,6 +443,15 @@ Gitlab::Application.routes.draw do
           )
         end
 
+        scope do
+          post(
+              '/create_dir/*id',
+              to: 'tree#create_dir',
+              constraints: { id: /.+/ },
+              as: 'create_dir'
+          )
+        end
+
         scope do
           get(
             '/blame/*id',
@@ -502,7 +472,11 @@ Gitlab::Application.routes.draw do
 
         resource  :avatar, only: [:show, :destroy]
         resources :commit, only: [:show], constraints: { id: /[[:alnum:]]{6,40}/ } do
-          get :branches, on: :member
+          member do
+            get :branches
+            get :ci
+            get :cancel_builds
+          end
         end
 
         resources :compare, only: [:index, :create]
@@ -570,8 +544,10 @@ Gitlab::Application.routes.draw do
           member do
             # tree viewer logs
             get 'logs_tree', constraints: { id: Gitlab::Regex.git_reference_regex }
+            # Directories with leading dots erroneously get rejected if git
+            # ref regex used in constraints. Regex verification now done in controller.
             get 'logs_tree/*path' => 'refs#logs_tree', as: :logs_file, constraints: {
-              id: Gitlab::Regex.git_reference_regex,
+              id: /.*/,
               path: /.*/
             }
           end
@@ -597,6 +573,32 @@ Gitlab::Application.routes.draw do
         resources :branches, only: [:index, :new, :create, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex }
         resources :tags, only: [:index, :new, :create, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex }
         resources :protected_branches, only: [:index, :create, :update, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex }
+        resource :variables, only: [:show, :update]
+        resources :triggers, only: [:index, :create, :destroy]
+        resource :ci_settings, only: [:edit, :update, :destroy]
+        resources :ci_web_hooks, only: [:index, :create, :destroy] do
+          member do
+            get :test
+          end
+        end
+
+        resources :ci_services, constraints: { id: /[^\/]+/ }, only: [:index, :edit, :update] do
+          member do
+            get :test
+          end
+        end
+
+        resources :builds, only: [:index, :show] do
+          collection do
+            get :cancel_all
+          end
+
+          member do
+            get :cancel
+            get :status
+            post :retry
+          end
+        end
 
         resources :hooks, only: [:index, :create, :destroy], constraints: { id: /\d+/ } do
           member do
@@ -652,8 +654,14 @@ Gitlab::Application.routes.draw do
             get ":secret/:filename", action: :show, as: :show, constraints: { filename: /[^\/]+/ }
           end
         end
-      end
 
+        resources :runners, only: [:index, :edit, :update, :destroy, :show] do
+          member do
+            get :resume
+            get :pause
+          end
+        end
+      end
     end
   end
 
diff --git a/db/fixtures/development/04_project.rb b/db/fixtures/development/04_project.rb
index 8f71198e47f9de7a1cc061148dfcb563d9a6084f..b463999996747aaeb53e31af3f2b0b21ea2c6422 100644
--- a/db/fixtures/development/04_project.rb
+++ b/db/fixtures/development/04_project.rb
@@ -73,8 +73,13 @@ Sidekiq::Testing.inline! do
       }
 
       project = Projects::CreateService.new(User.first, params).execute
+      # Seed-Fu runs this entire fixture in a transaction, so the `after_commit`
+      # hook won't run until after the fixture is loaded. That is too late
+      # since the Sidekiq::Testing block has already exited. Force clearing
+      # the `after_commit` queue to ensure the job is run now.
+      project.send(:_run_after_commit_queue)
 
-      if project.valid?
+      if project.valid? && project.valid_repo?
         print '.'
       else
         puts project.errors.full_messages
diff --git a/db/fixtures/development/05_users.rb b/db/fixtures/development/05_users.rb
index 378354efd5a056467f90d36674d4d13c9d09089a..03da29c4c686930c5020b6fac27400b204a485aa 100644
--- a/db/fixtures/development/05_users.rb
+++ b/db/fixtures/development/05_users.rb
@@ -1,5 +1,5 @@
 Gitlab::Seeder.quiet do
-  (2..20).each  do |i|
+  20.times do |i|
     begin
       User.create!(
         username: FFaker::Internet.user_name,
@@ -15,7 +15,7 @@ Gitlab::Seeder.quiet do
     end
   end
 
-  (1..5).each do |i|
+  5.times do |i|
     begin
       User.create!(
         username: "user#{i}",
diff --git a/db/fixtures/development/07_milestones.rb b/db/fixtures/development/07_milestones.rb
index a43116829d978032bbae30c695ed120c590cfc67..e028ac82ba33898e1f0185fd47845ec764e72fe9 100644
--- a/db/fixtures/development/07_milestones.rb
+++ b/db/fixtures/development/07_milestones.rb
@@ -1,6 +1,6 @@
 Gitlab::Seeder.quiet do
   Project.all.each do |project|
-    (1..5).each  do |i|
+    5.times do |i|
       milestone_params = {
         title: "v#{i}.0",
         description: FFaker::Lorem.sentence,
diff --git a/db/fixtures/development/09_issues.rb b/db/fixtures/development/09_issues.rb
index c636e96381ca4f58d24b4c806e98a1117c8263a4..4fa572fca9bdab3570781c49c95954b7dc1f164a 100644
--- a/db/fixtures/development/09_issues.rb
+++ b/db/fixtures/development/09_issues.rb
@@ -1,6 +1,6 @@
 Gitlab::Seeder.quiet do
   Project.all.each do |project|
-    (1..10).each  do |i|
+    10.times do
       issue_params = {
         title: FFaker::Lorem.sentence(6),
         description: FFaker::Lorem.sentence,
diff --git a/db/fixtures/development/12_snippets.rb b/db/fixtures/development/12_snippets.rb
index 3bd4b442adeaa1fee3418b45f52d8f8734be1df9..74898544a69a49c6656ba17669392ed00743d490 100644
--- a/db/fixtures/development/12_snippets.rb
+++ b/db/fixtures/development/12_snippets.rb
@@ -22,7 +22,7 @@ class Member < ActiveRecord::Base
 end
 eos
 
-  (1..50).each  do |i|
+  50.times do |i|
     user = User.all.sample
 
     PersonalSnippet.seed(:id, [{
diff --git a/db/migrate/20150924125150_add_project_id_to_ci_commit.rb b/db/migrate/20150924125150_add_project_id_to_ci_commit.rb
new file mode 100644
index 0000000000000000000000000000000000000000..1a761fe0f863f057b676bef372fb33cd094020a1
--- /dev/null
+++ b/db/migrate/20150924125150_add_project_id_to_ci_commit.rb
@@ -0,0 +1,5 @@
+class AddProjectIdToCiCommit < ActiveRecord::Migration
+  def up
+    add_column :ci_commits, :gl_project_id, :integer
+  end
+end
diff --git a/db/migrate/20150924125436_migrate_project_id_for_ci_commits.rb b/db/migrate/20150924125436_migrate_project_id_for_ci_commits.rb
new file mode 100644
index 0000000000000000000000000000000000000000..2be57b6062ebac7e17848c8ee3e8ca9485360b4b
--- /dev/null
+++ b/db/migrate/20150924125436_migrate_project_id_for_ci_commits.rb
@@ -0,0 +1,6 @@
+class MigrateProjectIdForCiCommits < ActiveRecord::Migration
+  def up
+    subquery = 'SELECT gitlab_id FROM ci_projects WHERE ci_projects.id = ci_commits.project_id'
+    execute("UPDATE ci_commits SET gl_project_id=(#{subquery}) WHERE gl_project_id IS NULL")
+  end
+end
diff --git a/db/migrate/20150930001110_merge_request_error_field.rb b/db/migrate/20150930001110_merge_request_error_field.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c2ee498ef3ffe8d64e1b117273c70c1b5fea0102
--- /dev/null
+++ b/db/migrate/20150930001110_merge_request_error_field.rb
@@ -0,0 +1,5 @@
+class MergeRequestErrorField < ActiveRecord::Migration
+  def up
+    add_column :merge_requests, :merge_error, :string
+  end
+end
diff --git a/db/migrate/20150930095736_add_null_to_name_for_ci_projects.rb b/db/migrate/20150930095736_add_null_to_name_for_ci_projects.rb
new file mode 100644
index 0000000000000000000000000000000000000000..8d47dac6441e87339cbe3a0a710d1f9e9a3391b2
--- /dev/null
+++ b/db/migrate/20150930095736_add_null_to_name_for_ci_projects.rb
@@ -0,0 +1,9 @@
+class AddNullToNameForCiProjects < ActiveRecord::Migration
+  def up
+    change_column_null :ci_projects, :name, true
+  end
+
+  def down
+    change_column_null :ci_projects, :name, false
+  end
+end
diff --git a/db/migrate/20151002112914_add_stage_idx_to_builds.rb b/db/migrate/20151002112914_add_stage_idx_to_builds.rb
new file mode 100644
index 0000000000000000000000000000000000000000..68a745ffef49d6c1839964560013d6d274ff9434
--- /dev/null
+++ b/db/migrate/20151002112914_add_stage_idx_to_builds.rb
@@ -0,0 +1,5 @@
+class AddStageIdxToBuilds < ActiveRecord::Migration
+  def change
+    add_column :ci_builds, :stage_idx, :integer
+  end
+end
diff --git a/db/migrate/20151002121400_add_index_for_builds.rb b/db/migrate/20151002121400_add_index_for_builds.rb
new file mode 100644
index 0000000000000000000000000000000000000000..4ffc1363910dab6f9e4443d06d2b1146d5f18136
--- /dev/null
+++ b/db/migrate/20151002121400_add_index_for_builds.rb
@@ -0,0 +1,5 @@
+class AddIndexForBuilds < ActiveRecord::Migration
+  def up
+    add_index :ci_builds, [:commit_id, :stage_idx, :created_at]
+  end
+end
diff --git a/db/migrate/20151002122929_add_ref_and_tag_to_builds.rb b/db/migrate/20151002122929_add_ref_and_tag_to_builds.rb
new file mode 100644
index 0000000000000000000000000000000000000000..e3d2ac1cea5cc43e34d52e07a1a055b5dbc20693
--- /dev/null
+++ b/db/migrate/20151002122929_add_ref_and_tag_to_builds.rb
@@ -0,0 +1,6 @@
+class AddRefAndTagToBuilds < ActiveRecord::Migration
+  def change
+    add_column :ci_builds, :tag, :boolean
+    add_column :ci_builds, :ref, :string
+  end
+end
diff --git a/db/migrate/20151002122943_migrate_ref_and_tag_to_build.rb b/db/migrate/20151002122943_migrate_ref_and_tag_to_build.rb
new file mode 100644
index 0000000000000000000000000000000000000000..01d7b3f6773822dcbae7116c76d0c3ff90acceb6
--- /dev/null
+++ b/db/migrate/20151002122943_migrate_ref_and_tag_to_build.rb
@@ -0,0 +1,6 @@
+class MigrateRefAndTagToBuild < ActiveRecord::Migration
+  def change
+    execute('UPDATE ci_builds SET ref=(SELECT ref FROM ci_commits WHERE ci_commits.id = ci_builds.commit_id) WHERE ref IS NULL')
+    execute('UPDATE ci_builds SET tag=(SELECT tag FROM ci_commits WHERE ci_commits.id = ci_builds.commit_id) WHERE tag IS NULL')
+  end
+end
diff --git a/db/migrate/20151005075649_add_user_id_to_build.rb b/db/migrate/20151005075649_add_user_id_to_build.rb
new file mode 100644
index 0000000000000000000000000000000000000000..0f4b92b8b79f3d587772627bf6cfea01c7125518
--- /dev/null
+++ b/db/migrate/20151005075649_add_user_id_to_build.rb
@@ -0,0 +1,5 @@
+class AddUserIdToBuild < ActiveRecord::Migration
+  def change
+    add_column :ci_builds, :user_id, :integer
+  end
+end
diff --git a/db/migrate/20151005150751_add_layout_option_for_users.rb b/db/migrate/20151005150751_add_layout_option_for_users.rb
new file mode 100644
index 0000000000000000000000000000000000000000..ead9b1f89774579614e0b536ef7d3e94ba8cc71e
--- /dev/null
+++ b/db/migrate/20151005150751_add_layout_option_for_users.rb
@@ -0,0 +1,5 @@
+class AddLayoutOptionForUsers < ActiveRecord::Migration
+  def change
+    add_column :users, :layout, :integer, default: 0
+  end
+end
\ No newline at end of file
diff --git a/db/migrate/20151005162154_remove_ci_enabled_from_application_settings.rb b/db/migrate/20151005162154_remove_ci_enabled_from_application_settings.rb
new file mode 100644
index 0000000000000000000000000000000000000000..be6aa810bb5ace751432733fbed51563fe0bcefe
--- /dev/null
+++ b/db/migrate/20151005162154_remove_ci_enabled_from_application_settings.rb
@@ -0,0 +1,5 @@
+class RemoveCiEnabledFromApplicationSettings < ActiveRecord::Migration
+  def change
+    remove_column :application_settings, :ci_enabled, :boolean, null: false, default: true
+  end
+end
diff --git a/db/migrate/20151007120511_namespaces_projects_path_lower_indexes.rb b/db/migrate/20151007120511_namespaces_projects_path_lower_indexes.rb
new file mode 100644
index 0000000000000000000000000000000000000000..7f6cd6d5a78a670a5d0820b3ee881aaa97c8da57
--- /dev/null
+++ b/db/migrate/20151007120511_namespaces_projects_path_lower_indexes.rb
@@ -0,0 +1,17 @@
+class NamespacesProjectsPathLowerIndexes < ActiveRecord::Migration
+  disable_ddl_transaction!
+
+  def up
+    return unless Gitlab::Database.postgresql?
+
+    execute 'CREATE INDEX CONCURRENTLY index_on_namespaces_lower_path ON namespaces (LOWER(path));'
+    execute 'CREATE INDEX CONCURRENTLY index_on_projects_lower_path ON projects (LOWER(path));'
+  end
+
+  def down
+    return unless Gitlab::Database.postgresql?
+
+    remove_index :namespaces, name: :index_on_namespaces_lower_path
+    remove_index :projects, name: :index_on_projects_lower_path
+  end
+end
diff --git a/db/migrate/20151008110232_add_users_lower_username_email_indexes.rb b/db/migrate/20151008110232_add_users_lower_username_email_indexes.rb
new file mode 100644
index 0000000000000000000000000000000000000000..2f2dc7767855c9afd0dc85bf7429f09b2af9b2da
--- /dev/null
+++ b/db/migrate/20151008110232_add_users_lower_username_email_indexes.rb
@@ -0,0 +1,17 @@
+class AddUsersLowerUsernameEmailIndexes < ActiveRecord::Migration
+  disable_ddl_transaction!
+
+  def up
+    return unless Gitlab::Database.postgresql?
+
+    execute 'CREATE INDEX CONCURRENTLY index_on_users_lower_username ON users (LOWER(username));'
+    execute 'CREATE INDEX CONCURRENTLY index_on_users_lower_email ON users (LOWER(email));'
+  end
+
+  def down
+    return unless Gitlab::Database.postgresql?
+
+    remove_index :users, :index_on_users_lower_username
+    remove_index :users, :index_on_users_lower_email
+  end
+end
diff --git a/db/migrate/20151008123042_add_type_and_description_to_builds.rb b/db/migrate/20151008123042_add_type_and_description_to_builds.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c72b1c611c6db7125921b5f2aebe8f3aa884661e
--- /dev/null
+++ b/db/migrate/20151008123042_add_type_and_description_to_builds.rb
@@ -0,0 +1,9 @@
+class AddTypeAndDescriptionToBuilds < ActiveRecord::Migration
+  def change
+    add_column :ci_builds, :type, :string
+    add_column :ci_builds, :target_url, :string
+    add_column :ci_builds, :description, :string
+    add_index :ci_builds, [:commit_id, :type, :ref]
+    add_index :ci_builds, [:commit_id, :type, :name, :ref]
+  end
+end
diff --git a/db/migrate/20151008130321_migrate_name_to_description_for_builds.rb b/db/migrate/20151008130321_migrate_name_to_description_for_builds.rb
new file mode 100644
index 0000000000000000000000000000000000000000..f5c44babd84277d0b7764942a114c54f7e1b32fb
--- /dev/null
+++ b/db/migrate/20151008130321_migrate_name_to_description_for_builds.rb
@@ -0,0 +1,5 @@
+class MigrateNameToDescriptionForBuilds < ActiveRecord::Migration
+  def change
+    execute("UPDATE ci_builds SET type='Ci::Build' WHERE type IS NULL")
+  end
+end
diff --git a/db/migrate/20151008143519_add_admin_notification_email_setting.rb b/db/migrate/20151008143519_add_admin_notification_email_setting.rb
new file mode 100644
index 0000000000000000000000000000000000000000..0bb581efe2c56d70d3041c17c065b7e631b00a11
--- /dev/null
+++ b/db/migrate/20151008143519_add_admin_notification_email_setting.rb
@@ -0,0 +1,5 @@
+class AddAdminNotificationEmailSetting < ActiveRecord::Migration
+  def change
+    add_column :application_settings, :admin_notification_email, :string
+  end
+end
diff --git a/db/migrate/20151016131433_add_ci_projects_gl_project_id_index.rb b/db/migrate/20151016131433_add_ci_projects_gl_project_id_index.rb
new file mode 100644
index 0000000000000000000000000000000000000000..52a47aa9c54debafcad6fd7e5936b6380a01cf48
--- /dev/null
+++ b/db/migrate/20151016131433_add_ci_projects_gl_project_id_index.rb
@@ -0,0 +1,5 @@
+class AddCiProjectsGlProjectIdIndex < ActiveRecord::Migration
+  def change
+    add_index :ci_commits, :gl_project_id
+  end
+end
diff --git a/db/migrate/20151016195451_add_ci_builds_and_projects_indexes.rb b/db/migrate/20151016195451_add_ci_builds_and_projects_indexes.rb
new file mode 100644
index 0000000000000000000000000000000000000000..7f1af1c758307f65a568079ddbe7aa9e635cc4e2
--- /dev/null
+++ b/db/migrate/20151016195451_add_ci_builds_and_projects_indexes.rb
@@ -0,0 +1,9 @@
+class AddCiBuildsAndProjectsIndexes < ActiveRecord::Migration
+  def change
+    add_index :ci_projects, :gitlab_id
+    add_index :ci_projects, :shared_runners_enabled
+
+    add_index :ci_builds, :type
+    add_index :ci_builds, :status
+  end
+end
diff --git a/db/migrate/20151016195706_add_notes_line_code_index.rb b/db/migrate/20151016195706_add_notes_line_code_index.rb
new file mode 100644
index 0000000000000000000000000000000000000000..aeeb1a759fab2aef1b184d24b683052647c643b2
--- /dev/null
+++ b/db/migrate/20151016195706_add_notes_line_code_index.rb
@@ -0,0 +1,5 @@
+class AddNotesLineCodeIndex < ActiveRecord::Migration
+  def change
+    add_index :notes, :line_code
+  end
+end
diff --git a/db/migrate/20151019111551_fix_build_tags.rb b/db/migrate/20151019111551_fix_build_tags.rb
new file mode 100644
index 0000000000000000000000000000000000000000..84b142183f8a7c60a14c3c8c6a15315750299cf0
--- /dev/null
+++ b/db/migrate/20151019111551_fix_build_tags.rb
@@ -0,0 +1,5 @@
+class FixBuildTags < ActiveRecord::Migration
+  def change
+    execute("UPDATE taggings SET taggable_type='CommitStatus' WHERE taggable_type='Ci::Build'")
+  end
+end
diff --git a/db/migrate/20151019111703_fail_build_without_names.rb b/db/migrate/20151019111703_fail_build_without_names.rb
new file mode 100644
index 0000000000000000000000000000000000000000..546b03d81295d0c0fba62eaf67615d14dcd3d8a5
--- /dev/null
+++ b/db/migrate/20151019111703_fail_build_without_names.rb
@@ -0,0 +1,5 @@
+class FailBuildWithoutNames < ActiveRecord::Migration
+  def change
+    execute("UPDATE ci_builds SET status='failed' WHERE name IS NULL AND status='pending'")
+  end
+end
diff --git a/db/migrate/20151020173516_ci_limits_to_mysql.rb b/db/migrate/20151020173516_ci_limits_to_mysql.rb
new file mode 100644
index 0000000000000000000000000000000000000000..9bb960082f58befe42999d26e654750eae9db8c9
--- /dev/null
+++ b/db/migrate/20151020173516_ci_limits_to_mysql.rb
@@ -0,0 +1,9 @@
+class CiLimitsToMysql < ActiveRecord::Migration
+  def change
+    return unless ActiveRecord::Base.configurations[Rails.env]['adapter'] =~ /^mysql/
+
+    # CI
+    change_column :ci_builds, :trace, :text, limit: 1073741823
+    change_column :ci_commits, :push_data, :text, limit: 16777215
+  end
+end
diff --git a/db/migrate/20151020173906_add_ci_builds_index_for_status.rb b/db/migrate/20151020173906_add_ci_builds_index_for_status.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c3f0e0606dab6b46be92e8993a3b815aea52f4af
--- /dev/null
+++ b/db/migrate/20151020173906_add_ci_builds_index_for_status.rb
@@ -0,0 +1,5 @@
+class AddCiBuildsIndexForStatus < ActiveRecord::Migration
+  def change
+    add_index :ci_builds, [:commit_id, :status, :type]
+  end
+end
diff --git a/db/migrate/limits_to_mysql.rb b/db/migrate/limits_to_mysql.rb
index 73605d4c5e3096900949f2bb2287ae6c3e3e3a7b..2b7afae6d7cb3f73197f2c6d9549ba216429af82 100644
--- a/db/migrate/limits_to_mysql.rb
+++ b/db/migrate/limits_to_mysql.rb
@@ -6,9 +6,5 @@ class LimitsToMysql < ActiveRecord::Migration
     change_column :merge_request_diffs, :st_diffs, :text, limit: 2147483647
     change_column :snippets, :content, :text, limit: 2147483647
     change_column :notes, :st_diff, :text, limit: 2147483647
-
-    # CI
-    change_column :ci_builds, :trace, :text, limit: 1073741823
-    change_column :ci_commits, :push_data, :text, limit: 16777215
   end
 end
diff --git a/db/schema.rb b/db/schema.rb
index 01ccda7a75e3e000300fedfd77a2003b3d7ab3d6..0fec00ebf8f66d7a074f131937829325da2ec436 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: 20150920161119) do
+ActiveRecord::Schema.define(version: 20151020173906) do
 
   # These are extensions that must be enabled in order to support this database
   enable_extension "plpgsql"
@@ -46,7 +46,7 @@ ActiveRecord::Schema.define(version: 20150920161119) do
     t.integer  "session_expire_delay",         default: 10080, null: false
     t.text     "import_sources"
     t.text     "help_page_text"
-    t.boolean  "ci_enabled",                   default: true,  null: false
+    t.string   "admin_notification_email"
   end
 
   create_table "audit_events", force: true do |t|
@@ -100,12 +100,25 @@ ActiveRecord::Schema.define(version: 20150920161119) do
     t.boolean  "allow_failure",      default: false, null: false
     t.string   "stage"
     t.integer  "trigger_request_id"
+    t.integer  "stage_idx"
+    t.boolean  "tag"
+    t.string   "ref"
+    t.integer  "user_id"
+    t.string   "type"
+    t.string   "target_url"
+    t.string   "description"
   end
 
+  add_index "ci_builds", ["commit_id", "stage_idx", "created_at"], name: "index_ci_builds_on_commit_id_and_stage_idx_and_created_at", using: :btree
+  add_index "ci_builds", ["commit_id", "status", "type"], name: "index_ci_builds_on_commit_id_and_status_and_type", using: :btree
+  add_index "ci_builds", ["commit_id", "type", "name", "ref"], name: "index_ci_builds_on_commit_id_and_type_and_name_and_ref", using: :btree
+  add_index "ci_builds", ["commit_id", "type", "ref"], name: "index_ci_builds_on_commit_id_and_type_and_ref", using: :btree
   add_index "ci_builds", ["commit_id"], name: "index_ci_builds_on_commit_id", using: :btree
   add_index "ci_builds", ["project_id", "commit_id"], name: "index_ci_builds_on_project_id_and_commit_id", using: :btree
   add_index "ci_builds", ["project_id"], name: "index_ci_builds_on_project_id", using: :btree
   add_index "ci_builds", ["runner_id"], name: "index_ci_builds_on_runner_id", using: :btree
+  add_index "ci_builds", ["status"], name: "index_ci_builds_on_status", using: :btree
+  add_index "ci_builds", ["type"], name: "index_ci_builds_on_type", using: :btree
 
   create_table "ci_commits", force: true do |t|
     t.integer  "project_id"
@@ -115,11 +128,13 @@ ActiveRecord::Schema.define(version: 20150920161119) do
     t.text     "push_data"
     t.datetime "created_at"
     t.datetime "updated_at"
-    t.boolean  "tag",          default: false
+    t.boolean  "tag",           default: false
     t.text     "yaml_errors"
     t.datetime "committed_at"
+    t.integer  "gl_project_id"
   end
 
+  add_index "ci_commits", ["gl_project_id"], name: "index_ci_commits_on_gl_project_id", using: :btree
   add_index "ci_commits", ["project_id", "committed_at", "id"], name: "index_ci_commits_on_project_id_and_committed_at_and_id", using: :btree
   add_index "ci_commits", ["project_id", "committed_at"], name: "index_ci_commits_on_project_id_and_committed_at", using: :btree
   add_index "ci_commits", ["project_id", "sha"], name: "index_ci_commits_on_project_id_and_sha", using: :btree
@@ -157,7 +172,7 @@ ActiveRecord::Schema.define(version: 20150920161119) do
   add_index "ci_jobs", ["project_id"], name: "index_ci_jobs_on_project_id", using: :btree
 
   create_table "ci_projects", force: true do |t|
-    t.string   "name",                                     null: false
+    t.string   "name"
     t.integer  "timeout",                  default: 3600,  null: false
     t.datetime "created_at"
     t.datetime "updated_at"
@@ -179,6 +194,9 @@ ActiveRecord::Schema.define(version: 20150920161119) do
     t.text     "generated_yaml_config"
   end
 
+  add_index "ci_projects", ["gitlab_id"], name: "index_ci_projects_on_gitlab_id", using: :btree
+  add_index "ci_projects", ["shared_runners_enabled"], name: "index_ci_projects_on_shared_runners_enabled", using: :btree
+
   create_table "ci_runner_projects", force: true do |t|
     t.integer  "runner_id",  null: false
     t.integer  "project_id", null: false
@@ -452,6 +470,7 @@ ActiveRecord::Schema.define(version: 20150920161119) do
     t.integer  "position",          default: 0
     t.datetime "locked_at"
     t.integer  "updated_by_id"
+    t.string   "merge_error"
   end
 
   add_index "merge_requests", ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree
@@ -518,6 +537,7 @@ ActiveRecord::Schema.define(version: 20150920161119) do
   add_index "notes", ["commit_id"], name: "index_notes_on_commit_id", using: :btree
   add_index "notes", ["created_at", "id"], name: "index_notes_on_created_at_and_id", using: :btree
   add_index "notes", ["created_at"], name: "index_notes_on_created_at", using: :btree
+  add_index "notes", ["line_code"], name: "index_notes_on_line_code", using: :btree
   add_index "notes", ["noteable_id", "noteable_type"], name: "index_notes_on_noteable_id_and_noteable_type", using: :btree
   add_index "notes", ["noteable_type"], name: "index_notes_on_noteable_type", using: :btree
   add_index "notes", ["project_id", "noteable_type"], name: "index_notes_on_project_id_and_noteable_type", using: :btree
@@ -751,6 +771,7 @@ ActiveRecord::Schema.define(version: 20150920161119) do
     t.integer  "dashboard",                  default: 0
     t.integer  "project_view",               default: 0
     t.integer  "consumed_timestep"
+    t.integer  "layout",                     default: 0
   end
 
   add_index "users", ["admin"], name: "index_users_on_admin", using: :btree
diff --git a/doc/api/commits.md b/doc/api/commits.md
index eb8d6a43592a0f2210317c59719fac951e9ca36a..9f72adc6ed9ac22a6233ecb4d7e0bb30465f6bac 100644
--- a/doc/api/commits.md
+++ b/doc/api/commits.md
@@ -62,7 +62,8 @@ Parameters:
   "authored_date": "2012-09-20T09:06:12+03:00",
   "parent_ids": [
     "ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba"
-  ]
+  ],
+  "status": "running"
 }
 ```
 
@@ -156,3 +157,84 @@ Parameters:
   "line_type": "new"
 }
 ```
+
+## Get the status of a commit
+
+Get the statuses of a commit in a project.
+
+```
+GET /projects/:id/repository/commits/:sha/statuses
+```
+
+Parameters:
+
+- `id` (required) - The ID of a project
+- `sha` (required) - The commit SHA
+- `ref` (optional) - Filter by ref name, it can be branch or tag
+- `stage` (optional) - Filter by stage
+- `name` (optional) - Filer by status name, eg. jenkins
+- `all` (optional) - The flag to return all statuses, not only latest ones
+
+```json
+[
+  {
+    "id": 13,
+    "sha": "b0b3a907f41409829b307a28b82fdbd552ee5a27",
+    "ref": "test",
+    "status": "success",
+    "name": "ci/jenkins",
+    "target_url": "http://jenkins/project/url",
+    "description": "Jenkins success",
+    "created_at": "2015-10-12T09:47:16.250Z",
+    "started_at": "2015-10-12T09:47:16.250Z"",
+    "finished_at": "2015-10-12T09:47:16.262Z",
+    "author": {
+      "id": 1,
+      "username": "admin",
+      "email": "admin@local.host",
+      "name": "Administrator",
+      "blocked": false,
+      "created_at": "2012-04-29T08:46:00Z"
+    }
+  }
+]
+```
+
+## Post the status to commit
+
+Adds or updates a status of a commit.
+
+```
+POST /projects/:id/statuses/:sha
+```
+
+- `id` (required) - The ID of a project
+- `sha` (required) - The commit SHA
+- `state` (required) - The state of the status. Can be: pending, running, success, failed, canceled
+- `ref` (optional) - The ref (branch or tag) to which the status refers
+- `name` or `context` (optional) - The label to differentiate this status from the status of other systems. Default: "default"
+- `target_url` (optional) - The target URL to associate with this status
+- `description` (optional) - The short description of the status
+
+```json
+{
+  "id": 13,
+  "sha": "b0b3a907f41409829b307a28b82fdbd552ee5a27",
+  "ref": "test",
+  "status": "success",
+  "name": "ci/jenkins",
+  "target_url": "http://jenkins/project/url",
+  "description": "Jenkins success",
+  "created_at": "2015-10-12T09:47:16.250Z",
+  "started_at": "2015-10-12T09:47:16.250Z"",
+  "finished_at": "2015-10-12T09:47:16.262Z",
+  "author": {
+    "id": 1,
+    "username": "admin",
+    "email": "admin@local.host",
+    "name": "Administrator",
+    "blocked": false,
+    "created_at": "2012-04-29T08:46:00Z"
+  }
+}
+```
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index bb551fc67f751dd7029b50416fb0d7e54ac313d6..ffa7f2cdf14d388d6c1bfaff2e3d73863168c73a 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -188,6 +188,7 @@ Parameters:
 - `title` (required)             - Title of MR
 - `description` (optional)       - Description of MR
 - `target_project_id` (optional) - The target project (numeric id)
+- `labels` (optional)            - Labels for MR as a comma-separated list
 
 ```json
 {
@@ -239,6 +240,7 @@ Parameters:
 - `title`                       - Title of MR
 - `description`                 - Description of MR
 - `state_event`                 - New state (close|reopen|merge)
+- `labels` (optional)           - Labels for MR as a comma-separated list
 
 ```json
 {
diff --git a/doc/ci/api/projects.md b/doc/ci/api/projects.md
index 54584db093898796d58a59160805a2e0f365778a..5585191e8269b340a92b859ae957e023f7072456 100644
--- a/doc/ci/api/projects.md
+++ b/doc/ci/api/projects.md
@@ -100,8 +100,6 @@ Parameters:
 
   * `name` (required) - The name of the project
   * `gitlab_id` (required) - The ID of the project on the Gitlab instance
-  * `path` (required) - The gitlab project path
-  * `ssh_url_to_repo` (required) - The gitlab SSH url to the repo
   * `default_ref` (optional) - The branch to run on (default to `master`)
 
 ### Update Project
@@ -114,9 +112,6 @@ authenticated user has access to.
 Parameters:
 
   * `name` - The name of the project
-  * `gitlab_id` - The ID of the project on the Gitlab instance
-  * `path` - The gitlab project path
-  * `ssh_url_to_repo` - The gitlab SSH url to the repo
   * `default_ref` - The branch to run on (default to `master`)
 
 ### Remove Project
diff --git a/doc/ci/docker/using_docker_build.md b/doc/ci/docker/using_docker_build.md
index a698fbc81841a16f2bdb25ebc9422abb83c2f8aa..5af27470d2fc31106bfea08f0afb64fa1ad8e101 100644
--- a/doc/ci/docker/using_docker_build.md
+++ b/doc/ci/docker/using_docker_build.md
@@ -1,6 +1,6 @@
 # Using Docker Build
 
-GitLab CI can allows you to use Docker Engine to build and test docker-based projects.
+GitLab CI allows you to use Docker Engine to build and test docker-based projects.
 
 **This also allows to you to use `docker-compose` and other docker-enabled tools.**
 
@@ -108,5 +108,4 @@ In order to do that follow the steps:
     ```
 
 1. However, by enabling `--docker-privileged` you are effectively disables all security mechanisms of containers and exposing your host to privilege escalation which can lead to container breakout.
-For more information you could be interested in checking out [Runtime privilege](https://docs.docker.com/reference/run/#runtime-privilege-linux-capabilities-and-lxc-configuration).
-
+For more information, check out [Runtime privilege](https://docs.docker.com/reference/run/#runtime-privilege-linux-capabilities-and-lxc-configuration).
\ No newline at end of file
diff --git a/doc/ci/docker/using_docker_images.md b/doc/ci/docker/using_docker_images.md
index 191e3a8144d2601c8d53501b0ccaae5b81db353e..ef8a7ec1e8613c45d1002b68999b1b0350ae09fa 100644
--- a/doc/ci/docker/using_docker_images.md
+++ b/doc/ci/docker/using_docker_images.md
@@ -90,7 +90,7 @@ you need to set MYSQL_ALLOW_EMPTY_PASSWORD.
     - mysql
     
     variables:
-      MYSQL_ALLOW_EMPTY_PASSWORD: yes
+      MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
     ```
 
 For other possible configuration variables check the 
diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md
index 04c6bf1e3a3a7037200b1a91acb265ead531a71a..022afb700424c25eab121cc08d00e667d4999e7f 100644
--- a/doc/ci/variables/README.md
+++ b/doc/ci/variables/README.md
@@ -15,21 +15,27 @@ The API_TOKEN will take the Secure Variable value: `SECURE`.
 
 ### Predefined variables (Environment Variables)
 
-| Variable                | Description |
+| Variable                | Runner | Description |
 |-------------------------|-------------|
-| **CI**                  | Mark that build is executed in CI environment |
-| **GITLAB_CI**           | Mark that build is executed in GitLab CI environment |
-| **CI_SERVER**           | Mark that build is executed in CI environment |
-| **CI_SERVER_NAME**      | CI server that is used to coordinate builds |
-| **CI_SERVER_VERSION**   | Not yet defined |
-| **CI_SERVER_REVISION**  | Not yet defined |
-| **CI_BUILD_REF**        | The commit revision for which project is built |
-| **CI_BUILD_BEFORE_SHA** | The first commit that were included in push request |
-| **CI_BUILD_REF_NAME**   | The branch or tag name for which project is built |
-| **CI_BUILD_ID**         | The unique id of the current build that GitLab CI uses internally |
-| **CI_BUILD_REPO**       | The URL to clone the Git repository |
-| **CI_PROJECT_ID**       | The unique id of the current project that GitLab CI uses internally |
-| **CI_PROJECT_DIR**      | The full path where the repository is cloned and where the build is ran |
+| **CI**                  | 0.4 | Mark that build is executed in CI environment |
+| **GITLAB_CI**           | all | Mark that build is executed in GitLab CI environment |
+| **CI_SERVER**           | all | Mark that build is executed in CI environment |
+| **CI_SERVER_NAME**      | all | CI server that is used to coordinate builds |
+| **CI_SERVER_VERSION**   | all | Not yet defined |
+| **CI_SERVER_REVISION**  | all | Not yet defined |
+| **CI_BUILD_REF**        | all | The commit revision for which project is built |
+| **CI_BUILD_TAG**        | 0.5 | The commit tag name. Present only when building tags. |
+| **CI_BUILD_NAME**       | 0.5 | The name of the build as defined in `.gitlab-ci.yml` |
+| **CI_BUILD_STAGE**      | 0.5 | The name of the stage as defined in `.gitlab-ci.yml` |
+| **CI_BUILD_BEFORE_SHA** | all | The first commit that were included in push request |
+| **CI_BUILD_REF_NAME**   | all | The branch or tag name for which project is built |
+| **CI_BUILD_ID**         | all | The unique id of the current build that GitLab CI uses internally |
+| **CI_BUILD_REPO**       | all | The URL to clone the Git repository |
+| **CI_BUILD_TRIGGERED**  | 0.5 | The flag to indicate that build was triggered |
+| **CI_PROJECT_ID**       | all | The unique id of the current project that GitLab CI uses internally |
+| **CI_PROJECT_DIR**      | all | The full path where the repository is cloned and where the build is ran |
+
+**Some of the variables are only available when using runner with at least defined version.**
 
 Example values:
 
@@ -39,6 +45,10 @@ export CI_BUILD_ID="50"
 export CI_BUILD_REF="1ecfd275763eff1d6b4844ea3168962458c9f27a"
 export CI_BUILD_REF_NAME="master"
 export CI_BUILD_REPO="https://gitlab.com/gitlab-org/gitlab-ce.git"
+export CI_BUILD_TAG="1.0.0"
+export CI_BUILD_NAME="spec:other"
+export CI_BUILD_STAGE="test"
+export CI_BUILD_TRIGGERED="true"
 export CI_PROJECT_DIR="/builds/gitlab-org/gitlab-ce"
 export CI_PROJECT_ID="34"
 export CI_SERVER="yes"
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index 4caeccacb7f94d1414aaecd6a53f658acfa61de9..ea8f72bc1358e38831d50c6796e63c3c58391fee 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -140,6 +140,7 @@ job_name:
 | except        | optional | Defines a list of git refs for which build is not created |
 | tags          | optional | Defines a list of tags which are used to select runner |
 | allow_failure | optional | Allow build to fail. Failed build doesn't contribute to commit status |
+| when          | optional | Define when to run build. Can be `on_success`, `on_failure` or `always` |
 
 ### script
 `script` is a shell script which is executed by runner. The shell script is prepended with `before_script`.
@@ -196,9 +197,58 @@ job:
 
 The above specification will make sure that `job` is built by a runner that have `ruby` AND `postgres` tags defined.
 
+### when
+`when` is used to implement jobs that are run in case of failure or despite the failure.
+
+`when` can be set to one of the following values:
+
+1. `on_success` - execute build only when all builds from prior stages succeeded. This is the default.
+1. `on_failure` - execute build only when at least one build from prior stages failed.
+1. `always` - execute build despite the status of builds from prior stages.
+
+```
+stages:
+- build
+- cleanup_build
+- test
+- deploy
+- cleanup
+
+build:
+  stage: build
+  script:
+  - make build
+
+cleanup_build:
+  stage: cleanup_build
+  script:
+  - cleanup build when failed
+  when: on_failure
+
+test:
+  stage: test
+  script:
+  - make test
+
+deploy:
+  stage: deploy
+  script:
+  - make deploy
+
+cleanup:
+  stage: cleanup
+  script:
+  - cleanup after builds
+  when: always
+```
+
+The above script will:
+1. Execute `cleanup_build` only when the `build` failed,
+2. Always execute `cleanup` as the last step in pipeline.
+
 ## Validate the .gitlab-ci.yml
 Each instance of GitLab CI has an embedded debug tool called Lint.
 You can find the link to the Lint in the project's settings page or use short url `/lint`.
 
 ## Skipping builds
-There is one more way to skip all builds, if your commit message contains tag [ci skip]. In this case, commit will be created but builds will be skipped
\ No newline at end of file
+There is one more way to skip all builds, if your commit message contains tag [ci skip]. In this case, commit will be created but builds will be skipped
diff --git a/doc/customization/welcome_message.md b/doc/customization/welcome_message.md
index 6c141d1fb7a1ef39481e11943d6ae98f979aa983..e993230bb8806a109187a73a5f6a92906a4b2356 100644
--- a/doc/customization/welcome_message.md
+++ b/doc/customization/welcome_message.md
@@ -8,31 +8,5 @@ It is possible to add a markdown-formatted welcome message to your GitLab
 sign-in page. Users of GitLab Enterprise Edition should use the [branded login
 page feature](/ee/customization/branded_login_page.html) instead.
 
-## Omnibus-gitlab example
-
-In `/etc/gitlab/gitlab.rb`:
-
-```ruby
-gitlab_rails['extra_sign_in_text'] = <<'EOS'
-# ACME GitLab
-Welcome to the [ACME](http://www.example.com) GitLab server!
-EOS
-```
-
-Run `sudo gitlab-ctl reconfigure` for changes to take effect.
-
-## Installation from source
-
-In `/home/git/gitlab/config/gitlab.yml`:
-
-```yaml
-# snip
-production:
-  # snip
-  extra:
-    sign_in_text: |
-      # ACME GitLab
-      Welcome to the [ACME](http://www.example.com) GitLab server!
-```      
-
-Run `sudo service gitlab reload` for the change to take effect.
+The welcome message (extra_sign_in_text) can now be set/changed in the Admin UI.  
+Admin area > Settings
\ No newline at end of file
diff --git a/doc/development/README.md b/doc/development/README.md
index 6bc8e1888db21cb6a86bdd0214d33b9f3baaa09c..d5bf166ad32065eb49d5f89c7089758773fd1703 100644
--- a/doc/development/README.md
+++ b/doc/development/README.md
@@ -8,3 +8,4 @@
 - [UI guide](ui_guide.md) for building GitLab with existing css styles and elements
 - [Migration Style Guide](migration_style_guide.md) for creating safe migrations
 - [How to dump production data to staging](dump_db.md)
+- [Benchmarking](benchmarking.md)
diff --git a/doc/development/benchmarking.md b/doc/development/benchmarking.md
new file mode 100644
index 0000000000000000000000000000000000000000..88e18ee95f9b43dcf2d796ac475bd6f79c66940c
--- /dev/null
+++ b/doc/development/benchmarking.md
@@ -0,0 +1,69 @@
+# Benchmarking
+
+GitLab CE comes with a set of benchmarks that are executed for every build. This
+makes it easier to measure performance of certain components over time.
+
+Benchmarks are written as RSpec tests using a few extra helpers. To write a
+benchmark, first tag the top-level `describe`:
+
+```ruby
+describe MaruTheCat, benchmark: true do
+
+end
+```
+
+This ensures the benchmark is executed separately from other test collections.
+It also exposes the various RSpec matchers used for writing benchmarks to the
+test group.
+
+Next, lets write the actual benchmark:
+
+```ruby
+describe MaruTheCat, benchmark: true do
+  let(:maru) { MaruTheChat.new }
+
+  describe '#jump_in_box' do
+    benchmark_subject { maru.jump_in_box }
+
+    it { is_expected.to iterate_per_second(9000) }
+  end
+end
+```
+
+Here `benchmark_subject` is a small wrapper around RSpec's `subject` method that
+makes it easier to specify the subject of a benchmark. Using RSpec's regular
+`subject` would require us to write the following instead:
+
+```ruby
+subject { -> { maru.jump_in_box } }
+```
+
+The `iterate_per_second` matcher defines the amount of times per second a
+subject should be executed. The higher the amount of iterations the better.
+
+By default the allowed standard deviation is a maximum of 30%. This can be
+adjusted by chaining the `with_maximum_stddev` on the `iterate_per_second`
+matcher:
+
+```ruby
+it { is_expected.to iterate_per_second(9000).with_maximum_stddev(50) }
+```
+
+This can be useful if the code in question depends on external resources of
+which the performance can vary a lot (e.g. physical HDDs, network calls, etc).
+However, in most cases 30% should be enough so only change this when really
+needed.
+
+## Benchmarks Location
+
+Benchmarks should be stored in `spec/benchmarks` and should follow the regular
+Rails specs structure. That is, model benchmarks go in `spec/benchmark/models`,
+benchmarks for code in the `lib` directory go in `spec/benchmarks/lib`, etc.
+
+## Underlying Technology
+
+The benchmark setup uses [benchmark-ips][benchmark-ips] which takes care of the
+heavy lifting such as warming up code, calculating iterations, standard
+deviation, etc.
+
+[benchmark-ips]: https://github.com/evanphx/benchmark-ips
diff --git a/doc/development/profiling.md b/doc/development/profiling.md
new file mode 100644
index 0000000000000000000000000000000000000000..80c86ef921e9fed698feda43b3c1fa26bc4cfb0a
--- /dev/null
+++ b/doc/development/profiling.md
@@ -0,0 +1,56 @@
+# Profiling
+
+To make it easier to track down performance problems GitLab comes with a set of
+profiling tools, some of these are available by default while others need to be
+explicitly enabled.
+
+## rack-mini-profiler
+
+This Gem is enabled by default in development only. It allows you to see the
+timings of the various components that made up a web request (e.g. the SQL
+queries executed and their execution timings).
+
+## Bullet
+
+Bullet is a Gem that can be used to track down N+1 query problems. Because
+Bullet adds quite a bit of logging noise it's disabled by default. To enable
+Bullet, set the environment variable `ENABLE_BULLET` to a non-empty value before
+starting GitLab. For example:
+
+    ENABLE_BULLET=true bundle exec rails s
+
+Bullet will log query problems to both the Rails log as well as the Chrome
+console.
+
+## ActiveRecord Query Trace
+
+This Gem adds backtraces for every ActiveRecord query in the Rails console. This
+can be useful to track down where a query was executed. Because this Gem adds
+quite a bit of noise (5-10 extra lines per ActiveRecord query) it's disabled by
+default. To use this Gem you'll need to set `ENABLE_QUERY_TRACE` to a non empty
+file before starting GitLab. For example:
+
+    ENABLE_QUERY_TRACE=true bundle exec rails s
+
+## rack-lineprof
+
+This is a Gem that can trace the execution time of code on a per line basis.
+Because this Gem can add quite a bit of overhead it's disabled by default. To
+enable it, set the environment variable `ENABLE_LINEPROF` to a non-empty value.
+For example:
+
+    ENABLE_LINEPROF=true bundle exec rails s
+
+Once enabled you'll need to add a query string parameter to a request to
+actually profile code execution. The name of the parameter is `lineprof` and
+should be set to a regular expression (minus the starting/ending slash) used to
+select what files to profile. To profile all files containing "foo" somewhere in
+the path you'd use the following parameter:
+
+    ?lineprof=foo
+
+Or when filtering for files containing "foo" and "bar" in their path:
+
+    ?lineprof=foo|bar
+
+Once set the profiling output will be displayed in your terminal.
diff --git a/doc/gitlab-basics/README.md b/doc/gitlab-basics/README.md
index b904c70e9805e5ce602a74908956d2c1aed15902..493e1d1b09c1b5a1fe0e188343630b4d705f028a 100644
--- a/doc/gitlab-basics/README.md
+++ b/doc/gitlab-basics/README.md
@@ -23,3 +23,5 @@ Step-by-step guides on the basics of working with Git and GitLab.
 * [Add an image](add-image.md)
 
 * [Create a Merge Request](add-merge-request.md)
+
+* [Create an Issue](create-issue.md)
diff --git a/doc/gitlab-basics/create-issue.md b/doc/gitlab-basics/create-issue.md
new file mode 100644
index 0000000000000000000000000000000000000000..87f078def0422ba2e20943b0152bbc5eab5d1f44
--- /dev/null
+++ b/doc/gitlab-basics/create-issue.md
@@ -0,0 +1,27 @@
+# How to create an Issue in GitLab
+
+The Issue Tracker is a good place to add things that need to be improved or solved in a project.  
+
+To create an Issue, sign in to GitLab.
+
+Go to the project where you'd like to create the Issue:
+
+![Select a project](basicsimages/select_project.png)
+
+Click on "Issues" on the left side of your screen:
+
+![Issues](basicsimages/issues.png)
+
+Click on the "+ new issue" button on the right side of your screen:
+
+![New issue](basicsimages/new_issue.png)
+
+Add a title and a description to your issue:
+
+![Issue title and description](basicsimages/issue_title.png)
+
+You may assign the Issue to a user, add a milestone and add labels (they are all optional). Then click on "submit new issue":
+
+![Submit new issue](basicsimages/submit_new_issue.png)
+
+Your Issue will now be added to the Issue Tracker and will be ready to be reviewed. You can comment on it and mention the people involved. You can also link Issues to the Merge Requests where the Issues are solved. To do this, you can use an [Issue closing pattern](http://doc.gitlab.com/ce/customization/issue_closing.html).
diff --git a/doc/hooks/custom_hooks.md b/doc/hooks/custom_hooks.md
index f7d4f3de68b3cccf22ddf656cd5d35e2d774894c..548c484bc0842e7edde8ac0750e971a140bec21e 100644
--- a/doc/hooks/custom_hooks.md
+++ b/doc/hooks/custom_hooks.md
@@ -2,7 +2,7 @@
 
 **Note: Custom git hooks must be configured on the filesystem of the GitLab
 server. Only GitLab server administrators will be able to complete these tasks.
-Please explore webhooks as an option if you do not have filesystem access.**
+Please explore webhooks as an option if you do not have filesystem access. For a user configurable Git Hooks interface, please see [GitLab Enterprise Edition Git Hooks](http://doc.gitlab.com/ee/git_hooks/git_hooks.html).**
 
 Git natively supports hooks that are executed on different actions.
 Examples of server-side git hooks include pre-receive, post-receive, and update.
diff --git a/doc/incoming_email/README.md b/doc/incoming_email/README.md
index 01ab22321edcce3598e3573676a94655c658a2b6..86d205ba7a54a846f72ff8e913440d637f87360b 100644
--- a/doc/incoming_email/README.md
+++ b/doc/incoming_email/README.md
@@ -4,32 +4,75 @@ GitLab can be set up to allow users to comment on issues and merge requests by r
 
 ## Get a mailbox
 
-Reply by email requires an IMAP-enabled email account, with a provider or server that supports [email sub-addressing](https://en.wikipedia.org/wiki/Email_address#Sub-addressing). Sub-addressing is a feature where any email to `user+some_arbitrary_tag@example.com` will end up in the mailbox for `user@example.com`, and is supported by providers such as Gmail, Yahoo! Mail, Outlook.com and iCloud, as well as the Postfix mail server which you can run on-premises.
+Reply by email requires an IMAP-enabled email account, with a provider or server that supports [email sub-addressing](https://en.wikipedia.org/wiki/Email_address#Sub-addressing). Sub-addressing is a feature where any email to `user+some_arbitrary_tag@example.com` will end up in the mailbox for `user@example.com`, and is supported by providers such as Gmail, Google Apps, Yahoo! Mail, Outlook.com and iCloud, as well as the Postfix mail server which you can run on-premises.
 
-If you want to use Gmail with Reply by email, make sure you have [IMAP access enabled](https://support.google.com/mail/troubleshooter/1668960?hl=en#ts=1665018) and [allow less secure apps to access the account](https://support.google.com/accounts/answer/6010255).
+If you want to use Gmail / Google Apps with Reply by email, make sure you have [IMAP access enabled](https://support.google.com/mail/troubleshooter/1668960?hl=en#ts=1665018) and [allow less secure apps to access the account](https://support.google.com/accounts/answer/6010255).
 
 To set up a basic Postfix mail server with IMAP access on Ubuntu, follow [these instructions](./postfix.md).
 
 ## Set it up
 
-In this example, we'll use the Gmail address `gitlab-incoming@gmail.com`.
-
 ### Omnibus package installations
 
-1. Find the `incoming_email` section in `/etc/gitlab/gitlab.rb`, enable the feature, enter the email address including a placeholder for the `key` that references the item being replied to and fill in the details for your specific IMAP server and email account:
+1. Find the `incoming_email` section in `/etc/gitlab/gitlab.rb`, enable the feature and fill in the details for your specific IMAP server and email account:
 
     ```ruby
+    # Configuration for Postfix mail server, assumes mailbox incoming@gitlab.example.com
     gitlab_rails['incoming_email_enabled'] = true
-    gitlab_rails['incoming_email_address'] = "gitlab-incoming+%{key}@gmail.com"
-    gitlab_rails['incoming_email_host'] = "imap.gmail.com" # IMAP server host
-    gitlab_rails['incoming_email_port'] = 993 # IMAP server port
-    gitlab_rails['incoming_email_ssl'] = true # Whether the IMAP server uses SSL
-    gitlab_rails['incoming_email_email'] = "gitlab-incoming@gmail.com"  # Email account username. Usually the full email address.
-    gitlab_rails['incoming_email_password'] = "password" # Email account password
-    gitlab_rails['incoming_email_mailbox_name'] = "inbox" # The name of the mailbox where incoming mail will end up. Usually "inbox".
+    
+    # The email address including a placeholder for the key that references the item being replied to.
+    # The `%{key}` placeholder is added after the user part, before the `@`.
+    gitlab_rails['incoming_email_address'] = "incoming+%{key}@gitlab.example.com"
+    
+    # Email account username
+    # With third party providers, this is usually the full email address.
+    # With self-hosted email servers, this is usually the user part of the email address.
+    gitlab_rails['incoming_email_email'] = "incoming"
+    # Email account password
+    gitlab_rails['incoming_email_password'] = "[REDACTED]"
+    
+    # IMAP server host
+    gitlab_rails['incoming_email_host'] = "gitlab.example.com"
+    # IMAP server port
+    gitlab_rails['incoming_email_port'] = 143
+    # Whether the IMAP server uses SSL
+    gitlab_rails['incoming_email_ssl'] = false
+    # Whether the IMAP server uses StartTLS
+    gitlab_rails['incoming_email_start_tls'] = false
+
+    # The mailbox where incoming mail will end up. Usually "inbox".
+    gitlab_rails['incoming_email_mailbox_name'] = "inbox"
     ```
 
-    As mentioned, the part after `+` in the address is ignored, and any email sent here will end up in the mailbox for `gitlab-incoming@gmail.com`.
+    ```ruby
+    # Configuration for Gmail / Google Apps, assumes mailbox gitlab-incoming@gmail.com
+    gitlab_rails['incoming_email_enabled'] = true
+    
+    # The email address including the `%{key}` placeholder that will be replaced to reference the item being replied to.
+    # The `%{key}` placeholder is added after the user part, after a `+` character, before the `@`.
+    gitlab_rails['incoming_email_address'] = "gitlab-incoming+%{key}@gmail.com"
+    
+    # Email account username
+    # With third party providers, this is usually the full email address.
+    # With self-hosted email servers, this is usually the user part of the email address.
+    gitlab_rails['incoming_email_email'] = "gitlab-incoming@gmail.com"
+    # Email account password
+    gitlab_rails['incoming_email_password'] = "[REDACTED]"
+    
+    # IMAP server host
+    gitlab_rails['incoming_email_host'] = "imap.gmail.com"
+    # IMAP server port
+    gitlab_rails['incoming_email_port'] = 993
+    # Whether the IMAP server uses SSL
+    gitlab_rails['incoming_email_ssl'] = true
+    # Whether the IMAP server uses StartTLS
+    gitlab_rails['incoming_email_start_tls'] = false
+
+    # The mailbox where incoming mail will end up. Usually "inbox".
+    gitlab_rails['incoming_email_mailbox_name'] = "inbox"
+    ```
+
+    As mentioned, the part after `+` in the address is ignored, and any email sent here will end up in the mailbox for `incoming@gitlab.example.com`/`gitlab-incoming@gmail.com`.
 
 1. Reconfigure GitLab for the changes to take effect:
 
@@ -53,155 +96,146 @@ In this example, we'll use the Gmail address `gitlab-incoming@gmail.com`.
     cd /home/git/gitlab
     ```
 
-1. Find the `incoming_email` section in `config/gitlab.yml`, enable the feature and enter the email address including a placeholder for the `key` that references the item being replied to:
+1. Find the `incoming_email` section in `config/gitlab.yml`, enable the feature and fill in the details for your specific IMAP server and email account:
 
     ```sh
     sudo editor config/gitlab.yml
     ```
 
     ```yaml
+    # Configuration for Postfix mail server, assumes mailbox incoming@gitlab.example.com
     incoming_email:
       enabled: true
-      address: "gitlab-incoming+%{key}@gmail.com"
-    ```
-
-    As mentioned, the part after `+` in the address is ignored, and any email sent here will end up in the mailbox for `gitlab-incoming@gmail.com`.
 
-2. Copy `config/mail_room.yml.example` to `config/mail_room.yml`:
+      # The email address including the `%{key}` placeholder that will be replaced to reference the item being replied to.
+      # The `%{key}` placeholder is added after the user part, after a `+` character, before the `@`.
+      address: "incoming+%{key}@gitlab.example.com"
 
-    ```sh
-    sudo cp config/mail_room.yml.example config/mail_room.yml
-    ```
+      # Email account username
+      # With third party providers, this is usually the full email address.
+      # With self-hosted email servers, this is usually the user part of the email address.
+      user: "incoming"
+      # Email account password
+      password: "[REDACTED]"
 
-3. Uncomment the configuration options in `config/mail_room.yml` and fill in the details for your specific IMAP server and email account:
+      # IMAP server host
+      host: "gitlab.example.com"
+      # IMAP server port
+      port: 143
+      # Whether the IMAP server uses SSL
+      ssl: false
+      # Whether the IMAP server uses StartTLS
+      start_tls: false
 
-    ```sh
-    sudo editor config/mail_room.yml
+      # The mailbox where incoming mail will end up. Usually "inbox".
+      mailbox: "inbox"
     ```
 
     ```yaml
-    :mailboxes:
-      -
-        # IMAP server host
-        :host: "imap.gmail.com"
-        # IMAP server port
-        :port: 993
-        # Whether the IMAP server uses SSL
-        :ssl: true
-        # Whether the IMAP server uses StartTLS
-        :start_tls: false
-        # Email account username. Usually the full email address.
-        :email: "gitlab-incoming@gmail.com"
-        # Email account password
-        :password: "[REDACTED]"
-        # The name of the mailbox where incoming mail will end up. Usually "inbox".
-        :name: "inbox"
-        # Always "sidekiq".
-        :delivery_method: sidekiq
-        # Always true.
-        :delete_after_delivery: true
-        :delivery_options:
-          # The URL to the Redis server used by Sidekiq. Should match the URL in config/resque.yml.
-          :redis_url: redis://localhost:6379
-          # Always "resque:gitlab".
-          :namespace: resque:gitlab
-          # Always "incoming_email".
-          :queue: incoming_email
-          # Always "EmailReceiverWorker"
-          :worker: EmailReceiverWorker
+    # Configuration for Gmail / Google Apps, assumes mailbox gitlab-incoming@gmail.com
+    incoming_email:
+      enabled: true
+
+      # The email address including the `%{key}` placeholder that will be replaced to reference the item being replied to.
+      # The `%{key}` placeholder is added after the user part, after a `+` character, before the `@`.
+      address: "gitlab-incoming+%{key}@gmail.com"
+
+      # Email account username
+      # With third party providers, this is usually the full email address.
+      # With self-hosted email servers, this is usually the user part of the email address.
+      user: "gitlab-incoming@gmail.com"
+      # Email account password
+      password: "[REDACTED]"
+
+      # IMAP server host
+      host: "imap.gmail.com"
+      # IMAP server port
+      port: 993
+      # Whether the IMAP server uses SSL
+      ssl: true
+      # Whether the IMAP server uses StartTLS
+      start_tls: false
+
+      # The mailbox where incoming mail will end up. Usually "inbox".
+      mailbox: "inbox"
     ```
 
-5. Edit the init script configuration at `/etc/default/gitlab` to enable `mail_room`:
+    As mentioned, the part after `+` in the address is ignored, and any email sent here will end up in the mailbox for `incoming@gitlab.example.com`/`gitlab-incoming@gmail.com`.
+
+1. Enable `mail_room` in the init script at `/etc/default/gitlab`:
 
     ```sh
     sudo mkdir -p /etc/default
     echo 'mail_room_enabled=true' | sudo tee -a /etc/default/gitlab
     ```
 
-6. Restart GitLab:
+1. Restart GitLab:
 
     ```sh
     sudo service gitlab restart
     ```
 
-7. Verify that everything is configured correctly:
+1. Verify that everything is configured correctly:
 
     ```sh
     sudo -u git -H bundle exec rake gitlab:incoming_email:check RAILS_ENV=production
     ```
 
-8. Reply by email should now be working.
+1. Reply by email should now be working.
 
 ### Development
 
 1. Go to the GitLab installation directory.
 
-1. Find the `incoming_email` section in `config/gitlab.yml`, enable the feature and enter the email address including a placeholder for the `key` that references the item being replied to:
+1. Find the `incoming_email` section in `config/gitlab.yml`, enable the feature and fill in the details for your specific IMAP server and email account:
 
     ```yaml
+    # Configuration for Gmail / Google Apps, assumes mailbox gitlab-incoming@gmail.com
     incoming_email:
       enabled: true
+
+      # The email address including a placeholder for the key that references the item being replied to.
+      # The `%{key}` placeholder is added after the user part, before the `@`.
       address: "gitlab-incoming+%{key}@gmail.com"
-    ```
 
-    As mentioned, the part after `+` is ignored, and this will end up in the mailbox for `gitlab-incoming@gmail.com`.
+      # Email account username
+      # With third party providers, this is usually the full email address.
+      # With self-hosted email servers, this is usually the user part of the email address.
+      user: "gitlab-incoming@gmail.com"
+      # Email account password
+      password: "[REDACTED]"
 
-2. Copy `config/mail_room.yml.example` to `config/mail_room.yml`:
+      # IMAP server host
+      host: "imap.gmail.com"
+      # IMAP server port
+      port: 993
+      # Whether the IMAP server uses SSL
+      ssl: true
+      # Whether the IMAP server uses StartTLS
+      start_tls: false
 
-    ```sh
-    sudo cp config/mail_room.yml.example config/mail_room.yml
+      # The mailbox where incoming mail will end up. Usually "inbox".
+      mailbox: "inbox"
     ```
 
-3. Uncomment the configuration options in `config/mail_room.yml` and fill in the details for your specific IMAP server and email account:
-
-    ```yaml
-    :mailboxes:
-      -
-        # IMAP server host
-        :host: "imap.gmail.com"
-        # IMAP server port
-        :port: 993
-        # Whether the IMAP server uses SSL
-        :ssl: true
-        # Whether the IMAP server uses StartTLS
-        :start_tls: false
-        # Email account username. Usually the full email address.
-        :email: "gitlab-incoming@gmail.com"
-        # Email account password
-        :password: "[REDACTED]"
-        # The name of the mailbox where incoming mail will end up. Usually "inbox".
-        :name: "inbox"
-        # Always "sidekiq".
-        :delivery_method: sidekiq
-        # Always true.
-        :delete_after_delivery: true
-        :delivery_options:
-          # The URL to the Redis server used by Sidekiq. Should match the URL in config/resque.yml.
-          :redis_url: redis://localhost:6379
-          # Always "resque:gitlab".
-          :namespace: resque:gitlab
-          # Always "incoming_email".
-          :queue: incoming_email
-          # Always "EmailReceiverWorker"
-          :worker: EmailReceiverWorker
-    ```
+    As mentioned, the part after `+` is ignored, and this will end up in the mailbox for `gitlab-incoming@gmail.com`.
 
-4. Uncomment the `mail_room` line in your `Procfile`:
+1. Uncomment the `mail_room` line in your `Procfile`:
 
     ```yaml
     mail_room: bundle exec mail_room -q -c config/mail_room.yml
     ```
 
-6. Restart GitLab:
+1. Restart GitLab:
 
     ```sh
     bundle exec foreman start
     ```
 
-7. Verify that everything is configured correctly:
+1. Verify that everything is configured correctly:
 
     ```sh
     bundle exec rake gitlab:incoming_email:check RAILS_ENV=development
     ```
 
-8. Reply by email should now be working.
+1. Reply by email should now be working.
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 039bb3c256131cad4082dc62265b1c42cff29d04..2e9ac7393e3d043dac3a733f631295179ee0c34e 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -115,8 +115,9 @@ Remove the old Ruby 1.8 if present
 Download Ruby and compile it:
 
     mkdir /tmp/ruby && cd /tmp/ruby
-    curl -L --progress http://cache.ruby-lang.org/pub/ruby/2.1/ruby-2.1.6.tar.gz | tar xz
-    cd ruby-2.1.6
+    curl -O --progress https://cache.ruby-lang.org/pub/ruby/2.1/ruby-2.1.7.tar.gz
+    echo 'e2e195a4a58133e3ad33b955c829bb536fa3c075  ruby-2.1.7.tar.gz' | shasum -c - && tar xzf ruby-2.1.7.tar.gz
+    cd ruby-2.1.7
     ./configure --disable-install-rdoc
     make
     sudo make install
@@ -130,12 +131,15 @@ Install the Bundler Gem:
 Since GitLab 8.0, Git HTTP requests are handled by gitlab-git-http-server.
 This is a small daemon written in Go.
 To install gitlab-git-http-server we need a Go compiler.
+The instructions below assume you use 64-bit Linux. You can find
+downloads for other platforms at the [Go download
+page](https://golang.org/dl).
 
-    curl -O --progress https://storage.googleapis.com/golang/go1.5.linux-amd64.tar.gz
-    echo '5817fa4b2252afdb02e11e8b9dc1d9173ef3bd5a  go1.5.linux-amd64.tar.gz' | shasum -c - && \
-      sudo tar -C /usr/local -xzf go1.5.linux-amd64.tar.gz
+    curl -O --progress https://storage.googleapis.com/golang/go1.5.1.linux-amd64.tar.gz
+    echo '46eecd290d8803887dec718c691cc243f2175fe0  go1.5.1.linux-amd64.tar.gz' | shasum -c - && \
+      sudo tar -C /usr/local -xzf go1.5.1.linux-amd64.tar.gz
     sudo ln -sf /usr/local/go/bin/{go,godoc,gofmt} /usr/local/bin/
-    rm go1.5.linux-amd64.tar.gz
+    rm go1.5.1.linux-amd64.tar.gz
 
 ## 4. System Users
 
@@ -207,9 +211,9 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da
 ### Clone the Source
 
     # Clone GitLab repository
-    sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 8-0-stable gitlab
+    sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 8-1-stable gitlab
 
-**Note:** You can change `8-0-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
+**Note:** You can change `8-1-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
 
 ### Configure It
 
@@ -321,6 +325,7 @@ GitLab Shell is an SSH access and repository management software developed speci
     cd /home/git
     sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-git-http-server.git
     cd gitlab-git-http-server
+    sudo -u git -H git checkout 0.3.0
     sudo -u git -H make
 
 ### Initialize Database and Activate Advanced Features
diff --git a/doc/integration/ldap.md b/doc/integration/ldap.md
index 3bc5df21ef4232df773e779a102d38df9c652696..9b7d8fa3969694931a22505468d1ea89d8f546d2 100644
--- a/doc/integration/ldap.md
+++ b/doc/integration/ldap.md
@@ -173,3 +173,23 @@ Tip: if you want to limit access to the nested members of an Active Directory gr
 ```
 
 Please note that GitLab does not support the custom filter syntax used by omniauth-ldap.
+
+## Limitations
+
+GitLab's LDAP client is based on [omniauth-ldap](https://gitlab.com/gitlab-org/omniauth-ldap)
+which encapsulates Ruby's `Net::LDAP` class. It provides a pure-Ruby implementation
+of the LDAP client protocol. As a result, GitLab is limited by `omniauth-ldap` and may impact your LDAP 
+server settings.
+
+### TLS Client Authentication  
+Not implemented by `Net::LDAP`.  
+So you should disable anonymous LDAP authentication and enable simple or SASL 
+authentication. TLS client authentication setting in your LDAP server cannot be
+mandatory and clients cannot be authenticated with the TLS protocol. 
+
+### TLS Server Authentication  
+Not supported by GitLab's configuration options.  
+When setting `method: ssl`, the underlying authentication method used by 
+`omniauth-ldap` is `simple_tls`.  This method establishes TLS encryption with 
+the LDAP server before any LDAP-protocol data is exchanged but no validation of
+the LDAP server's SSL certificate is performed.
\ No newline at end of file
diff --git a/doc/markdown/markdown.md b/doc/markdown/markdown.md
index d83838127c90bfd1e83949e2d3798d82a0b933d9..ac3851f8c95fa9a1acc8ea95fa244382422a6844 100644
--- a/doc/markdown/markdown.md
+++ b/doc/markdown/markdown.md
@@ -274,7 +274,7 @@ The IDs are generated from the content of the header according to the following
 1. All spaces are converted to hyphens
 1. Two or more hyphens in a row are converted to one
 1. If a header with the same ID has already been generated, a unique
-   incrementing number is appended.
+   incrementing number is appended, starting at 1.
 
 For example:
 
@@ -291,8 +291,8 @@ Would generate the following link IDs:
 1. `this-header-has-spaces-in-it`
 1. `this-header-has-a-in-it`
 1. `this-header-has-unicode-in-it-한글`
+1. `this-header-has-spaces-in-it`
 1. `this-header-has-spaces-in-it-1`
-1. `this-header-has-spaces-in-it-2`
 
 Note that the Emoji processing happens before the header IDs are generated, so the Emoji is converted to an image which then gets removed from the ID.
 
diff --git a/doc/migrate_ci_to_ce/README.md b/doc/migrate_ci_to_ce/README.md
index 2725bf343eee5dea5a94d1e5e1eeb9e877c821e8..5ec0a2069b59cc58866340d9ad6409c1c8213949 100644
--- a/doc/migrate_ci_to_ce/README.md
+++ b/doc/migrate_ci_to_ce/README.md
@@ -28,13 +28,20 @@ upgrade to 8.0 until you finish the migration procedure.
 
 ### Before upgrading
 
-If you have GitLab CI installed using omnibus-gitlab packages but *you don't want to migrate your existing data*:
+If you have GitLab CI installed using omnibus-gitlab packages but **you don't want to migrate your existing data**:
 
 ```bash
 mv /var/opt/gitlab/gitlab-ci/builds /var/opt/gitlab/gitlab-ci/builds.$(date +%s)
 ```
 
-and run `sudo gitlab-ctl reconfigure`.
+run `sudo gitlab-ctl reconfigure` and you can reach CI at `gitlab.example.com/ci`.
+
+If you want to migrate your existing data, continue reading.
+
+#### 0. Updating Omnibus from versions prior to 7.13
+
+If you are updating from older versions you should first update to 7.14 and then to 8.0.
+Otherwise it's pretty likely that you will encounter problems described in the [Troubleshooting](#troubleshooting).
 
 #### 1. Verify that backups work
 
@@ -43,6 +50,7 @@ Make sure that the backup script on both servers can connect to the database.
 ```
 # On your CI server:
 # Omnibus
+sudo chown gitlab-ci:gitlab-ci /var/opt/gitlab/gitlab-ci/builds
 sudo gitlab-ci-rake backup:create
 
 # Source
@@ -143,7 +151,7 @@ sudo gitlab-ctl stop ci-sidekiq
 # Source
 sudo service gitlab_ci stop
 cd /home/gitlab_ci/gitlab-ci
-sudo -u gitlab_ci -H bundle exec whenever --clear-crontab
+sudo -u gitlab_ci -H bundle exec whenever --clear-crontab RAILS_ENV=production
 ```
 
 ### II. Moving data
@@ -176,6 +184,7 @@ will need this file later.
 ```
 # On your CI server:
 # Omnibus
+sudo chown gitlab-ci:gitlab-ci /var/opt/gitlab/gitlab-ci/builds
 sudo gitlab-ci-rake backup:create
 
 # Source
@@ -222,6 +231,7 @@ be no CI data yet because you turned CI on the GitLab server off earlier.
 ```
 # On your GitLab server:
 # Omnibus
+sudo chown git:git /var/opt/gitlab/gitlab-ci/builds
 sudo gitlab-rake ci:migrate
 
 # Source
@@ -319,3 +329,107 @@ You should also make sure that you can:
 
 If something went wrong and you need to restore a backup, consult the [Backup
 restoration](../raketasks/backup_restore.md) guide.
+
+### Troubleshooting
+
+#### show:secrets problem (Omnibus-only)
+If you see errors like this:
+```
+Missing `secret_key_base` or `db_key_base` for 'production' environment. The secrets will be generated and stored in `config/secrets.yml`
+rake aborted!
+Errno::EACCES: Permission denied @ rb_sysopen - config/secrets.yml
+```
+
+This can happen if you are updating from versions prior to 7.13 straight to 8.0.
+The fix for this is to update to Omnibus 7.14 first and then update it to 8.0.
+
+#### Permission denied when accessing /var/opt/gitlab/gitlab-ci/builds
+To fix that issue you have to change builds/ folder permission before doing final backup:
+```
+sudo chown -R gitlab-ci:gitlab-ci /var/opt/gitlab/gitlab-ci/builds
+```
+
+Then before executing `ci:migrate` you need to fix builds folder permission:
+```
+sudo chown git:git /var/opt/gitlab/gitlab-ci/builds
+```
+
+#### Problems when importing CI database to GitLab
+If you were migrating CI database from MySQL to PostgreSQL manually you can see errros during import about missing sequences:
+```
+ALTER SEQUENCE
+ERROR:  relation "ci_builds_id_seq" does not exist
+ERROR:  relation "ci_commits_id_seq" does not exist
+ERROR:  relation "ci_events_id_seq" does not exist
+ERROR:  relation "ci_jobs_id_seq" does not exist
+ERROR:  relation "ci_projects_id_seq" does not exist
+ERROR:  relation "ci_runner_projects_id_seq" does not exist
+ERROR:  relation "ci_runners_id_seq" does not exist
+ERROR:  relation "ci_services_id_seq" does not exist
+ERROR:  relation "ci_taggings_id_seq" does not exist
+ERROR:  relation "ci_tags_id_seq" does not exist
+CREATE TABLE
+```
+
+To fix that you need to apply this SQL statement before doing final backup:
+```
+# Omnibus
+gitlab-ci-rails dbconsole <<EOF
+-- ALTER TABLES - DROP DEFAULTS
+ALTER TABLE ONLY ci_application_settings ALTER COLUMN id DROP DEFAULT;
+ALTER TABLE ONLY ci_builds ALTER COLUMN id DROP DEFAULT;
+ALTER TABLE ONLY ci_commits ALTER COLUMN id DROP DEFAULT;
+ALTER TABLE ONLY ci_events ALTER COLUMN id DROP DEFAULT;
+ALTER TABLE ONLY ci_jobs ALTER COLUMN id DROP DEFAULT;
+ALTER TABLE ONLY ci_projects ALTER COLUMN id DROP DEFAULT;
+ALTER TABLE ONLY ci_runner_projects ALTER COLUMN id DROP DEFAULT;
+ALTER TABLE ONLY ci_runners ALTER COLUMN id DROP DEFAULT;
+ALTER TABLE ONLY ci_services ALTER COLUMN id DROP DEFAULT;
+ALTER TABLE ONLY ci_taggings ALTER COLUMN id DROP DEFAULT;
+ALTER TABLE ONLY ci_tags ALTER COLUMN id DROP DEFAULT;
+ALTER TABLE ONLY ci_trigger_requests ALTER COLUMN id DROP DEFAULT;
+ALTER TABLE ONLY ci_triggers ALTER COLUMN id DROP DEFAULT;
+ALTER TABLE ONLY ci_variables ALTER COLUMN id DROP DEFAULT;
+ALTER TABLE ONLY ci_web_hooks ALTER COLUMN id DROP DEFAULT;
+
+-- ALTER SEQUENCES
+ALTER SEQUENCE ci_application_settings_id_seq OWNED BY ci_application_settings.id;
+ALTER SEQUENCE ci_builds_id_seq OWNED BY ci_builds.id;
+ALTER SEQUENCE ci_commits_id_seq OWNED BY ci_commits.id;
+ALTER SEQUENCE ci_events_id_seq OWNED BY ci_events.id;
+ALTER SEQUENCE ci_jobs_id_seq OWNED BY ci_jobs.id;
+ALTER SEQUENCE ci_projects_id_seq OWNED BY ci_projects.id;
+ALTER SEQUENCE ci_runner_projects_id_seq OWNED BY ci_runner_projects.id;
+ALTER SEQUENCE ci_runners_id_seq OWNED BY ci_runners.id;
+ALTER SEQUENCE ci_services_id_seq OWNED BY ci_services.id;
+ALTER SEQUENCE ci_taggings_id_seq OWNED BY ci_taggings.id;
+ALTER SEQUENCE ci_tags_id_seq OWNED BY ci_tags.id;
+ALTER SEQUENCE ci_trigger_requests_id_seq OWNED BY ci_trigger_requests.id;
+ALTER SEQUENCE ci_triggers_id_seq OWNED BY ci_triggers.id;
+ALTER SEQUENCE ci_variables_id_seq OWNED BY ci_variables.id;
+ALTER SEQUENCE ci_web_hooks_id_seq OWNED BY ci_web_hooks.id;
+
+-- ALTER TABLES - RE-APPLY DEFAULTS
+ALTER TABLE ONLY ci_application_settings ALTER COLUMN id SET DEFAULT nextval('ci_application_settings_id_seq'::regclass);
+ALTER TABLE ONLY ci_builds ALTER COLUMN id SET DEFAULT nextval('ci_builds_id_seq'::regclass);
+ALTER TABLE ONLY ci_commits ALTER COLUMN id SET DEFAULT nextval('ci_commits_id_seq'::regclass);
+ALTER TABLE ONLY ci_events ALTER COLUMN id SET DEFAULT nextval('ci_events_id_seq'::regclass);
+ALTER TABLE ONLY ci_jobs ALTER COLUMN id SET DEFAULT nextval('ci_jobs_id_seq'::regclass);
+ALTER TABLE ONLY ci_projects ALTER COLUMN id SET DEFAULT nextval('ci_projects_id_seq'::regclass);
+ALTER TABLE ONLY ci_runner_projects ALTER COLUMN id SET DEFAULT nextval('ci_runner_projects_id_seq'::regclass);
+ALTER TABLE ONLY ci_runners ALTER COLUMN id SET DEFAULT nextval('ci_runners_id_seq'::regclass);
+ALTER TABLE ONLY ci_services ALTER COLUMN id SET DEFAULT nextval('ci_services_id_seq'::regclass);
+ALTER TABLE ONLY ci_taggings ALTER COLUMN id SET DEFAULT nextval('ci_taggings_id_seq'::regclass);
+ALTER TABLE ONLY ci_tags ALTER COLUMN id SET DEFAULT nextval('ci_tags_id_seq'::regclass);
+ALTER TABLE ONLY ci_trigger_requests ALTER COLUMN id SET DEFAULT nextval('ci_trigger_requests_id_seq'::regclass);
+ALTER TABLE ONLY ci_triggers ALTER COLUMN id SET DEFAULT nextval('ci_triggers_id_seq'::regclass);
+ALTER TABLE ONLY ci_variables ALTER COLUMN id SET DEFAULT nextval('ci_variables_id_seq'::regclass);
+ALTER TABLE ONLY ci_web_hooks ALTER COLUMN id SET DEFAULT nextval('ci_web_hooks_id_seq'::regclass);
+EOF
+
+# Source
+cd /home/gitlab_ci/gitlab-ci
+sudo -u gitlab_ci -H bundle exec rails dbconsole production <<EOF
+... COPY SQL STATEMENTS FROM ABOVE ...
+EOF
+```
diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md
index 4ff5e74d438601a68f8b272bb9651f1187d0a944..06f582dcee87c076bfd04dd370cd8cde3ec4befa 100644
--- a/doc/raketasks/backup_restore.md
+++ b/doc/raketasks/backup_restore.md
@@ -7,14 +7,16 @@
 A backup creates an archive file that contains the database, all repositories and all attachments.
 This archive will be saved in backup_path (see `config/gitlab.yml`).
 The filename will be `[TIMESTAMP]_gitlab_backup.tar`. This timestamp can be used to restore an specific backup.
-You can only restore a backup to exactly the same version of GitLab that you created it on, for example 7.2.1. The best way to migrate your repositories from one server to another is through backup restore.
+You can only restore a backup to exactly the same version of GitLab that you created it
+on, for example 7.2.1. The best way to migrate your repositories from one server to
+another is through backup restore.
 
 You need to keep a separate copy of `/etc/gitlab/gitlab-secrets.json`
 (for omnibus packages) or `/home/git/gitlab/.secret` (for installations
 from source). This file contains the database encryption key used
 for two-factor authentication. If you restore a GitLab backup without
 restoring the database encryption key, users who have two-factor
-authentication enabled will loose access to your GitLab server.
+authentication enabled will lose access to your GitLab server.
 
 If you are interested in GitLab CI backup please follow to the [CI backup documentation](https://gitlab.com/gitlab-org/gitlab-ci/blob/master/doc/raketasks/backup_restore.md)*
 
@@ -95,6 +97,8 @@ For installations from source:
         aws_secret_access_key: 'secret123'
       # The remote 'directory' to store your backups. For S3, this would be the bucket name.
       remote_directory: 'my.s3.bucket'
+      # Turns on AWS Server-Side Encryption with Amazon S3-Managed Keys for backups, this is optional
+      # encryption: 'AES256'
 ```
 
 If you are uploading your backups to S3 you will probably want to create a new
@@ -369,7 +373,11 @@ For more information see similar questions on postgresql issue tracker[here](htt
 
 ## Note
 This documentation is for GitLab CE.
-We backup GitLab.com and make sure your data is secure, but you can't use these methods
-to export / backup your data yourself from GitLab.com.
+We backup GitLab.com and make sure your data is secure, but you can't use these methods to export / backup your data yourself from GitLab.com.
 
 Issues are stored in the database. They can't be stored in Git itself.
+
+To migrate your repositories from one server to another with an up-to-date version of
+GitLab, you can use the [import rake task](import.md) to do a mass import of the
+repository. Note that if you do an import rake task, rather than a backup restore, you
+will have all your repositories, but not any other data.
diff --git a/doc/raketasks/cleanup.md b/doc/raketasks/cleanup.md
index 96d67f7b5d664fa24eaa378adc189849db2a9cf8..8fbcbb983e9edfd8f9e8b3d32c2fb0b33e15a7dd 100644
--- a/doc/raketasks/cleanup.md
+++ b/doc/raketasks/cleanup.md
@@ -12,7 +12,8 @@ sudo gitlab-rake gitlab:cleanup:dirs
 bundle exec rake gitlab:cleanup:dirs RAILS_ENV=production
 ```
 
-Remove repositories (global only for now) from `/home/git/repositories` if they don't exist in GitLab database.
+Rename repositories from `/home/git/repositories` if they don't exist in GitLab database.
+The repositories get a `+orphaned+TIMESTAMP` suffix so that they cannot block new repositories from being created.
 
 ```
 # omnibus-gitlab
diff --git a/doc/raketasks/user_management.md b/doc/raketasks/user_management.md
index 4fbd20762da60f9d89ef09c3c0df99ad56f542a3..629d38efc5355042124c94a0a9c88ba73a7a32aa 100644
--- a/doc/raketasks/user_management.md
+++ b/doc/raketasks/user_management.md
@@ -56,3 +56,17 @@ bundle exec rake gitlab:import:all_users_to_all_groups RAILS_ENV=production
 ```
 block_auto_created_users: false
 ```
+
+## Disable Two-factor Authentication (2FA) for all users
+
+This task will disable 2FA for all users that have it enabled. This can be
+useful if GitLab's `.secret` file has been lost and users are unable to login,
+for example.
+
+```bash
+# omnibus-gitlab
+sudo gitlab-rake gitlab:two_factor:disable_for_all_users
+
+# installation from source
+bundle exec rake gitlab:two_factor:disable_for_all_users RAILS_ENV=production
+```
diff --git a/doc/release/monthly.md b/doc/release/monthly.md
index c56e99a7005e1677278b8d2bad637aab8b7b368b..bd8a67d1d85a81f438db55db5cbb6c0449db1bf9 100644
--- a/doc/release/monthly.md
+++ b/doc/release/monthly.md
@@ -74,20 +74,19 @@ Xth: (1 working day before the 22nd)
 - [ ] Update GitLab.com with the latest RC (#LINK)
 - [ ] Update ci.gitLab.com with the latest RC (#LINK)
 
-22nd before 12AM CET:
+22nd before 1200 CET:
 
-Release before 12AM CET / 3AM PST, to make sure the majority of our users
+Release before 1200 CET / 2AM PST, to make sure the majority of our users
 get the new version on the 22nd and there is sufficient time in the European
 workday to quickly fix any issues.
 
 - [ ] Merge CE stable into EE stable (#LINK)
 - [ ] Create the 'x.y.0' tag with the [release tools](https://dev.gitlab.org/gitlab/release-tools) (#LINK)
 - [ ] Create the 'x.y.0' version on version.gitlab.com
-- [ ] Try to do before 11AM CET: Create and push omnibus tags for x.y.0 (will auto-release the packages) (#LINK)
-- [ ] Try to do before 12AM CET: Publish the release blog post (#LINK)
+- [ ] Try to do before 1100 CET: Create and push omnibus tags for x.y.0 (will auto-release the packages) (#LINK)
+- [ ] Try to do before 1200 CET: Publish the release blog post (#LINK)
 - [ ] Tweet about the release (blog post) (#LINK)
-- [ ] Schedule a second tweet of the release announcement with the same text at 6PM CET / 9AM PST
-
+- [ ] Schedule a second tweet of the release announcement with the same text at 1800 CET / 8AM PST
 ```
 
 - - -
@@ -223,4 +222,4 @@ Consider creating a post on Hacker News.
 
 ## Create a WIP blogpost for the next release
 
-Create a WIP blogpost using [release blog template](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/doc/release_blog_template.md).
\ No newline at end of file
+Create a WIP blogpost using [release blog template](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/doc/release_blog_template.md).
diff --git a/doc/system_hooks/system_hooks.md b/doc/system_hooks/system_hooks.md
index b0e4613cdefb712a07f0f501197e8abd1ecdcf15..5cb05b13b3ec8c945452e6155feec426d0938474 100644
--- a/doc/system_hooks/system_hooks.md
+++ b/doc/system_hooks/system_hooks.md
@@ -48,16 +48,17 @@ X-Gitlab-Event: System Hook
 
 ```json
 {
-         "created_at": "2012-07-21T07:30:56Z",
-         "event_name": "user_add_to_team",
-     "project_access": "Master",
-         "project_id": 74,
-       "project_name": "StoreCloud",
-       "project_path": "storecloud",
-         "user_email": "johnsmith@gmail.com",
-          "user_name": "John Smith",
-            "user_id": 41,
- "project_visibility": "private",
+                  "created_at": "2012-07-21T07:30:56Z",
+                  "event_name": "user_add_to_team",
+              "project_access": "Master",
+                  "project_id": 74,
+                "project_name": "StoreCloud",
+                "project_path": "storecloud",
+ "project_path_with_namespace": "jsmith/storecloud",
+                  "user_email": "johnsmith@gmail.com",
+                   "user_name": "John Smith",
+                     "user_id": 41,
+          "project_visibility": "private",
 }
 ```
 
@@ -65,16 +66,17 @@ X-Gitlab-Event: System Hook
 
 ```json
 {
-         "created_at": "2012-07-21T07:30:56Z",
-         "event_name": "user_remove_from_team",
-     "project_access": "Master",
-         "project_id": 74,
-       "project_name": "StoreCloud",
-       "project_path": "storecloud",
-         "user_email": "johnsmith@gmail.com",
-          "user_name": "John Smith",
-            "user_id": 41,
- "project_visibility": "private",
+                  "created_at": "2012-07-21T07:30:56Z",
+                  "event_name": "user_remove_from_team",
+              "project_access": "Master",
+                  "project_id": 74,
+                "project_name": "StoreCloud",
+                "project_path": "storecloud",
+ "project_path_with_namespace": "jsmith/storecloud",
+                  "user_email": "johnsmith@gmail.com",
+                   "user_name": "John Smith",
+                     "user_id": 41,
+          "project_visibility": "private",
 }
 ```
 
diff --git a/doc/update/7.14-to-8.0.md b/doc/update/7.14-to-8.0.md
index 86c0825dff965c41e76bb4da6650d3135f206029..305017b704816cea41a22b80e18efbd1d355ae7a 100644
--- a/doc/update/7.14-to-8.0.md
+++ b/doc/update/7.14-to-8.0.md
@@ -84,6 +84,7 @@ Now we download `gitlab-git-http-server` and install it in `/home/git/gitlab-git
 cd /home/git
 sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-git-http-server.git
 cd gitlab-git-http-server
+sudo -u git -H git checkout 0.2.14
 sudo -u git -H make
 ```
 
@@ -101,7 +102,7 @@ EOF
 ```
 
 If your Git repositories are in a directory other than `/home/git/repositories`,
-you need to tell `gitlab-git-http-server` about it via `/etc/gitlab/default`.
+you need to tell `gitlab-git-http-server` about it via `/etc/default/gitlab`.
 See `lib/support/init.d/gitlab.default.example` for the options.
 
 ### 6. Copy secrets
@@ -168,18 +169,28 @@ git diff origin/7-14-stable:lib/support/nginx/gitlab origin/8-0-stable:lib/suppo
 ```
 
 If you are using Apache instead of NGINX please see the updated [Apache templates](https://gitlab.com/gitlab-org/gitlab-recipes/tree/master/web-server/apache).
+Also note that because Apache does not support upstreams behind Unix sockets you will need to let gitlab-git-http-server listen on a TCP port. You can do this via [/etc/default/gitlab](https://gitlab.com/gitlab-org/gitlab-ce/blob/8-0-stable/lib/support/init.d/gitlab.default.example#L34).
 
 ### 9. Migrate GitLab CI to GitLab CE/EE
 
 Now, GitLab CE and EE has CI integrated. However, migrations don't happen automatically and you need to do it manually.
 Please follow the following guide [to migrate](../migrate_ci_to_ce/README.md) your GitLab CI instance to GitLab CE/EE.
 
-### 10. Start application
+### 10. Use Redis v2.4.0+
+
+Previous versions of GitLab allowed Redis versions >= 2.0 to be used, but
+Sidekiq jobs could fail due to lack of support for the SREM command. GitLab
+8.0 now checks that Redis >= 2.4.0 is used. You can check your Redis version
+with the following command:
+
+    redis-cli info | grep redis_version
+
+### 11. Start application
 
     sudo service gitlab start
     sudo service nginx restart
 
-### 11. Check application status
+### 12. Check application status
 
 Check if GitLab and its environment are configured correctly:
 
diff --git a/doc/update/8.0-to-8.1.md b/doc/update/8.0-to-8.1.md
new file mode 100644
index 0000000000000000000000000000000000000000..d57c0d0674d44cdfbc3ce68fffd57b803816009d
--- /dev/null
+++ b/doc/update/8.0-to-8.1.md
@@ -0,0 +1,171 @@
+# From 8.0 to 8.1
+
+**NOTE:** GitLab 8.0 introduced several significant changes related to
+installation and configuration which *are not duplicated here*. Be sure you're
+already running a working version of 8.0 before proceeding with this guide.
+
+### 0. Double-check your Git version
+
+**This notice applies only to /usr/local/bin/git**
+
+If you compiled Git from source on your GitLab server then please double-check
+that you are using a version that protects against CVE-2014-9390. For six
+months after this vulnerability became known the GitLab installation guide
+still contained instructions that would install the outdated, 'vulnerable' Git
+version 2.1.2.
+
+Run the following command to get your current Git version:
+
+```sh
+/usr/local/bin/git --version
+```
+
+If you see 'No such file or directory' then you did not install Git according
+to the outdated instructions from the GitLab installation guide and you can go
+to the next step 'Stop server' below.
+
+If you see a version string then it should be v1.8.5.6, v1.9.5, v2.0.5, v2.1.4,
+v2.2.1 or newer. You can use the [instructions in the GitLab source
+installation
+guide](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/install/installation.md#1-packages-dependencies)
+to install a newer version of Git.
+
+### 1. Stop server
+
+    sudo service gitlab stop
+
+### 2. Backup
+
+```bash
+cd /home/git/gitlab
+sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
+```
+
+### 3. Get latest code
+
+```bash
+sudo -u git -H git fetch --all
+sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
+```
+
+For GitLab Community Edition:
+
+```bash
+sudo -u git -H git checkout 8-1-stable
+```
+
+OR
+
+For GitLab Enterprise Edition:
+
+```bash
+sudo -u git -H git checkout 8-1-stable-ee
+```
+
+### 4. Update gitlab-shell
+
+```bash
+cd /home/git/gitlab-shell
+sudo -u git -H git fetch
+sudo -u git -H git checkout v2.6.5
+```
+
+### 5. Update gitlab-git-http-server
+
+```bash
+cd /home/git/gitlab-git-http-server
+sudo -u git -H git fetch origin
+sudo -u git -H git checkout 0.3.0
+sudo -u git -H make
+```
+
+### 6. Install libs, migrations, etc.
+
+```bash
+cd /home/git/gitlab
+
+# MySQL installations (note: the line below states '--without postgres')
+sudo -u git -H bundle install --without postgres development test --deployment
+
+# PostgreSQL installations (note: the line below states '--without mysql')
+sudo -u git -H bundle install --without mysql development test --deployment
+
+# Run database migrations
+sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
+
+# Clean up assets and cache
+sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS_ENV=production
+
+# Update init.d script
+sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
+```
+
+### 7. Update configuration files
+
+#### New configuration options for `gitlab.yml`
+
+There are new configuration options available for [`gitlab.yml`](config/gitlab.yml.example). View them with the command below and apply them manually to your current `gitlab.yml`:
+
+```sh
+git diff origin/8-0-stable:config/gitlab.yml.example origin/8-1-stable:config/gitlab.yml.example
+```
+
+#### Nginx configuration
+
+View changes between the previous recommended Nginx configuration and the
+current one:
+
+```sh
+# For HTTPS configurations
+git diff origin/8-0-stable:lib/support/nginx/gitlab-ssl origin/8-1-stable:lib/support/nginx/gitlab-ssl
+
+# For HTTP configurations
+git diff origin/8-0-stable:lib/support/nginx/gitlab origin/8-1-stable:lib/support/nginx/gitlab
+```
+
+If you are using Apache instead of NGINX please see the updated [Apache templates].
+Also note that because Apache does not support upstreams behind Unix sockets you
+will need to let gitlab-git-http-server listen on a TCP port. You can do this
+via [/etc/default/gitlab].
+
+[Apache templates]: https://gitlab.com/gitlab-org/gitlab-recipes/tree/master/web-server/apache
+[/etc/default/gitlab]: https://gitlab.com/gitlab-org/gitlab-ce/blob/8-1-stable/lib/support/init.d/gitlab.default.example#L34
+
+### 8. Start application
+
+    sudo service gitlab start
+    sudo service nginx restart
+
+### 9. Check application status
+
+Check if GitLab and its environment are configured correctly:
+
+    sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production
+
+To make sure you didn't miss anything run a more thorough check:
+
+    sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
+
+If all items are green, then congratulations, the upgrade is complete!
+
+## Things went south? Revert to previous version (8.0)
+
+### 1. Revert the code to the previous version
+
+Follow the [upgrade guide from 7.14 to 8.0](7.14-to-8.0.md), except for the database migration
+(The backup is already migrated to the previous version)
+
+### 2. Restore from the backup
+
+```bash
+cd /home/git/gitlab
+sudo -u git -H bundle exec rake gitlab:backup:restore RAILS_ENV=production
+```
+
+If you have more than one backup `*.tar` file(s) please add `BACKUP=timestamp_of_backup` to the command above.
+
+## Troubleshooting
+
+### "You appear to have cloned an empty repository."
+
+See the [7.14 to 8.0 update guide](7.14-to-8.0.md#troubleshooting).
diff --git a/doc/update/patch_versions.md b/doc/update/patch_versions.md
index a66a863f6c45e215c6b9878baa69c3291c1d5c52..593722eb01ff43e7af394446ca7f52827441742c 100644
--- a/doc/update/patch_versions.md
+++ b/doc/update/patch_versions.md
@@ -23,9 +23,11 @@ sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
 cd /home/git/gitlab
 sudo -u git -H git fetch --all
 sudo -u git -H git checkout -- Gemfile.lock db/schema.rb
-LATEST_TAG=$(git describe --tags `git rev-list --tags --max-count=1`)
-sudo -u git -H git checkout $LATEST_TAG -b $LATEST_TAG
+sudo -u git -H git checkout LATEST_TAG -b LATEST_TAG
 ```
+Replace `LATEST_TAG` with the latest GitLab tag you want to update to, for example `v8.0.3`.  
+Use `git tag -l 'v*.[0-9]' --sort='v:refname'` to see a list of all tags.  
+Make sure to update patch versions only (check your current version with `cat VERSION`)
 
 ### 3. Update gitlab-shell to the corresponding version
 
@@ -47,9 +49,7 @@ sudo -u git -H bundle install --without development test mysql --deployment
 sudo -u git -H bundle install --without development test postgres --deployment
 
 sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
-sudo -u git -H bundle exec rake assets:clean RAILS_ENV=production
-sudo -u git -H bundle exec rake assets:precompile RAILS_ENV=production
-sudo -u git -H bundle exec rake cache:clear RAILS_ENV=production
+sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS_ENV=production
 ```
 
 ### 5. Start application
diff --git a/doc/web_hooks/web_hooks.md b/doc/web_hooks/web_hooks.md
index c185ccfcac31f4a70efd37b108fa825249900b72..ef99a69f60a81bb21e5553cc7bee73cce5ab092a 100644
--- a/doc/web_hooks/web_hooks.md
+++ b/doc/web_hooks/web_hooks.md
@@ -314,7 +314,8 @@ X-Gitlab-Event: Note Hook
         "name": "John Smith",
         "email": "john@example.com"
       }
-    }
+    },
+    "work_in_progress": false
   }
 }
 ```
@@ -500,6 +501,7 @@ X-Gitlab-Event: Merge Request Hook
         "email": "gitlabdev@dv6700.(none)"
       }
     },
+    "work_in_progress": false,
     "url": "http://example.com/diaspora/merge_requests/1",
     "action": "open"
   }
@@ -537,4 +539,4 @@ When you press 'Test Hook' in GitLab, you should see something like this in the
 {"before":"077a85dd266e6f3573ef7e9ef8ce3343ad659c4e","after":"95cd4a99e93bc4bbabacfa2cd10e6725b1403c60",<SNIP>}
 example.com - - [14/May/2014:07:45:26 EDT] "POST / HTTP/1.1" 200 0
 - -> /
-```
\ No newline at end of file
+```
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..e5a5d8dd53ddba7f3ccc105938e16406b4f4a50e
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,2 @@
+app:
+  image: gitlab/gitlab-ce:latest
diff --git a/docker/.dockerignore b/docker/.dockerignore
deleted file mode 100644
index dd449725e188f816bcebfc05678064efcbc29a81..0000000000000000000000000000000000000000
--- a/docker/.dockerignore
+++ /dev/null
@@ -1 +0,0 @@
-*.md
diff --git a/docker/Dockerfile b/docker/Dockerfile
deleted file mode 100644
index 304bb97409e813c9e855293257a1bb295248d7af..0000000000000000000000000000000000000000
--- a/docker/Dockerfile
+++ /dev/null
@@ -1,50 +0,0 @@
-FROM ubuntu:14.04
-MAINTAINER Sytse Sijbrandij
-
-# Install required packages
-RUN apt-get update -q \
-    && DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends \
-      ca-certificates \
-      openssh-server \
-      wget \
-      apt-transport-https \
-      vim \
-      nano
-
-# Download & Install GitLab
-# If you run GitLab Enterprise Edition point it to a location where you have downloaded it.
-RUN echo "deb https://packages.gitlab.com/gitlab/gitlab-ce/ubuntu/ `lsb_release -cs` main" > /etc/apt/sources.list.d/gitlab_gitlab-ce.list
-RUN wget -q -O - https://packages.gitlab.com/gpg.key | apt-key add -
-RUN apt-get update && apt-get install -yq --no-install-recommends gitlab-ce
-
-# Manage SSHD through runit
-RUN mkdir -p /opt/gitlab/sv/sshd/supervise \
-    && mkfifo /opt/gitlab/sv/sshd/supervise/ok \
-    && printf "#!/bin/sh\nexec 2>&1\numask 077\nexec /usr/sbin/sshd -D" > /opt/gitlab/sv/sshd/run \
-    && chmod a+x /opt/gitlab/sv/sshd/run \
-    && ln -s /opt/gitlab/sv/sshd /opt/gitlab/service \
-    && mkdir -p /var/run/sshd
-
-# Disabling use DNS in ssh since it tends to slow connecting
-RUN echo "UseDNS no" >> /etc/ssh/sshd_config
-
-# Prepare default configuration
-RUN ( \
-  echo "" && \
-  echo "# Docker options" && \
-  echo "# Prevent Postgres from trying to allocate 25% of total memory" && \
-  echo "postgresql['shared_buffers'] = '1MB'" ) >> /etc/gitlab/gitlab.rb && \
-  mkdir -p /assets/ && \
-  cp /etc/gitlab/gitlab.rb /assets/gitlab.rb
-
-# Expose web & ssh
-EXPOSE 443 80 22
-
-# Define data volumes
-VOLUME ["/etc/gitlab", "/var/opt/gitlab", "/var/log/gitlab"]
-
-# Copy assets
-COPY assets/wrapper /usr/local/bin/
-
-# Wrapper to handle signal, trigger runit and reconfigure GitLab
-CMD ["/usr/local/bin/wrapper"]
diff --git a/docker/README.md b/docker/README.md
index e4d56cdb33676b50b4154eb49359e666757ff857..7514d610aecc51143e091d26f2fc392f7764ef0c 100644
--- a/docker/README.md
+++ b/docker/README.md
@@ -1,169 +1,7 @@
 # GitLab Docker images
 
-The GitLab docker image is [available on Docker Hub](https://registry.hub.docker.com/u/gitlab/gitlab-ce/).
-
-## After starting a container
-
-After starting a container you can go to [http://localhost:8080/](http://localhost:8080/) or [http://192.168.59.103:8080/](http://192.168.59.103:8080/) if you use boot2docker.
-
-It might take a while before the docker container is responding to queries.
-
-You can check the status with something like `sudo docker logs -f gitlab`.
-
-You can login to the web interface with username `root` and password `5iveL!fe`.
-
-Next time, you can just use docker start and stop to run the container.
-
-## Run the image
-
-Run the image:
-```bash
-sudo docker run --detach \
-	--publish 8443:443 --publish 8080:80 --publish 2222:22 \
-	--name gitlab \
-	--restart always \
-	--volume /srv/gitlab/config:/etc/gitlab \
-	--volume /srv/gitlab/logs:/var/log/gitlab \
-	--volume /srv/gitlab/data:/var/opt/gitlab \
-	gitlab/gitlab-ce:latest
-```
-
-This will download and start GitLab CE container and publish ports needed to access SSH, HTTP and HTTPS.
-All GitLab data will be stored as subdirectories of `/srv/gitlab/`.
-The container will automatically `restart` after system reboot.
-
-After this you can login to the web interface as explained above in 'After starting a container'.
-
-## Where is the data stored?
-
-The GitLab container uses host mounted volumes to store persistent data:
-- `/srv/gitlab/data` mounted as `/var/opt/gitlab` in the container is used for storing *application data*
-- `/srv/gitlab/logs` mounted as `/var/log/gitlab` in the container is used for storing *logs*
-- `/srv/gitlab/config` mounted as `/etc/gitlab` in the container is used for storing *configuration*
-
-You can fine tune these directories to meet your requirements.
-
-### Configure GitLab
-
-This container uses the official Omnibus GitLab distribution, so all configuration is done in the unique configuration file `/etc/gitlab/gitlab.rb`.
-
-To access GitLab configuration, you can start an bash in a new the context of running container, you will be able to browse all directories and use your favorite text editor:
-```bash
-sudo docker exec -it gitlab /bin/bash
-```
-
-You can also edit just `/etc/gitlab/gitlab.rb`:
-```bash
-sudo docker exec -it gitlab vi /etc/gitlab/gitlab.rb
-```
-
-**You should set the `external_url` to point to a valid URL.**
-
-**You may also be interesting in [Enabling HTTPS](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/settings/nginx.md#enable-https).**
-
-**To receive e-mails from GitLab you have to configure the [SMTP settings](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/settings/smtp.md),
-because Docker image doesn't have a SMTP server.**
-
-**Note** that GitLab will reconfigure itself **at each container start.** You will need to restart the container to reconfigure your GitLab:
-
-```bash
-sudo docker restart gitlab
-```
-
-For more options for configuring the container please check [Omnibus GitLab documentation](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md#configuration).
-
-## Diagnose potential problems
-
-Read container logs:
-```bash
-sudo docker logs gitlab
-```
-
-Enter running container:
-```bash
-sudo docker exec -it gitlab /bin/bash
-```
-
-From within container you can administrer GitLab container as you would normally administer Omnibus installation: https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md.
-
-### Upgrade GitLab to newer version
-
-To upgrade GitLab to new version you have to do:
-1. pull new image,
-```bash
-sudo docker stop gitlab
-```
-
-1. stop running container,
-```bash
-sudo docker rm gitlab
-```
-
-1. remove existing container,
-```bash
-sudo docker pull gitlab/gitlab-ce:latest
-```
-
-1. create the container once again with previously specified options.
-```bash
-sudo docker run --detach \
-	--publish 8443:443 --publish 8080:80 --publish 2222:22 \
-	--name gitlab \
-	--restart always \
-	--volume /srv/gitlab/config:/etc/gitlab \
-	--volume /srv/gitlab/logs:/var/log/gitlab \
-	--volume /srv/gitlab/data:/var/opt/gitlab \
-	gitlab/gitlab-ce:latest
-```
-
-On the first run GitLab will reconfigure and update itself.
-
-### Run GitLab CE on public IP address
-
-You can make Docker to use your IP address and forward all traffic to the GitLab CE container.
-You can do that by modifying the `--publish` ([Binding container ports to the host](https://docs.docker.com/articles/networking/#binding-ports)):
-
-> --publish=[] : Publish a container᾿s port or a range of ports to the host format: ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort | containerPort
-
-To expose GitLab CE on IP 1.1.1.1:
-
-```bash
-sudo docker run --detach \
-	--publish 1.1.1.1:443:443 --publish 1.1.1.1:80:80 --publish 1.1.1.1:22:22 \
-	--name gitlab \
-	--restart always \
-	--volume /srv/gitlab/config:/etc/gitlab \
-	--volume /srv/gitlab/logs:/var/log/gitlab \
-	--volume /srv/gitlab/data:/var/opt/gitlab \
-	gitlab/gitlab-ce:latest
-```
-
-You can then access GitLab instance at http://1.1.1.1/ and https://1.1.1.1/.
-
-### Build the image
-
-This guide will also let you know how to build docker image yourself.
-Please run the command from the GitLab repo root directory.
-People using boot2docker should run all the commands without sudo.
-
-```bash
-sudo docker build --tag gitlab/gitlab-ce:latest docker/
-```
-
-### Publish the image to Dockerhub
-
-- Ensure the containers are running
-- Login to Dockerhub with `sudo docker login`
-
-```bash
-sudo docker login
-sudo docker push gitlab/gitlab-ce:latest
-```
-
-## Troubleshooting
-
-Please see the [troubleshooting](troubleshooting.md) file in this directory.
-
-Note: We use `fig.yml` to have compatibility with fig and because docker-compose also supports it.
-
-Our docker image runs chef at every start to generate GitLab configuration.
+* The official GitLab Community Edition Docker image is [available on Docker Hub](https://registry.hub.docker.com/u/gitlab/gitlab-ce/).
+* The official GitLab Enterprise Edition Docker image is [available on Docker Hub](https://registry.hub.docker.com/u/gitlab/gitlab-ee/).
+* The complete usage guide can be found in [Using GitLab Docker images](http://doc.gitlab.com/omnibus/docker/)
+* The Dockerfile used for building public images is in [Omnibus Repository](https://gitlab.com/gitlab-org/omnibus-gitlab/tree/master/docker)
+* Check the guide for [creating Omnibus-based Docker Image](http://doc.gitlab.com/omnibus/build/README.html#Build-Docker-image)
diff --git a/docker/assets/wrapper b/docker/assets/wrapper
deleted file mode 100755
index 8bc8370fbc941b120c66f393528d7731c91a1dab..0000000000000000000000000000000000000000
--- a/docker/assets/wrapper
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/bin/bash
-
-function sigterm_handler() {
-    echo "SIGTERM signal received, try to gracefully shutdown all services..."
-    gitlab-ctl stop
-}
-
-trap "sigterm_handler; exit" TERM
-
-function entrypoint() {
-    /opt/gitlab/embedded/bin/runsvdir-start &
-    gitlab-ctl reconfigure # will also start everything
-    gitlab-ctl tail # tail all logs
-}
-
-if [[ ! -e /etc/gitlab/gitlab.rb ]]; then
-	cp /assets/gitlab.rb /etc/gitlab/gitlab.rb
-	chmod 0600 /etc/gitlab/gitlab.rb
-fi
-
-entrypoint
diff --git a/docker/fig.yml b/docker/fig.yml
deleted file mode 100644
index 989551cbfe278212c0eaa192ebc93f5f7d1ca9bc..0000000000000000000000000000000000000000
--- a/docker/fig.yml
+++ /dev/null
@@ -1,2 +0,0 @@
-app:
-  build: .
diff --git a/docker/marathon.json b/docker/marathon.json
deleted file mode 100644
index 9b2091a8c224888003e1749d481521ee1da38576..0000000000000000000000000000000000000000
--- a/docker/marathon.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
-  "id": "/gitlab",
-  "ports": [0,0],
-  "cpus": 2,
-  "mem": 2048.0,
-  "disk": 10240.0,
-  "container": {
-    "type": "DOCKER",
-    "docker": {
-      "network": "HOST",
-      "image": "gitlab/gitlab-ce:latest"
-    },
-    "volumes": [
-      {
-          "containerPath": "/etc/gitlab",
-          "hostPath": "/var/data/etc/gitlab",
-          "mode": "RW"
-      },
-      {
-          "containerPath": "/var/opt/gitlab",
-          "hostPath": "/var/data/opt/gitlab",
-          "mode": "RW"
-      },
-      {
-          "containerPath": "/var/log/gitlab",
-          "hostPath": "/var/data/log/gitlab",
-          "mode": "RW"
-      }
-    ]
-  }
-}
\ No newline at end of file
diff --git a/docker/troubleshooting.md b/docker/troubleshooting.md
deleted file mode 100644
index 63482547daa832aa70446f9a37f42b6b283f1993..0000000000000000000000000000000000000000
--- a/docker/troubleshooting.md
+++ /dev/null
@@ -1,84 +0,0 @@
-# Troubleshooting
-
-This is to troubleshoot https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/245
-But it might contain useful commands for other cases as well.
-
-The configuration to add the postgres log in vim is:
-postgresql['log_directory'] = '/var/log/gitlab/postgresql'
-
-# Commands
-
-```bash
-sudo docker build --tag gitlab/gitlab-ce:latest docker/
-
-sudo docker rm -f gitlab
-
-sudo docker exec -it gitlab vim /etc/gitlab/gitlab.rb
-
-sudo docker exec gitlab tail -f /var/log/gitlab/reconfigure.log
-
-sudo docker exec gitlab tail -f /var/log/gitlab/postgresql/current
-
-sudo docker exec gitlab cat /var/opt/gitlab/postgresql/data/postgresql.conf | grep shared_buffers
-
-sudo docker exec gitlab cat /etc/gitlab/gitlab.rb
-```
-
-# Interactively
-
-```bash
-# First start a GitLab container without starting GitLab
-# This is almost the same as starting the GitLab container except:
-# - we run interactively (-t -i)
-# - we define TERM=linux because it allows to use arrow keys in vi (!!!)
-# - we choose another startup command (bash)
-sudo docker run --ti \
-    -e TERM=linux
-	--publish 80443:443 --publish 8080:80 --publish 2222:22 \
-	--name gitlab \
-	--restart always \
-	--volume /srv/gitlab/config:/etc/gitlab \
-	--volume /srv/gitlab/logs:/var/log/gitlab \
-	--volume /srv/gitlab/data:/var/opt/gitlab \
-	gitlab/gitlab-ce:latest \
-	bash
-
-# Configure GitLab to redirect PostgreSQL logs
-echo "postgresql['log_directory'] = '/var/log/gitlab/postgresql'" >> /etc/gitlab/gitlab.rb
-
-# Prevent Postgres from allocating 25% of total memory
-echo "postgresql['shared_buffers'] = '1MB'" >> /etc/gitlab/gitlab.rb
-
-# You can now start GitLab manually from Bash (in the background)
-# Maybe the command below is still missing something to run in the background
-gitlab-ctl reconfigure > /var/log/gitlab/reconfigure.log & /opt/gitlab/embedded/bin/runsvdir-start &
-
-# Inspect PostgreSQL config
-cat /var/opt/gitlab/postgresql/data/postgresql.conf | grep shared_buffers
-
-# And tail the logs (PostgreSQL log may not exist immediately)
-tail -f /var/log/gitlab/reconfigure.log /var/log/gitlab/postgresql/current
-
-# And get the memory
-cat /proc/meminfo
-head /proc/sys/kernel/shmmax /proc/sys/kernel/shmall
-free -m
-
-```
-
-# Cleanup
-
-Remove ALL docker containers and images (also non GitLab ones).
-**Be careful, because the `-v` also removes volumes attached to the images.**
-
-```bash
-# Remove all containers with attached volumes
-docker rm -v $(docker ps -a -q)
-
-# Remove all images
-docker rmi $(docker images -q)
-
-# Remove GitLab persistent data
-rm -rf /srv/gitlab
-```
-
diff --git a/features/abuse_report.feature b/features/abuse_report.feature
index 3e1cb455b774c3d5795802869fb50a15bc05a43a..212972a762a61fabd9c8c8ec1bb4bed853f75bca 100644
--- a/features/abuse_report.feature
+++ b/features/abuse_report.feature
@@ -8,3 +8,10 @@ Feature: Abuse reports
     And I click "Report abuse" button
     When I fill and submit abuse form
     Then I should see success message
+
+  Scenario: Report abuse available only once
+    Given I visit "Mike" user page
+    And I click "Report abuse" button
+    When I fill and submit abuse form
+    And I visit "Mike" user page
+    Then I should see a red "Report abuse" button
diff --git a/features/dashboard/new_project.feature b/features/dashboard/new_project.feature
index bbd82a85e3a719b44da8cb24a07e6cc089b8ef29..763920683570d31726b29c602cf5b46c977e5676 100644
--- a/features/dashboard/new_project.feature
+++ b/features/dashboard/new_project.feature
@@ -7,24 +7,24 @@ Background:
   And I click "New project" link
 
   @javascript
-  Scenario: I should see New projects page
-  Then I see "New project" page
+  Scenario: I should see New Projects page
+  Then I see "New Project" page
   Then I see all possible import optios
 
   @javascript
   Scenario: I should see instructions on how to import from Git URL
-  Given I see "New project" page
+  Given I see "New Project" page
   When I click on "Any repo by URL"
   Then I see instructions on how to import from Git URL
 
   @javascript
   Scenario: I should see instructions on how to import from GitHub
-  Given I see "New project" page
+  Given I see "New Project" page
   When I click on "Import project from GitHub"
   Then I see instructions on how to import from GitHub
 
   @javascript
   Scenario: I should see Google Code import page
-  Given I see "New project" page
+  Given I see "New Project" page
   When I click on "Google Code"
   Then I redirected to Google Code import page
diff --git a/features/project/commits/commits.feature b/features/project/commits/commits.feature
index 34161b81d44cde307683cf64c393f662583ac20a..e4beeb59adc38a3ceb46c7db3d71d631e05090ff 100644
--- a/features/project/commits/commits.feature
+++ b/features/project/commits/commits.feature
@@ -20,6 +20,8 @@ Feature: Project Commits
     Given commit has ci status
     And I click on commit link
     Then I see commit ci info
+    And I click status link
+    Then I see builds list
 
   Scenario: I browse commit with side-by-side diff view
     Given I click on commit link
diff --git a/features/project/merge_requests.feature b/features/project/merge_requests.feature
index 947f668e432cab53a0494a70b1e7b978ba866a76..83055188bac82d399a9b048840c2c8b71119e8f7 100644
--- a/features/project/merge_requests.feature
+++ b/features/project/merge_requests.feature
@@ -115,40 +115,40 @@ Feature: Project Merge Requests
     Given project "Shop" have "Bug NS-05" open merge request with diffs inside
     And I visit merge request page "Bug NS-05"
     And I click on the Changes tab
-    And I leave a comment like "Line is wrong" on line 39 of the second file
-    And I click link "Hide inline discussion" of the second file
-    Then I should not see a comment like "Line is wrong here" in the second file
+    And I leave a comment like "Line is wrong" on line 39 of the third file
+    And I click link "Hide inline discussion" of the third file
+    Then I should not see a comment like "Line is wrong here" in the third file
 
   @javascript
   Scenario: I show comments on a merge request diff with comments in a single file
     Given project "Shop" have "Bug NS-05" open merge request with diffs inside
     And I visit merge request page "Bug NS-05"
     And I click on the Changes tab
-    And I leave a comment like "Line is wrong" on line 39 of the second file
-    Then I should see a comment like "Line is wrong" in the second file
+    And I leave a comment like "Line is wrong" on line 39 of the third file
+    Then I should see a comment like "Line is wrong" in the third file
 
   @javascript
   Scenario: I hide comments on a merge request diff with comments in multiple files
     Given project "Shop" have "Bug NS-05" open merge request with diffs inside
     And I visit merge request page "Bug NS-05"
     And I click on the Changes tab
-    And I leave a comment like "Line is correct" on line 12 of the first file
-    And I leave a comment like "Line is wrong" on line 39 of the second file
-    And I click link "Hide inline discussion" of the second file
-    Then I should not see a comment like "Line is wrong here" in the second file
-    And I should still see a comment like "Line is correct" in the first file
+    And I leave a comment like "Line is correct" on line 12 of the second file
+    And I leave a comment like "Line is wrong" on line 39 of the third file
+    And I click link "Hide inline discussion" of the third file
+    Then I should not see a comment like "Line is wrong here" in the third file
+    And I should still see a comment like "Line is correct" in the second file
 
   @javascript
   Scenario: I show comments on a merge request diff with comments in multiple files
     Given project "Shop" have "Bug NS-05" open merge request with diffs inside
     And I visit merge request page "Bug NS-05"
     And I click on the Changes tab
-    And I leave a comment like "Line is correct" on line 12 of the first file
-    And I leave a comment like "Line is wrong" on line 39 of the second file
-    And I click link "Hide inline discussion" of the second file
-    And I click link "Show inline discussion" of the second file
-    Then I should see a comment like "Line is wrong" in the second file
-    And I should still see a comment like "Line is correct" in the first file
+    And I leave a comment like "Line is correct" on line 12 of the second file
+    And I leave a comment like "Line is wrong" on line 39 of the third file
+    And I click link "Hide inline discussion" of the third file
+    And I click link "Show inline discussion" of the third file
+    Then I should see a comment like "Line is wrong" in the third file
+    And I should still see a comment like "Line is correct" in the second file
 
   @javascript
   Scenario: I unfold diff
@@ -163,8 +163,8 @@ Feature: Project Merge Requests
     Given project "Shop" have "Bug NS-05" open merge request with diffs inside
     And I visit merge request page "Bug NS-05"
     And I click on the Changes tab
-    And I leave a comment like "Line is correct" on line 12 of the first file
-    And I leave a comment like "Line is wrong" on line 39 of the second file
+    And I leave a comment like "Line is correct" on line 12 of the second file
+    And I leave a comment like "Line is wrong" on line 39 of the third file
     And I click Side-by-side Diff tab
     Then I should see comments on the side-by-side diff page
 
diff --git a/features/project/project.feature b/features/project/project.feature
index b3fb0794547e4773ee6c57ccccfaf05cfde247c3..1a53945eb04f562a7890d316b33a265a2bf96045 100644
--- a/features/project/project.feature
+++ b/features/project/project.feature
@@ -31,6 +31,12 @@ Feature: Project
     And I visit project "Shop" page
     Then I should see project "Shop" README
 
+  Scenario: I should see last commit with CI
+    Given project "Shop" has CI enabled
+    Given project "Shop" has CI build
+    And I visit project "Shop" page
+    And I should see last commit with CI status
+
   @javascript
   Scenario: I should see project activity
     When I visit project "Shop" activity page
diff --git a/features/project/service.feature b/features/project/service.feature
index fdff640ec857e1ea267fbf77af7d3312a266c2d7..5014b52b9f67a65fbcedfdbd401dd8107741a1d2 100644
--- a/features/project/service.feature
+++ b/features/project/service.feature
@@ -72,6 +72,7 @@ Feature: Project Services
     And I click Atlassian Bamboo CI service link
     And I fill Atlassian Bamboo CI settings
     Then I should see Atlassian Bamboo CI service settings saved
+    And I should see empty field Change Password
 
   Scenario: Activate jetBrains TeamCity CI service
     When I visit project "Shop" services page
diff --git a/features/project/snippets.feature b/features/project/snippets.feature
index 77e42a1a38b93bc146942348a9b24e33d730713a..270557cbde7adfb8e8a250308bf6c6dd1a600ed7 100644
--- a/features/project/snippets.feature
+++ b/features/project/snippets.feature
@@ -30,5 +30,5 @@ Feature: Project Snippets
 
   Scenario: I destroy "Snippet one"
     Given I visit snippet page "Snippet one"
-    And I click link "Remove Snippet"
+    And I click link "Delete"
     Then I should not see "Snippet one" in snippets
diff --git a/features/project/source/browse_files.feature b/features/project/source/browse_files.feature
index 58574166ef3e90a5ab6857970aa31d70215c7613..6b0484b6a38ebcbb95315d5ba093489a6b05f7e2 100644
--- a/features/project/source/browse_files.feature
+++ b/features/project/source/browse_files.feature
@@ -21,12 +21,12 @@ Feature: Project Source Browse Files
     Then I should see raw file content
 
   Scenario: I can create file
-    Given I click on "new file" link in repo
+    Given I click on "New file" link in repo
     Then I can see new file page
 
   @javascript
   Scenario: I can create and commit file
-    Given I click on "new file" link in repo
+    Given I click on "New file" link in repo
     And I edit code
     And I fill the new file name
     And I fill the commit message
@@ -36,14 +36,13 @@ Feature: Project Source Browse Files
 
   @javascript
   Scenario: I can upload file and commit
-    Given I click on "new file" link in repo
-    Then I can see new file page
-    And I can see "upload an existing one"
-    And I click on "upload"
+    Given I click on "Upload file" link in repo
     And I upload a new text file
     And I fill the upload file commit message
+    And I fill the new branch name
     And I click on "Upload file"
     Then I can see the new text file
+    And I am redirected to the uploaded file on new branch
     And I can see the new commit message
 
   @javascript
@@ -59,7 +58,7 @@ Feature: Project Source Browse Files
 
   @javascript
   Scenario: I can create and commit file and specify new branch
-    Given I click on "new file" link in repo
+    Given I click on "New file" link in repo
     And I edit code
     And I fill the new file name
     And I fill the commit message
@@ -83,7 +82,7 @@ Feature: Project Source Browse Files
 
   @javascript
   Scenario: If I enter an illegal file name I see an error message
-    Given I click on "new file" link in repo
+    Given I click on "New file" link in repo
     And I fill the new file name with an illegal name
     And I edit code
     And I fill the commit message
@@ -138,6 +137,24 @@ Feature: Project Source Browse Files
     Then I am on the ".gitignore" edit file page
     And I see a commit error message
 
+  @javascript
+  Scenario: I can create directory in repo
+    When I click on "New directory" link in repo
+    And I fill the new directory name
+    And I fill the commit message
+    And I fill the new branch name
+    And I click on "Create directory"
+    Then I am redirected to the new directory
+
+  @javascript
+  Scenario: I attempt to create an existing directory
+    When I click on "New directory" link in repo
+    And I fill an existing directory name
+    And I fill the commit message
+    And I click on "Create directory"
+    Then I see "Unable to create directory"
+    And I am redirected to the root directory
+
   @javascript
   Scenario: I can see editing preview
     Given I click on ".gitignore" file in repo
@@ -188,3 +205,9 @@ Feature: Project Source Browse Files
     And I see the ref 'test' has been selected
     And I visit the 'test' tree
     Then I see the commit data
+
+  @javascript
+  Scenario: I browse code with a leading dot in the directory
+    Given I switch ref to fix
+    And I visit the fix tree
+    Then I see the commit data for a directory with a leading dot
diff --git a/features/snippets/snippets.feature b/features/snippets/snippets.feature
index 4f617b6bed820cf16922048381e14d1ffb302144..e15d7c79342e7d38d74f7b758ba02e5d629a4586 100644
--- a/features/snippets/snippets.feature
+++ b/features/snippets/snippets.feature
@@ -24,7 +24,7 @@ Feature: Snippets
 
   Scenario: I destroy "Personal snippet one"
     Given I visit snippet page "Personal snippet one"
-    And I click link "Destroy"
+    And I click link "Delete"
     Then I should not see "Personal snippet one" in snippets
 
   Scenario: I create new internal snippet
diff --git a/features/steps/abuse_reports.rb b/features/steps/abuse_reports.rb
index 8f9ddb2899fb62a6c9f14d9565a54e907335d81c..499accb0b080a5d7499a6988c05e535ba6afea16 100644
--- a/features/steps/abuse_reports.rb
+++ b/features/steps/abuse_reports.rb
@@ -22,6 +22,10 @@ class Spinach::Features::AbuseReports < Spinach::FeatureSteps
     user_mike
   end
 
+  step 'I should see a red "Report abuse" button' do
+    expect(page).to have_button("Already reported for abuse")
+  end
+
   def user_mike
     @user_mike ||= create(:user, name: 'Mike')
   end
diff --git a/features/steps/admin/labels.rb b/features/steps/admin/labels.rb
index d64380abf73c84d9d4314f3a6683c7aa09d9c750..b45d98658bc83ac9a8894c99d005d9c97845e5d7 100644
--- a/features/steps/admin/labels.rb
+++ b/features/steps/admin/labels.rb
@@ -38,7 +38,7 @@ class Spinach::Features::AdminIssuesLabels < Spinach::FeatureSteps
 
   step 'I should see labels help message' do
     page.within '.labels' do
-      expect(page).to have_content 'There are no any labels yet'
+      expect(page).to have_content 'There are no labels yet'
     end
   end
 
diff --git a/features/steps/admin/projects.rb b/features/steps/admin/projects.rb
index 17233f89f38adb2fc2332c1b11e801a4216eca67..5a1cc9aa15145c6f190efef66e92cd6d617f1112 100644
--- a/features/steps/admin/projects.rb
+++ b/features/steps/admin/projects.rb
@@ -41,6 +41,8 @@ class Spinach::Features::AdminProjects < Spinach::FeatureSteps
   end
 
   step 'I transfer project to group \'Web\'' do
+    allow_any_instance_of(Projects::TransferService).
+      to receive(:move_uploads_to_new_namespace).and_return(true)
     find(:xpath, "//input[@id='new_namespace_id']").set group.id
     click_button 'Transfer'
   end
diff --git a/features/steps/dashboard/new_project.rb b/features/steps/dashboard/new_project.rb
index 1e09162a5b513db22c97633c1273f524da9e9c5b..44a4aa9844a239384b943f2f21db51d39f40b3ef 100644
--- a/features/steps/dashboard/new_project.rb
+++ b/features/steps/dashboard/new_project.rb
@@ -3,13 +3,13 @@ class Spinach::Features::NewProject < Spinach::FeatureSteps
   include SharedPaths
   include SharedProject
 
-  step 'I click "New project" link' do
+  step 'I click "New Project" link' do
     page.within('.content') do
-      click_link "New project"
+      click_link "New Project"
     end
   end
 
-  step 'I see "New project" page' do
+  step 'I see "New Project" page' do
     expect(page).to have_content('Project path')
   end
 
diff --git a/features/steps/groups.rb b/features/steps/groups.rb
index 95bc9baf8d82abf5cccf5e8779c22f050e518097..69ddfa42c062df0d9f9b3d49b0c6bdd889d6ec46 100644
--- a/features/steps/groups.rb
+++ b/features/steps/groups.rb
@@ -282,9 +282,9 @@ class Spinach::Features::Groups < Spinach::FeatureSteps
     milestone1_project2 = create :milestone,
                             title: "Version 7.2",
                             project: project2
-    milestone1_project3 = create :milestone,
-                            title: "Version 7.2",
-                            project: @project3
+    create :milestone,
+      title: "Version 7.2",
+      project: @project3
     milestone2_project1 = create :milestone,
                             title: "GL-113",
                             project: @project1
@@ -301,28 +301,28 @@ class Spinach::Features::Groups < Spinach::FeatureSteps
                assignee: current_user,
                author: current_user,
                milestone: milestone2_project1
-    issue2 = create :issue,
-               project: project2,
-               assignee: current_user,
-               author: current_user,
-               milestone: milestone1_project2
-    issue3 = create :issue,
-               project: @project3,
-               assignee: current_user,
-               author: current_user,
-               milestone: milestone1_project1
-    mr1 = create :merge_request,
-            source_project: @project1,
-            target_project: @project1,
-            assignee: current_user,
-            author: current_user,
-            milestone: milestone2_project1
-    mr2 = create :merge_request,
-            source_project: project2,
-            target_project: project2,
-            assignee: current_user,
-            author: current_user,
-            milestone: milestone2_project2
+    create :issue,
+      project: project2,
+      assignee: current_user,
+      author: current_user,
+      milestone: milestone1_project2
+    create :issue,
+      project: @project3,
+      assignee: current_user,
+      author: current_user,
+      milestone: milestone1_project1
+    create :merge_request,
+      source_project: @project1,
+      target_project: @project1,
+      assignee: current_user,
+      author: current_user,
+      milestone: milestone2_project1
+    create :merge_request,
+      source_project: project2,
+      target_project: project2,
+      assignee: current_user,
+      author: current_user,
+      milestone: milestone2_project2
     @mr3 = create :merge_request,
             source_project: @project3,
             target_project: @project3,
diff --git a/features/steps/project/commits/commits.rb b/features/steps/project/commits/commits.rb
index 56f1f06fb06867c3e3295d75c14cbc303aecd869..e5b3f27135da84d9ec21e8b0dc0cf23a7d032904 100644
--- a/features/steps/project/commits/commits.rb
+++ b/features/steps/project/commits/commits.rb
@@ -103,11 +103,21 @@ class Spinach::Features::ProjectCommits < Spinach::FeatureSteps
   end
 
   step 'commit has ci status' do
-    @project.enable_ci(@user)
-    create :ci_commit, project: @project.gitlab_ci_project, sha: sample_commit.id
+    @project.enable_ci
+    ci_commit = create :ci_commit, gl_project: @project, sha: sample_commit.id
+    create :ci_build, commit: ci_commit
   end
 
   step 'I see commit ci info' do
-    expect(page).to have_content "build: skipped"
+    expect(page).to have_content "build: pending"
+  end
+
+  step 'I click status link' do
+    find('.commit-ci-menu').click_link "Builds"
+  end
+
+  step 'I see builds list' do
+    expect(page).to have_content "build: pending"
+    expect(page).to have_content "Latest builds"
   end
 end
diff --git a/features/steps/project/fork.rb b/features/steps/project/fork.rb
index 370960845cc5c4340137bcfdfa68fdf7d0645f7b..b0230add34f9e96410eab16a6ec6b9cd64a1a981 100644
--- a/features/steps/project/fork.rb
+++ b/features/steps/project/fork.rb
@@ -5,8 +5,7 @@ class Spinach::Features::ProjectFork < Spinach::FeatureSteps
 
   step 'I click link "Fork"' do
     expect(page).to have_content "Shop"
-    expect(page).to have_content "Fork"
-    click_link "Fork"
+    click_link "Fork project"
   end
 
   step 'I am a member of project "Shop"' do
diff --git a/features/steps/project/graph.rb b/features/steps/project/graph.rb
index 9453d636445d973540e49224a17dcfcb35378198..4abd5288d51de108d9467bafed76fa1ddb2de36f 100644
--- a/features/steps/project/graph.rb
+++ b/features/steps/project/graph.rb
@@ -32,6 +32,6 @@ class Spinach::Features::ProjectGraph < Spinach::FeatureSteps
   end
 
   def project
-    project ||= Project.find_by(name: "Shop")
+    @project ||= Project.find_by(name: "Shop")
   end
 end
diff --git a/features/steps/project/issues/issues.rb b/features/steps/project/issues/issues.rb
index 239392eab9673ad7ad4de86d4038de16684acbde..af2da41badb220f0fa07e965fc9d079242a43d96 100644
--- a/features/steps/project/issues/issues.rb
+++ b/features/steps/project/issues/issues.rb
@@ -223,11 +223,11 @@ class Spinach::Features::ProjectIssues < Spinach::FeatureSteps
   end
 
   step 'project \'Shop\' has issue \'Bugfix1\' with description: \'Description for issue1\'' do
-    issue = create(:issue, title: 'Bugfix1', description: 'Description for issue1', project: project)
+    create(:issue, title: 'Bugfix1', description: 'Description for issue1', project: project)
   end
 
   step 'project \'Shop\' has issue \'Feature1\' with description: \'Feature submitted for issue1\'' do
-    issue = create(:issue, title: 'Feature1', description: 'Feature submitted for issue1', project: project)
+    create(:issue, title: 'Feature1', description: 'Feature submitted for issue1', project: project)
   end
 
   step 'I fill in issue search with \'Description for issue1\'' do
diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb
index c92998631ff85edb9d400158ba2ed34117a6e03a..875bf6c4676096455410eed1cab449c52436671f 100644
--- a/features/steps/project/merge_requests.rb
+++ b/features/steps/project/merge_requests.rb
@@ -224,43 +224,43 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
     end
   end
 
-  step 'I click link "Hide inline discussion" of the second file' do
-    page.within '.files [id^=diff]:nth-child(2)' do
+  step 'I click link "Hide inline discussion" of the third file' do
+    page.within '.files [id^=diff]:nth-child(3)' do
       find('.js-toggle-diff-comments').trigger('click')
     end
   end
 
-  step 'I click link "Show inline discussion" of the second file' do
-    page.within '.files [id^=diff]:nth-child(2)' do
+  step 'I click link "Show inline discussion" of the third file' do
+    page.within '.files [id^=diff]:nth-child(3)' do
       find('.js-toggle-diff-comments').trigger('click')
     end
   end
 
-  step 'I should not see a comment like "Line is wrong" in the second file' do
-    page.within '.files [id^=diff]:nth-child(2)' do
+  step 'I should not see a comment like "Line is wrong" in the third file' do
+    page.within '.files [id^=diff]:nth-child(3)' do
       expect(page).not_to have_visible_content "Line is wrong"
     end
   end
 
-  step 'I should see a comment like "Line is wrong" in the second file' do
-    page.within '.files [id^=diff]:nth-child(2) .note-body > .note-text' do
+  step 'I should see a comment like "Line is wrong" in the third file' do
+    page.within '.files [id^=diff]:nth-child(3) .note-body > .note-text' do
       expect(page).to have_visible_content "Line is wrong"
     end
   end
 
-  step 'I should not see a comment like "Line is wrong here" in the second file' do
-    page.within '.files [id^=diff]:nth-child(2)' do
+  step 'I should not see a comment like "Line is wrong here" in the third file' do
+    page.within '.files [id^=diff]:nth-child(3)' do
       expect(page).not_to have_visible_content "Line is wrong here"
     end
   end
 
-  step 'I should see a comment like "Line is wrong here" in the second file' do
-    page.within '.files [id^=diff]:nth-child(2) .note-body > .note-text' do
+  step 'I should see a comment like "Line is wrong here" in the third file' do
+    page.within '.files [id^=diff]:nth-child(3) .note-body > .note-text' do
       expect(page).to have_visible_content "Line is wrong here"
     end
   end
 
-  step 'I leave a comment like "Line is correct" on line 12 of the first file' do
+  step 'I leave a comment like "Line is correct" on line 12 of the second file' do
     init_diff_note_first_file
 
     page.within(".js-discussion-note-form") do
@@ -268,12 +268,12 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
       click_button "Add Comment"
     end
 
-    page.within ".files [id^=diff]:nth-child(1) .note-body > .note-text" do
+    page.within ".files [id^=diff]:nth-child(2) .note-body > .note-text" do
       expect(page).to have_content "Line is correct"
     end
   end
 
-  step 'I leave a comment like "Line is wrong" on line 39 of the second file' do
+  step 'I leave a comment like "Line is wrong" on line 39 of the third file' do
     init_diff_note_second_file
 
     page.within(".js-discussion-note-form") do
@@ -282,8 +282,8 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
     end
   end
 
-  step 'I should still see a comment like "Line is correct" in the first file' do
-    page.within '.files [id^=diff]:nth-child(1) .note-body > .note-text' do
+  step 'I should still see a comment like "Line is correct" in the second file' do
+    page.within '.files [id^=diff]:nth-child(2) .note-body > .note-text' do
       expect(page).to have_visible_content "Line is correct"
     end
   end
@@ -303,7 +303,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
   end
 
   step 'I should see comments on the side-by-side diff page' do
-    page.within '.files [id^=diff]:nth-child(1) .parallel .note-body > .note-text' do
+    page.within '.files [id^=diff]:nth-child(2) .parallel .note-body > .note-text' do
       expect(page).to have_visible_content "Line is correct"
     end
   end
diff --git a/features/steps/project/project.rb b/features/steps/project/project.rb
index 15f77734cb2053014828b638797aa7a3cf40286d..d76891d5bdebb426d8ace148e69bee65cf2aafa8 100644
--- a/features/steps/project/project.rb
+++ b/features/steps/project/project.rb
@@ -86,13 +86,13 @@ class Spinach::Features::Project < Spinach::FeatureSteps
   end
 
   step 'I should see project "Forum" README' do
-    page.within('#README') do
+    page.within('.readme-holder') do
       expect(page).to have_content 'Sample repo for testing gitlab features'
     end
   end
 
   step 'I should see project "Shop" README' do
-    page.within('#README') do
+    page.within('.readme-holder') do
       expect(page).to have_content 'testme'
     end
   end
diff --git a/features/steps/project/redirects.rb b/features/steps/project/redirects.rb
index 0e724138a8ab2a55eaa024154984ce240f640a38..1ffd5cb9de55f2a868156290d320214a9c7127d1 100644
--- a/features/steps/project/redirects.rb
+++ b/features/steps/project/redirects.rb
@@ -39,7 +39,6 @@ class Spinach::Features::ProjectRedirects < Spinach::FeatureSteps
 
   step 'Authenticate' do
     admin = create(:admin)
-    project = Project.find_by(name: 'Community')
     fill_in "user_login", with: admin.email
     fill_in "user_password", with: admin.password
     click_button "Sign in"
@@ -54,7 +53,6 @@ class Spinach::Features::ProjectRedirects < Spinach::FeatureSteps
 
   step 'I get redirected to signin page where I sign in' do
     admin = create(:admin)
-    project = Project.find_by(name: 'Enterprise')
     fill_in "user_login", with: admin.email
     fill_in "user_password", with: admin.password
     click_button "Sign in"
diff --git a/features/steps/project/services.rb b/features/steps/project/services.rb
index d3b462bfd31116eebff6aa694c2aaf7a0f1eb94d..1c700df0c631cc64bdbc7fc99764558f57d438cf 100644
--- a/features/steps/project/services.rb
+++ b/features/steps/project/services.rb
@@ -202,6 +202,10 @@ class Spinach::Features::ProjectServices < Spinach::FeatureSteps
     expect(find_field('Username').value).to eq 'user'
   end
 
+  step 'I should see empty field Change Password' do
+    expect(find_field('Change Password').value).to be_nil
+  end
+
   step 'I click JetBrains TeamCity CI service link' do
     click_link 'JetBrains TeamCity CI'
   end
diff --git a/features/steps/project/snippets.rb b/features/steps/project/snippets.rb
index db8ad08bb9e9c098bc012c21b653ec8aaa601419..a3aef9bf8c30c417093bb70d34489fd6b05a93fd 100644
--- a/features/steps/project/snippets.rb
+++ b/features/steps/project/snippets.rb
@@ -22,7 +22,7 @@ class Spinach::Features::ProjectSnippets < Spinach::FeatureSteps
   end
 
   step 'I click link "New Snippet"' do
-    click_link "Add new snippet"
+    click_link "New Snippet"
   end
 
   step 'I click link "Snippet one"' do
@@ -42,13 +42,13 @@ class Spinach::Features::ProjectSnippets < Spinach::FeatureSteps
   end
 
   step 'I click link "Edit"' do
-    page.within ".file-title" do
+    page.within ".page-title" do
       click_link "Edit"
     end
   end
 
-  step 'I click link "Remove Snippet"' do
-    click_link "remove"
+  step 'I click link "Delete"' do
+    click_link "Delete"
   end
 
   step 'I submit new snippet "Snippet three"' do
diff --git a/features/steps/project/source/browse_files.rb b/features/steps/project/source/browse_files.rb
index a1a49dd58a60c3a780ed612dafce054172b6ae48..1b27500497aed85d395f09052d162c7c15390965 100644
--- a/features/steps/project/source/browse_files.rb
+++ b/features/steps/project/source/browse_files.rb
@@ -71,7 +71,7 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
   end
 
   step 'I fill the new branch name' do
-    fill_in :new_branch, with: 'new_branch_name'
+    fill_in :new_branch, with: 'new_branch_name', visible: true
   end
 
   step 'I fill the new file name with an illegal name' do
@@ -90,6 +90,10 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
     click_button 'Commit Changes'
   end
 
+  step 'I click on "Create directory"' do
+    click_button 'Create directory'
+  end
+
   step 'I click on "Remove"' do
     click_button 'Remove'
   end
@@ -110,21 +114,32 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
     expect(page).to have_css '.line_holder.new'
   end
 
-  step 'I click on "new file" link in repo' do
-    click_link 'new-file-link'
+  step 'I click on "New file" link in repo' do
+    find('.add-to-tree').click
+    click_link 'Create file'
   end
 
-  step 'I can see new file page' do
-    expect(page).to have_content "new file"
-    expect(page).to have_content "Commit message"
+  step 'I click on "Upload file" link in repo' do
+    find('.add-to-tree').click
+    click_link 'Upload file'
+  end
+
+  step 'I click on "New directory" link in repo' do
+    find('.add-to-tree').click
+    click_link 'New directory'
+  end
+
+  step 'I fill the new directory name' do
+    fill_in :dir_name, with: new_dir_name
   end
 
-  step 'I can see "upload an existing one"' do
-    expect(page).to have_content "upload an existing one"
+  step 'I fill an existing directory name' do
+    fill_in :dir_name, with: 'files'
   end
 
-  step 'I click on "upload"' do
-    click_link 'upload'
+  step 'I can see new file page' do
+    expect(page).to have_content "new file"
+    expect(page).to have_content "Commit message"
   end
 
   step 'I click on "Upload file"' do
@@ -228,10 +243,30 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
       @project.namespace, @project, 'new_branch_name/' + new_file_name))
   end
 
+  step 'I am redirected to the uploaded file on new branch' do
+    expect(current_path).to eq(namespace_project_blob_path(
+      @project.namespace, @project,
+      'new_branch_name/' + File.basename(test_text_file)))
+  end
+
+  step 'I am redirected to the new directory' do
+    expect(current_path).to eq(namespace_project_tree_path(
+      @project.namespace, @project, 'new_branch_name/' + new_dir_name))
+  end
+
+  step 'I am redirected to the root directory' do
+    expect(current_path).to eq(namespace_project_tree_path(
+      @project.namespace, @project, 'master/'))
+  end
+
   step "I don't see the permalink link" do
     expect(page).not_to have_link('permalink')
   end
 
+  step 'I see "Unable to create directory"' do
+    expect(page).to have_content('Directory already exists')
+  end
+
   step 'I see a commit error message' do
     expect(page).to have_content('Your changes could not be committed')
   end
@@ -251,6 +286,10 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
     select "'test'", from: 'ref'
   end
 
+  step "I switch ref to fix" do
+    select "fix", from: 'ref'
+  end
+
   step "I see the ref 'test' has been selected" do
     expect(page).to have_selector '.select2-chosen', text: "'test'"
   end
@@ -259,11 +298,20 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
     visit namespace_project_tree_path(@project.namespace, @project, "'test'")
   end
 
+  step "I visit the fix tree" do
+    visit namespace_project_tree_path(@project.namespace, @project, "fix/.testdir")
+  end
+
   step 'I see the commit data' do
     expect(page).to have_css('.tree-commit-link', visible: true)
     expect(page).not_to have_content('Loading commit data...')
   end
 
+  step 'I see the commit data for a directory with a leading dot' do
+    expect(page).to have_css('.tree-commit-link', visible: true)
+    expect(page).not_to have_content('Loading commit data...')
+  end
+
   private
 
   def set_new_content
@@ -287,6 +335,12 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
     'not_a_file.md'
   end
 
+  # Constant value that is a valid directory and
+  # not a directory present at root of the seed repository.
+  def new_dir_name
+    'new_dir/subdir'
+  end
+
   def drop_in_dropzone(file_path)
     # Generate a fake input selector
     page.execute_script <<-JS
diff --git a/features/steps/shared/group.rb b/features/steps/shared/group.rb
index 2d17fb34ccbf6dcf25e79e90a82ad5561fdd2f88..83a04576973d9e2e7f7602e26bb2b0f45c364d03 100644
--- a/features/steps/shared/group.rb
+++ b/features/steps/shared/group.rb
@@ -37,7 +37,7 @@ module SharedGroup
     group = Group.find_by(name: groupname) || create(:group, name: groupname)
     group.add_user(user, role)
     project ||= create(:project, namespace: group, path: "project#{@project_count}")
-    event   ||= create(:closed_issue_event, project: project)
+    create(:closed_issue_event, project: project)
     project.team << [user, :master]
     @project_count += 1
   end
diff --git a/features/steps/shared/project.rb b/features/steps/shared/project.rb
index fa841f67510a68550d7f77b2afe87f50096cc576..7021fac5fe4b4c5ab0b0548aa4cf16f921bb75e4 100644
--- a/features/steps/shared/project.rb
+++ b/features/steps/shared/project.rb
@@ -199,11 +199,18 @@ module SharedProject
 
   step 'project "Shop" has CI enabled' do
     project = Project.find_by(name: "Shop")
-    project.enable_ci(@user)
+    project.enable_ci
   end
 
   step 'project "Shop" has CI build' do
     project = Project.find_by(name: "Shop")
-    create :ci_commit, project: project.gitlab_ci_project, sha: project.commit.sha
+    create :ci_commit, gl_project: project, sha: project.commit.sha
+  end
+
+  step 'I should see last commit with CI status' do
+    page.within ".project-last-commit" do
+      expect(page).to have_content(project.commit.sha[0..6])
+      expect(page).to have_content("skipped")
+    end
   end
 end
diff --git a/features/steps/snippets/snippets.rb b/features/steps/snippets/snippets.rb
index 6ff48e0c6b8eed0405532831d94699c5197af1f3..80d1ddeef055177d7df0d3ef3e2e46843e2a3609 100644
--- a/features/steps/snippets/snippets.rb
+++ b/features/steps/snippets/snippets.rb
@@ -13,13 +13,13 @@ class Spinach::Features::Snippets < Spinach::FeatureSteps
   end
 
   step 'I click link "Edit"' do
-    page.within ".file-title" do
+    page.within ".page-title" do
       click_link "Edit"
     end
   end
 
-  step 'I click link "Destroy"' do
-    click_link "remove"
+  step 'I click link "Delete"' do
+    click_link "Delete"
   end
 
   step 'I submit new snippet "Personal snippet three"' do
diff --git a/features/steps/snippets/user.rb b/features/steps/snippets/user.rb
index dea3256229fca2f612dd069beb4ca6110bfafa22..997c605bce2e595787fd5d8c6ba32273d105592a 100644
--- a/features/steps/snippets/user.rb
+++ b/features/steps/snippets/user.rb
@@ -32,19 +32,19 @@ class Spinach::Features::SnippetsUser < Spinach::FeatureSteps
   end
 
   step 'I click "Internal" filter' do
-    page.within('.nav-tabs') do
+    page.within('.snippet-scope-menu') do
       click_link "Internal"
     end
   end
 
   step 'I click "Private" filter' do
-    page.within('.nav-tabs') do
+    page.within('.snippet-scope-menu') do
       click_link "Private"
     end
   end
 
   step 'I click "Public" filter' do
-    page.within('.nav-tabs') do
+    page.within('.snippet-scope-menu') do
       click_link "Public"
     end
   end
diff --git a/lib/api/api.rb b/lib/api/api.rb
index c09488d3547713f815e9c236f18fe36e909b5aa9..afc0402f9e1d3462ba0b800f1171aed3b087dfce 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -46,6 +46,7 @@ module API
     mount Services
     mount Files
     mount Commits
+    mount CommitStatus
     mount Namespaces
     mount Branches
     mount Labels
diff --git a/lib/api/commit_statuses.rb b/lib/api/commit_statuses.rb
new file mode 100644
index 0000000000000000000000000000000000000000..2c0596c9dfb64cf730fada8ac4bf16157677294d
--- /dev/null
+++ b/lib/api/commit_statuses.rb
@@ -0,0 +1,80 @@
+require 'mime/types'
+
+module API
+  # Project commit statuses API
+  class CommitStatus < Grape::API
+    resource :projects do
+      before { authenticate! }
+
+      # Get a commit's statuses
+      #
+      # Parameters:
+      #   id (required) - The ID of a project
+      #   sha (required) - The commit hash
+      #   ref (optional) - The ref
+      #   stage (optional) - The stage
+      #   name (optional) - The name
+      #   all (optional) - Show all statuses, default: false
+      # Examples:
+      #   GET /projects/:id/repository/commits/:sha/statuses
+      get ':id/repository/commits/:sha/statuses' do
+        authorize! :read_commit_statuses, user_project
+        sha = params[:sha]
+        ci_commit = user_project.ci_commit(sha)
+        not_found! 'Commit' unless ci_commit
+        statuses = ci_commit.statuses
+        statuses = statuses.latest unless parse_boolean(params[:all])
+        statuses = statuses.where(ref: params[:ref]) if params[:ref].present?
+        statuses = statuses.where(stage: params[:stage]) if params[:stage].present?
+        statuses = statuses.where(name: params[:name]) if params[:name].present?
+        present paginate(statuses), with: Entities::CommitStatus
+      end
+
+      # Post status to commit
+      #
+      # Parameters:
+      #   id (required) - The ID of a project
+      #   sha (required) - The commit hash
+      #   ref (optional) - The ref
+      #   state (required) - The state of the status. Can be: pending, running, success, error or failure
+      #   target_url (optional) - The target URL to associate with this status
+      #   description (optional) - A short description of the status
+      #   name or context (optional) - A string label to differentiate this status from the status of other systems. Default: "default"
+      # Examples:
+      #   POST /projects/:id/statuses/:sha
+      post ':id/statuses/:sha' do
+        authorize! :create_commit_status, user_project
+        required_attributes! [:state]
+        attrs = attributes_for_keys [:ref, :target_url, :description, :context, :name]
+        commit = @project.commit(params[:sha])
+        not_found! 'Commit' unless commit
+
+        ci_commit = @project.ensure_ci_commit(commit.sha)
+
+        name = params[:name] || params[:context]
+        status = GenericCommitStatus.running_or_pending.find_by(commit: ci_commit, name: name, ref: params[:ref])
+        status ||= GenericCommitStatus.new(commit: ci_commit, user: current_user)
+        status.update(attrs)
+
+        case params[:state].to_s
+        when 'running'
+          status.run
+        when 'success'
+          status.success
+        when 'failed'
+          status.drop
+        when 'canceled'
+          status.cancel
+        else
+          status.status = params[:state].to_s
+        end
+
+        if status.save
+          present status, with: Entities::CommitStatus
+        else
+          render_validation_error!(status)
+        end
+      end
+    end
+  end
+end
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 9620d36ac4170e459e67ff4458741e1b9fce2fc4..883a5e14b17cea75fc45ed50d82b9fadf7533c19 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -149,6 +149,7 @@ module API
 
     class RepoCommitDetail < RepoCommit
       expose :parent_ids, :committed_date, :authored_date
+      expose :status
     end
 
     class ProjectSnippet < Grape::Entity
@@ -228,6 +229,12 @@ module API
       expose :created_at
     end
 
+    class CommitStatus < Grape::Entity
+      expose :id, :sha, :ref, :status, :name, :target_url, :description,
+             :created_at, :started_at, :finished_at
+      expose :author, using: Entities::UserBasic
+    end
+
     class Event < Grape::Entity
       expose :title, :project_id, :action_name
       expose :target_id, :target_type, :author_id
@@ -255,6 +262,18 @@ module API
       expose :notification_level
     end
 
+    class ProjectService < Grape::Entity
+      expose :id, :title, :created_at, :updated_at, :active
+      expose :push_events, :issues_events, :merge_requests_events, :tag_push_events, :note_events
+      # Expose serialized properties
+      expose :properties do |service, options|
+        field_names = service.fields.
+          select { |field| options[:include_passwords] || field[:type] != 'password' }.
+          map { |field| field[:name] }
+        service.properties.slice(*field_names)
+      end
+    end
+
     class ProjectWithAccess < Project
       expose :permissions do
         expose :project_access, using: Entities::ProjectAccess do |project, options|
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 7fada98fcdc3e0cfd94b487845d426204aecaeea..549b1f9e9a7090d8ca205e54afda4c90834e0886 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -63,11 +63,11 @@ module API
           user_project.build_missing_services
 
           service_method = "#{underscored_service}_service"
-          
+
           send_service(service_method)
         end
       end
-   
+
       @project_service || not_found!("Service")
     end
 
@@ -149,7 +149,6 @@ module API
     end
 
     def attributes_for_keys(keys, custom_params = nil)
-      params_hash = custom_params || params
       attrs = {}
       keys.each do |key|
         if params[key].present? or (params.has_key?(key) and params[key] == false)
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index 63ea2f054386730e65afd4cbe2ec6e2a0afa33aa..6eb84baf9cb0aab677a820a2f4b05ad861e832bd 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -99,7 +99,7 @@ module API
       #   id (required)            - The ID of a project - this will be the source of the merge request
       #   source_branch (required) - The source branch
       #   target_branch (required) - The target branch
-      #   target_project           - The target project of the merge request defaults to the :id of the project
+      #   target_project_id        - The target project of the merge request defaults to the :id of the project
       #   assignee_id              - Assignee user ID
       #   title (required)         - Title of MR
       #   description              - Description of MR
@@ -249,8 +249,16 @@ module API
         required_attributes! [:note]
 
         merge_request = user_project.merge_requests.find(params[:merge_request_id])
-        note = merge_request.notes.new(note: params[:note], project_id: user_project.id)
-        note.author = current_user
+
+        authorize! :create_note, merge_request
+
+        opts = {
+          note: params[:note],
+          noteable_type: 'MergeRequest',
+          noteable_id: merge_request.id
+        }
+
+        note = ::Notes::CreateService.new(user_project, current_user, opts).execute
 
         if note.save
           present note, with: Entities::MRNote
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index c2fb36b41433eeffe4d3fa568f9777d7e137bcaf..67ee66a2058a2be885df8cfe1d820a922d9060b5 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -246,8 +246,8 @@ module API
       # Example Request:
       #  DELETE /projects/:id/fork
       delete ":id/fork" do
-        authenticated_as_admin!
-        unless user_project.forked_project_link.nil?
+        authorize! :remove_fork_project, user_project
+        if user_project.forked?
           user_project.forked_project_link.destroy
         end
       end
diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb
index 2d96c9666d2a907119fecdfcf8948a19e16a0478..20d568cf4626ed9b7b292a11c066c30b0daccc6e 100644
--- a/lib/api/repositories.rb
+++ b/lib/api/repositories.rb
@@ -133,7 +133,7 @@ module API
         authorize! :download_code, user_project
 
         begin
-          file_path = ArchiveRepositoryService.new(
+          ArchiveRepositoryService.new(
             user_project,
             params[:sha],
             params[:format]
@@ -141,17 +141,6 @@ module API
         rescue
           not_found!('File')
         end
-
-        if file_path && File.exists?(file_path)
-          data = File.open(file_path, 'rb').read
-          basename = File.basename(file_path)
-          header['Content-Disposition'] = "attachment; filename=\"#{basename}\""
-          content_type MIME::Types.type_for(file_path).first.content_type
-          env['api.format'] = :binary
-          present data
-        else
-          redirect request.fullpath
-        end
       end
 
       # Compare two branches, tags or commits
diff --git a/lib/api/services.rb b/lib/api/services.rb
index 6727e80ac1e0f10a0e799a974afaa7d2aa730268..203f04a6259203b46ed4ebca5168c6053c0409d5 100644
--- a/lib/api/services.rb
+++ b/lib/api/services.rb
@@ -57,7 +57,7 @@ module API
       #   GET /project/:id/services/gitlab-ci
       #
       get ':id/services/:service_slug' do
-        present project_service
+        present project_service, with: Entities::ProjectService, include_passwords: current_user.is_admin?
       end
     end
   end
diff --git a/lib/backup/manager.rb b/lib/backup/manager.rb
index ac63f89c6ec4f3caef5d09b56f0122dbbcba4355..5c42f25f4a267a3fbd8ad10dd8deb4f8ffe64bba 100644
--- a/lib/backup/manager.rb
+++ b/lib/backup/manager.rb
@@ -45,7 +45,8 @@ module Backup
       directory = connection.directories.get(remote_directory)
 
       if directory.files.create(key: tar_file, body: File.open(tar_file), public: false,
-          multipart_chunk_size: Gitlab.config.backup.upload.multipart_chunk_size)
+          multipart_chunk_size: Gitlab.config.backup.upload.multipart_chunk_size,
+          encryption: Gitlab.config.backup.upload.encryption)
         $progress.puts "done".green
       else
         puts "uploading backup to #{remote_directory} failed".red
@@ -55,7 +56,7 @@ module Backup
 
     def cleanup
       $progress.print "Deleting tmp directories ... "
-      
+
       backup_contents.each do |dir|
         next unless File.exist?(File.join(Gitlab.config.backup.path, dir))
 
@@ -75,7 +76,7 @@ module Backup
 
       if keep_time > 0
         removed = 0
-        
+
         Dir.chdir(Gitlab.config.backup.path) do
           file_list = Dir.glob('*_gitlab_backup.tar')
           file_list.map! { |f| $1.to_i if f =~ /(\d+)_gitlab_backup.tar/ }
diff --git a/lib/ci/api/api.rb b/lib/ci/api/api.rb
index 5109c84e0ea564988fb0e48bdc975d11471c5f7d..218d8c3adccbfb5b32f2610cb6c6a1441e93e558 100644
--- a/lib/ci/api/api.rb
+++ b/lib/ci/api/api.rb
@@ -23,10 +23,6 @@ module Ci
         rack_response({ 'message' => '500 Internal Server Error' }, 500)
       end
 
-      before do
-        check_enable_flag!
-      end
-
       format :json
 
       helpers Helpers
diff --git a/lib/ci/api/commits.rb b/lib/ci/api/commits.rb
index bac463a59096e1797c5ba627cbe1406a6be5b47c..a60769d83059f431585697a4137c2d721febb227 100644
--- a/lib/ci/api/commits.rb
+++ b/lib/ci/api/commits.rb
@@ -51,7 +51,7 @@ module Ci
           required_attributes! [:project_id, :data, :project_token]
           project = Ci::Project.find(params[:project_id])
           authenticate_project_token!(project)
-          commit = Ci::CreateCommitService.new.execute(project, params[:data])
+          commit = Ci::CreateCommitService.new.execute(project, current_user, params[:data])
 
           if commit.persisted?
             present commit, with: Entities::CommitWithBuilds
diff --git a/lib/ci/api/entities.rb b/lib/ci/api/entities.rb
index f47bc1236b818fdbe14e1a9edb0fe1d03a54f23d..b80c0b8b2735427e5703f2175cb939c03e4b1a26 100644
--- a/lib/ci/api/entities.rb
+++ b/lib/ci/api/entities.rb
@@ -2,7 +2,7 @@ module Ci
   module API
     module Entities
       class Commit < Grape::Entity
-        expose :id, :ref, :sha, :project_id, :before_sha, :created_at
+        expose :id, :sha, :project_id, :created_at
         expose :status, :finished_at, :duration
         expose :git_commit_message, :git_author_name, :git_author_email
       end
@@ -12,7 +12,7 @@ module Ci
       end
 
       class Build < Grape::Entity
-        expose :id, :commands, :ref, :sha, :project_id, :repo_url,
+        expose :id, :commands, :ref, :sha, :status, :project_id, :repo_url,
           :before_sha, :allow_git_fetch, :project_name
 
         expose :options do |model|
diff --git a/lib/ci/api/helpers.rb b/lib/ci/api/helpers.rb
index 8e893aa5cc613a7f1c32a18c0b046f0af979b48e..e602cda81d610402356e8e0654752c8ddecb1fdf 100644
--- a/lib/ci/api/helpers.rb
+++ b/lib/ci/api/helpers.rb
@@ -3,12 +3,6 @@ module Ci
     module Helpers
       UPDATE_RUNNER_EVERY = 60
 
-      def check_enable_flag!
-        unless current_application_settings.ci_enabled
-          render_api_error!('400 (Bad request) CI is disabled', 400)
-        end
-      end
-
       def authenticate_runners!
         forbidden! unless params[:token] == GitlabCi::REGISTRATION_TOKEN
       end
diff --git a/lib/ci/api/projects.rb b/lib/ci/api/projects.rb
index 66bcf65e8c4ff3ba56f5e7002c48e61b9b130ebc..d719ad9e8d592f8dfb85084b97ad850e2fbe567d 100644
--- a/lib/ci/api/projects.rb
+++ b/lib/ci/api/projects.rb
@@ -75,23 +75,17 @@ module Ci
         # Create Gitlab CI project using Gitlab project info
         #
         # Parameters:
-        #   name (required)            - The name of the project
         #   gitlab_id (required)       - The gitlab id of the project
-        #   path (required)            - The gitlab project path, ex. randx/six
-        #   ssh_url_to_repo (required) - The gitlab ssh url to the repo
         #   default_ref                - The branch to run against (defaults to `master`)
         # Example Request:
         #   POST /projects
         post do
-          required_attributes! [:name, :gitlab_id, :ssh_url_to_repo]
+          required_attributes! [:gitlab_id]
 
           filtered_params = {
-            name:            params[:name],
             gitlab_id:       params[:gitlab_id],
             # we accept gitlab_url for backward compatibility for a while (added to 7.11)
-            path:            params[:path] || params[:gitlab_url].sub(/.*\/(.*\/.*)$/, '\1'),
-            default_ref:     params[:default_ref] || 'master',
-            ssh_url_to_repo: params[:ssh_url_to_repo]
+            default_ref:     params[:default_ref] || 'master'
           }
 
           project = Ci::Project.new(filtered_params)
@@ -109,11 +103,7 @@ module Ci
         #
         # Parameters:
         #   id (required)   - The ID of a project
-        #   name            - The name of the project
-        #   gitlab_id       - The gitlab id of the project
-        #   path            - The gitlab project path, ex. randx/six
-        #   ssh_url_to_repo - The gitlab ssh url to the repo
-        #   default_ref     - The branch to run against (defaults to `master`)
+        #   default_ref      - The branch to run against (defaults to `master`)
         # Example Request:
         #   PUT /projects/:id
         put ":id" do
@@ -121,12 +111,7 @@ module Ci
 
           unauthorized! unless can?(current_user, :admin_project, project.gl_project)
 
-          attrs = attributes_for_keys [:name, :gitlab_id, :path, :gitlab_url, :default_ref, :ssh_url_to_repo]
-
-          # we accept gitlab_url for backward compatibility for a while (added to 7.11)
-          if attrs[:gitlab_url] && !attrs[:path]
-            attrs[:path] = attrs[:gitlab_url].sub(/.*\/(.*\/.*)$/, '\1')
-          end
+          attrs = attributes_for_keys [:default_ref]
 
           if project.update_attributes(attrs)
             present project, with: Entities::Project
diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb
index e625e790df8f06175a5f7c42ebef95e80bb8dae4..efcd2faffc74b143ffb1ad12904160195585fe1a 100644
--- a/lib/ci/gitlab_ci_yaml_processor.rb
+++ b/lib/ci/gitlab_ci_yaml_processor.rb
@@ -5,7 +5,7 @@ module Ci
     DEFAULT_STAGES = %w(build test deploy)
     DEFAULT_STAGE = 'test'
     ALLOWED_YAML_KEYS = [:before_script, :image, :services, :types, :stages, :variables]
-    ALLOWED_JOB_KEYS = [:tags, :script, :only, :except, :type, :image, :services, :allow_failure, :type, :stage]
+    ALLOWED_JOB_KEYS = [:tags, :script, :only, :except, :type, :image, :services, :allow_failure, :type, :stage, :when]
 
     attr_reader :before_script, :image, :services, :variables
 
@@ -85,13 +85,15 @@ module Ci
 
     def build_job(name, job)
       {
+        stage_idx: stages.index(job[:stage]),
         stage: job[:stage],
-        script: "#{@before_script.join("\n")}\n#{normalize_script(job[:script])}",
-        tags: job[:tags] || [],
+        commands: "#{@before_script.join("\n")}\n#{normalize_script(job[:script])}",
+        tag_list: job[:tags] || [],
         name: name,
         only: job[:only],
         except: job[:except],
         allow_failure: job[:allow_failure] || false,
+        when: job[:when] || 'on_success',
         options: {
           image: job[:image] || @image,
           services: job[:services] || @services
@@ -137,62 +139,74 @@ module Ci
       end
 
       @jobs.each do |name, job|
-        validate_job!("#{name} job", job)
+        validate_job!(name, job)
       end
 
       true
     end
 
     def validate_job!(name, job)
+      if name.blank? || !validate_string(name)
+        raise ValidationError, "job name should be non-empty string"
+      end
+
       job.keys.each do |key|
         unless ALLOWED_JOB_KEYS.include? key
-          raise ValidationError, "#{name}: unknown parameter #{key}"
+          raise ValidationError, "#{name} job: unknown parameter #{key}"
         end
       end
 
-      if !job[:script].is_a?(String) && !validate_array_of_strings(job[:script])
-        raise ValidationError, "#{name}: script should be a string or an array of a strings"
+      if !validate_string(job[:script]) && !validate_array_of_strings(job[:script])
+        raise ValidationError, "#{name} job: script should be a string or an array of a strings"
       end
 
       if job[:stage]
         unless job[:stage].is_a?(String) && job[:stage].in?(stages)
-          raise ValidationError, "#{name}: stage parameter should be #{stages.join(", ")}"
+          raise ValidationError, "#{name} job: stage parameter should be #{stages.join(", ")}"
         end
       end
 
-      if job[:image] && !job[:image].is_a?(String)
-        raise ValidationError, "#{name}: image should be a string"
+      if job[:image] && !validate_string(job[:image])
+        raise ValidationError, "#{name} job: image should be a string"
       end
 
       if job[:services] && !validate_array_of_strings(job[:services])
-        raise ValidationError, "#{name}: services should be an array of strings"
+        raise ValidationError, "#{name} job: services should be an array of strings"
       end
 
       if job[:tags] && !validate_array_of_strings(job[:tags])
-        raise ValidationError, "#{name}: tags parameter should be an array of strings"
+        raise ValidationError, "#{name} job: tags parameter should be an array of strings"
       end
 
       if job[:only] && !validate_array_of_strings(job[:only])
-        raise ValidationError, "#{name}: only parameter should be an array of strings"
+        raise ValidationError, "#{name} job: only parameter should be an array of strings"
       end
 
       if job[:except] && !validate_array_of_strings(job[:except])
-        raise ValidationError, "#{name}: except parameter should be an array of strings"
+        raise ValidationError, "#{name} job: except parameter should be an array of strings"
       end
 
       if job[:allow_failure] && !job[:allow_failure].in?([true, false])
-        raise ValidationError, "#{name}: allow_failure parameter should be an boolean"
+        raise ValidationError, "#{name} job: allow_failure parameter should be an boolean"
+      end
+
+      if job[:when] && !job[:when].in?(%w(on_success on_failure always))
+        raise ValidationError, "#{name} job: when parameter should be on_success, on_failure or always"
       end
     end
 
     private
 
     def validate_array_of_strings(values)
-      values.is_a?(Array) && values.all? {|tag| tag.is_a?(String)}
+      values.is_a?(Array) && values.all? { |value| validate_string(value) }
     end
 
     def validate_variables(variables)
-      variables.is_a?(Hash) && variables.all? {|key, value| key.is_a?(Symbol) && value.is_a?(String)}
+      variables.is_a?(Hash) && variables.all? { |key, value| validate_string(key) && validate_string(value) }
+    end
+
+    def validate_string(value)
+      value.is_a?(String) || value.is_a?(Symbol)
     end
   end
 end
diff --git a/lib/ci/migrate/builds.rb b/lib/ci/migrate/builds.rb
deleted file mode 100644
index c4f62e552959481d8fd9dce257de43dc73523bd3..0000000000000000000000000000000000000000
--- a/lib/ci/migrate/builds.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-module Ci
-  module Migrate
-    class Builds
-      attr_reader :app_builds_dir, :backup_builds_tarball, :backup_dir
-
-      def initialize
-        @app_builds_dir = Settings.gitlab_ci.builds_path
-        @backup_dir = Gitlab.config.backup.path
-        @backup_builds_tarball = File.join(backup_dir, 'builds/builds.tar.gz')
-      end
-
-      def restore
-        backup_existing_builds_dir
-
-        FileUtils.mkdir_p(app_builds_dir, mode: 0700)
-        unless system('tar', '-C', app_builds_dir, '-zxf', backup_builds_tarball)
-          abort 'Restore failed'.red
-        end
-      end
-
-      def backup_existing_builds_dir
-        timestamped_builds_path = File.join(app_builds_dir, '..', "builds.#{Time.now.to_i}")
-        if File.exists?(app_builds_dir)
-          FileUtils.mv(app_builds_dir, File.expand_path(timestamped_builds_path))
-        end
-      end
-    end
-  end
-end
diff --git a/lib/ci/migrate/database.rb b/lib/ci/migrate/database.rb
deleted file mode 100644
index bf9b80f1f624f97e0a61183b204ae0059b0184b6..0000000000000000000000000000000000000000
--- a/lib/ci/migrate/database.rb
+++ /dev/null
@@ -1,67 +0,0 @@
-require 'yaml'
-
-module Ci
-  module Migrate
-    class Database
-      attr_reader :config
-
-      def initialize
-        @config = YAML.load_file(File.join(Rails.root, 'config', 'database.yml'))[Rails.env]
-      end
-
-      def restore
-        decompress_rd, decompress_wr = IO.pipe
-        decompress_pid = spawn(*%W(gzip -cd), out: decompress_wr, in: db_file_name)
-        decompress_wr.close
-
-        restore_pid = case config["adapter"]
-                        when /^mysql/ then
-                          $progress.print "Restoring MySQL database #{config['database']} ... "
-                          # Workaround warnings from MySQL 5.6 about passwords on cmd line
-                          ENV['MYSQL_PWD'] = config["password"].to_s if config["password"]
-                          spawn('mysql', *mysql_args, config['database'], in: decompress_rd)
-                        when "postgresql" then
-                          $progress.print "Restoring PostgreSQL database #{config['database']} ... "
-                          pg_env
-                          spawn('psql', config['database'], in: decompress_rd)
-                      end
-        decompress_rd.close
-
-        success = [decompress_pid, restore_pid].all? { |pid| Process.waitpid(pid); $?.success? }
-        abort 'Restore failed' unless success
-      end
-
-      protected
-
-      def db_file_name
-        File.join(Gitlab.config.backup.path, 'db', 'database.sql.gz')
-      end
-
-      def mysql_args
-        args = {
-          'host' => '--host',
-          'port' => '--port',
-          'socket' => '--socket',
-          'username' => '--user',
-          'encoding' => '--default-character-set'
-        }
-        args.map { |opt, arg| "#{arg}=#{config[opt]}" if config[opt] }.compact
-      end
-
-      def pg_env
-        ENV['PGUSER'] = config["username"] if config["username"]
-        ENV['PGHOST'] = config["host"] if config["host"]
-        ENV['PGPORT'] = config["port"].to_s if config["port"]
-        ENV['PGPASSWORD'] = config["password"].to_s if config["password"]
-      end
-
-      def report_success(success)
-        if success
-          puts '[DONE]'.green
-        else
-          puts '[FAILED]'.red
-        end
-      end
-    end
-  end
-end
diff --git a/lib/ci/migrate/manager.rb b/lib/ci/migrate/manager.rb
deleted file mode 100644
index e5e4fb784eb9c92dd5f41c1c6f84d5a3ebc4ef01..0000000000000000000000000000000000000000
--- a/lib/ci/migrate/manager.rb
+++ /dev/null
@@ -1,72 +0,0 @@
-module Ci
-  module Migrate
-    class Manager
-      CI_IMPORT_PREFIX = '8.0' # Only allow imports from CI 8.0.x
-
-      def cleanup
-        $progress.print "Deleting tmp directories ... "
-
-        backup_contents.each do |dir|
-          next unless File.exist?(File.join(Gitlab.config.backup.path, dir))
-
-          if FileUtils.rm_rf(File.join(Gitlab.config.backup.path, dir))
-            $progress.puts "done".green
-          else
-            puts "deleting tmp directory '#{dir}' failed".red
-            abort 'Backup failed'
-          end
-        end
-      end
-
-      def unpack
-        Dir.chdir(Gitlab.config.backup.path)
-
-        # check for existing backups in the backup dir
-        file_list = Dir.glob("*_gitlab_ci_backup.tar").each.map { |f| f.split(/_/).first.to_i }
-        puts "no backups found" if file_list.count == 0
-
-        if file_list.count > 1 && ENV["BACKUP"].nil?
-          puts "Found more than one backup, please specify which one you want to restore:"
-          puts "rake gitlab:backup:restore BACKUP=timestamp_of_backup"
-          exit 1
-        end
-
-        tar_file = ENV["BACKUP"].nil? ? File.join("#{file_list.first}_gitlab_ci_backup.tar") : File.join(ENV["BACKUP"] + "_gitlab_ci_backup.tar")
-
-        unless File.exists?(tar_file)
-          puts "The specified CI backup doesn't exist!"
-          exit 1
-        end
-
-        $progress.print "Unpacking backup ... "
-
-        unless Kernel.system(*%W(tar -xf #{tar_file}))
-          puts "unpacking backup failed".red
-          exit 1
-        else
-          $progress.puts "done".green
-        end
-
-        ENV["VERSION"] = "#{settings[:db_version]}" if settings[:db_version].to_i > 0
-
-        # restoring mismatching backups can lead to unexpected problems
-        if !settings[:gitlab_version].start_with?(CI_IMPORT_PREFIX)
-          puts "GitLab CI version mismatch:".red
-          puts "  Your current GitLab CI version (#{GitlabCi::VERSION}) differs from the GitLab CI (#{settings[:gitlab_version]}) version in the backup!".red
-          exit 1
-        end
-      end
-
-      private
-
-      def backup_contents
-        ["db", "builds", "backup_information.yml"]
-      end
-
-      def settings
-        @settings ||= YAML.load_file("backup_information.yml")
-      end
-    end
-  end
-end
-
diff --git a/lib/ci/migrate/tags.rb b/lib/ci/migrate/tags.rb
deleted file mode 100644
index 97e043ece27f47b7ebf92c72db7399a58f8143ee..0000000000000000000000000000000000000000
--- a/lib/ci/migrate/tags.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-require 'yaml'
-
-module Ci
-  module Migrate
-    class Tags
-      def restore
-        puts 'Inserting tags...'
-        connection.select_all('SELECT ci_tags.name FROM ci_tags').each do |tag|
-          begin
-            connection.execute("INSERT INTO tags (name) VALUES(#{ActiveRecord::Base::sanitize(tag['name'])})")
-          rescue ActiveRecord::RecordNotUnique
-          end
-        end
-
-        ActiveRecord::Base.transaction do
-          puts 'Deleting old taggings...'
-          connection.execute "DELETE FROM taggings WHERE context = 'tags' AND taggable_type LIKE 'Ci::%'"
-
-          puts 'Inserting taggings...'
-          connection.execute(
-            'INSERT INTO taggings (taggable_type, taggable_id, tag_id, context) ' +
-              "SELECT CONCAT('Ci::', ci_taggings.taggable_type), ci_taggings.taggable_id, tags.id, 'tags' FROM ci_taggings " +
-              'JOIN ci_tags ON ci_tags.id = ci_taggings.tag_id ' +
-              'JOIN tags ON tags.name = ci_tags.name '
-          )
-
-          puts 'Resetting counters... '
-          connection.execute(
-            'UPDATE tags SET ' +
-              'taggings_count = (SELECT COUNT(*) FROM taggings WHERE tags.id = taggings.tag_id)'
-          )
-        end
-      end
-
-      protected
-
-      def connection
-        ActiveRecord::Base.connection
-      end
-    end
-  end
-end
diff --git a/lib/ci/status.rb b/lib/ci/status.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c02b3b8f3e4c6666051edbacae4e0a7620de187e
--- /dev/null
+++ b/lib/ci/status.rb
@@ -0,0 +1,21 @@
+module Ci
+  class Status
+    def self.get_status(statuses)
+      statuses.reject! { |status| status.try(&:allow_failure?) }
+
+      if statuses.none?
+        'skipped'
+      elsif statuses.all?(&:success?)
+        'success'
+      elsif statuses.all?(&:pending?)
+        'pending'
+      elsif statuses.any?(&:running?) || statuses.any?(&:pending?)
+        'running'
+      elsif statuses.all?(&:canceled?)
+        'canceled'
+      else
+        'failed'
+      end
+    end
+  end
+end
diff --git a/lib/event_filter.rb b/lib/event_filter.rb
index 163937c02cfa75007e8e148ebec52c03915b21a3..f15b2cfd231090bc57b49bacd46849fd954120de 100644
--- a/lib/event_filter.rb
+++ b/lib/event_filter.rb
@@ -47,7 +47,7 @@ class EventFilter
 
     actions << Event::COMMENTED if filter.include? 'comments'
 
-    events = events.where(action: actions)
+    events.where(action: actions)
   end
 
   def options(key)
diff --git a/lib/extracts_path.rb b/lib/extracts_path.rb
index 322aed5e27c33e61b071ae87f6407677619673f5..51e46da82ccd24dd61ff938167bc728518d0820f 100644
--- a/lib/extracts_path.rb
+++ b/lib/extracts_path.rb
@@ -110,7 +110,7 @@ module ExtractsPath
                                                       @project, @ref, @path)
 
   rescue RuntimeError, NoMethodError, InvalidPathError
-    not_found!
+    render_404
   end
 
   def tree
diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb
index 0353b3b7ed3dc627661ba1b3d0bc1e5a865d1655..6830a916bcb619c8ce9b3f691ab8322a7e8910d4 100644
--- a/lib/gitlab/backend/grack_auth.rb
+++ b/lib/gitlab/backend/grack_auth.rb
@@ -193,7 +193,14 @@ module Grack
     end
 
     def render_grack_auth_ok
-      [200, { "Content-Type" => "application/json" }, [JSON.dump({ 'GL_ID' => Gitlab::ShellEnv.gl_id(@user) })]]
+      [
+        200,
+        { "Content-Type" => "application/json" },
+        [JSON.dump({
+          'GL_ID' => Gitlab::ShellEnv.gl_id(@user),
+          'RepoPath' => project.repository.path_to_repo,
+        })]
+      ]
     end
 
     def render_not_found
diff --git a/lib/gitlab/backend/shell.rb b/lib/gitlab/backend/shell.rb
index 14ee4701e7bb9faa44e664c9c36124a91efd4305..01b8bda05c6741cf7b914735722447388cec42f7 100644
--- a/lib/gitlab/backend/shell.rb
+++ b/lib/gitlab/backend/shell.rb
@@ -4,7 +4,8 @@ module Gitlab
 
     class KeyAdder < Struct.new(:io)
       def add_key(id, key)
-        io.puts("#{id}\t#{key.strip}")
+        key.gsub!(/[[:space:]]+/, ' ').strip!
+        io.puts("#{id}\t#{key}")
       end
     end
 
diff --git a/lib/gitlab/contributions_calendar.rb b/lib/gitlab/contributions_calendar.rb
index 45bb904ed7afacefd386483c0a37c74887e458d6..8a7f8dc5003626551bbaa6f6abb2429d94cedaea 100644
--- a/lib/gitlab/contributions_calendar.rb
+++ b/lib/gitlab/contributions_calendar.rb
@@ -12,7 +12,6 @@ module Gitlab
 
       @timestamps = {}
       date_from = 1.year.ago
-      date_to = Date.today
 
       events = Event.reorder(nil).contributions.where(author_id: user.id).
         where("created_at > ?", date_from).where(project_id: projects).
diff --git a/lib/gitlab/database.rb b/lib/gitlab/database.rb
new file mode 100644
index 0000000000000000000000000000000000000000..71f37f1fef8b27d5092792d7bd9b77b65541c9be
--- /dev/null
+++ b/lib/gitlab/database.rb
@@ -0,0 +1,11 @@
+module Gitlab
+  module Database
+    def self.mysql?
+      ActiveRecord::Base.connection.adapter_name.downcase == 'mysql2'
+    end
+
+    def self.postgresql?
+      ActiveRecord::Base.connection.adapter_name.downcase == 'postgresql'
+    end
+  end
+end
diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb
index 4daf65331e8738d961ffdcfd96154e180431b74f..142058aa69d46e0b1429c5e0b0b8f18ae09cfb16 100644
--- a/lib/gitlab/diff/file.rb
+++ b/lib/gitlab/diff/file.rb
@@ -44,6 +44,14 @@ module Gitlab
           diff.old_path
         end
       end
+
+      def added_lines
+        diff_lines.select(&:added?).size
+      end
+
+      def removed_lines
+        diff_lines.select(&:removed?).size
+      end
     end
   end
 end
diff --git a/lib/gitlab/diff/line.rb b/lib/gitlab/diff/line.rb
index 8ac1b15e88a965eb40f3cbfa32926e314053e865..0072194606e69b5c9da9f086c80bd7fa2a630e16 100644
--- a/lib/gitlab/diff/line.rb
+++ b/lib/gitlab/diff/line.rb
@@ -7,6 +7,14 @@ module Gitlab
         @text, @type, @index = text, type, index
         @old_pos, @new_pos = old_pos, new_pos
       end
+
+      def added?
+        type == 'new'
+      end
+
+      def removed?
+        type == 'old'
+      end
     end
   end
 end
diff --git a/lib/gitlab/diff/parser.rb b/lib/gitlab/diff/parser.rb
index c1d9520ddf10deacc2f90daf96af9693618f71c7..7015fe36c3dbdcb402d67d294e63b0ffdaefab43 100644
--- a/lib/gitlab/diff/parser.rb
+++ b/lib/gitlab/diff/parser.rb
@@ -14,8 +14,6 @@ module Gitlab
         lines_arr = ::Gitlab::InlineDiff.processing lines
 
         lines_arr.each do |line|
-          raw_line = line.dup
-
           next if filename?(line)
 
           full_line = html_escape(line.gsub(/\n/, ''))
diff --git a/lib/gitlab/fogbugz_import/project_creator.rb b/lib/gitlab/fogbugz_import/project_creator.rb
index f02ea43910f1ac3b5ba8390c8897954e99028ef7..8b1b6f48ed500573377c4e91ed59405f12b28c0a 100644
--- a/lib/gitlab/fogbugz_import/project_creator.rb
+++ b/lib/gitlab/fogbugz_import/project_creator.rb
@@ -23,7 +23,7 @@ module Gitlab
           import_url: Project::UNKNOWN_IMPORT_URL
         ).execute
 
-        import_data = project.create_import_data(
+        project.create_import_data(
           data: {
             'repo' => repo.raw_data,
             'user_map' => user_map,
diff --git a/lib/gitlab/google_code_import/project_creator.rb b/lib/gitlab/google_code_import/project_creator.rb
index 0cfeaf9d61c4aaec5da765c9b6c4de0fbc358d77..1cb7d16aeb3f0021ea7528f29b5be797e3b2caa1 100644
--- a/lib/gitlab/google_code_import/project_creator.rb
+++ b/lib/gitlab/google_code_import/project_creator.rb
@@ -23,7 +23,7 @@ module Gitlab
           import_url: repo.import_url
         ).execute
 
-        import_data = project.create_import_data(
+        project.create_import_data(
           data: {
             "repo"      => repo.raw_data,
             "user_map"  => user_map
diff --git a/lib/gitlab/incoming_email.rb b/lib/gitlab/incoming_email.rb
index 856ccc710848110ededb0de9755bbab0d22ff441..9068d79c95e29a0ee1011209ca0434fb3e2516c0 100644
--- a/lib/gitlab/incoming_email.rb
+++ b/lib/gitlab/incoming_email.rb
@@ -24,12 +24,12 @@ module Gitlab
         match[1]
       end
 
-      private
-
       def config
         Gitlab.config.incoming_email
       end
 
+      private
+
       def address_regex
         wildcard_address = config.address
         return nil unless wildcard_address
diff --git a/lib/gitlab/ldap/user.rb b/lib/gitlab/ldap/user.rb
index cb66fd500fe28da06d8db47fcc36b0b5ca212227..4be99dd88c29dd87ba829973da60aeca464dbf2d 100644
--- a/lib/gitlab/ldap/user.rb
+++ b/lib/gitlab/ldap/user.rb
@@ -14,7 +14,7 @@ module Gitlab
           # LDAP distinguished name is case-insensitive
           identity = ::Identity.
             where(provider: provider).
-            where('lower(extern_uid) = ?', uid.downcase).last
+            where('lower(extern_uid) = ?', uid.mb_chars.downcase.to_s).last
           identity && identity.user
         end
       end
@@ -35,7 +35,7 @@ module Gitlab
       end
 
       def find_by_email
-        ::User.find_by(email: auth_hash.email)
+        ::User.find_by(email: auth_hash.email.downcase)
       end
 
       def update_user_attributes
diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb
index ae5f2544691bd7ba415cf2da80cfc6a623351535..b082bfc434bca43f89185a53e5e72db89015f1a6 100644
--- a/lib/gitlab/markdown.rb
+++ b/lib/gitlab/markdown.rb
@@ -7,6 +7,14 @@ module Gitlab
   module Markdown
     # Convert a Markdown String into an HTML-safe String of HTML
     #
+    # Note that while the returned HTML will have been sanitized of dangerous
+    # HTML, it may post a risk of information leakage if it's not also passed
+    # through `post_process`.
+    #
+    # Also note that the returned String is always HTML, not XHTML. Views
+    # requiring XHTML, such as Atom feeds, need to call `post_process` on the
+    # result, providing the appropriate `pipeline` option.
+    #
     # markdown - Markdown String
     # context  - Hash of context options passed to our HTML Pipeline
     #
@@ -31,6 +39,33 @@ module Gitlab
       renderer.render(markdown)
     end
 
+    # Perform post-processing on an HTML String
+    #
+    # This method is used to perform state-dependent changes to a String of
+    # HTML, such as removing references that the current user doesn't have
+    # permission to make (`RedactorFilter`).
+    #
+    # html     - String to process
+    # options  - Hash of options to customize output
+    #            :pipeline  - Symbol pipeline type
+    #            :project   - Project
+    #            :user      - User object
+    #
+    # Returns an HTML-safe String
+    def self.post_process(html, options)
+      context = {
+        project:      options[:project],
+        current_user: options[:user]
+      }
+      doc = post_processor.to_document(html, context)
+
+      if options[:pipeline] == :atom
+        doc.to_html(save_with: Nokogiri::XML::Node::SaveOptions::AS_XHTML)
+      else
+        doc.to_html
+      end.html_safe
+    end
+
     # Provide autoload paths for filters to prevent a circular dependency error
     autoload :AutolinkFilter,               'gitlab/markdown/autolink_filter'
     autoload :CommitRangeReferenceFilter,   'gitlab/markdown/commit_range_reference_filter'
@@ -41,6 +76,7 @@ module Gitlab
     autoload :IssueReferenceFilter,         'gitlab/markdown/issue_reference_filter'
     autoload :LabelReferenceFilter,         'gitlab/markdown/label_reference_filter'
     autoload :MergeRequestReferenceFilter,  'gitlab/markdown/merge_request_reference_filter'
+    autoload :RedactorFilter,               'gitlab/markdown/redactor_filter'
     autoload :RelativeLinkFilter,           'gitlab/markdown/relative_link_filter'
     autoload :SanitizationFilter,           'gitlab/markdown/sanitization_filter'
     autoload :SnippetReferenceFilter,       'gitlab/markdown/snippet_reference_filter'
@@ -48,27 +84,22 @@ module Gitlab
     autoload :TableOfContentsFilter,        'gitlab/markdown/table_of_contents_filter'
     autoload :TaskListFilter,               'gitlab/markdown/task_list_filter'
     autoload :UserReferenceFilter,          'gitlab/markdown/user_reference_filter'
+    autoload :UploadLinkFilter,             'gitlab/markdown/upload_link_filter'
 
-    # Public: Parse the provided text with GitLab-Flavored Markdown
+    # Public: Parse the provided HTML with GitLab-Flavored Markdown
+    #
+    # html    - HTML String
+    # options - A Hash of options used to customize output (default: {})
+    #           :no_header_anchors - Disable header anchors in TableOfContentsFilter
+    #           :path              - Current path String
+    #           :pipeline          - Symbol pipeline type
+    #           :project           - Current Project object
+    #           :project_wiki      - Current ProjectWiki object
+    #           :ref               - Current ref String
     #
-    # text         - the source text
-    # options      - A Hash of options used to customize output (default: {}):
-    #                :xhtml               - output XHTML instead of HTML
-    #                :reference_only_path - Use relative path for reference links
-    def self.gfm(text, options = {})
-      return text if text.nil?
-
-      # Duplicate the string so we don't alter the original, then call to_str
-      # to cast it back to a String instead of a SafeBuffer. This is required
-      # for gsub calls to work as we need them to.
-      text = text.dup.to_str
-
-      options.reverse_merge!(
-        xhtml:                false,
-        reference_only_path:  true,
-        project:              options[:project],
-        current_user:         options[:current_user]
-      )
+    # Returns an HTML-safe String
+    def self.gfm(html, options = {})
+      return '' unless html.present?
 
       @pipeline ||= HTML::Pipeline.new(filters)
 
@@ -77,41 +108,36 @@ module Gitlab
         pipeline: options[:pipeline],
 
         # EmojiFilter
-        asset_root: Gitlab.config.gitlab.base_url,
         asset_host: Gitlab::Application.config.asset_host,
-
-        # TableOfContentsFilter
-        no_header_anchors: options[:no_header_anchors],
+        asset_root: Gitlab.config.gitlab.base_url,
 
         # ReferenceFilter
-        current_user:    options[:current_user],
-        only_path:       options[:reference_only_path],
-        project:         options[:project],
+        only_path: only_path_pipeline?(options[:pipeline]),
+        project:   options[:project],
 
         # RelativeLinkFilter
+        project_wiki:   options[:project_wiki],
         ref:            options[:ref],
         requested_path: options[:path],
-        project_wiki:   options[:project_wiki]
-      }
-
-      result = @pipeline.call(text, context)
 
-      save_options = 0
-      if options[:xhtml]
-        save_options |= Nokogiri::XML::Node::SaveOptions::AS_XHTML
-      end
-
-      text = result[:output].to_html(save_with: save_options)
+        # TableOfContentsFilter
+        no_header_anchors: options[:no_header_anchors]
+      }
 
-      text.html_safe
+      @pipeline.to_html(html, context).html_safe
     end
 
     private
 
-    def self.renderer
-      @markdown ||= begin
-        renderer = Redcarpet::Render::HTML.new
-        Redcarpet::Markdown.new(renderer, redcarpet_options)
+    # Check if a pipeline enables the `only_path` context option
+    #
+    # Returns Boolean
+    def self.only_path_pipeline?(pipeline)
+      case pipeline
+      when :atom, :email
+        false
+      else
+        true
       end
     end
 
@@ -129,6 +155,17 @@ module Gitlab
       }.freeze
     end
 
+    def self.renderer
+      @markdown ||= begin
+        renderer = Redcarpet::Render::HTML.new
+        Redcarpet::Markdown.new(renderer, redcarpet_options)
+      end
+    end
+
+    def self.post_processor
+      @post_processor ||= HTML::Pipeline.new([Gitlab::Markdown::RedactorFilter])
+    end
+
     # Filters used in our pipeline
     #
     # SanitizationFilter should come first so that all generated reference HTML
@@ -140,6 +177,7 @@ module Gitlab
         Gitlab::Markdown::SyntaxHighlightFilter,
         Gitlab::Markdown::SanitizationFilter,
 
+        Gitlab::Markdown::UploadLinkFilter,
         Gitlab::Markdown::RelativeLinkFilter,
         Gitlab::Markdown::EmojiFilter,
         Gitlab::Markdown::TableOfContentsFilter,
diff --git a/lib/gitlab/markdown/commit_range_reference_filter.rb b/lib/gitlab/markdown/commit_range_reference_filter.rb
index bb496135d923680695d3dc9b37c7a6f070c39311..e070edae0a4c43f7747c4a207955f051ebbe265f 100644
--- a/lib/gitlab/markdown/commit_range_reference_filter.rb
+++ b/lib/gitlab/markdown/commit_range_reference_filter.rb
@@ -26,6 +26,18 @@ module Gitlab
         end
       end
 
+      def self.referenced_by(node)
+        project = Project.find(node.attr("data-project")) rescue nil
+        return unless project
+
+        id = node.attr("data-commit-range")
+        range = CommitRange.new(id, project)
+
+        return unless range.valid_commits?
+
+        { commit_range: range }
+      end
+
       def initialize(*args)
         super
 
@@ -53,13 +65,11 @@ module Gitlab
           range = CommitRange.new(id, project)
 
           if range.valid_commits?
-            push_result(:commit_range, range)
-
             url = url_for_commit_range(project, range)
 
             title = range.reference_title
             klass = reference_class(:commit_range)
-            data  = data_attribute(project.id)
+            data  = data_attribute(project: project.id, commit_range: id)
 
             project_ref += '@' if project_ref
 
diff --git a/lib/gitlab/markdown/commit_reference_filter.rb b/lib/gitlab/markdown/commit_reference_filter.rb
index fcbb2e936a5e3d3b1566f1e896695e60c0fff68c..8cdbeb1f9cf7101b0201a65003c125e9f8e5ffcf 100644
--- a/lib/gitlab/markdown/commit_reference_filter.rb
+++ b/lib/gitlab/markdown/commit_reference_filter.rb
@@ -26,6 +26,18 @@ module Gitlab
         end
       end
 
+      def self.referenced_by(node)
+        project = Project.find(node.attr("data-project")) rescue nil
+        return unless project
+
+        id = node.attr("data-commit")
+        commit = commit_from_ref(project, id)
+
+        return unless commit
+
+        { commit: commit }
+      end
+
       def call
         replace_text_nodes_matching(Commit.reference_pattern) do |content|
           commit_link_filter(content)
@@ -39,17 +51,15 @@ module Gitlab
       # Returns a String with commit references replaced with links. All links
       # have `gfm` and `gfm-commit` class names attached for styling.
       def commit_link_filter(text)
-        self.class.references_in(text) do |match, commit_ref, project_ref|
+        self.class.references_in(text) do |match, id, project_ref|
           project = self.project_from_ref(project_ref)
 
-          if commit = commit_from_ref(project, commit_ref)
-            push_result(:commit, commit)
-
+          if commit = self.class.commit_from_ref(project, id)
             url = url_for_commit(project, commit)
 
             title = escape_once(commit.link_title)
             klass = reference_class(:commit)
-            data  = data_attribute(project.id)
+            data  = data_attribute(project: project.id, commit: id)
 
             project_ref += '@' if project_ref
 
@@ -62,9 +72,9 @@ module Gitlab
         end
       end
 
-      def commit_from_ref(project, commit_ref)
+      def self.commit_from_ref(project, id)
         if project && project.valid_repo?
-          project.commit(commit_ref)
+          project.commit(id)
         end
       end
 
diff --git a/lib/gitlab/markdown/cross_project_reference.rb b/lib/gitlab/markdown/cross_project_reference.rb
index 855748fdccc3f708f9bf1bb9c81b762d76aa0d40..6ab04a584b0c8e8166a9e5cc908b5ac7e6140897 100644
--- a/lib/gitlab/markdown/cross_project_reference.rb
+++ b/lib/gitlab/markdown/cross_project_reference.rb
@@ -13,18 +13,11 @@ module Gitlab
       #
       # ref - String reference.
       #
-      # Returns a Project, or nil if the reference can't be accessed
+      # Returns a Project, or nil if the reference can't be found
       def project_from_ref(ref)
         return context[:project] unless ref
 
-        other = Project.find_with_namespace(ref)
-        return nil unless other && user_can_reference_project?(other)
-
-        other
-      end
-
-      def user_can_reference_project?(project, user = context[:current_user])
-        Ability.abilities.allowed?(user, :read_project, project)
+        Project.find_with_namespace(ref)
       end
     end
   end
diff --git a/lib/gitlab/markdown/external_issue_reference_filter.rb b/lib/gitlab/markdown/external_issue_reference_filter.rb
index f7c43e1ca89a3da59e500275830033baaa5bfbb5..8f86f13976abc847adb81542675fb4177a970c1d 100644
--- a/lib/gitlab/markdown/external_issue_reference_filter.rb
+++ b/lib/gitlab/markdown/external_issue_reference_filter.rb
@@ -47,8 +47,9 @@ module Gitlab
 
           title = escape_once("Issue in #{project.external_issue_tracker.title}")
           klass = reference_class(:issue)
+          data  = data_attribute(project: project.id)
 
-          %(<a href="#{url}"
+          %(<a href="#{url}" #{data}
                title="#{title}"
                class="#{klass}">#{match}</a>)
         end
diff --git a/lib/gitlab/markdown/issue_reference_filter.rb b/lib/gitlab/markdown/issue_reference_filter.rb
index 01320f807963b2d4f1b730529174232061ff9825..481d282f7b1c6cb30609b4d6a82f7b7379ab55fc 100644
--- a/lib/gitlab/markdown/issue_reference_filter.rb
+++ b/lib/gitlab/markdown/issue_reference_filter.rb
@@ -27,6 +27,10 @@ module Gitlab
         end
       end
 
+      def self.referenced_by(node)
+        { issue: LazyReference.new(Issue, node.attr("data-issue")) }
+      end
+
       def call
         replace_text_nodes_matching(Issue.reference_pattern) do |content|
           issue_link_filter(content)
@@ -45,13 +49,11 @@ module Gitlab
           project = self.project_from_ref(project_ref)
 
           if project && issue = project.get_issue(id)
-            push_result(:issue, issue)
-
             url = url_for_issue(id, project, only_path: context[:only_path])
 
             title = escape_once("Issue: #{issue.title}")
             klass = reference_class(:issue)
-            data  = data_attribute(project.id)
+            data  = data_attribute(project: project.id, issue: issue.id)
 
             %(<a href="#{url}" #{data}
                  title="#{title}"
diff --git a/lib/gitlab/markdown/label_reference_filter.rb b/lib/gitlab/markdown/label_reference_filter.rb
index 1e5cb12071eff475e8f3f1ad78f1380fff1eed03..618acb7a57814c32c1bc31f131a2d6cde8fdb40d 100644
--- a/lib/gitlab/markdown/label_reference_filter.rb
+++ b/lib/gitlab/markdown/label_reference_filter.rb
@@ -22,6 +22,10 @@ module Gitlab
         end
       end
 
+      def self.referenced_by(node)
+        { label: LazyReference.new(Label, node.attr("data-label")) }
+      end
+
       def call
         replace_text_nodes_matching(Label.reference_pattern) do |content|
           label_link_filter(content)
@@ -41,11 +45,9 @@ module Gitlab
           params = label_params(id, name)
 
           if label = project.labels.find_by(params)
-            push_result(:label, label)
-
             url = url_for_label(project, label)
             klass = reference_class(:label)
-            data = data_attribute(project.id)
+            data = data_attribute(project: project.id, label: label.id)
 
             %(<a href="#{url}" #{data}
                  class="#{klass}">#{render_colored_label(label)}</a>)
diff --git a/lib/gitlab/markdown/merge_request_reference_filter.rb b/lib/gitlab/markdown/merge_request_reference_filter.rb
index ecbd263d0e01a3863d19c3edbc1d3a8fc177eedc..5bc632698082556ec3132314a941fc14e12a924a 100644
--- a/lib/gitlab/markdown/merge_request_reference_filter.rb
+++ b/lib/gitlab/markdown/merge_request_reference_filter.rb
@@ -27,6 +27,10 @@ module Gitlab
         end
       end
 
+      def self.referenced_by(node)
+        { merge_request: LazyReference.new(MergeRequest, node.attr("data-merge-request")) }
+      end
+
       def call
         replace_text_nodes_matching(MergeRequest.reference_pattern) do |content|
           merge_request_link_filter(content)
@@ -45,11 +49,9 @@ module Gitlab
           project = self.project_from_ref(project_ref)
 
           if project && merge_request = project.merge_requests.find_by(iid: id)
-            push_result(:merge_request, merge_request)
-
             title = escape_once("Merge Request: #{merge_request.title}")
             klass = reference_class(:merge_request)
-            data  = data_attribute(project.id)
+            data  = data_attribute(project: project.id, merge_request: merge_request.id)
 
             url = url_for_merge_request(merge_request, project)
 
diff --git a/lib/gitlab/markdown/redactor_filter.rb b/lib/gitlab/markdown/redactor_filter.rb
new file mode 100644
index 0000000000000000000000000000000000000000..a1f3a8a8ebfc180a02fcf64b437947f9f6426e07
--- /dev/null
+++ b/lib/gitlab/markdown/redactor_filter.rb
@@ -0,0 +1,40 @@
+require 'gitlab/markdown'
+require 'html/pipeline/filter'
+
+module Gitlab
+  module Markdown
+    # HTML filter that removes references to records that the current user does
+    # not have permission to view.
+    #
+    # Expected to be run in its own post-processing pipeline.
+    #
+    class RedactorFilter < HTML::Pipeline::Filter
+      def call
+        doc.css('a.gfm').each do |node|
+          unless user_can_reference?(node)
+            node.replace(node.text)
+          end
+        end
+
+        doc
+      end
+
+      private
+
+      def user_can_reference?(node)
+        if node.has_attribute?('data-reference-filter')
+          reference_type = node.attr('data-reference-filter')
+          reference_filter = reference_type.constantize
+
+          reference_filter.user_can_reference?(current_user, node, context)
+        else
+          true
+        end
+      end
+
+      def current_user
+        context[:current_user]
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/markdown/reference_filter.rb b/lib/gitlab/markdown/reference_filter.rb
index 9b293c957d6807ad6c18b22fb89c9f4b125e797a..a4c560f578cae024b180fb3d05c0f0dd6e85f215 100644
--- a/lib/gitlab/markdown/reference_filter.rb
+++ b/lib/gitlab/markdown/reference_filter.rb
@@ -11,30 +11,57 @@ module Gitlab
     # Context options:
     #   :project (required) - Current project, ignored if reference is cross-project.
     #   :only_path          - Generate path-only links.
-    #
-    # Results:
-    #   :references - A Hash of references that were found and replaced.
     class ReferenceFilter < HTML::Pipeline::Filter
-      def initialize(*args)
-        super
+      LazyReference = Struct.new(:klass, :ids) do
+        def self.load(refs)
+          lazy_references, values = refs.partition { |ref| ref.is_a?(self) }
+
+          lazy_values = lazy_references.group_by(&:klass).flat_map do |klass, refs|
+            ids = refs.flat_map(&:ids)
+            klass.where(id: ids)
+          end
+
+          values + lazy_values
+        end
+
+        def load
+          self.klass.where(id: self.ids)
+        end
+      end
+
+      def self.user_can_reference?(user, node, context)
+        if node.has_attribute?('data-project')
+          project_id = node.attr('data-project').to_i
+          return true if project_id == context[:project].try(:id)
+
+          project = Project.find(project_id) rescue nil
+          Ability.abilities.allowed?(user, :read_project, project)
+        else
+          true
+        end
+      end
 
-        result[:references] = Hash.new { |hash, type| hash[type] = [] }
+      def self.referenced_by(node)
+        raise NotImplementedError, "#{self} does not implement #{__method__}"
       end
 
       # Returns a data attribute String to attach to a reference link
       #
-      # id   - Object ID
-      # type - Object type (default: :project)
+      # attributes - Hash, where the key becomes the data attribute name and the
+      #              value is the data attribute value
       #
       # Examples:
       #
-      #   data_attribute(1)         # => "data-project-id=\"1\""
-      #   data_attribute(2, :user)  # => "data-user-id=\"2\""
-      #   data_attribute(3, :group) # => "data-group-id=\"3\""
+      #   data_attribute(project: 1, issue: 2)
+      #   # => "data-reference-filter=\"Gitlab::Markdown::SomeReferenceFilter\" data-project=\"1\" data-issue=\"2\""
+      #
+      #   data_attribute(project: 3, merge_request: 4)
+      #   # => "data-reference-filter=\"Gitlab::Markdown::SomeReferenceFilter\" data-project=\"3\" data-merge-request=\"4\""
       #
       # Returns a String
-      def data_attribute(id, type = :project)
-        %Q(data-#{type}-id="#{id}")
+      def data_attribute(attributes = {})
+        attributes[:reference_filter] = self.class.name
+        attributes.map { |key, value| %Q(data-#{key.to_s.dasherize}="#{value}") }.join(" ")
       end
 
       def escape_once(html)
@@ -59,16 +86,6 @@ module Gitlab
         context[:project]
       end
 
-      # Add a reference to the pipeline's result Hash
-      #
-      # type   - Singular Symbol reference type (e.g., :issue, :user, etc.)
-      # values - One or more Objects to add
-      def push_result(type, *values)
-        return if values.empty?
-
-        result[:references][type].push(*values)
-      end
-
       def reference_class(type)
         "gfm gfm-#{type}"
       end
@@ -85,15 +102,15 @@ module Gitlab
       # Yields the current node's String contents. The result of the block will
       # replace the node's existing content and update the current document.
       #
-      # Returns the updated Nokogiri::XML::Document object.
+      # Returns the updated Nokogiri::HTML::DocumentFragment object.
       def replace_text_nodes_matching(pattern)
         return doc if project.nil?
 
         search_text_nodes(doc).each do |node|
-          content = node.to_html
-
-          next unless content.match(pattern)
           next if ignored_ancestry?(node)
+          next unless node.text =~ pattern
+
+          content = node.to_html
 
           html = yield content
 
diff --git a/lib/gitlab/markdown/reference_gatherer_filter.rb b/lib/gitlab/markdown/reference_gatherer_filter.rb
new file mode 100644
index 0000000000000000000000000000000000000000..00f983675e6b90ba15b344e4ec56bd4ffc61c606
--- /dev/null
+++ b/lib/gitlab/markdown/reference_gatherer_filter.rb
@@ -0,0 +1,63 @@
+require 'gitlab/markdown'
+require 'html/pipeline/filter'
+
+module Gitlab
+  module Markdown
+    # HTML filter that gathers all referenced records that the current user has
+    # permission to view.
+    #
+    # Expected to be run in its own post-processing pipeline.
+    #
+    class ReferenceGathererFilter < HTML::Pipeline::Filter
+      def initialize(*)
+        super
+
+        result[:references] ||= Hash.new { |hash, type| hash[type] = [] }
+      end
+
+      def call
+        doc.css('a.gfm').each do |node|
+          gather_references(node)
+        end
+
+        load_lazy_references unless context[:load_lazy_references] == false
+
+        doc
+      end
+
+      private
+
+      def gather_references(node)
+        return unless node.has_attribute?('data-reference-filter')
+
+        reference_type = node.attr('data-reference-filter')
+        reference_filter = reference_type.constantize
+
+        return if context[:reference_filter] && reference_filter != context[:reference_filter]
+
+        return unless reference_filter.user_can_reference?(current_user, node, context)
+
+        references = reference_filter.referenced_by(node)
+        return unless references
+
+        references.each do |type, values|
+          Array.wrap(values).each do |value|
+            result[:references][type] << value
+          end
+        end
+      end
+
+      # Will load all references of one type using one query.
+      def load_lazy_references
+        refs = result[:references]
+        refs.each do |type, values|
+          refs[type] = ReferenceFilter::LazyReference.load(values)
+        end
+      end
+
+      def current_user
+        context[:current_user]
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/markdown/snippet_reference_filter.rb b/lib/gitlab/markdown/snippet_reference_filter.rb
index e2cf89cb1d853d7df94586f10f807cb5fca8b43e..f783f951711d974f656f2c3bebad63bb131034d1 100644
--- a/lib/gitlab/markdown/snippet_reference_filter.rb
+++ b/lib/gitlab/markdown/snippet_reference_filter.rb
@@ -27,6 +27,10 @@ module Gitlab
         end
       end
 
+      def self.referenced_by(node)
+        { snippet: LazyReference.new(Snippet, node.attr("data-snippet")) }
+      end
+
       def call
         replace_text_nodes_matching(Snippet.reference_pattern) do |content|
           snippet_link_filter(content)
@@ -45,11 +49,9 @@ module Gitlab
           project = self.project_from_ref(project_ref)
 
           if project && snippet = project.snippets.find_by(id: id)
-            push_result(:snippet, snippet)
-
             title = escape_once("Snippet: #{snippet.title}")
             klass = reference_class(:snippet)
-            data  = data_attribute(project.id)
+            data  = data_attribute(project: project.id, snippet: snippet.id)
 
             url = url_for_snippet(snippet, project)
 
diff --git a/lib/gitlab/markdown/upload_link_filter.rb b/lib/gitlab/markdown/upload_link_filter.rb
new file mode 100644
index 0000000000000000000000000000000000000000..fbada73ab865c9a677863164f8a1b814839fdf13
--- /dev/null
+++ b/lib/gitlab/markdown/upload_link_filter.rb
@@ -0,0 +1,47 @@
+require 'gitlab/markdown'
+require 'html/pipeline/filter'
+require 'uri'
+
+module Gitlab
+  module Markdown
+    # HTML filter that "fixes" relative upload links to files.
+    # Context options:
+    #   :project (required) - Current project
+    #
+    class UploadLinkFilter < HTML::Pipeline::Filter
+      def call
+        doc.search('a').each do |el|
+          process_link_attr el.attribute('href')
+        end
+
+        doc.search('img').each do |el|
+          process_link_attr el.attribute('src')
+        end
+
+        doc
+      end
+
+      protected
+
+      def process_link_attr(html_attr)
+        return if html_attr.blank?
+
+        uri = html_attr.value
+        if uri.starts_with?("/uploads/")
+          html_attr.value = build_url(uri).to_s
+        end
+      end
+
+      def build_url(uri)
+        File.join(Gitlab.config.gitlab.url, context[:project].path_with_namespace, uri)
+      end
+
+      # Ensure that a :project key exists in context
+      #
+      # Note that while the key might exist, its value could be nil!
+      def validate
+        needs :project
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/markdown/user_reference_filter.rb b/lib/gitlab/markdown/user_reference_filter.rb
index 6f436ea71675f9256057bfe259f0e578e281d117..2a594e1662ed9f2e9d00b01542ecafeb58e49ee4 100644
--- a/lib/gitlab/markdown/user_reference_filter.rb
+++ b/lib/gitlab/markdown/user_reference_filter.rb
@@ -23,6 +23,31 @@ module Gitlab
         end
       end
 
+      def self.referenced_by(node)
+        if node.has_attribute?('data-group')
+          group = Group.find(node.attr('data-group')) rescue nil
+          return unless group
+
+          { user: group.users }
+        elsif node.has_attribute?('data-user')
+          { user: LazyReference.new(User, node.attr('data-user')) }
+        elsif node.has_attribute?('data-project')
+          project = Project.find(node.attr('data-project')) rescue nil
+          return unless project
+
+          { user: project.team.members.flatten }
+        end
+      end
+
+      def self.user_can_reference?(user, node, context)
+        if node.has_attribute?('data-group')
+          group = Group.find(node.attr('data-group')) rescue nil
+          Ability.abilities.allowed?(user, :read_group, group)
+        else
+          super
+        end
+      end
+
       def call
         replace_text_nodes_matching(User.reference_pattern) do |content|
           user_link_filter(content)
@@ -61,14 +86,12 @@ module Gitlab
       def link_to_all
         project = context[:project]
 
-        # FIXME (rspeicher): Law of Demeter
-        push_result(:user, *project.team.members.flatten)
-
         url = urls.namespace_project_url(project.namespace, project,
                                          only_path: context[:only_path])
+        data = data_attribute(project: project.id)
 
         text = User.reference_prefix + 'all'
-        %(<a href="#{url}" class="#{link_class}">#{text}</a>)
+        %(<a href="#{url}" #{data} class="#{link_class}">#{text}</a>)
       end
 
       def link_to_namespace(namespace)
@@ -80,30 +103,20 @@ module Gitlab
       end
 
       def link_to_group(group, namespace)
-        return unless user_can_reference_group?(namespace)
-
-        push_result(:user, *namespace.users)
-
         url = urls.group_url(group, only_path: context[:only_path])
-        data = data_attribute(namespace.id, :group)
+        data = data_attribute(group: namespace.id)
 
         text = Group.reference_prefix + group
         %(<a href="#{url}" #{data} class="#{link_class}">#{text}</a>)
       end
 
       def link_to_user(user, namespace)
-        push_result(:user, namespace.owner)
-
         url = urls.user_url(user, only_path: context[:only_path])
-        data = data_attribute(namespace.owner_id, :user)
+        data = data_attribute(user: namespace.owner_id)
 
         text = User.reference_prefix + user
         %(<a href="#{url}" #{data} class="#{link_class}">#{text}</a>)
       end
-
-      def user_can_reference_group?(group)
-        Ability.abilities.allowed?(context[:current_user], :read_group, group)
-      end
     end
   end
 end
diff --git a/lib/gitlab/reference_extractor.rb b/lib/gitlab/reference_extractor.rb
index 0961bd80421a966bdc575fcce10eaa055ce6ecfe..da8df8a3025550e5a23d73c19c303fd0894464ef 100644
--- a/lib/gitlab/reference_extractor.rb
+++ b/lib/gitlab/reference_extractor.rb
@@ -3,11 +3,12 @@ require 'gitlab/markdown'
 module Gitlab
   # Extract possible GFM references from an arbitrary String for further processing.
   class ReferenceExtractor
-    attr_accessor :project, :current_user
+    attr_accessor :project, :current_user, :load_lazy_references
 
-    def initialize(project, current_user = nil)
+    def initialize(project, current_user = nil, load_lazy_references: true)
       @project = project
       @current_user = current_user
+      @load_lazy_references = load_lazy_references
     end
 
     def analyze(text)
@@ -26,9 +27,9 @@ module Gitlab
     def references
       @references ||= Hash.new do |references, type|
         type = type.to_sym
-        return references[type] if references.has_key?(type)
+        next references[type] if references.has_key?(type)
 
-        references[type] = pipeline_result(type).uniq
+        references[type] = pipeline_result(type)
       end
     end
 
@@ -39,21 +40,34 @@ module Gitlab
     #
     # Returns the results Array for the requested filter type
     def pipeline_result(filter_type)
-      klass  = filter_type.to_s.camelize + 'ReferenceFilter'
+      return [] if @text.blank?
+      
+      klass  = "#{filter_type.to_s.camelize}ReferenceFilter"
       filter = Gitlab::Markdown.const_get(klass)
 
       context = {
         project: project,
         current_user: current_user,
+        
         # We don't actually care about the links generated
         only_path: true,
-        ignore_blockquotes: true
+        ignore_blockquotes: true,
+
+        # ReferenceGathererFilter
+        load_lazy_references: false,
+        reference_filter:     filter
       }
 
-      pipeline = HTML::Pipeline.new([filter], context)
+      pipeline = HTML::Pipeline.new([filter, Gitlab::Markdown::ReferenceGathererFilter], context)
       result = pipeline.call(@text)
 
-      result[:references][filter_type]
+      values = result[:references][filter_type].uniq
+
+      if @load_lazy_references
+        values = Gitlab::Markdown::ReferenceFilter::LazyReference.load(values).uniq
+      end
+
+      values
     end
   end
 end
diff --git a/lib/gitlab/uploads_transfer.rb b/lib/gitlab/uploads_transfer.rb
new file mode 100644
index 0000000000000000000000000000000000000000..be8fcc7b2d256db48600707493f343e198ea4370
--- /dev/null
+++ b/lib/gitlab/uploads_transfer.rb
@@ -0,0 +1,35 @@
+module Gitlab
+  class UploadsTransfer
+    def move_project(project_path, namespace_path_was, namespace_path)
+      new_namespace_folder = File.join(root_dir, namespace_path)
+      FileUtils.mkdir_p(new_namespace_folder) unless Dir.exist?(new_namespace_folder)
+      from = File.join(root_dir, namespace_path_was, project_path)
+      to = File.join(root_dir, namespace_path, project_path)
+      move(from, to, "")
+    end
+
+    def rename_project(path_was, path, namespace_path)
+      base_dir = File.join(root_dir, namespace_path)
+      move(path_was, path, base_dir)
+    end
+
+    def rename_namespace(path_was, path)
+      move(path_was, path)
+    end
+
+    private
+
+    def move(path_was, path, base_dir = nil)
+      base_dir = root_dir unless base_dir
+      from = File.join(base_dir, path_was)
+      to = File.join(base_dir, path)
+      FileUtils.mv(from, to)
+    rescue Errno::ENOENT
+      false
+    end
+
+    def root_dir
+      File.join(Rails.root, "public", "uploads")
+    end
+  end
+end
diff --git a/lib/support/nginx/gitlab b/lib/support/nginx/gitlab
index 7218a4d2f2092c57eb21da7d3a88f41c81df29ea..1e55c5a04868be641c30c196b09230e6682377cf 100644
--- a/lib/support/nginx/gitlab
+++ b/lib/support/nginx/gitlab
@@ -113,7 +113,25 @@ server {
     proxy_pass http://gitlab;
   }
 
-  location ~ [-\/\w\.]+\.git\/ {
+  location ~ ^/[\w\.-]+/[\w\.-]+/(info/refs|git-upload-pack|git-receive-pack)$ {
+    # 'Error' 418 is a hack to re-use the @gitlab-git-http-server block
+    error_page 418 = @gitlab-git-http-server;
+    return 418;
+  }
+
+  location ~ ^/[\w\.-]+/[\w\.-]+/repository/archive {
+    # 'Error' 418 is a hack to re-use the @gitlab-git-http-server block
+    error_page 418 = @gitlab-git-http-server;
+    return 418;
+  }
+
+  location ~ ^/api/v3/projects/.*/repository/archive {
+    # 'Error' 418 is a hack to re-use the @gitlab-git-http-server block
+    error_page 418 = @gitlab-git-http-server;
+    return 418;
+  }
+
+  location @gitlab-git-http-server {
     ## If you use HTTPS make sure you disable gzip compression
     ## to be safe against BREACH attack.
     # gzip off;
diff --git a/lib/support/nginx/gitlab-ssl b/lib/support/nginx/gitlab-ssl
index 7dabfba87e22f73c48d6147f949d7e6f2a2c3a8b..08641bbcc178f4c5ede2559b4d7e781f7ccd9395 100644
--- a/lib/support/nginx/gitlab-ssl
+++ b/lib/support/nginx/gitlab-ssl
@@ -160,7 +160,25 @@ server {
     proxy_pass http://gitlab;
   }
 
-  location ~ [-\/\w\.]+\.git\/ {
+  location ~ ^/[\w\.-]+/[\w\.-]+/(info/refs|git-upload-pack|git-receive-pack)$ {
+    # 'Error' 418 is a hack to re-use the @gitlab-git-http-server block
+    error_page 418 = @gitlab-git-http-server;
+    return 418;
+  }
+
+  location ~ ^/[\w\.-]+/[\w\.-]+/repository/archive {
+    # 'Error' 418 is a hack to re-use the @gitlab-git-http-server block
+    error_page 418 = @gitlab-git-http-server;
+    return 418;
+  }
+
+  location ~ ^/api/v3/projects/.*/repository/archive {
+    # 'Error' 418 is a hack to re-use the @gitlab-git-http-server block
+    error_page 418 = @gitlab-git-http-server;
+    return 418;
+  }
+
+  location @gitlab-git-http-server {
     ## If you use HTTPS make sure you disable gzip compression
     ## to be safe against BREACH attack.
     gzip off;
diff --git a/lib/tasks/ci/migrate.rake b/lib/tasks/ci/migrate.rake
deleted file mode 100644
index 1de664c85e160a8306a1af46b838f731656d9397..0000000000000000000000000000000000000000
--- a/lib/tasks/ci/migrate.rake
+++ /dev/null
@@ -1,87 +0,0 @@
-namespace :ci do
-  desc 'GitLab | Import and migrate CI database'
-  task migrate: :environment do
-    warn_user_is_not_gitlab
-    configure_cron_mode
-
-    unless ENV['force'] == 'yes'
-      puts 'This will remove all CI related data and restore it from the provided backup.'
-      ask_to_continue
-      puts ''
-    end
-
-    # disable CI for time of migration
-    enable_ci(false)
-
-    # unpack archives
-    migrate = Ci::Migrate::Manager.new
-    migrate.unpack
-
-    Rake::Task['ci:migrate:db'].invoke
-    Rake::Task['ci:migrate:builds'].invoke
-    Rake::Task['ci:migrate:tags'].invoke
-    Rake::Task['ci:migrate:services'].invoke
-
-    # enable CI for time of migration
-    enable_ci(true)
-
-    migrate.cleanup
-  end
-
-  namespace :migrate do
-    desc 'GitLab | Import CI database'
-    task db: :environment do
-      configure_cron_mode
-      $progress.puts 'Restoring database ... '.blue
-      Ci::Migrate::Database.new.restore
-      $progress.puts 'done'.green
-    end
-
-    desc 'GitLab | Import CI builds'
-    task builds: :environment do
-      configure_cron_mode
-      $progress.puts 'Restoring builds ... '.blue
-      Ci::Migrate::Builds.new.restore
-      $progress.puts 'done'.green
-    end
-
-    desc 'GitLab | Migrate CI tags'
-    task tags: :environment do
-      configure_cron_mode
-      $progress.puts 'Migrating tags ... '.blue
-      ::Ci::Migrate::Tags.new.restore
-      $progress.puts 'done'.green
-    end
-
-    desc 'GitLab | Migrate CI auto-increments'
-    task autoincrements: :environment do
-      c = ActiveRecord::Base.connection
-      c.tables.select { |t| t.start_with?('ci_') }.each do |table|
-        result = c.select_one("SELECT id FROM #{table} ORDER BY id DESC LIMIT 1")
-        if result
-          ai_val = result['id'].to_i + 1
-          puts "Resetting auto increment ID for #{table} to #{ai_val}"
-          if c.adapter_name == 'PostgreSQL'
-            c.execute("ALTER SEQUENCE #{table}_id_seq RESTART WITH #{ai_val}")
-          else
-            c.execute("ALTER TABLE #{table} AUTO_INCREMENT = #{ai_val}")
-          end
-        end
-      end
-    end
-
-    desc 'GitLab | Migrate CI services'
-    task services: :environment do
-      $progress.puts 'Migrating services ... '.blue
-      c = ActiveRecord::Base.connection
-      c.execute("UPDATE ci_services SET type=CONCAT('Ci::', type) WHERE type NOT LIKE 'Ci::%'")
-      $progress.puts 'done'.green
-    end
-  end
-
-  def enable_ci(enabled)
-    settings = ApplicationSetting.current || ApplicationSetting.create_from_defaults
-    settings.ci_enabled = enabled
-    settings.save!
-  end
-end
diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake
index 66f1ecf385f4f24979905b6e7c8061532d93348d..2e73f792a9da901baf6f06a911cac14941a90d8a 100644
--- a/lib/tasks/gitlab/check.rake
+++ b/lib/tasks/gitlab/check.rake
@@ -335,7 +335,7 @@ namespace :gitlab do
       print "Redis version >= #{min_redis_version}? ... "
 
       redis_version = run(%W(redis-cli --version))
-      redis_version = redis_version.try(:match, /redis-cli (.*)/)
+      redis_version = redis_version.try(:match, /redis-cli (\d+\.\d+\.\d+)/)
       if redis_version &&
           (Gem::Version.new(redis_version[1]) > Gem::Version.new(min_redis_version))
         puts "yes".green
@@ -642,7 +642,6 @@ namespace :gitlab do
 
       if Gitlab.config.incoming_email.enabled
         check_address_formatted_correctly
-        check_mail_room_config_exists
         check_imap_authentication
 
         if Rails.env.production?
@@ -744,42 +743,16 @@ namespace :gitlab do
       end
     end
 
-    def check_mail_room_config_exists
-      print "MailRoom config exists? ... "
-
-      mail_room_config_file = Rails.root.join("config", "mail_room.yml")
-
-      if File.exists?(mail_room_config_file)
-        puts "yes".green
-      else
-        puts "no".red
-        try_fixing_it(
-          "Copy config/mail_room.yml.example to config/mail_room.yml",
-          "Check that the information in config/mail_room.yml is correct"
-        )
-        for_more_information(
-          "doc/incoming_email/README.md"
-        )
-        fix_and_rerun
-      end
-    end
-
     def check_imap_authentication
       print "IMAP server credentials are correct? ... "
 
-      mail_room_config_file = Rails.root.join("config", "mail_room.yml")
-
-      unless File.exists?(mail_room_config_file)
-        puts "can't check because of previous errors".magenta
-        return
-      end
-
-      config = YAML.load_file(mail_room_config_file)[:mailboxes].first rescue nil
+      config = Gitlab.config.incoming_email
 
       if config
         begin
-          imap = Net::IMAP.new(config[:host], port: config[:port], ssl: config[:ssl])
-          imap.login(config[:email], config[:password])
+          imap = Net::IMAP.new(config.host, port: config.port, ssl: config.ssl)
+          imap.starttls if config.start_tls
+          imap.login(config.user, config.password)
           connected = true
         rescue
           connected = false
@@ -791,7 +764,7 @@ namespace :gitlab do
       else
         puts "no".red
         try_fixing_it(
-          "Check that the information in config/mail_room.yml is correct"
+          "Check that the information in config/gitlab.yml is correct"
         )
         for_more_information(
           "doc/incoming_email/README.md"
diff --git a/lib/tasks/gitlab/cleanup.rake b/lib/tasks/gitlab/cleanup.rake
index 6b1e371614706036a5aff815c2d4239037dd89a1..9f5852ac6133b967180f8efb36cb64eb956f2572 100644
--- a/lib/tasks/gitlab/cleanup.rake
+++ b/lib/tasks/gitlab/cleanup.rake
@@ -46,43 +46,24 @@ namespace :gitlab do
     desc "GitLab | Cleanup | Clean repositories"
     task repos: :environment  do
       warn_user_is_not_gitlab
-      remove_flag = ENV['REMOVE']
-
-      git_base_path = Gitlab.config.gitlab_shell.repos_path
-      all_dirs = Dir.glob(git_base_path + '/*')
-
-      global_projects = Project.in_namespace(nil).pluck(:path)
-
-      puts git_base_path.yellow
-      puts "Looking for global repos to remove... "
-
-      # skip non git repo
-      all_dirs.select! do |dir|
-        dir =~ /.git$/
-      end
-
-      # skip existing repos
-      all_dirs.reject! do |dir|
-        repo_name = File.basename dir
-        path = repo_name.gsub(/\.git$/, "")
-        global_projects.include?(path)
-      end
 
-      all_dirs.each do |dir_path|
-        if remove_flag
-          if FileUtils.rm_rf dir_path
-            puts "Removed...#{dir_path}".red
-          else
-            puts "Cannot remove #{dir_path}".red
-          end
-        else
-          puts "Can be removed: #{dir_path}".red
+      move_suffix = "+orphaned+#{Time.now.to_i}"
+      repo_root = Gitlab.config.gitlab_shell.repos_path
+      # Look for global repos (legacy, depth 1) and normal repos (depth 2)
+      IO.popen(%W(find #{repo_root} -mindepth 1 -maxdepth 2 -name *.git)) do |find|
+        find.each_line do |path|
+          path.chomp!
+          repo_with_namespace = path.
+            sub(repo_root, '').
+            sub(%r{^/*}, '').
+            chomp('.git').
+            chomp('.wiki')
+          next if Project.find_with_namespace(repo_with_namespace)
+          new_path = path + move_suffix
+          puts path.inspect + ' -> ' + new_path.inspect
+          File.rename(path, new_path)
         end
       end
-
-      unless remove_flag
-        puts "To cleanup this directories run this command with REMOVE=true".yellow
-      end
     end
 
     desc "GitLab | Cleanup | Block users that have been removed in LDAP"
diff --git a/lib/tasks/gitlab/setup.rake b/lib/tasks/gitlab/setup.rake
index 0ac4b0fa8a36d6cc25bb8ddee696a6a4a747381e..4cbccf2ca897c469aafe0c1f5989f6452922c9a8 100644
--- a/lib/tasks/gitlab/setup.rake
+++ b/lib/tasks/gitlab/setup.rake
@@ -16,6 +16,7 @@ namespace :gitlab do
 
     Rake::Task["db:setup"].invoke
     Rake::Task["add_limits_mysql"].invoke
+    Rake::Task["setup_postgresql"].invoke
     Rake::Task["db:seed_fu"].invoke
   rescue Gitlab::TaskAbortedByUserError
     puts "Quitting...".red
diff --git a/lib/tasks/gitlab/two_factor.rake b/lib/tasks/gitlab/two_factor.rake
new file mode 100644
index 0000000000000000000000000000000000000000..9196677a01769d19df4fb4858f84850312fb0589
--- /dev/null
+++ b/lib/tasks/gitlab/two_factor.rake
@@ -0,0 +1,23 @@
+namespace :gitlab do
+  namespace :two_factor do
+    desc "GitLab | Disable Two-factor authentication (2FA) for all users"
+    task disable_for_all_users: :environment do
+      scope = User.with_two_factor
+      count = scope.count
+
+      if count > 0
+        puts "This will disable 2FA for #{count.to_s.red} users..."
+
+        begin
+          ask_to_continue
+          scope.find_each(&:disable_two_factor!)
+          puts "Successfully disabled 2FA for #{count} users.".green
+        rescue Gitlab::TaskAbortedByUserError
+          puts "Quitting...".red
+        end
+      else
+        puts "There are currently no users with 2FA enabled.".yellow
+      end
+    end
+  end
+end
diff --git a/lib/tasks/migrate/setup_postgresql.rake b/lib/tasks/migrate/setup_postgresql.rake
new file mode 100644
index 0000000000000000000000000000000000000000..141a0b74ec0b4a8151b40fd3320dfccd613f6888
--- /dev/null
+++ b/lib/tasks/migrate/setup_postgresql.rake
@@ -0,0 +1,8 @@
+require Rails.root.join('db/migrate/20151007120511_namespaces_projects_path_lower_indexes')
+require Rails.root.join('db/migrate/20151008110232_add_users_lower_username_email_indexes')
+
+desc 'GitLab | Sets up PostgreSQL'
+task setup_postgresql: :environment do
+  NamespacesProjectsPathLowerIndexes.new.up
+  AddUsersLowerUsernameEmailIndexes.new.up
+end
diff --git a/lib/tasks/spec.rake b/lib/tasks/spec.rake
index 831746815d7acdd9f144e585cfc82fc80aafc62f..365ff2defd41e3bc9c7a65269e9e6be1376f7dec 100644
--- a/lib/tasks/spec.rake
+++ b/lib/tasks/spec.rake
@@ -19,11 +19,20 @@ namespace :spec do
     run_commands(cmds)
   end
 
+  desc 'GitLab | Rspec | Run benchmark specs'
+  task :benchmark do
+    cmds = [
+      %W(rake gitlab:setup),
+      %W(rspec spec --tag @benchmark)
+    ]
+    run_commands(cmds)
+  end
+
   desc 'GitLab | Rspec | Run other specs'
   task :other do
     cmds = [
       %W(rake gitlab:setup),
-      %W(rspec spec --tag ~@api --tag ~@feature)
+      %W(rspec spec --tag ~@api --tag ~@feature --tag ~@benchmark)
     ]
     run_commands(cmds)
   end
@@ -33,7 +42,7 @@ desc "GitLab | Run specs"
 task :spec do
   cmds = [
     %W(rake gitlab:setup),
-    %W(rspec spec),
+    %W(rspec spec --tag ~@benchmark),
   ]
   run_commands(cmds)
 end
diff --git a/public/robots.txt b/public/robots.txt
index 528f421083e0551c796f0b855fb421e5f5494893..4f616c7f4c1cacff6e93558f47911b883fb5cd76 100644
--- a/public/robots.txt
+++ b/public/robots.txt
@@ -38,7 +38,8 @@ Disallow: /*/*/edit
 Disallow: /*/*/raw
 Disallow: /*/*/blame
 Disallow: /*/*/commits/*/*
-Disallow: /*/*/commit
+Disallow: /*/*/commit/*.patch
+Disallow: /*/*/commit/*.diff
 Disallow: /*/*/compare
 Disallow: /*/*/branches/new
 Disallow: /*/*/tags/new
diff --git a/public/uploads/.gitkeep b/public/uploads/.gitkeep
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/spec/benchmarks/finders/trending_projects_finder_spec.rb b/spec/benchmarks/finders/trending_projects_finder_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..551ce21840d6869e8314300f4aa4f2b41a8f7c05
--- /dev/null
+++ b/spec/benchmarks/finders/trending_projects_finder_spec.rb
@@ -0,0 +1,14 @@
+require 'spec_helper'
+
+describe TrendingProjectsFinder, benchmark: true do
+  describe '#execute' do
+    let(:finder) { described_class.new }
+    let(:user)   { create(:user) }
+
+    # to_a is used to force actually running the query (instead of just building
+    # it).
+    benchmark_subject { finder.execute(user).non_archived.to_a }
+
+    it { is_expected.to iterate_per_second(500) }
+  end
+end
diff --git a/spec/benchmarks/lib/gitlab/markdown/reference_filter_spec.rb b/spec/benchmarks/lib/gitlab/markdown/reference_filter_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..34cd9f7e4eb398bd64d8d65226d15bc7488767c4
--- /dev/null
+++ b/spec/benchmarks/lib/gitlab/markdown/reference_filter_spec.rb
@@ -0,0 +1,41 @@
+require 'spec_helper'
+
+describe Gitlab::Markdown::ReferenceFilter, benchmark: true do
+  let(:input) do
+    html = <<-EOF
+<p>Hello @alice and @bob, how are you doing today?</p>
+<p>This is simple @dummy text to see how the @ReferenceFilter class performs
+when @processing HTML.</p>
+    EOF
+
+    Nokogiri::HTML.fragment(html)
+  end
+
+  let(:project) { create(:empty_project) }
+
+  let(:filter) { described_class.new(input, project: project) }
+
+  describe '#replace_text_nodes_matching' do
+    let(:iterations) { 6000 }
+
+    describe 'with identical input and output HTML' do
+      benchmark_subject do
+        filter.replace_text_nodes_matching(User.reference_pattern) do |content|
+          content
+        end
+      end
+
+      it { is_expected.to iterate_per_second(iterations) }
+    end
+
+    describe 'with different input and output HTML' do
+      benchmark_subject do
+        filter.replace_text_nodes_matching(User.reference_pattern) do |content|
+          '@eve'
+        end
+      end
+
+      it { is_expected.to iterate_per_second(iterations) }
+    end
+  end
+end
diff --git a/spec/benchmarks/models/milestone_spec.rb b/spec/benchmarks/models/milestone_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..a94afc4c40d899a89b0813e5ccfef31799ec7eee
--- /dev/null
+++ b/spec/benchmarks/models/milestone_spec.rb
@@ -0,0 +1,17 @@
+require 'spec_helper'
+
+describe Milestone, benchmark: true do
+  describe '#sort_issues' do
+    let(:milestone) { create(:milestone) }
+
+    let(:issue1) { create(:issue, milestone: milestone) }
+    let(:issue2) { create(:issue, milestone: milestone) }
+    let(:issue3) { create(:issue, milestone: milestone) }
+
+    let(:issue_ids) { [issue3.id, issue2.id, issue1.id] }
+
+    benchmark_subject { milestone.sort_issues(issue_ids) }
+
+    it { is_expected.to iterate_per_second(500) }
+  end
+end
diff --git a/spec/benchmarks/models/project_spec.rb b/spec/benchmarks/models/project_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..cee0949edc53476ebe3a48d41d68b8bb2b9afd50
--- /dev/null
+++ b/spec/benchmarks/models/project_spec.rb
@@ -0,0 +1,50 @@
+require 'spec_helper'
+
+describe Project, benchmark: true do
+  describe '.trending' do
+    let(:group)    { create(:group) }
+    let(:project1) { create(:empty_project, :public, group: group) }
+    let(:project2) { create(:empty_project, :public, group: group) }
+
+    let(:iterations) { 500 }
+
+    before do
+      2.times do
+        create(:note_on_commit, project: project1)
+      end
+
+      create(:note_on_commit, project: project2)
+    end
+
+    describe 'without an explicit start date' do
+      benchmark_subject { described_class.trending.to_a }
+
+      it { is_expected.to iterate_per_second(iterations) }
+    end
+
+    describe 'with an explicit start date' do
+      let(:date) { 1.month.ago }
+
+      benchmark_subject { described_class.trending(date).to_a }
+
+      it { is_expected.to iterate_per_second(iterations) }
+    end
+  end
+
+  describe '.find_with_namespace' do
+    let(:group)   { create(:group, name: 'sisinmaru') }
+    let(:project) { create(:project, name: 'maru', namespace: group) }
+
+    describe 'using a capitalized namespace' do
+      benchmark_subject { described_class.find_with_namespace('sisinmaru/MARU') }
+
+      it { is_expected.to iterate_per_second(600) }
+    end
+
+    describe 'using a lowercased namespace' do
+      benchmark_subject { described_class.find_with_namespace('sisinmaru/maru') }
+
+      it { is_expected.to iterate_per_second(600) }
+    end
+  end
+end
diff --git a/spec/benchmarks/models/project_team_spec.rb b/spec/benchmarks/models/project_team_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..8b039ef731738b6f6afb8873b29ecded195f5c48
--- /dev/null
+++ b/spec/benchmarks/models/project_team_spec.rb
@@ -0,0 +1,23 @@
+require 'spec_helper'
+
+describe ProjectTeam, benchmark: true do
+  describe '#max_member_access' do
+    let(:group)   { create(:group) }
+    let(:project) { create(:empty_project, group: group) }
+    let(:user)    { create(:user) }
+
+    before do
+      project.team << [user, :master]
+
+      5.times do
+        project.team << [create(:user), :reporter]
+
+        project.group.add_user(create(:user), :reporter)
+      end
+    end
+
+    benchmark_subject { project.team.max_member_access(user.id) }
+
+    it { is_expected.to iterate_per_second(35000) }
+  end
+end
diff --git a/spec/benchmarks/models/user_spec.rb b/spec/benchmarks/models/user_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..cc5c3904193930ab407e6ab4d8e3280058ad2d41
--- /dev/null
+++ b/spec/benchmarks/models/user_spec.rb
@@ -0,0 +1,42 @@
+require 'spec_helper'
+
+describe User, benchmark: true do
+  describe '.by_login' do
+    before do
+      %w{Alice Bob Eve}.each do |name|
+        create(:user,
+               email: "#{name}@gitlab.com",
+               username: name,
+               name: name)
+      end
+    end
+
+    # The iteration count is based on the query taking little over 1 ms when
+    # using PostgreSQL.
+    let(:iterations) { 900 }
+
+    describe 'using a capitalized username' do
+      benchmark_subject { User.by_login('Alice') }
+
+      it { is_expected.to iterate_per_second(iterations) }
+    end
+
+    describe 'using a lowercase username' do
+      benchmark_subject { User.by_login('alice') }
+
+      it { is_expected.to iterate_per_second(iterations) }
+    end
+
+    describe 'using a capitalized Email address' do
+      benchmark_subject { User.by_login('Alice@gitlab.com') }
+
+      it { is_expected.to iterate_per_second(iterations) }
+    end
+
+    describe 'using a lowercase Email address' do
+      benchmark_subject { User.by_login('alice@gitlab.com') }
+
+      it { is_expected.to iterate_per_second(iterations) }
+    end
+  end
+end
diff --git a/spec/controllers/abuse_reports_controller_spec.rb b/spec/controllers/abuse_reports_controller_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..0faab8d7ff0b2e3885325bf5a9f48947bcc55111
--- /dev/null
+++ b/spec/controllers/abuse_reports_controller_spec.rb
@@ -0,0 +1,72 @@
+require 'spec_helper'
+
+describe AbuseReportsController do
+  let(:reporter)    { create(:user) }
+  let(:user)        { create(:user) }
+  let(:message)     { "This user is a spammer" }
+
+  before do
+    sign_in(reporter)
+  end
+
+  describe "POST create" do
+    context "with admin notification email set" do
+      let(:admin_email) { "admin@example.com"}
+
+      before(:each) do
+        stub_application_setting(admin_notification_email: admin_email)
+      end
+
+      it "sends a notification email" do
+        post :create,
+          abuse_report: {
+            user_id: user.id,
+            message: message
+          }
+
+        email = ActionMailer::Base.deliveries.last
+
+        expect(email.to).to eq([admin_email])
+        expect(email.subject).to include(user.username)
+        expect(email.text_part.body).to include(message)
+      end
+
+      it "saves the abuse report" do
+        expect do
+          post :create,
+            abuse_report: {
+              user_id: user.id,
+              message: message
+            }
+        end.to change { AbuseReport.count }.by(1)
+      end
+    end
+
+    context "without admin notification email set" do
+      before(:each) do
+        stub_application_setting(admin_notification_email: nil)
+      end
+
+      it "does not send a notification email" do
+        expect do
+          post :create,
+            abuse_report: {
+              user_id: user.id,
+              message: message
+            }
+        end.not_to change { ActionMailer::Base.deliveries.count }
+      end
+
+      it "saves the abuse report" do
+        expect do
+          post :create,
+            abuse_report: {
+              user_id: user.id,
+              message: message
+            }
+        end.to change { AbuseReport.count }.by(1)
+      end
+    end
+  end
+
+end
diff --git a/spec/controllers/admin/users_controller_spec.rb b/spec/controllers/admin/users_controller_spec.rb
index c40b2c2a5838116e5ac354a61c5bd8cd47400215..fcbe62cace85c9f243e489679fb82b486d8fc488 100644
--- a/spec/controllers/admin/users_controller_spec.rb
+++ b/spec/controllers/admin/users_controller_spec.rb
@@ -7,6 +7,21 @@ describe Admin::UsersController do
     sign_in(admin)
   end
 
+  describe 'POST login_as' do
+    let(:user) { create(:user) }
+
+    it 'logs admin as another user' do
+      expect(warden.authenticate(scope: :user)).not_to eq(user)
+      post :login_as, id: user.username
+      expect(warden.authenticate(scope: :user)).to eq(user)
+    end
+
+    it 'redirects user to homepage' do
+      post :login_as, id: user.username
+      expect(response).to redirect_to(root_path)
+    end
+  end
+
   describe 'DELETE #user with projects' do
     let(:user) { create(:user) }
     let(:project) { create(:project, namespace: user.namespace) }
@@ -22,6 +37,32 @@ describe Admin::UsersController do
     end
   end
 
+  describe 'PUT block/:id' do
+    let(:user) { create(:user) }
+
+    it 'blocks user' do
+      put :block, id: user.username
+      user.reload
+      expect(user.blocked?).to be_truthy
+      expect(flash[:notice]).to eq 'Successfully blocked'
+    end
+  end
+
+  describe 'PUT unblock/:id' do
+    let(:user) { create(:user) }
+
+    before do
+      user.block
+    end
+
+    it 'unblocks user' do
+      put :unblock, id: user.username
+      user.reload
+      expect(user.blocked?).to be_falsey
+      expect(flash[:notice]).to eq 'Successfully unblocked'
+    end
+  end
+
   describe 'PUT unlock/:id' do
     let(:user) { create(:user) }
 
diff --git a/spec/controllers/ci/commits_controller_spec.rb b/spec/controllers/ci/commits_controller_spec.rb
deleted file mode 100644
index b71e7505731241b109e4215e1a7a252a21f8c55f..0000000000000000000000000000000000000000
--- a/spec/controllers/ci/commits_controller_spec.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-require "spec_helper"
-
-describe Ci::CommitsController do
-  before do
-    @project = FactoryGirl.create :ci_project
-  end
-
-  describe "GET /status" do
-    it "returns status of commit" do
-      commit = FactoryGirl.create :ci_commit, project: @project
-      get :status, id: commit.sha, ref_id: commit.ref, project_id: @project.id
-
-      expect(response).to be_success
-      expect(response.code).to eq('200')
-      JSON.parse(response.body)["status"] == "pending"
-    end
-
-    it "returns not_found status" do
-      commit = FactoryGirl.create :ci_commit, project: @project
-      get :status, id: commit.sha, ref_id: "deploy", project_id: @project.id
-
-      expect(response).to be_success
-      expect(response.code).to eq('200')
-      JSON.parse(response.body)["status"] == "not_found"
-    end
-  end
-end
diff --git a/spec/controllers/import/github_controller_spec.rb b/spec/controllers/import/github_controller_spec.rb
index 766be578f7f34be0ba9b01e47f5f232efe378105..bbf8adef534548e2c4dcff99a154e15058ecda87 100644
--- a/spec/controllers/import/github_controller_spec.rb
+++ b/spec/controllers/import/github_controller_spec.rb
@@ -41,7 +41,7 @@ describe Import::GithubController do
 
     it "assigns variables" do
       @project = create(:project, import_type: 'github', creator_id: user.id)
-      stub_client(repos: [@repo], orgs: [@org], org_repos: [@org_repo])
+      stub_client(repos: [@repo, @org_repo], orgs: [@org], org_repos: [@org_repo])
 
       get :status
 
diff --git a/spec/controllers/invites_controller_spec.rb b/spec/controllers/invites_controller_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..3c6e54839b5eb1d0ef5d76211aa9dfa81493c04d
--- /dev/null
+++ b/spec/controllers/invites_controller_spec.rb
@@ -0,0 +1,33 @@
+require 'spec_helper'
+
+describe InvitesController do
+  let(:token) { '123456' }
+  let(:user) { create(:user) }
+  let(:member) { create(:project_member, invite_token: token, invite_email: 'test@abc.com', user: user) }
+
+  before do
+    controller.instance_variable_set(:@member, member)
+    sign_in(user)
+  end
+
+  describe 'GET #accept' do
+    it 'accepts user' do
+      get :accept, id: token
+      member.reload
+
+      expect(response.status).to eq(302)
+      expect(member.user).to eq(user)
+      expect(flash[:notice]).to include 'You have been granted'
+    end
+  end
+
+  describe 'GET #decline' do
+    it 'declines user' do
+      get :decline, id: token
+      expect{member.reload}.to raise_error ActiveRecord::RecordNotFound
+
+      expect(response.status).to eq(302)
+      expect(flash[:notice]).to include 'You have declined the invitation to join'
+    end
+  end
+end
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index 871b9219ca92fd24e1f6b717b617dfbf1f941a2b..76d56bc989d97507a399a8aa60ba96122164f194 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -8,28 +8,34 @@ describe Projects::IssuesController do
   before do
     sign_in(user)
     project.team << [user, :developer]
-    controller.instance_variable_set(:@project, project)
   end
 
   describe "GET #index" do
     it "returns index" do
-      get :index, namespace_id: project.namespace.id, project_id: project.id
+      get :index, namespace_id: project.namespace.path, project_id: project.path
 
       expect(response.status).to eq(200)
     end
 
+    it "return 301 if request path doesn't match project path" do
+      get :index, namespace_id: project.namespace.path, project_id: project.path.upcase
+
+      expect(response).to redirect_to(namespace_project_issues_path(project.namespace, project))
+    end
+
     it "returns 404 when issues are disabled" do
       project.issues_enabled = false
       project.save
 
-      get :index, namespace_id: project.namespace.id, project_id: project.id
+      get :index, namespace_id: project.namespace.path, project_id: project.path
       expect(response.status).to eq(404)
     end
 
     it "returns 404 when external issue tracker is enabled" do
+      controller.instance_variable_set(:@project, project)
       allow(project).to receive(:default_issues_tracker?).and_return(false)
 
-      get :index, namespace_id: project.namespace.id, project_id: project.id
+      get :index, namespace_id: project.namespace.path, project_id: project.path
       expect(response.status).to eq(404)
     end
 
diff --git a/spec/controllers/projects/repositories_controller_spec.rb b/spec/controllers/projects/repositories_controller_spec.rb
index 91856ed0cc0341fbd49a0e7d98be6ae3bd63c385..18a30033ed8ed73dd048fc155bd00cb22957d174 100644
--- a/spec/controllers/projects/repositories_controller_spec.rb
+++ b/spec/controllers/projects/repositories_controller_spec.rb
@@ -33,33 +33,5 @@ describe Projects::RepositoriesController do
         expect(response.status).to eq(404)
       end
     end
-
-    context "when the service doesn't return a path" do
-
-      before do
-        allow(service).to receive(:execute).and_return(nil)
-      end
-
-      it "reloads the page" do
-        get :archive, namespace_id: project.namespace.path, project_id: project.path, ref: "master", format: "zip"
-
-        expect(response).to redirect_to(archive_namespace_project_repository_path(project.namespace, project, ref: "master", format: "zip"))
-      end
-    end
-
-    context "when the service returns a path" do
-
-      let(:path) { Rails.root.join("spec/fixtures/dk.png").to_s }
-
-      before do
-        allow(service).to receive(:execute).and_return(path)
-      end
-
-      it "sends the file" do
-        get :archive, namespace_id: project.namespace.path, project_id: project.path, ref: "master", format: "zip"
-
-        expect(response.body).to eq(File.binread(path))
-      end
-    end
   end
 end
diff --git a/spec/controllers/projects/services_controller_spec.rb b/spec/controllers/projects/services_controller_spec.rb
index d4ecd98e12d2038e1e499c21ffeb9df386942950..ccd8c741c832427ade04df1b95499031c2ba8700 100644
--- a/spec/controllers/projects/services_controller_spec.rb
+++ b/spec/controllers/projects/services_controller_spec.rb
@@ -10,26 +10,43 @@ describe Projects::ServicesController do
     project.team << [user, :master]
     controller.instance_variable_set(:@project, project)
     controller.instance_variable_set(:@service, service)
-    request.env["HTTP_REFERER"] = "/"
   end
 
-  describe "#test" do
-    context 'success' do
-      it "should redirect and show success message" do
-        expect(service).to receive(:test).and_return({ success: true, result: 'done' })
-        get :test, namespace_id: project.namespace.id, project_id: project.id, id: service.id, format: :html
-        expect(response.status).to redirect_to('/')
-        expect(flash[:notice]).to eq('We sent a request to the provided URL')
-      end
+  shared_examples_for 'services controller' do |referrer|
+    before do
+      request.env["HTTP_REFERER"] = referrer
     end
 
-    context 'failure' do
-      it "should redirect and show failure message" do
-        expect(service).to receive(:test).and_return({ success: false, result: 'Bad test' })
-        get :test, namespace_id: project.namespace.id, project_id: project.id, id: service.id, format: :html
-        expect(response.status).to redirect_to('/')
-        expect(flash[:alert]).to eq('We tried to send a request to the provided URL but an error occurred: Bad test')
+    describe "#test" do
+      context 'success' do
+        it "should redirect and show success message" do
+          expect(service).to receive(:test).and_return({ success: true, result: 'done' })
+          get :test, namespace_id: project.namespace.id, project_id: project.id, id: service.id, format: :html
+          expect(response.status).to redirect_to('/')
+          expect(flash[:notice]).to eq('We sent a request to the provided URL')
+        end
+      end
+
+      context 'failure' do
+        it "should redirect and show failure message" do
+          expect(service).to receive(:test).and_return({ success: false, result: 'Bad test' })
+          get :test, namespace_id: project.namespace.id, project_id: project.id, id: service.id, format: :html
+          expect(response.status).to redirect_to('/')
+          expect(flash[:alert]).to eq('We tried to send a request to the provided URL but an error occurred: Bad test')
+        end
       end
     end
   end
+
+  describe 'referrer defined' do
+    it_should_behave_like 'services controller' do
+      let!(:referrer) { "/" }
+    end
+  end
+
+  describe 'referrer undefined' do
+    it_should_behave_like 'services controller' do
+      let!(:referrer) { nil }
+    end
+  end
 end
diff --git a/spec/controllers/projects/tree_controller_spec.rb b/spec/controllers/projects/tree_controller_spec.rb
index 53915856357570e992a65547d3bcc0d6c3ee88d6..a474574c6e5a40284b9a57e9d6ad9ffdd44b81a5 100644
--- a/spec/controllers/projects/tree_controller_spec.rb
+++ b/spec/controllers/projects/tree_controller_spec.rb
@@ -88,4 +88,40 @@ describe Projects::TreeController do
       end
     end
   end
+
+  describe '#create_dir' do
+    render_views
+
+    before do
+      post(:create_dir,
+           namespace_id: project.namespace.to_param,
+           project_id: project.to_param,
+           id: 'master',
+           dir_name: path,
+           new_branch: target_branch,
+           commit_message: 'Test commit message')
+    end
+
+    context 'successful creation' do
+      let(:path) { 'files/new_dir'}
+      let(:target_branch) { 'master-test'}
+
+      it 'redirects to the new directory' do
+        expect(subject).
+            to redirect_to("/#{project.path_with_namespace}/blob/#{target_branch}/#{path}")
+        expect(flash[:notice]).to eq('The directory has been successfully created')
+      end
+    end
+
+    context 'unsuccessful creation' do
+      let(:path) { 'README.md' }
+      let(:target_branch) { 'master'}
+
+      it 'does not allow overwriting of existing files' do
+        expect(subject).
+            to redirect_to("/#{project.path_with_namespace}/blob/master")
+        expect(flash[:alert]).to eq('Directory already exists as a file')
+      end
+    end
+  end
 end
diff --git a/spec/controllers/projects/uploads_controller_spec.rb b/spec/controllers/projects/uploads_controller_spec.rb
index f51abfedae529db22d8ec3705233e27e1d0dc61f..93c4494c6607ef084889c7b8faab31158d4bd433 100644
--- a/spec/controllers/projects/uploads_controller_spec.rb
+++ b/spec/controllers/projects/uploads_controller_spec.rb
@@ -33,7 +33,7 @@ describe Projects::UploadsController do
 
       it 'returns a content with original filename, new link, and correct type.' do
         expect(response.body).to match '\"alt\":\"rails_sample\"'
-        expect(response.body).to match "\"url\":\"http://localhost/#{project.path_with_namespace}/uploads"
+        expect(response.body).to match "\"url\":\"/uploads"
         expect(response.body).to match '\"is_image\":true'
       end
     end
@@ -49,7 +49,7 @@ describe Projects::UploadsController do
 
       it 'returns a content with original filename, new link, and correct type.' do
         expect(response.body).to match '\"alt\":\"doc_sample.txt\"'
-        expect(response.body).to match "\"url\":\"http://localhost/#{project.path_with_namespace}/uploads"
+        expect(response.body).to match "\"url\":\"/uploads"
         expect(response.body).to match '\"is_image\":false'
       end
     end
diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb
index 29233e9fae6fa3c21124b9deeb02edbb46635025..4bb47c6b02559c73c815f659801c16060aa13b80 100644
--- a/spec/controllers/projects_controller_spec.rb
+++ b/spec/controllers/projects_controller_spec.rb
@@ -21,6 +21,71 @@ describe ProjectsController do
         expect(response.body).to include("content='#{content}'")
       end
     end
+
+    context "rendering default project view" do
+      render_views
+
+      it "renders the activity view" do
+        allow(controller).to receive(:current_user).and_return(user)
+        allow(user).to receive(:project_view).and_return('activity')
+
+        get :show, namespace_id: public_project.namespace.path, id: public_project.path
+        expect(response).to render_template('_activity')
+      end
+
+      it "renders the readme view" do
+        allow(controller).to receive(:current_user).and_return(user)
+        allow(user).to receive(:project_view).and_return('readme')
+
+        get :show, namespace_id: public_project.namespace.path, id: public_project.path
+        expect(response).to render_template('_readme')
+      end
+
+      it "renders the files view" do
+        allow(controller).to receive(:current_user).and_return(user)
+        allow(user).to receive(:project_view).and_return('files')
+
+        get :show, namespace_id: public_project.namespace.path, id: public_project.path
+        expect(response).to render_template('_files')
+      end
+    end
+
+    context "when requested with case sensitive namespace and project path" do
+      context "when there is a match with the same casing" do
+        it "loads the project" do
+          get :show, namespace_id: public_project.namespace.path, id: public_project.path
+
+          expect(assigns(:project)).to eq(public_project)
+          expect(response.status).to eq(200)
+        end
+      end
+
+      context "when there is a match with different casing" do
+        it "redirects to the normalized path" do
+          get :show, namespace_id: public_project.namespace.path, id: public_project.path.upcase
+
+          expect(assigns(:project)).to eq(public_project)
+          expect(response).to redirect_to("/#{public_project.path_with_namespace}")
+        end
+
+
+        # MySQL queries are case insensitive by default, so this spec would fail.
+        if Gitlab::Database.postgresql?
+          context "when there is also a match with the same casing" do
+
+            let!(:other_project) { create(:project, :public, namespace: public_project.namespace, path: public_project.path.upcase) }
+
+            it "loads the exactly matched project" do
+
+              get :show, namespace_id: public_project.namespace.path, id: public_project.path.upcase
+
+              expect(assigns(:project)).to eq(other_project)
+              expect(response.status).to eq(200)
+            end
+          end
+        end
+      end
+    end
   end
 
   describe "POST #toggle_star" do
@@ -48,4 +113,50 @@ describe ProjectsController do
       expect(user.starred?(public_project)).to be_falsey
     end
   end
+
+  describe "DELETE remove_fork" do
+    context 'when signed in' do
+      before do
+        sign_in(user)
+      end
+
+      context 'with forked project' do
+        let(:project_fork) { create(:project, namespace: user.namespace) }
+
+        before do
+          create(:forked_project_link, forked_to_project: project_fork)
+        end
+
+        it 'should remove fork from project' do
+          delete(:remove_fork,
+              namespace_id: project_fork.namespace.to_param,
+              id: project_fork.to_param, format: :js)
+
+          expect(project_fork.forked?).to be_falsey
+          expect(flash[:notice]).to eq('The fork relationship has been removed.')
+          expect(response).to render_template(:remove_fork)
+        end
+      end
+
+      context 'when project not forked' do
+        let(:unforked_project) { create(:project, namespace: user.namespace) }
+
+        it 'should do nothing if project was not forked' do
+          delete(:remove_fork,
+              namespace_id: unforked_project.namespace.to_param,
+              id: unforked_project.to_param, format: :js)
+
+          expect(flash[:notice]).to be_nil
+          expect(response).to render_template(:remove_fork)
+        end
+      end
+    end
+
+    it "does nothing if user is not signed in" do
+      delete(:remove_fork,
+          namespace_id: project.namespace.to_param,
+          id: project.to_param, format: :js)
+      expect(response.status).to eq(401)
+    end
+  end
 end
diff --git a/spec/controllers/root_controller_spec.rb b/spec/controllers/root_controller_spec.rb
index 64dfe8f34e30cadde01e53b872dde8e3406152b5..5a104ae7c99a193dc9eb7e9744a0f15f143d4769 100644
--- a/spec/controllers/root_controller_spec.rb
+++ b/spec/controllers/root_controller_spec.rb
@@ -10,7 +10,7 @@ describe RootController do
         allow(subject).to receive(:current_user).and_return(user)
       end
 
-      context 'who has customized their dashboard setting' do
+      context 'who has customized their dashboard setting for starred projects' do
         before do
           user.update_attribute(:dashboard, 'stars')
         end
@@ -21,6 +21,28 @@ describe RootController do
         end
       end
 
+      context 'who has customized their dashboard setting for project activities' do
+        before do
+          user.update_attribute(:dashboard, 'project_activity')
+        end
+
+        it 'redirects to the activity list' do
+          get :index
+          expect(response).to redirect_to activity_dashboard_path
+        end
+      end
+
+      context 'who has customized their dashboard setting for starred project activities' do
+        before do
+          user.update_attribute(:dashboard, 'starred_project_activity')
+        end
+
+        it 'redirects to the activity list' do
+          get :index
+          expect(response).to redirect_to activity_dashboard_path(filter: 'starred')
+        end
+      end
+
       context 'who uses the default dashboard setting' do
         it 'renders the default dashboard' do
           get :index
diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb
index 99da5a187769d86792457f154c7523bdcd2ff58d..2fcd70182b9765414d1fc6c3dd2ab1c2c5ef5de8 100644
--- a/spec/factories/ci/builds.rb
+++ b/spec/factories/ci/builds.rb
@@ -27,6 +27,9 @@
 
 FactoryGirl.define do
   factory :ci_build, class: Ci::Build do
+    name 'test'
+    ref 'master'
+    tag false
     started_at 'Di 29. Okt 09:51:28 CET 2013'
     finished_at 'Di 29. Okt 09:53:28 CET 2013'
     commands 'ls -a'
@@ -43,5 +46,9 @@ FactoryGirl.define do
       started_at nil
       finished_at nil
     end
+
+    factory :ci_build_tag do
+      tag true
+    end
   end
 end
diff --git a/spec/factories/ci/commits.rb b/spec/factories/ci/commits.rb
index 70930c789c3329ab1c53c5b176e0f94daa27c16f..79e000b7ccb1c164e519f93d70904303a3ff3c51 100644
--- a/spec/factories/ci/commits.rb
+++ b/spec/factories/ci/commits.rb
@@ -17,58 +17,32 @@
 
 # Read about factories at https://github.com/thoughtbot/factory_girl
 FactoryGirl.define do
-  factory :ci_commit, class: Ci::Commit do
-    ref 'master'
-    before_sha '76de212e80737a608d939f648d959671fb0a0142'
+  factory :ci_empty_commit, class: Ci::Commit do
     sha '97de212e80737a608d939f648d959671fb0a0142'
-    push_data do
-      {
-        ref: 'refs/heads/master',
-        before: '76de212e80737a608d939f648d959671fb0a0142',
-        after: '97de212e80737a608d939f648d959671fb0a0142',
-        user_name: 'Git User',
-        user_email: 'git@example.com',
-        repository: {
-          name: 'test-data',
-          url: 'ssh://git@gitlab.com/test/test-data.git',
-          description: '',
-          homepage: 'http://gitlab.com/test/test-data'
-        },
-        commits: [
-          {
-            id: '97de212e80737a608d939f648d959671fb0a0142',
-            message: 'Test commit message',
-            timestamp: '2014-09-23T13:12:25+02:00',
-            url: 'https://gitlab.com/test/test-data/commit/97de212e80737a608d939f648d959671fb0a0142',
-            author: {
-              name: 'Git User',
-              email: 'git@user.com'
-            }
-          }
-        ],
-        total_commits_count: 1,
-        ci_yaml_file: File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml'))
-      }
-    end
+
+    gl_project factory: :empty_project
 
     factory :ci_commit_without_jobs do
-      after(:create) do |commit, evaluator|
-        commit.push_data[:ci_yaml_file] = YAML.dump({})
-        commit.save
+      after(:build) do |commit|
+        allow(commit).to receive(:ci_yaml_file) { YAML.dump({}) }
       end
     end
 
     factory :ci_commit_with_one_job do
-      after(:create) do |commit, evaluator|
-        commit.push_data[:ci_yaml_file] = YAML.dump({ rspec: { script: "ls" } })
-        commit.save
+      after(:build) do |commit|
+        allow(commit).to receive(:ci_yaml_file) { YAML.dump({ rspec: { script: "ls" } }) }
       end
     end
 
     factory :ci_commit_with_two_jobs do
-      after(:create) do |commit, evaluator|
-        commit.push_data[:ci_yaml_file] = YAML.dump({ rspec: { script: "ls" }, spinach: { script: "ls" } })
-        commit.save
+      after(:build) do |commit|
+        allow(commit).to receive(:ci_yaml_file) { YAML.dump({ rspec: { script: "ls" }, spinach: { script: "ls" } }) }
+      end
+    end
+
+    factory :ci_commit do
+      after(:build) do |commit|
+        allow(commit).to receive(:ci_yaml_file) { File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml')) }
       end
     end
   end
diff --git a/spec/factories/ci/projects.rb b/spec/factories/ci/projects.rb
index e6bd0685f8de98a5e5682225551aed2904776087..111e1a8281680219c26870507ab8e3d35e687293 100644
--- a/spec/factories/ci/projects.rb
+++ b/spec/factories/ci/projects.rb
@@ -29,21 +29,9 @@
 
 FactoryGirl.define do
   factory :ci_project_without_token, class: Ci::Project do
-    sequence :name do |n|
-      "GitLab / gitlab-shell#{n}"
-    end
-
     default_ref 'master'
 
-    sequence :path do |n|
-      "gitlab/gitlab-shell#{n}"
-    end
-
-    sequence :ssh_url_to_repo do |n|
-      "git@demo.gitlab.com:gitlab/gitlab-shell#{n}.git"
-    end
-
-    gl_project factory: :project
+    gl_project factory: :empty_project
 
     factory :ci_project do
       token 'iPWx6WM4lhHNedGfBpPJNP'
diff --git a/spec/factories/commit_statuses.rb b/spec/factories/commit_statuses.rb
new file mode 100644
index 0000000000000000000000000000000000000000..52de437052d99e4047900e64560c5771a06afb13
--- /dev/null
+++ b/spec/factories/commit_statuses.rb
@@ -0,0 +1,15 @@
+FactoryGirl.define do
+  factory :commit_status, class: CommitStatus do
+    started_at 'Di 29. Okt 09:51:28 CET 2013'
+    finished_at 'Di 29. Okt 09:53:28 CET 2013'
+    name 'default'
+    status 'success'
+    description 'commit status'
+    commit factory: :ci_commit
+
+    factory :generic_commit_status, class: GenericCommitStatus do
+      name 'generic'
+      description 'external commit status'
+    end
+  end
+end
diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb
index 8671776158291f31e40ab53c97ac39f7b6a8f492..c2c7364f6c51b59dd9d75182f2d3b85a3577ccb4 100644
--- a/spec/features/admin/admin_users_spec.rb
+++ b/spec/features/admin/admin_users_spec.rb
@@ -111,6 +111,27 @@ describe "Admin::Users", feature: true  do
       expect(page).to have_content(@user.name)
     end
 
+    describe 'Login as another user' do
+      it 'should show login button for other users and check that it works' do
+        another_user = create(:user)
+
+        visit admin_user_path(another_user)
+
+        click_link 'Log in as this user'
+
+        expect(page).to have_content("Logged in as #{another_user.username}")
+
+        page.within '.sidebar-user .username' do
+          expect(page).to have_content(another_user.username)
+        end
+      end
+
+      it 'should not show login button for admin itself' do
+        visit admin_user_path(@user)
+        expect(page).not_to have_content('Log in as this user')
+      end
+    end
+
     describe 'Two-factor Authentication status' do
       it 'shows when enabled' do
         @user.update_attribute(:two_factor_enabled, true)
diff --git a/spec/features/builds_spec.rb b/spec/features/builds_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..154857e77fef6f7d5e89238a81107134c1b4f1d9
--- /dev/null
+++ b/spec/features/builds_spec.rb
@@ -0,0 +1,89 @@
+require 'spec_helper'
+
+describe "Builds" do
+  before do
+    login_as(:user)
+    @commit = FactoryGirl.create :ci_commit
+    @build = FactoryGirl.create :ci_build, commit: @commit
+    @gl_project = @commit.project.gl_project
+    @gl_project.team << [@user, :master]
+  end
+
+  describe "GET /:project/builds" do
+    context "Running scope" do
+      before do
+        @build.run!
+        visit namespace_project_builds_path(@gl_project.namespace, @gl_project)
+      end
+
+      it { expect(page).to have_content 'Running' }
+      it { expect(page).to have_content 'Cancel all' }
+      it { expect(page).to have_content @build.short_sha }
+      it { expect(page).to have_content @build.ref }
+      it { expect(page).to have_content @build.name }
+    end
+
+    context "Finished scope" do
+      before do
+        @build.run!
+        visit namespace_project_builds_path(@gl_project.namespace, @gl_project, scope: :finished)
+      end
+
+      it { expect(page).to have_content 'No builds to show' }
+      it { expect(page).to have_content 'Cancel all' }
+    end
+
+    context "All builds" do
+      before do
+        @gl_project.ci_builds.running_or_pending.each(&:success)
+        visit namespace_project_builds_path(@gl_project.namespace, @gl_project, scope: :all)
+      end
+
+      it { expect(page).to have_content 'All' }
+      it { expect(page).to have_content @build.short_sha }
+      it { expect(page).to have_content @build.ref }
+      it { expect(page).to have_content @build.name }
+      it { expect(page).to_not have_content 'Cancel all' }
+    end
+  end
+
+  describe "GET /:project/builds/:id/cancel_all" do
+    before do
+      @build.run!
+      visit cancel_all_namespace_project_builds_path(@gl_project.namespace, @gl_project)
+    end
+
+    it { expect(page).to have_content 'No builds to show' }
+    it { expect(page).to_not have_content 'Cancel all' }
+  end
+
+  describe "GET /:project/builds/:id" do
+    before do
+      visit namespace_project_build_path(@gl_project.namespace, @gl_project, @build)
+    end
+
+    it { expect(page).to have_content @commit.sha[0..7] }
+    it { expect(page).to have_content @commit.git_commit_message }
+    it { expect(page).to have_content @commit.git_author_name }
+  end
+
+  describe "GET /:project/builds/:id/cancel" do
+    before do
+      @build.run!
+      visit cancel_namespace_project_build_path(@gl_project.namespace, @gl_project, @build)
+    end
+
+    it { expect(page).to have_content 'canceled' }
+    it { expect(page).to have_content 'Retry' }
+  end
+
+  describe "POST /:project/builds/:id/retry" do
+    before do
+      visit cancel_namespace_project_build_path(@gl_project.namespace, @gl_project, @build)
+      click_link 'Retry'
+    end
+
+    it { expect(page).to have_content 'pending' }
+    it { expect(page).to have_content 'Cancel' }
+  end
+end
diff --git a/spec/features/ci/admin/builds_spec.rb b/spec/features/ci/admin/builds_spec.rb
index 88ef9c144af14b29b0a17d059fb2bf95ec9b9881..623d466c67b2a09f0078def8f12e8371bb1c310c 100644
--- a/spec/features/ci/admin/builds_spec.rb
+++ b/spec/features/ci/admin/builds_spec.rb
@@ -1,8 +1,7 @@
 require 'spec_helper'
 
 describe "Admin Builds" do
-  let(:project) { FactoryGirl.create :ci_project }
-  let(:commit) { FactoryGirl.create :ci_commit, project: project }
+  let(:commit) { FactoryGirl.create :ci_commit }
   let(:build) { FactoryGirl.create :ci_build, commit: commit }
 
   before do
@@ -22,10 +21,10 @@ describe "Admin Builds" do
 
   describe "Tabs" do
     it "shows all builds" do
-      build = FactoryGirl.create :ci_build, commit: commit, status: "pending"
-      build1 = FactoryGirl.create :ci_build, commit: commit, status: "running"
-      build2 = FactoryGirl.create :ci_build, commit: commit, status: "success"
-      build3 = FactoryGirl.create :ci_build, commit: commit, status: "failed"
+      FactoryGirl.create :ci_build, commit: commit, status: "pending"
+      FactoryGirl.create :ci_build, commit: commit, status: "running"
+      FactoryGirl.create :ci_build, commit: commit, status: "success"
+      FactoryGirl.create :ci_build, commit: commit, status: "failed"
 
       visit ci_admin_builds_path
 
diff --git a/spec/features/ci/admin/runners_spec.rb b/spec/features/ci/admin/runners_spec.rb
index b25121f08066c7dbba319165ea35bd661f9f82a2..b83744f53a8c4ea731a057f4563d47ec57979726 100644
--- a/spec/features/ci/admin/runners_spec.rb
+++ b/spec/features/ci/admin/runners_spec.rb
@@ -2,8 +2,7 @@ require 'spec_helper'
 
 describe "Admin Runners" do
   before do
-    skip_ci_admin_auth
-    login_as :user
+    login_as :admin
   end
 
   describe "Runners page" do
@@ -20,16 +19,16 @@ describe "Admin Runners" do
 
     describe 'search' do
       before do
-        FactoryGirl.create :ci_runner, description: 'foo'
-        FactoryGirl.create :ci_runner, description: 'bar'
+        FactoryGirl.create :ci_runner, description: 'runner-foo'
+        FactoryGirl.create :ci_runner, description: 'runner-bar'
 
         search_form = find('#runners-search')
-        search_form.fill_in 'search', with: 'foo'
+        search_form.fill_in 'search', with: 'runner-foo'
         search_form.click_button 'Search'
       end
 
-      it { expect(page).to have_content("foo") }
-      it { expect(page).not_to have_content("bar") }
+      it { expect(page).to have_content("runner-foo") }
+      it { expect(page).not_to have_content("runner-bar") }
     end
   end
 
@@ -37,8 +36,8 @@ describe "Admin Runners" do
     let(:runner) { FactoryGirl.create :ci_runner }
 
     before do
-      FactoryGirl.create(:ci_project, name: "foo")
-      FactoryGirl.create(:ci_project, name: "bar")
+      @project1 = FactoryGirl.create(:ci_project)
+      @project2 = FactoryGirl.create(:ci_project)
       visit ci_admin_runner_path(runner)
     end
 
@@ -47,19 +46,19 @@ describe "Admin Runners" do
     end
 
     describe 'projects' do
-      it { expect(page).to have_content("foo") }
-      it { expect(page).to have_content("bar") }
+      it { expect(page).to have_content(@project1.name_with_namespace) }
+      it { expect(page).to have_content(@project2.name_with_namespace) }
     end
 
     describe 'search' do
       before do
         search_form = find('#runner-projects-search')
-        search_form.fill_in 'search', with: 'foo'
+        search_form.fill_in 'search', with: @project1.gl_project.name
         search_form.click_button 'Search'
       end
 
-      it { expect(page).to have_content("foo") }
-      it { expect(page).not_to have_content("bar") }
+      it { expect(page).to have_content(@project1.name_with_namespace) }
+      it { expect(page).not_to have_content(@project2.name_with_namespace) }
     end
   end
 end
diff --git a/spec/features/ci/builds_spec.rb b/spec/features/ci/builds_spec.rb
deleted file mode 100644
index 2f020e524e2206a200e3d6866379fb707438f2de..0000000000000000000000000000000000000000
--- a/spec/features/ci/builds_spec.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-require 'spec_helper'
-
-describe "Builds" do
-  context :private_project do
-    before do
-      @project = FactoryGirl.create :ci_project
-      @commit = FactoryGirl.create :ci_commit, project: @project
-      @build = FactoryGirl.create :ci_build, commit: @commit
-      login_as :user
-      @project.gl_project.team << [@user, :master]
-    end
-
-    describe "GET /:project/builds/:id" do
-      before do
-        visit ci_project_build_path(@project, @build)
-      end
-
-      it { expect(page).to have_content @commit.sha[0..7] }
-      it { expect(page).to have_content @commit.git_commit_message }
-      it { expect(page).to have_content @commit.git_author_name }
-    end
-
-    describe "GET /:project/builds/:id/cancel" do
-      before do
-        @build.run!
-        visit cancel_ci_project_build_path(@project, @build)
-      end
-
-      it { expect(page).to have_content 'canceled' }
-      it { expect(page).to have_content 'Retry' }
-    end
-
-    describe "POST /:project/builds/:id/retry" do
-      before do
-        @build.cancel!
-        visit ci_project_build_path(@project, @build)
-        click_link 'Retry'
-      end
-
-      it { expect(page).to have_content 'pending' }
-      it { expect(page).to have_content 'Cancel' }
-    end
-  end
-
-  context :public_project do
-    describe "Show page public accessible" do
-      before do
-        @project = FactoryGirl.create :ci_public_project
-        @commit = FactoryGirl.create :ci_commit, project: @project
-        @runner = FactoryGirl.create :ci_specific_runner
-        @build = FactoryGirl.create :ci_build, commit: @commit, runner: @runner
-
-        stub_gitlab_calls
-        visit ci_project_build_path(@project, @build)
-      end
-
-      it { expect(page).to have_content @commit.sha[0..7] }
-    end
-  end
-end
diff --git a/spec/features/ci/commits_spec.rb b/spec/features/ci/commits_spec.rb
deleted file mode 100644
index 40a62ca457454e15e42a71467e8aef3e8ad74948..0000000000000000000000000000000000000000
--- a/spec/features/ci/commits_spec.rb
+++ /dev/null
@@ -1,69 +0,0 @@
-require 'spec_helper'
-
-describe "Commits" do
-  include Ci::CommitsHelper
-
-  context "Authenticated user" do
-    before do
-      @project = FactoryGirl.create :ci_project
-      @commit = FactoryGirl.create :ci_commit, project: @project
-      @build = FactoryGirl.create :ci_build, commit: @commit
-      login_as :user
-      @project.gl_project.team << [@user, :master]
-    end
-
-    describe "GET /:project/commits/:sha" do
-      before do
-        visit ci_commit_path(@commit)
-      end
-
-      it { expect(page).to have_content @commit.sha[0..7] }
-      it { expect(page).to have_content @commit.git_commit_message }
-      it { expect(page).to have_content @commit.git_author_name }
-    end
-
-    describe "Cancel commit" do
-      it "cancels commit" do
-        visit ci_commit_path(@commit)
-        click_on "Cancel"
-
-        expect(page).to have_content "canceled"
-      end
-    end
-
-    describe ".gitlab-ci.yml not found warning" do
-      it "does not show warning" do
-        visit ci_commit_path(@commit)
-
-        expect(page).not_to have_content ".gitlab-ci.yml not found in this commit"
-      end
-
-      it "shows warning" do
-        @commit.push_data[:ci_yaml_file] = nil
-        @commit.save
-
-        visit ci_commit_path(@commit)
-
-        expect(page).to have_content ".gitlab-ci.yml not found in this commit"
-      end
-    end
-  end
-
-  context "Public pages" do
-    before do
-      @project = FactoryGirl.create :ci_public_project
-      @commit = FactoryGirl.create :ci_commit, project: @project
-      @build = FactoryGirl.create :ci_build, commit: @commit
-    end
-
-    describe "GET /:project/commits/:sha" do
-      before do
-        visit ci_commit_path(@commit)
-      end
-
-      it { expect(page).to have_content @commit.sha[0..7] }
-      it { expect(page).to have_content @commit.git_commit_message }
-      it { expect(page).to have_content @commit.git_author_name }
-    end
-  end
-end
diff --git a/spec/features/ci/projects_spec.rb b/spec/features/ci/projects_spec.rb
deleted file mode 100644
index 7c8cd1ce5c7d266444b483d9accf627ecce9ffb3..0000000000000000000000000000000000000000
--- a/spec/features/ci/projects_spec.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-require 'spec_helper'
-
-describe "Projects" do
-  let(:user)    { create(:user) }
-
-  before do
-    login_as(user)
-    @project = FactoryGirl.create :ci_project, name: "GitLab / gitlab-shell"
-    @project.gl_project.team << [user, :master]
-  end
-
-  describe "GET /ci/projects/:id" do
-    before do
-      visit ci_project_path(@project)
-    end
-
-    it { expect(page).to have_content @project.name }
-    it { expect(page).to have_content 'All commits' }
-  end
-
-  describe "GET /ci/projects/:id/edit" do
-    before do
-      visit edit_ci_project_path(@project)
-    end
-
-    it { expect(page).to have_content @project.name }
-    it { expect(page).to have_content 'Build Schedule' }
-
-    it "updates configuration" do
-      fill_in 'Timeout', with: '70'
-      click_button 'Save changes'
-
-      expect(page).to have_content 'was successfully updated'
-
-      expect(find_field('Timeout').value).to eq '70'
-    end
-  end
-end
diff --git a/spec/features/ci_settings_spec.rb b/spec/features/ci_settings_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..7e25e8830182b10ca7f3ca797688de8eecd7f896
--- /dev/null
+++ b/spec/features/ci_settings_spec.rb
@@ -0,0 +1,22 @@
+require 'spec_helper'
+
+describe "CI settings" do
+  let(:user) { create(:user) }
+  before { login_as(user) }
+
+  before do
+    @project = FactoryGirl.create :ci_project
+    @gl_project = @project.gl_project
+    @gl_project.team << [user, :master]
+    visit edit_namespace_project_ci_settings_path(@gl_project.namespace, @gl_project)
+  end
+
+  it { expect(page).to have_content 'Build Schedule' }
+
+  it "updates configuration" do
+    fill_in 'Timeout', with: '70'
+    click_button 'Save changes'
+    expect(page).to have_content 'was successfully updated'
+    expect(find_field('Timeout').value).to eq '70'
+  end
+end
diff --git a/spec/features/ci_web_hooks_spec.rb b/spec/features/ci_web_hooks_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..efae0a42c1ef00da94ba694a4a18c0f2de894b30
--- /dev/null
+++ b/spec/features/ci_web_hooks_spec.rb
@@ -0,0 +1,27 @@
+require 'spec_helper'
+
+describe 'CI web hooks' do
+  let(:user) { create(:user) }
+  before { login_as(user) }
+
+  before do
+    @project = FactoryGirl.create :ci_project
+    @gl_project = @project.gl_project
+    @gl_project.team << [user, :master]
+    visit namespace_project_ci_web_hooks_path(@gl_project.namespace, @gl_project)
+  end
+
+  context 'create a trigger' do
+    before do
+      fill_in 'web_hook_url', with: 'http://example.com'
+      click_on 'Add Web Hook'
+    end
+
+    it { expect(@project.web_hooks.count).to eq(1) }
+
+    it 'revokes the trigger' do
+      click_on 'Remove'
+      expect(@project.web_hooks.count).to eq(0)
+    end
+  end
+end
diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..1adc2cdf70a235bfaab9d1b8b3433c033ef077d3
--- /dev/null
+++ b/spec/features/commits_spec.rb
@@ -0,0 +1,61 @@
+require 'spec_helper'
+
+describe "Commits" do
+  include CiStatusHelper
+
+  let(:project) { create(:project) }
+
+  describe "CI" do
+    before do
+      login_as :user
+      project.team << [@user, :master]
+      @ci_project = project.ensure_gitlab_ci_project
+      @commit = FactoryGirl.create :ci_commit, gl_project: project, sha: project.commit.sha
+      @build = FactoryGirl.create :ci_build, commit: @commit
+      @generic_status = FactoryGirl.create :generic_commit_status, commit: @commit
+    end
+
+    before do
+      stub_ci_commit_to_return_yaml_file
+    end
+
+    describe "GET /:project/commits/:sha" do
+      before do
+        visit ci_status_path(@commit)
+      end
+
+      it { expect(page).to have_content @commit.sha[0..7] }
+      it { expect(page).to have_content @commit.git_commit_message }
+      it { expect(page).to have_content @commit.git_author_name }
+    end
+
+    describe "Cancel all builds" do
+      it "cancels commit" do
+        visit ci_status_path(@commit)
+        click_on "Cancel all"
+        expect(page).to have_content "canceled"
+      end
+    end
+
+    describe "Cancel build" do
+      it "cancels build" do
+        visit ci_status_path(@commit)
+        click_on "Cancel"
+        expect(page).to have_content "canceled"
+      end
+    end
+
+    describe ".gitlab-ci.yml not found warning" do
+      it "does not show warning" do
+        visit ci_status_path(@commit)
+        expect(page).not_to have_content ".gitlab-ci.yml not found in this commit"
+      end
+
+      it "shows warning" do
+        stub_ci_commit_yaml_file(nil)
+        visit ci_status_path(@commit)
+        expect(page).to have_content ".gitlab-ci.yml not found in this commit"
+      end
+    end
+  end
+end
diff --git a/spec/features/login_spec.rb b/spec/features/login_spec.rb
index cef432e512b8a285c7fb14bc3bdfd51e8d4db78e..922c76285d1865baca9aa06007aab96e9985a7df 100644
--- a/spec/features/login_spec.rb
+++ b/spec/features/login_spec.rb
@@ -95,7 +95,7 @@ feature 'Login', feature: true do
       user = create(:user, password: 'not-the-default')
 
       login_with(user)
-      expect(page).to have_content('Invalid email or password.')
+      expect(page).to have_content('Invalid login or password.')
     end
   end
 end
diff --git a/spec/features/markdown_spec.rb b/spec/features/markdown_spec.rb
index c557a1061af269741f7c9d674e57b7d5ba994fdb..fdd8cf07b12cf14c792caaaac76296ac368206f1 100644
--- a/spec/features/markdown_spec.rb
+++ b/spec/features/markdown_spec.rb
@@ -220,7 +220,7 @@ describe 'GitLab Markdown', feature: true do
     end
   end
 
-  # `markdown` calls these two methods
+  # Fake a `current_user` helper
   def current_user
     @feat.user
   end
diff --git a/spec/features/password_reset_spec.rb b/spec/features/password_reset_spec.rb
index 2b6311e4fd7ae6a2884e9843ba3293129331724b..85e70b4d47f3dcbf547724b6b0991c3e4447ac6b 100644
--- a/spec/features/password_reset_spec.rb
+++ b/spec/features/password_reset_spec.rb
@@ -1,53 +1,43 @@
 require 'spec_helper'
 
 feature 'Password reset', feature: true do
-  def forgot_password
-    click_on 'Forgot your password?'
-    fill_in 'Email', with: user.email
-    click_button 'Reset password'
-    user.reload
-  end
-
-  def get_reset_token
-    mail = ActionMailer::Base.deliveries.last
-    body = mail.body.encoded
-    body.scan(/reset_password_token=(.+)\"/).flatten.first
-  end
-
-  def reset_password(password = 'password')
-    visit edit_user_password_path(reset_password_token: get_reset_token)
+  describe 'throttling' do
+    it 'sends reset instructions when not previously sent' do
+      visit root_path
+      forgot_password(create(:user))
 
-    fill_in 'New password', with: password
-    fill_in 'Confirm new password', with: password
-    click_button 'Change your password'
-  end
+      expect(page).to have_content(I18n.t('devise.passwords.send_instructions'))
+      expect(current_path).to eq new_user_session_path
+    end
 
-  describe 'with two-factor authentication' do
-    let(:user) { create(:user, :two_factor) }
+    it 'sends reset instructions when previously sent more than a minute ago' do
+      user = create(:user)
+      user.send_reset_password_instructions
+      user.update_attribute(:reset_password_sent_at, 5.minutes.ago)
 
-    it 'requires login after password reset' do
       visit root_path
+      forgot_password(user)
 
-      forgot_password
-      reset_password
-
-      expect(page).to have_content("Your password was changed successfully.")
-      expect(page).not_to have_content("You are now signed in.")
+      expect(page).to have_content(I18n.t('devise.passwords.send_instructions'))
       expect(current_path).to eq new_user_session_path
     end
-  end
 
-  describe 'without two-factor authentication' do
-    let(:user) { create(:user) }
+    it "throttles multiple resets in a short timespan" do
+      user = create(:user)
+      user.send_reset_password_instructions
 
-    it 'automatically logs in after password reset' do
       visit root_path
+      forgot_password(user)
 
-      forgot_password
-      reset_password
-
-      expect(current_path).to eq root_path
-      expect(page).to have_content("Your password was changed successfully. You are now signed in.")
+      expect(page).to have_content(I18n.t('devise.passwords.recently_reset'))
+      expect(current_path).to eq new_user_password_path
     end
   end
+
+  def forgot_password(user)
+    click_on 'Forgot your password?'
+    fill_in 'Email', with: user.email
+    click_button 'Reset password'
+    user.reload
+  end
 end
diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb
index a362c54b9ad5ac7aa95fe40bd227bdc23230a791..09fcff2444ac83771442c68f0935fd591fdd4305 100644
--- a/spec/features/projects_spec.rb
+++ b/spec/features/projects_spec.rb
@@ -34,6 +34,27 @@ feature 'Project', feature: true do
     end
   end
 
+  describe 'remove forked relationship', js: true do
+    let(:user)    { create(:user) }
+    let(:project) { create(:project, namespace: user.namespace) }
+
+    before do
+      login_with user
+      create(:forked_project_link, forked_to_project: project)
+      visit edit_namespace_project_path(project.namespace, project)
+    end
+
+    it 'should remove fork' do
+      expect(page).to have_content 'Remove fork relationship'
+
+      remove_with_confirm('Remove fork relationship', project.path)
+
+      expect(page).to have_content 'The fork relationship has been removed.'
+      expect(project.forked?).to be_falsey
+      expect(page).not_to have_content 'Remove fork relationship'
+    end
+  end
+
   describe 'removal', js: true do
     let(:user)    { create(:user) }
     let(:project) { create(:project, namespace: user.namespace) }
@@ -45,13 +66,13 @@ feature 'Project', feature: true do
     end
 
     it 'should remove project' do
-      expect { remove_project }.to change {Project.count}.by(-1)
+      expect { remove_with_confirm('Remove project', project.path) }.to change {Project.count}.by(-1)
     end
   end
 
-  def remove_project
-    click_link "Remove project"
-    fill_in 'confirm_name_input', with: project.path
+  def remove_with_confirm(button_text, confirm_with)
+    click_button button_text
+    fill_in 'confirm_name_input', with: confirm_with
     click_button 'Confirm'
   end
 end
diff --git a/spec/features/ci/runners_spec.rb b/spec/features/runners_spec.rb
similarity index 87%
rename from spec/features/ci/runners_spec.rb
rename to spec/features/runners_spec.rb
index 15147f15eb3649b8219626d14353dcaa2b2f0a42..06adb7633b28b0ae7e63dbfd9f292a76ab19c07c 100644
--- a/spec/features/ci/runners_spec.rb
+++ b/spec/features/runners_spec.rb
@@ -1,11 +1,10 @@
 require 'spec_helper'
 
 describe "Runners" do
-  let(:user)    { create(:user) }
+  include GitlabRoutingHelper
 
-  before do
-    login_as(user)
-  end
+  let(:user) { create(:user) }
+  before { login_as(user) }
 
   describe "specific runners" do
     before do
@@ -20,18 +19,17 @@ describe "Runners" do
       @specific_runner2 = FactoryGirl.create :ci_specific_runner
       @project.runners << @specific_runner
       @project2.runners << @specific_runner2
+
+      visit runners_path(@project.gl_project)
     end
 
     it "places runners in right places" do
-      visit ci_project_runners_path(@project)
       expect(page.find(".available-specific-runners")).to have_content(@specific_runner2.display_name)
       expect(page.find(".activated-specific-runners")).to have_content(@specific_runner.display_name)
       expect(page.find(".available-shared-runners")).to have_content(@shared_runner.display_name)
     end
 
     it "enables specific runner for project" do
-      visit ci_project_runners_path(@project)
-
       within ".available-specific-runners" do
         click_on "Enable for this project"
       end
@@ -41,8 +39,7 @@ describe "Runners" do
 
     it "disables specific runner for project" do
       @project2.runners << @specific_runner
-
-      visit ci_project_runners_path(@project)
+      visit runners_path(@project.gl_project)
 
       within ".activated-specific-runners" do
         click_on "Disable for this project"
@@ -52,8 +49,6 @@ describe "Runners" do
     end
 
     it "removes specific runner for project if this is last project for that runners" do
-      visit ci_project_runners_path(@project)
-
       within ".activated-specific-runners" do
         click_on "Remove runner"
       end
@@ -66,13 +61,11 @@ describe "Runners" do
     before do
       @project = FactoryGirl.create :ci_project
       @project.gl_project.team << [user, :master]
+      visit runners_path(@project.gl_project)
     end
 
     it "enables shared runners" do
-      visit ci_project_runners_path(@project)
-
       click_on "Enable shared runners"
-
       expect(@project.reload.shared_runners_enabled).to be_truthy
     end
   end
@@ -83,13 +76,11 @@ describe "Runners" do
       @project.gl_project.team << [user, :master]
       @specific_runner = FactoryGirl.create :ci_specific_runner
       @project.runners << @specific_runner
+      visit runners_path(@project.gl_project)
     end
 
     it "shows runner information" do
-      visit ci_project_runners_path(@project)
-
       click_on @specific_runner.short_sha
-
       expect(page).to have_content(@specific_runner.platform)
     end
   end
diff --git a/spec/features/ci/triggers_spec.rb b/spec/features/triggers_spec.rb
similarity index 68%
rename from spec/features/ci/triggers_spec.rb
rename to spec/features/triggers_spec.rb
index c6afeb746281fa1307aa42612454e81ec8955d1e..69492d58878f57bf4409a7180b8efe88828654bc 100644
--- a/spec/features/ci/triggers_spec.rb
+++ b/spec/features/triggers_spec.rb
@@ -1,13 +1,14 @@
 require 'spec_helper'
 
 describe 'Triggers' do
-  let(:user)    { create(:user) }
+  let(:user) { create(:user) }
+  before { login_as(user) }
 
   before do
-    login_as(user)
     @project = FactoryGirl.create :ci_project
-    @project.gl_project.team << [user, :master]
-    visit ci_project_triggers_path(@project)
+    @gl_project = @project.gl_project
+    @gl_project.team << [user, :master]
+    visit namespace_project_triggers_path(@gl_project.namespace, @gl_project)
   end
 
   context 'create a trigger' do
diff --git a/spec/features/users_spec.rb b/spec/features/users_spec.rb
index efcb8a31abe64fc0e8f6e12110156c0960521d13..c124816203189592e6fb861c3335d642d32f776e 100644
--- a/spec/features/users_spec.rb
+++ b/spec/features/users_spec.rb
@@ -1,6 +1,8 @@
 require 'spec_helper'
 
 feature 'Users', feature: true do
+  let(:user) { create(:user, username: 'user1', name: 'User 1', email: 'user1@gitlab.com') }
+
   scenario 'GET /users/sign_in creates a new user account' do
     visit new_user_session_path
     fill_in 'user_name', with: 'Name Surname'
@@ -11,7 +13,6 @@ feature 'Users', feature: true do
   end
 
   scenario 'Successful user signin invalidates password reset token' do
-    user = create(:user)
     expect(user.reset_password_token).to be_nil
 
     visit new_user_password_path
@@ -28,7 +29,6 @@ feature 'Users', feature: true do
     expect(user.reset_password_token).to be_nil
   end
 
-  let!(:user) { create(:user, username: 'user1', name: 'User 1', email: 'user1@gitlab.com') }
   scenario 'Should show one error if email is already taken' do
     visit new_user_session_path
     fill_in 'user_name', with: 'Another user name'
diff --git a/spec/features/ci/variables_spec.rb b/spec/features/variables_spec.rb
similarity index 68%
rename from spec/features/ci/variables_spec.rb
rename to spec/features/variables_spec.rb
index e387b3be555d29ce6b3dc2bfb67e67416a0d3615..adb602f3edd211e8862033ab9b2529fb64a07722 100644
--- a/spec/features/ci/variables_spec.rb
+++ b/spec/features/variables_spec.rb
@@ -1,28 +1,25 @@
 require 'spec_helper'
 
 describe "Variables" do
-  let(:user)    { create(:user) }
-
-  before do
-    login_as(user)
-  end
+  let(:user) { create(:user) }
+  before { login_as(user) }
 
   describe "specific runners" do
     before do
       @project = FactoryGirl.create :ci_project
-      @project.gl_project.team << [user, :master]
+      @gl_project = @project.gl_project
+      @gl_project.team << [user, :master]
     end
 
     it "creates variable", js: true do
-      visit ci_project_variables_path(@project)
+      visit namespace_project_variables_path(@gl_project.namespace, @gl_project)
       click_on "Add a variable"
       fill_in "Key", with: "SECRET_KEY"
       fill_in "Value", with: "SECRET_VALUE"
       click_on "Save changes"
-      
+
       expect(page).to have_content("Variables were successfully updated.")
       expect(@project.variables.count).to eq(1)
     end
-
   end
 end
diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb
index db20b23f87d55b62909ff9859b75e270b58e4e95..b16480554622bf064284ce14688d2083a72332c3 100644
--- a/spec/finders/issues_finder_spec.rb
+++ b/spec/finders/issues_finder_spec.rb
@@ -6,9 +6,11 @@ describe IssuesFinder do
   let(:project1) { create(:project) }
   let(:project2) { create(:project) }
   let(:milestone) { create(:milestone, project: project1) }
+  let(:label) { create(:label, project: project2) }
   let(:issue1) { create(:issue, author: user, assignee: user, project: project1, milestone: milestone) }
   let(:issue2) { create(:issue, author: user, assignee: user, project: project2) }
   let(:issue3) { create(:issue, author: user2, assignee: user2, project: project2) }
+  let!(:label_link) { create(:label_link, label: label, target: issue2) }
 
   before do
     project1.team << [user, :master]
@@ -48,6 +50,24 @@ describe IssuesFinder do
         expect(issues).to eq([issue1])
       end
 
+      it 'should filter by no milestone id' do
+        params = { scope: "all", milestone_title: Milestone::None.title, state: 'opened' }
+        issues = IssuesFinder.new(user, params).execute
+        expect(issues).to match_array([issue2, issue3])
+      end
+
+      it 'should filter by label name' do
+        params = { scope: "all", label_name: label.title, state: 'opened' }
+        issues = IssuesFinder.new(user, params).execute
+        expect(issues).to eq([issue2])
+      end
+
+      it 'should filter by no label name' do
+        params = { scope: "all", label_name: Label::None.title, state: 'opened' }
+        issues = IssuesFinder.new(user, params).execute
+        expect(issues).to match_array([issue1, issue3])
+      end
+
       it 'should be empty for unauthorized user' do
         params = { scope: "all", state: 'opened' }
         issues = IssuesFinder.new(nil, params).execute
diff --git a/spec/finders/trending_projects_finder_spec.rb b/spec/finders/trending_projects_finder_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..a49cbfd5160194614615fa7c9df99a5bc701c6d3
--- /dev/null
+++ b/spec/finders/trending_projects_finder_spec.rb
@@ -0,0 +1,39 @@
+require 'spec_helper'
+
+describe TrendingProjectsFinder do
+  let(:user) { build(:user) }
+
+  describe '#execute' do
+    describe 'without an explicit start date' do
+      subject { described_class.new }
+
+      it 'returns the trending projects' do
+        relation = double(:ar_relation)
+
+        allow(subject).to receive(:projects_for)
+          .with(user)
+          .and_return(relation)
+
+        allow(relation).to receive(:trending)
+          .with(an_instance_of(ActiveSupport::TimeWithZone))
+      end
+    end
+
+    describe 'with an explicit start date' do
+      let(:date) { 2.months.ago }
+
+      subject { described_class.new }
+
+      it 'returns the trending projects' do
+        relation = double(:ar_relation)
+
+        allow(subject).to receive(:projects_for)
+          .with(user)
+          .and_return(relation)
+
+        allow(relation).to receive(:trending)
+          .with(date)
+      end
+    end
+  end
+end
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index eadabb2e7b49ef3b573beec4c08b4bd06e109969..670be75f763e44938304364205eea93e4aed00c1 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -99,6 +99,15 @@ describe ApplicationHelper do
 
       helper.avatar_icon('foo@example.com', 20, 2)
     end
+
+    describe 'using a User' do
+      it 'should return an URL for the avatar' do
+        user = create(:user, avatar: File.open(avatar_file_path))
+
+        expect(helper.avatar_icon(user).to_s).
+          to match("/uploads/user/avatar/#{user.id}/banana_sample.gif")
+      end
+    end
   end
 
   describe 'gravatar_icon' do
diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb
index be0e0c747b7d99b176f82257f8b8b04702b0a022..762ec25c4f5555305e1c741f6f852d272ecf179d 100644
--- a/spec/helpers/gitlab_markdown_helper_spec.rb
+++ b/spec/helpers/gitlab_markdown_helper_spec.rb
@@ -11,12 +11,15 @@ describe GitlabMarkdownHelper do
   let(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
   let(:snippet)       { create(:project_snippet, project: project) }
 
-  # Helper expects a current_user method.
-  let(:current_user) { user }
-
   before do
+    # Ensure the generated reference links aren't redacted
+    project.team << [user, :master]
+
     # Helper expects a @project instance variable
-    @project = project
+    helper.instance_variable_set(:@project, project)
+
+    # Stub the `current_user` helper
+    allow(helper).to receive(:current_user).and_return(user)
   end
 
   describe "#markdown" do
@@ -25,23 +28,23 @@ describe GitlabMarkdownHelper do
 
       it "should link to the merge request" do
         expected = namespace_project_merge_request_path(project.namespace, project, merge_request)
-        expect(markdown(actual)).to match(expected)
+        expect(helper.markdown(actual)).to match(expected)
       end
 
       it "should link to the commit" do
         expected = namespace_project_commit_path(project.namespace, project, commit)
-        expect(markdown(actual)).to match(expected)
+        expect(helper.markdown(actual)).to match(expected)
       end
 
       it "should link to the issue" do
         expected = namespace_project_issue_path(project.namespace, project, issue)
-        expect(markdown(actual)).to match(expected)
+        expect(helper.markdown(actual)).to match(expected)
       end
     end
 
     describe "override default project" do
       let(:actual) { issue.to_reference }
-      let(:second_project) { create(:project) }
+      let(:second_project) { create(:project, :public) }
       let(:second_issue) { create(:issue, project: second_project) }
 
       it 'should link to the issue' do
@@ -56,7 +59,7 @@ describe GitlabMarkdownHelper do
     let(:issues)      { create_list(:issue, 2, project: project) }
 
     it 'should handle references nested in links with all the text' do
-      actual = link_to_gfm("This should finally fix #{issues[0].to_reference} and #{issues[1].to_reference} for real", commit_path)
+      actual = helper.link_to_gfm("This should finally fix #{issues[0].to_reference} and #{issues[1].to_reference} for real", commit_path)
       doc = Nokogiri::HTML.parse(actual)
 
       # Make sure we didn't create invalid markup
@@ -86,7 +89,7 @@ describe GitlabMarkdownHelper do
     end
 
     it 'should forward HTML options' do
-      actual = link_to_gfm("Fixed in #{commit.id}", commit_path, class: 'foo')
+      actual = helper.link_to_gfm("Fixed in #{commit.id}", commit_path, class: 'foo')
       doc = Nokogiri::HTML.parse(actual)
 
       expect(doc.css('a')).to satisfy do |v|
@@ -97,15 +100,21 @@ describe GitlabMarkdownHelper do
 
     it "escapes HTML passed in as the body" do
       actual = "This is a <h1>test</h1> - see #{issues[0].to_reference}"
-      expect(link_to_gfm(actual, commit_path)).
+      expect(helper.link_to_gfm(actual, commit_path)).
         to match('&lt;h1&gt;test&lt;/h1&gt;')
     end
 
     it 'ignores reference links when they are the entire body' do
       text = issues[0].to_reference
-      act = link_to_gfm(text, '/foo')
+      act = helper.link_to_gfm(text, '/foo')
       expect(act).to eq %Q(<a href="/foo">#{issues[0].to_reference}</a>)
     end
+
+    it 'should replace commit message with emoji to link' do
+      actual = link_to_gfm(':book:Book', '/foo')
+      expect(actual).
+        to eq %Q(<img class="emoji" title=":book:" alt=":book:" src="http://localhost/assets/emoji/1F4D6.png" height="20" width="20" align="absmiddle"><a href="/foo">Book</a>)
+    end
   end
 
   describe '#render_wiki_content' do
diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb
index c08ddb4cae1bd6ba25dd6a110b8cb9cead4a67c6..78a6b631eb25cb059abd0a8dfe21fc9e8a885560 100644
--- a/spec/helpers/issues_helper_spec.rb
+++ b/spec/helpers/issues_helper_spec.rb
@@ -117,4 +117,14 @@ describe IssuesHelper do
     end
   end
 
+  describe "#merge_requests_sentence" do
+    subject { merge_requests_sentence(merge_requests)}
+    let(:merge_requests) do
+      [ build(:merge_request, iid: 1), build(:merge_request, iid: 2),
+        build(:merge_request, iid: 3)]
+    end
+
+    it { is_expected.to eq("!1, !2, or !3") }
+  end
+
 end
diff --git a/spec/helpers/merge_requests_helper.rb b/spec/helpers/merge_requests_helper.rb
deleted file mode 100644
index 5262d64404814c8dc164d2cc8ee2d7cc96335f86..0000000000000000000000000000000000000000
--- a/spec/helpers/merge_requests_helper.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require 'spec_helper'
-
-describe MergeRequestsHelper do
-  describe :issues_sentence do
-    subject { issues_sentence(issues) }
-    let(:issues) do
-      [build(:issue, iid: 1), build(:issue, iid: 2), build(:issue, iid: 3)]
-    end
-
-    it { is_expected.to eq('#1, #2, and #3') }
-  end
-end
diff --git a/spec/helpers/merge_requests_helper_spec.rb b/spec/helpers/merge_requests_helper_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..0ef1efb8bce1ee6c01105aab7be74fd62b8af73a
--- /dev/null
+++ b/spec/helpers/merge_requests_helper_spec.rb
@@ -0,0 +1,32 @@
+require 'spec_helper'
+
+describe MergeRequestsHelper do
+  describe "#issues_sentence" do
+    subject { issues_sentence(issues) }
+    let(:issues) do
+      [build(:issue, iid: 1), build(:issue, iid: 2), build(:issue, iid: 3)]
+    end
+
+    it { is_expected.to eq('#1, #2, and #3') }
+  end
+
+  describe "#format_mr_branch_names" do
+    describe "within the same project" do
+      let(:merge_request) { create(:merge_request) }
+      subject { format_mr_branch_names(merge_request) }
+
+      it { is_expected.to eq([merge_request.source_branch, merge_request.target_branch]) }
+    end
+
+    describe "within different projects" do
+      let(:project) { create(:project) }
+      let(:fork_project) { create(:project, forked_from_project: project) }
+      let(:merge_request) { create(:merge_request, source_project: fork_project, target_project: project) }
+      subject { format_mr_branch_names(merge_request) }
+      let(:source_title) { "#{fork_project.path_with_namespace}:#{merge_request.source_branch}" }
+      let(:target_title) { "#{project.path_with_namespace}:#{merge_request.target_branch}" }
+
+      it { is_expected.to eq([source_title, target_title]) }
+    end
+  end
+end
diff --git a/spec/helpers/preferences_helper_spec.rb b/spec/helpers/preferences_helper_spec.rb
index 06f69262b71a2773d0879f9b68bf68d6d5e5badb..e5df59c4fbaddf6eb3cee252ce12715763d0dc60 100644
--- a/spec/helpers/preferences_helper_spec.rb
+++ b/spec/helpers/preferences_helper_spec.rb
@@ -8,14 +8,18 @@ describe PreferencesHelper do
     end
 
     it 'raises an exception when defined choices may be using the wrong key' do
-      expect(User).to receive(:dashboards).and_return(foo: 'foo', bar: 'bar')
+      dashboards = User.dashboards.dup
+      dashboards[:projects_changed] = dashboards.delete :projects
+      expect(User).to receive(:dashboards).and_return(dashboards)
       expect { helper.dashboard_choices }.to raise_error(KeyError)
     end
 
     it 'provides better option descriptions' do
       expect(helper.dashboard_choices).to match_array [
         ['Your Projects (default)', 'projects'],
-        ['Starred Projects',        'stars']
+        ['Starred Projects',        'stars'],
+        ["Your Projects' Activity", 'project_activity'],
+        ["Starred Projects' Activity", 'starred_project_activity']
       ]
     end
   end
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index 99abb95d9069a50a1c9d7dbcb8634f704ddb6771..f2efb528aeb6cc1c9397e7a5c9a8676286f4085d 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -61,13 +61,27 @@ describe ProjectsHelper do
     end
 
     it "returns a valid cach key" do
-      expect(helper.send(:readme_cache_key)).to eq("#{project.id}-#{project.commit.id}-readme")
+      expect(helper.send(:readme_cache_key)).to eq("#{project.path_with_namespace}-#{project.commit.id}-readme")
     end
 
     it "returns a valid cache key if HEAD does not exist" do
       allow(project).to receive(:commit) { nil }
 
-      expect(helper.send(:readme_cache_key)).to eq("#{project.id}-nil-readme")
+      expect(helper.send(:readme_cache_key)).to eq("#{project.path_with_namespace}-nil-readme")
+    end
+  end
+
+  describe 'link_to_member' do
+    let(:group)   { create(:group) }
+    let(:project) { create(:empty_project, group: group) }
+    let(:user)    { create(:user) }
+
+    describe 'using the default options' do
+      it 'returns an HTML link to the user' do
+        link = helper.link_to_member(project, user)
+
+        expect(link).to match(%r{/u/#{user.username}})
+      end
     end
   end
 end
diff --git a/spec/helpers/ci/runners_helper_spec.rb b/spec/helpers/runners_helper_spec.rb
similarity index 81%
rename from spec/helpers/ci/runners_helper_spec.rb
rename to spec/helpers/runners_helper_spec.rb
index 6d0e2d3d1e11155f1ab04703e72183d4773cd3f2..35f91b7decfde61701c8567d40bcf2fba7499a98 100644
--- a/spec/helpers/ci/runners_helper_spec.rb
+++ b/spec/helpers/runners_helper_spec.rb
@@ -1,6 +1,6 @@
 require 'spec_helper'
 
-describe Ci::RunnersHelper do
+describe RunnersHelper do
   it "returns - not contacted yet" do
     runner = FactoryGirl.build :ci_runner
     expect(runner_status_icon(runner)).to include("not connected yet")
@@ -12,7 +12,7 @@ describe Ci::RunnersHelper do
   end
 
   it "returns online text" do
-    runner = FactoryGirl.build(:ci_runner, contacted_at: 1.hour.ago, active: true)
+    runner = FactoryGirl.build(:ci_runner, contacted_at: 1.second.ago, active: true)
     expect(runner_status_icon(runner)).to include("Runner is online")
   end
 end
diff --git a/spec/helpers/ci/application_helper_spec.rb b/spec/helpers/time_helper_spec.rb
similarity index 96%
rename from spec/helpers/ci/application_helper_spec.rb
rename to spec/helpers/time_helper_spec.rb
index 6a216715b7f879d8e65047fa278b0ab27197fcf0..3f62527c5bbc1e756e69b89ba376d6e198530f04 100644
--- a/spec/helpers/ci/application_helper_spec.rb
+++ b/spec/helpers/time_helper_spec.rb
@@ -1,6 +1,6 @@
 require 'spec_helper'
 
-describe Ci::ApplicationHelper do
+describe TimeHelper do
   describe "#duration_in_words" do
     it "returns minutes and seconds" do
       intervals_in_words = {
diff --git a/spec/javascripts/behaviors/quick_submit_spec.js.coffee b/spec/javascripts/behaviors/quick_submit_spec.js.coffee
new file mode 100644
index 0000000000000000000000000000000000000000..09708c12ed43b535c4f1d91dfb212a4461cdc93b
--- /dev/null
+++ b/spec/javascripts/behaviors/quick_submit_spec.js.coffee
@@ -0,0 +1,70 @@
+#= require behaviors/quick_submit
+
+describe 'Quick Submit behavior', ->
+  fixture.preload('behaviors/quick_submit.html')
+
+  beforeEach ->
+    fixture.load('behaviors/quick_submit.html')
+
+    # Prevent a form submit from moving us off the testing page
+    $('form').submit (e) -> e.preventDefault()
+
+    @spies = {
+      submit: spyOnEvent('form', 'submit')
+    }
+
+  it 'does not respond to other keyCodes', ->
+    $('input').trigger(keydownEvent(keyCode: 32))
+
+    expect(@spies.submit).not.toHaveBeenTriggered()
+
+  it 'does not respond to Enter alone', ->
+    $('input').trigger(keydownEvent(ctrlKey: false, metaKey: false))
+
+    expect(@spies.submit).not.toHaveBeenTriggered()
+
+  it 'does not respond to repeated events', ->
+    $('input').trigger(keydownEvent(repeat: true))
+
+    expect(@spies.submit).not.toHaveBeenTriggered()
+
+  it 'disables submit buttons', ->
+    $('textarea').trigger(keydownEvent())
+
+    expect($('input[type=submit]')).toBeDisabled()
+    expect($('button[type=submit]')).toBeDisabled()
+
+  # We cannot stub `navigator.userAgent` for CI's `rake teaspoon` task, so we'll
+  # only run the tests that apply to the current platform
+  if navigator.userAgent.match(/Macintosh/)
+    it 'responds to Meta+Enter', ->
+      $('input').trigger(keydownEvent())
+
+      expect(@spies.submit).toHaveBeenTriggered()
+
+    it 'excludes other modifier keys', ->
+      $('input').trigger(keydownEvent(altKey: true))
+      $('input').trigger(keydownEvent(ctrlKey: true))
+      $('input').trigger(keydownEvent(shiftKey: true))
+
+      expect(@spies.submit).not.toHaveBeenTriggered()
+  else
+    it 'responds to Ctrl+Enter', ->
+      $('input').trigger(keydownEvent())
+
+      expect(@spies.submit).toHaveBeenTriggered()
+
+    it 'excludes other modifier keys', ->
+      $('input').trigger(keydownEvent(altKey: true))
+      $('input').trigger(keydownEvent(metaKey: true))
+      $('input').trigger(keydownEvent(shiftKey: true))
+
+      expect(@spies.submit).not.toHaveBeenTriggered()
+
+  keydownEvent = (options) ->
+    if navigator.userAgent.match(/Macintosh/)
+      defaults = { keyCode: 13, metaKey: true }
+    else
+      defaults = { keyCode: 13, ctrlKey: true }
+
+    $.Event('keydown', $.extend({}, defaults, options))
diff --git a/spec/javascripts/fixtures/behaviors/quick_submit.html.haml b/spec/javascripts/fixtures/behaviors/quick_submit.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..b80a28a33ea82eac1a0345c76f424ea2dcf2db48
--- /dev/null
+++ b/spec/javascripts/fixtures/behaviors/quick_submit.html.haml
@@ -0,0 +1,6 @@
+%form{ action: '/foo' }
+  %input.js-quick-submit{ type: 'text' }
+  %textarea.js-quick-submit
+
+  %input{ type: 'submit'} Submit
+  %button.btn{ type: 'submit' } Submit
diff --git a/spec/javascripts/fixtures/line_highlighter.html.haml b/spec/javascripts/fixtures/line_highlighter.html.haml
index da1ebcdb23cacb744c7824b612e5c496f15ce086..514877340e4f2ba38b55037cc92318798c0c003e 100644
--- a/spec/javascripts/fixtures/line_highlighter.html.haml
+++ b/spec/javascripts/fixtures/line_highlighter.html.haml
@@ -1,4 +1,4 @@
-#tree-content-holder
+#blob-content-holder
   .file-content
     .line-numbers
       - 1.upto(25) do |i|
diff --git a/spec/javascripts/line_highlighter_spec.js.coffee b/spec/javascripts/line_highlighter_spec.js.coffee
index 57453c716a5df44f2e7df4268beab377a993d9fb..a073f21e7bcbe563f53bab788be747dbf9fea754 100644
--- a/spec/javascripts/line_highlighter_spec.js.coffee
+++ b/spec/javascripts/line_highlighter_spec.js.coffee
@@ -39,7 +39,7 @@ describe 'LineHighlighter', ->
       expect(spy).toHaveBeenPrevented()
 
     it 'handles garbage input from the hash', ->
-      func = -> new LineHighlighter('#tree-content-holder')
+      func = -> new LineHighlighter('#blob-content-holder')
       expect(func).not.toThrow()
 
   describe '#clickHandler', ->
diff --git a/spec/javascripts/spec_helper.coffee b/spec/javascripts/spec_helper.coffee
index 47b41dd2c8161025053acf709cedf1e00ec7579b..90b02a6aec59b150f5347b28ce1683693a36f08a 100644
--- a/spec/javascripts/spec_helper.coffee
+++ b/spec/javascripts/spec_helper.coffee
@@ -9,6 +9,7 @@
 # require the specific files that are being used in the spec that tests them.
 
 #= require jquery
+#= require jquery.turbolinks
 #= require bootstrap
 #= require underscore
 
diff --git a/spec/lib/ci/charts_spec.rb b/spec/lib/ci/charts_spec.rb
index 24894e8198380661b25750032988acb1efa2015d..83e2ad220b832995607ea94d86ee3a023704d386 100644
--- a/spec/lib/ci/charts_spec.rb
+++ b/spec/lib/ci/charts_spec.rb
@@ -4,13 +4,12 @@ describe "Charts" do
 
   context "build_times" do
     before do
-      @project = FactoryGirl.create(:ci_project)
-      @commit = FactoryGirl.create(:ci_commit, project: @project)
+      @commit = FactoryGirl.create(:ci_commit)
       FactoryGirl.create(:ci_build, commit: @commit)
     end
 
     it 'should return build times in minutes' do
-      chart = Ci::Charts::BuildTime.new(@project)
+      chart = Ci::Charts::BuildTime.new(@commit.project)
       expect(chart.build_times).to eq([2])
     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 49482ac2b12c2fb5e8a7d7e24c17996af589e761..abdb6b89ac55e592e7dd7cd4885a0eedcb5fdefd 100644
--- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
+++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
@@ -17,13 +17,15 @@ module Ci
         expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(1)
         expect(config_processor.builds_for_stage_and_ref(type, "master").first).to eq({
           stage: "test",
+          stage_idx: 1,
           except: nil,
           name: :rspec,
           only: nil,
-          script: "pwd\nrspec",
-          tags: [],
+          commands: "pwd\nrspec",
+          tag_list: [],
           options: {},
-          allow_failure: false
+          allow_failure: false,
+          when: "on_success"
         })
       end
 
@@ -115,15 +117,17 @@ module Ci
         expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({
           except: nil,
           stage: "test",
+          stage_idx: 1,
           name: :rspec,
           only: nil,
-          script: "pwd\nrspec",
-          tags: [],
+          commands: "pwd\nrspec",
+          tag_list: [],
           options: {
             image: "ruby:2.1",
             services: ["mysql"]
           },
-          allow_failure: false
+          allow_failure: false,
+          when: "on_success"
         })
       end
 
@@ -141,15 +145,17 @@ module Ci
         expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({
           except: nil,
           stage: "test",
+          stage_idx: 1,
           name: :rspec,
           only: nil,
-          script: "pwd\nrspec",
-          tags: [],
+          commands: "pwd\nrspec",
+          tag_list: [],
           options: {
             image: "ruby:2.5",
             services: ["postgresql"]
           },
-          allow_failure: false
+          allow_failure: false,
+          when: "on_success"
         })
       end
     end
@@ -171,6 +177,21 @@ module Ci
       end
     end
 
+    describe "When" do
+      %w(on_success on_failure always).each do |when_state|
+        it "returns #{when_state} when defined" do
+          config = YAML.dump({
+                               rspec: { script: "rspec", when: when_state }
+                             })
+
+          config_processor = GitlabCiYamlProcessor.new(config)
+          builds = config_processor.builds_for_stage_and_ref("test", "master")
+          expect(builds.size).to eq(1)
+          expect(builds.first[:when]).to eq(when_state)
+        end
+      end
+    end
+
     describe "Error handling" do
       it "indicates that object is invalid" do
         expect{GitlabCiYamlProcessor.new("invalid_yaml\n!ccdvlf%612334@@@@")}.to raise_error(GitlabCiYamlProcessor::ValidationError)
@@ -197,6 +218,20 @@ module Ci
         end.to raise_error(GitlabCiYamlProcessor::ValidationError, "image should be a string")
       end
 
+      it "returns errors if job name is blank" do
+        config = YAML.dump({ '' => { script: "test" } })
+        expect do
+          GitlabCiYamlProcessor.new(config)
+        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "job name should be non-empty string")
+      end
+
+      it "returns errors if job name is non-string" do
+        config = YAML.dump({ 10 => { script: "test" } })
+        expect do
+          GitlabCiYamlProcessor.new(config)
+        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "job name should be non-empty string")
+      end
+
       it "returns errors if job image parameter is invalid" do
         config = YAML.dump({ rspec: { script: "test", image: ["test"] } })
         expect do
@@ -308,6 +343,13 @@ module Ci
           GitlabCiYamlProcessor.new(config)
         end.to raise_error(GitlabCiYamlProcessor::ValidationError, "variables should be a map of key-valued strings")
       end
+
+      it "returns errors if job when is not on_success, on_failure or always" do
+        config = YAML.dump({ rspec: { script: "test", when: 1 } })
+        expect do
+          GitlabCiYamlProcessor.new(config)
+        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: when parameter should be on_success, on_failure or always")
+      end
     end
   end
 end
diff --git a/spec/lib/gitlab/backend/grack_auth_spec.rb b/spec/lib/gitlab/backend/grack_auth_spec.rb
index 829a9c197ef84c23523d6eea20a427eeb3794f5b..37c527221a0b7c80854f2f48517693bb38523357 100644
--- a/spec/lib/gitlab/backend/grack_auth_spec.rb
+++ b/spec/lib/gitlab/backend/grack_auth_spec.rb
@@ -151,14 +151,14 @@ describe Grack::Auth do
                 end
 
                 it "repeated attempts followed by successful attempt" do
-                  for n in 0..maxretry do
+                  maxretry.times.each do
                     expect(attempt_login(false)).to eq(401)
                   end
 
                   expect(attempt_login(true)).to eq(200)
                   expect(Rack::Attack::Allow2Ban.banned?(ip)).to be_falsey
 
-                  for n in 0..maxretry do
+                  maxretry.times.each do
                     expect(attempt_login(false)).to eq(401)
                   end
                 end
diff --git a/spec/lib/gitlab/backend/shell_spec.rb b/spec/lib/gitlab/backend/shell_spec.rb
index b6d04330599bd2988f13e0e06f828418fc8f7f07..b60e23454d60f875ca722fca949fd1c228e98ccf 100644
--- a/spec/lib/gitlab/backend/shell_spec.rb
+++ b/spec/lib/gitlab/backend/shell_spec.rb
@@ -15,4 +15,17 @@ describe Gitlab::Shell do
   it { is_expected.to respond_to :fork_repository }
 
   it { expect(gitlab_shell.url_to_repo('diaspora')).to eq(Gitlab.config.gitlab_shell.ssh_path_prefix + "diaspora.git") }
+
+  describe Gitlab::Shell::KeyAdder do
+    describe '#add_key' do
+      it 'normalizes space characters in the key' do
+        io = spy
+        adder = described_class.new(io)
+
+        adder.add_key('key-42', "sha-rsa foo\tbar\tbaz")
+
+        expect(io).to have_received(:puts).with("key-42\tsha-rsa foo bar baz")
+      end
+    end
+  end
 end
diff --git a/spec/lib/gitlab/closing_issue_extractor_spec.rb b/spec/lib/gitlab/closing_issue_extractor_spec.rb
index 5d7ff4f612250f25320354b8b0bf86c314378000..21254f778d3f39798b1a88f276aea8f35e718926 100644
--- a/spec/lib/gitlab/closing_issue_extractor_spec.rb
+++ b/spec/lib/gitlab/closing_issue_extractor_spec.rb
@@ -140,28 +140,28 @@ describe Gitlab::ClosingIssueExtractor do
         message = "Closes #{reference} and fix #{reference2}"
 
         expect(subject.closed_by_message(message)).
-            to eq([issue, other_issue])
+            to match_array([issue, other_issue])
       end
 
       it 'fetches comma-separated issues references in single line message' do
         message = "Closes #{reference}, closes #{reference2}"
 
         expect(subject.closed_by_message(message)).
-            to eq([issue, other_issue])
+            to match_array([issue, other_issue])
       end
 
       it 'fetches comma-separated issues numbers in single line message' do
         message = "Closes #{reference}, #{reference2} and #{reference3}"
 
         expect(subject.closed_by_message(message)).
-            to eq([issue, other_issue, third_issue])
+            to match_array([issue, other_issue, third_issue])
       end
 
       it 'fetches issues in multi-line message' do
         message = "Awesome commit (closes #{reference})\nAlso fixes #{reference2}"
 
         expect(subject.closed_by_message(message)).
-            to eq([issue, other_issue])
+            to match_array([issue, other_issue])
       end
 
       it 'fetches issues in hybrid message' do
@@ -169,7 +169,7 @@ describe Gitlab::ClosingIssueExtractor do
                   "Also fixing issues #{reference2}, #{reference3} and #4"
 
         expect(subject.closed_by_message(message)).
-            to eq([issue, other_issue, third_issue])
+            to match_array([issue, other_issue, third_issue])
       end
     end
   end
diff --git a/spec/lib/gitlab/database_spec.rb b/spec/lib/gitlab/database_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..7cdebdf209aa540ba73e8f075491e20518167680
--- /dev/null
+++ b/spec/lib/gitlab/database_spec.rb
@@ -0,0 +1,17 @@
+require 'spec_helper'
+
+describe Gitlab::Database do
+  # These are just simple smoke tests to check if the methods work (regardless
+  # of what they may return).
+  describe '.mysql?' do
+    subject { described_class.mysql? }
+
+    it { is_expected.to satisfy { |val| val == true || val == false } }
+  end
+
+  describe '.postgresql?' do
+    subject { described_class.postgresql? }
+
+    it { is_expected.to satisfy { |val| val == true || val == false } }
+  end
+end
diff --git a/spec/lib/gitlab/email/attachment_uploader_spec.rb b/spec/lib/gitlab/email/attachment_uploader_spec.rb
index e8208e15e29ead60bb92b74ea82da81661dc40bf..8fb432367b63ddc603ca6b128f88537c7d6b9c7b 100644
--- a/spec/lib/gitlab/email/attachment_uploader_spec.rb
+++ b/spec/lib/gitlab/email/attachment_uploader_spec.rb
@@ -13,7 +13,6 @@ describe Gitlab::Email::AttachmentUploader do
       expect(link).not_to be_nil
       expect(link[:is_image]).to be_truthy
       expect(link[:alt]).to eq("bricks")
-      expect(link[:url]).to include("/#{project.path_with_namespace}")
       expect(link[:url]).to include("bricks.png")
     end
   end
diff --git a/spec/lib/gitlab/ldap/user_spec.rb b/spec/lib/gitlab/ldap/user_spec.rb
index fd2e5f6d0e170df0dc56f347b2f99d61fb3b04e6..b5b56a349526774d7f5dd98194a4e1d7092d3844 100644
--- a/spec/lib/gitlab/ldap/user_spec.rb
+++ b/spec/lib/gitlab/ldap/user_spec.rb
@@ -13,6 +13,17 @@ describe Gitlab::LDAP::User do
   let(:auth_hash) do
     OmniAuth::AuthHash.new(uid: 'my-uid', provider: 'ldapmain', info: info)
   end
+  let(:ldap_user_upper_case) { Gitlab::LDAP::User.new(auth_hash_upper_case) }
+  let(:info_upper_case) do
+    {
+      name: 'John',
+      email: 'John@Example.com', # Email address has upper case chars
+      nickname: 'john'
+    }
+  end
+  let(:auth_hash_upper_case) do
+    OmniAuth::AuthHash.new(uid: 'my-uid', provider: 'ldapmain', info: info_upper_case)
+  end
 
   describe :changed? do
     it "marks existing ldap user as changed" do
@@ -57,6 +68,16 @@ describe Gitlab::LDAP::User do
       expect(existing_user.id).to eql ldap_user.gl_user.id
     end
 
+    it 'connects to existing ldap user if the extern_uid changes and email address has upper case characters' do
+      existing_user = create(:omniauth_user, email: 'john@example.com', extern_uid: 'old-uid', provider: 'ldapmain')
+      expect{ ldap_user_upper_case.save }.not_to change{ User.count }
+
+      existing_user.reload
+      expect(existing_user.ldap_identity.extern_uid).to eql 'my-uid'
+      expect(existing_user.ldap_identity.provider).to eql 'ldapmain'
+      expect(existing_user.id).to eql ldap_user.gl_user.id
+    end
+
     it 'maintains an identity per provider' do
       existing_user = create(:omniauth_user, email: 'john@example.com', provider: 'twitter')
       expect(existing_user.identities.count).to eql(1)
diff --git a/spec/lib/gitlab/markdown/commit_range_reference_filter_spec.rb b/spec/lib/gitlab/markdown/commit_range_reference_filter_spec.rb
index 3c6c84a0416aed1799818d493ea7b6a7b1def02b..e5b8d723fe5614652cc98000511f8250d554d1d7 100644
--- a/spec/lib/gitlab/markdown/commit_range_reference_filter_spec.rb
+++ b/spec/lib/gitlab/markdown/commit_range_reference_filter_spec.rb
@@ -4,7 +4,7 @@ module Gitlab::Markdown
   describe CommitRangeReferenceFilter do
     include FilterSpecHelper
 
-    let(:project) { create(:project) }
+    let(:project) { create(:project, :public) }
     let(:commit1) { project.commit }
     let(:commit2) { project.commit("HEAD~2") }
 
@@ -75,12 +75,20 @@ module Gitlab::Markdown
         expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-commit_range'
       end
 
-      it 'includes a data-project-id attribute' do
+      it 'includes a data-project attribute' do
         doc = filter("See #{reference}")
         link = doc.css('a').first
 
-        expect(link).to have_attribute('data-project-id')
-        expect(link.attr('data-project-id')).to eq project.id.to_s
+        expect(link).to have_attribute('data-project')
+        expect(link.attr('data-project')).to eq project.id.to_s
+      end
+
+      it 'includes a data-commit-range attribute' do
+        doc = filter("See #{reference}")
+        link = doc.css('a').first
+
+        expect(link).to have_attribute('data-commit-range')
+        expect(link.attr('data-commit-range')).to eq range.to_reference
       end
 
       it 'supports an :only_path option' do
@@ -92,59 +100,45 @@ module Gitlab::Markdown
       end
 
       it 'adds to the results hash' do
-        result = pipeline_result("See #{reference}")
+        result = reference_pipeline_result("See #{reference}")
         expect(result[:references][:commit_range]).not_to be_empty
       end
     end
 
     context 'cross-project reference' do
       let(:namespace) { create(:namespace, name: 'cross-reference') }
-      let(:project2)  { create(:project, namespace: namespace) }
+      let(:project2)  { create(:project, :public, namespace: namespace) }
       let(:reference) { range.to_reference(project) }
 
       before do
         range.project = project2
       end
 
-      context 'when user can access reference' do
-        before { allow_cross_reference! }
-
-        it 'links to a valid reference' do
-          doc = filter("See #{reference}")
-
-          expect(doc.css('a').first.attr('href')).
-            to eq urls.namespace_project_compare_url(project2.namespace, project2, range.to_param)
-        end
-
-        it 'links with adjacent text' do
-          doc = filter("Fixed (#{reference}.)")
-
-          exp = Regexp.escape("#{project2.to_reference}@#{range.to_s}")
-          expect(doc.to_html).to match(/\(<a.+>#{exp}<\/a>\.\)/)
-        end
+      it 'links to a valid reference' do
+        doc = filter("See #{reference}")
 
-        it 'ignores invalid commit IDs on the referenced project' do
-          exp = act = "Fixed #{project2.to_reference}@#{commit1.id.reverse}...#{commit2.id}"
-          expect(filter(act).to_html).to eq exp
+        expect(doc.css('a').first.attr('href')).
+          to eq urls.namespace_project_compare_url(project2.namespace, project2, range.to_param)
+      end
 
-          exp = act = "Fixed #{project2.to_reference}@#{commit1.id}...#{commit2.id.reverse}"
-          expect(filter(act).to_html).to eq exp
-        end
+      it 'links with adjacent text' do
+        doc = filter("Fixed (#{reference}.)")
 
-        it 'adds to the results hash' do
-          result = pipeline_result("See #{reference}")
-          expect(result[:references][:commit_range]).not_to be_empty
-        end
+        exp = Regexp.escape("#{project2.to_reference}@#{range.to_s}")
+        expect(doc.to_html).to match(/\(<a.+>#{exp}<\/a>\.\)/)
       end
 
-      context 'when user cannot access reference' do
-        before { disallow_cross_reference! }
+      it 'ignores invalid commit IDs on the referenced project' do
+        exp = act = "Fixed #{project2.to_reference}@#{commit1.id.reverse}...#{commit2.id}"
+        expect(filter(act).to_html).to eq exp
 
-        it 'ignores valid references' do
-          exp = act = "See #{reference}"
+        exp = act = "Fixed #{project2.to_reference}@#{commit1.id}...#{commit2.id.reverse}"
+        expect(filter(act).to_html).to eq exp
+      end
 
-          expect(filter(act).to_html).to eq exp
-        end
+      it 'adds to the results hash' do
+        result = reference_pipeline_result("See #{reference}")
+        expect(result[:references][:commit_range]).not_to be_empty
       end
     end
   end
diff --git a/spec/lib/gitlab/markdown/commit_reference_filter_spec.rb b/spec/lib/gitlab/markdown/commit_reference_filter_spec.rb
index 9ed438252b3dbd6685c694b76a277fc5355ae923..d080efbf3d4fa011a7cea580601322c7120c2189 100644
--- a/spec/lib/gitlab/markdown/commit_reference_filter_spec.rb
+++ b/spec/lib/gitlab/markdown/commit_reference_filter_spec.rb
@@ -4,7 +4,7 @@ module Gitlab::Markdown
   describe CommitReferenceFilter do
     include FilterSpecHelper
 
-    let(:project) { create(:project) }
+    let(:project) { create(:project, :public) }
     let(:commit)  { project.commit }
 
     it 'requires project context' do
@@ -71,12 +71,20 @@ module Gitlab::Markdown
         expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-commit'
       end
 
-      it 'includes a data-project-id attribute' do
+      it 'includes a data-project attribute' do
         doc = filter("See #{reference}")
         link = doc.css('a').first
 
-        expect(link).to have_attribute('data-project-id')
-        expect(link.attr('data-project-id')).to eq project.id.to_s
+        expect(link).to have_attribute('data-project')
+        expect(link.attr('data-project')).to eq project.id.to_s
+      end
+
+      it 'includes a data-commit attribute' do
+        doc = filter("See #{reference}")
+        link = doc.css('a').first
+
+        expect(link).to have_attribute('data-commit')
+        expect(link.attr('data-commit')).to eq commit.id
       end
 
       it 'supports an :only_path context' do
@@ -88,53 +96,39 @@ module Gitlab::Markdown
       end
 
       it 'adds to the results hash' do
-        result = pipeline_result("See #{reference}")
+        result = reference_pipeline_result("See #{reference}")
         expect(result[:references][:commit]).not_to be_empty
       end
     end
 
     context 'cross-project reference' do
       let(:namespace) { create(:namespace, name: 'cross-reference') }
-      let(:project2)  { create(:project, namespace: namespace) }
+      let(:project2)  { create(:project, :public, namespace: namespace) }
       let(:commit)    { project2.commit }
       let(:reference) { commit.to_reference(project) }
 
-      context 'when user can access reference' do
-        before { allow_cross_reference! }
-
-        it 'links to a valid reference' do
-          doc = filter("See #{reference}")
-
-          expect(doc.css('a').first.attr('href')).
-            to eq urls.namespace_project_commit_url(project2.namespace, project2, commit.id)
-        end
-
-        it 'links with adjacent text' do
-          doc = filter("Fixed (#{reference}.)")
+      it 'links to a valid reference' do
+        doc = filter("See #{reference}")
 
-          exp = Regexp.escape(project2.to_reference)
-          expect(doc.to_html).to match(/\(<a.+>#{exp}@#{commit.short_id}<\/a>\.\)/)
-        end
+        expect(doc.css('a').first.attr('href')).
+          to eq urls.namespace_project_commit_url(project2.namespace, project2, commit.id)
+      end
 
-        it 'ignores invalid commit IDs on the referenced project' do
-          exp = act = "Committed #{invalidate_reference(reference)}"
-          expect(filter(act).to_html).to eq exp
-        end
+      it 'links with adjacent text' do
+        doc = filter("Fixed (#{reference}.)")
 
-        it 'adds to the results hash' do
-          result = pipeline_result("See #{reference}")
-          expect(result[:references][:commit]).not_to be_empty
-        end
+        exp = Regexp.escape(project2.to_reference)
+        expect(doc.to_html).to match(/\(<a.+>#{exp}@#{commit.short_id}<\/a>\.\)/)
       end
 
-      context 'when user cannot access reference' do
-        before { disallow_cross_reference! }
-
-        it 'ignores valid references' do
-          exp = act = "See #{reference}"
+      it 'ignores invalid commit IDs on the referenced project' do
+        exp = act = "Committed #{invalidate_reference(reference)}"
+        expect(filter(act).to_html).to eq exp
+      end
 
-          expect(filter(act).to_html).to eq exp
-        end
+      it 'adds to the results hash' do
+        result = reference_pipeline_result("See #{reference}")
+        expect(result[:references][:commit]).not_to be_empty
       end
     end
   end
diff --git a/spec/lib/gitlab/markdown/cross_project_reference_spec.rb b/spec/lib/gitlab/markdown/cross_project_reference_spec.rb
index 4698d6138c20cc67e5261af8f09adc808524165b..8d4f9e403a603bfe37c1f6d22fa3df75f0e13dcf 100644
--- a/spec/lib/gitlab/markdown/cross_project_reference_spec.rb
+++ b/spec/lib/gitlab/markdown/cross_project_reference_spec.rb
@@ -2,20 +2,16 @@ require 'spec_helper'
 
 module Gitlab::Markdown
   describe CrossProjectReference do
-    # context in the html-pipeline sense, not in the rspec sense
-    let(:context) do
-      {
-        current_user: double('user'),
-        project: double('project')
-      }
-    end
-
     include described_class
 
     describe '#project_from_ref' do
       context 'when no project was referenced' do
         it 'returns the project from context' do
-          expect(project_from_ref(nil)).to eq context[:project]
+          project = double
+
+          allow(self).to receive(:context).and_return({ project: project })
+
+          expect(project_from_ref(nil)).to eq project
         end
       end
 
@@ -26,29 +22,13 @@ module Gitlab::Markdown
       end
 
       context 'when referenced project exists' do
-        let(:project2) { double('referenced project') }
+        it 'returns the referenced project' do
+          project2 = double('referenced project')
 
-        before do
           expect(Project).to receive(:find_with_namespace).
             with('cross/reference').and_return(project2)
-        end
-
-        context 'and the user has permission to read it' do
-          it 'returns the referenced project' do
-            expect(self).to receive(:user_can_reference_project?).
-              with(project2).and_return(true)
-
-            expect(project_from_ref('cross/reference')).to eq project2
-          end
-        end
-
-        context 'and the user does not have permission to read it' do
-          it 'returns nil' do
-            expect(self).to receive(:user_can_reference_project?).
-              with(project2).and_return(false)
 
-            expect(project_from_ref('cross/reference')).to be_nil
-          end
+          expect(project_from_ref('cross/reference')).to eq project2
         end
       end
     end
diff --git a/spec/lib/gitlab/markdown/issue_reference_filter_spec.rb b/spec/lib/gitlab/markdown/issue_reference_filter_spec.rb
index 1dd54f58588747a4a926600501a8d58852be9990..94c80ae6611aeb2221ecabc6b57d6971de02887c 100644
--- a/spec/lib/gitlab/markdown/issue_reference_filter_spec.rb
+++ b/spec/lib/gitlab/markdown/issue_reference_filter_spec.rb
@@ -8,7 +8,7 @@ module Gitlab::Markdown
       IssuesHelper
     end
 
-    let(:project) { create(:empty_project) }
+    let(:project) { create(:empty_project, :public) }
     let(:issue)   { create(:issue, project: project) }
 
     it 'requires project context' do
@@ -68,12 +68,20 @@ module Gitlab::Markdown
         expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-issue'
       end
 
-      it 'includes a data-project-id attribute' do
+      it 'includes a data-project attribute' do
         doc = filter("Issue #{reference}")
         link = doc.css('a').first
 
-        expect(link).to have_attribute('data-project-id')
-        expect(link.attr('data-project-id')).to eq project.id.to_s
+        expect(link).to have_attribute('data-project')
+        expect(link.attr('data-project')).to eq project.id.to_s
+      end
+
+      it 'includes a data-issue attribute' do
+        doc = filter("See #{reference}")
+        link = doc.css('a').first
+
+        expect(link).to have_attribute('data-issue')
+        expect(link.attr('data-issue')).to eq issue.id.to_s
       end
 
       it 'supports an :only_path context' do
@@ -85,60 +93,46 @@ module Gitlab::Markdown
       end
 
       it 'adds to the results hash' do
-        result = pipeline_result("Fixed #{reference}")
+        result = reference_pipeline_result("Fixed #{reference}")
         expect(result[:references][:issue]).to eq [issue]
       end
     end
 
     context 'cross-project reference' do
       let(:namespace) { create(:namespace, name: 'cross-reference') }
-      let(:project2)  { create(:empty_project, namespace: namespace) }
+      let(:project2)  { create(:empty_project, :public, namespace: namespace) }
       let(:issue)     { create(:issue, project: project2) }
       let(:reference) { issue.to_reference(project) }
 
-      context 'when user can access reference' do
-        before { allow_cross_reference! }
-
-        it 'ignores valid references when cross-reference project uses external tracker' do
-          expect_any_instance_of(Project).to receive(:get_issue).
-            with(issue.iid).and_return(nil)
-
-          exp = act = "Issue #{reference}"
-          expect(filter(act).to_html).to eq exp
-        end
+      it 'ignores valid references when cross-reference project uses external tracker' do
+        expect_any_instance_of(Project).to receive(:get_issue).
+          with(issue.iid).and_return(nil)
 
-        it 'links to a valid reference' do
-          doc = filter("See #{reference}")
-
-          expect(doc.css('a').first.attr('href')).
-            to eq helper.url_for_issue(issue.iid, project2)
-        end
-
-        it 'links with adjacent text' do
-          doc = filter("Fixed (#{reference}.)")
-          expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
-        end
+        exp = act = "Issue #{reference}"
+        expect(filter(act).to_html).to eq exp
+      end
 
-        it 'ignores invalid issue IDs on the referenced project' do
-          exp = act = "Fixed #{invalidate_reference(reference)}"
+      it 'links to a valid reference' do
+        doc = filter("See #{reference}")
 
-          expect(filter(act).to_html).to eq exp
-        end
+        expect(doc.css('a').first.attr('href')).
+          to eq helper.url_for_issue(issue.iid, project2)
+      end
 
-        it 'adds to the results hash' do
-          result = pipeline_result("Fixed #{reference}")
-          expect(result[:references][:issue]).to eq [issue]
-        end
+      it 'links with adjacent text' do
+        doc = filter("Fixed (#{reference}.)")
+        expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
       end
 
-      context 'when user cannot access reference' do
-        before { disallow_cross_reference! }
+      it 'ignores invalid issue IDs on the referenced project' do
+        exp = act = "Fixed #{invalidate_reference(reference)}"
 
-        it 'ignores valid references' do
-          exp = act = "See #{reference}"
+        expect(filter(act).to_html).to eq exp
+      end
 
-          expect(filter(act).to_html).to eq exp
-        end
+      it 'adds to the results hash' do
+        result = reference_pipeline_result("Fixed #{reference}")
+        expect(result[:references][:issue]).to eq [issue]
       end
     end
   end
diff --git a/spec/lib/gitlab/markdown/label_reference_filter_spec.rb b/spec/lib/gitlab/markdown/label_reference_filter_spec.rb
index e32089de376615e94eaabe7bbed84837d9440052..fc21b65a8437106d35f54ac484d0f4bdbda86cf8 100644
--- a/spec/lib/gitlab/markdown/label_reference_filter_spec.rb
+++ b/spec/lib/gitlab/markdown/label_reference_filter_spec.rb
@@ -5,7 +5,7 @@ module Gitlab::Markdown
   describe LabelReferenceFilter do
     include FilterSpecHelper
 
-    let(:project)   { create(:empty_project) }
+    let(:project)   { create(:empty_project, :public) }
     let(:label)     { create(:label, project: project) }
     let(:reference) { label.to_reference }
 
@@ -25,12 +25,20 @@ module Gitlab::Markdown
       expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-label'
     end
 
-    it 'includes a data-project-id attribute' do
+    it 'includes a data-project attribute' do
       doc = filter("Label #{reference}")
       link = doc.css('a').first
 
-      expect(link).to have_attribute('data-project-id')
-      expect(link.attr('data-project-id')).to eq project.id.to_s
+      expect(link).to have_attribute('data-project')
+      expect(link.attr('data-project')).to eq project.id.to_s
+    end
+
+    it 'includes a data-label attribute' do
+      doc = filter("See #{reference}")
+      link = doc.css('a').first
+
+      expect(link).to have_attribute('data-label')
+      expect(link.attr('data-label')).to eq label.id.to_s
     end
 
     it 'supports an :only_path context' do
@@ -42,7 +50,7 @@ module Gitlab::Markdown
     end
 
     it 'adds to the results hash' do
-      result = pipeline_result("Label #{reference}")
+      result = reference_pipeline_result("Label #{reference}")
       expect(result[:references][:label]).to eq [label]
     end
 
diff --git a/spec/lib/gitlab/markdown/merge_request_reference_filter_spec.rb b/spec/lib/gitlab/markdown/merge_request_reference_filter_spec.rb
index 66616b9336824b1fbc8aea063dc1cb3681b4b4de..3ef6cdfff33b11ca5f39a87c5f069608c497b904 100644
--- a/spec/lib/gitlab/markdown/merge_request_reference_filter_spec.rb
+++ b/spec/lib/gitlab/markdown/merge_request_reference_filter_spec.rb
@@ -4,7 +4,7 @@ module Gitlab::Markdown
   describe MergeRequestReferenceFilter do
     include FilterSpecHelper
 
-    let(:project) { create(:project) }
+    let(:project) { create(:project, :public) }
     let(:merge)   { create(:merge_request, source_project: project) }
 
     it 'requires project context' do
@@ -56,12 +56,20 @@ module Gitlab::Markdown
         expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-merge_request'
       end
 
-      it 'includes a data-project-id attribute' do
+      it 'includes a data-project attribute' do
         doc = filter("Merge #{reference}")
         link = doc.css('a').first
 
-        expect(link).to have_attribute('data-project-id')
-        expect(link.attr('data-project-id')).to eq project.id.to_s
+        expect(link).to have_attribute('data-project')
+        expect(link.attr('data-project')).to eq project.id.to_s
+      end
+
+      it 'includes a data-merge-request attribute' do
+        doc = filter("See #{reference}")
+        link = doc.css('a').first
+
+        expect(link).to have_attribute('data-merge-request')
+        expect(link.attr('data-merge-request')).to eq merge.id.to_s
       end
 
       it 'supports an :only_path context' do
@@ -73,53 +81,39 @@ module Gitlab::Markdown
       end
 
       it 'adds to the results hash' do
-        result = pipeline_result("Merge #{reference}")
+        result = reference_pipeline_result("Merge #{reference}")
         expect(result[:references][:merge_request]).to eq [merge]
       end
     end
 
     context 'cross-project reference' do
       let(:namespace) { create(:namespace, name: 'cross-reference') }
-      let(:project2)  { create(:project, namespace: namespace) }
+      let(:project2)  { create(:project, :public, namespace: namespace) }
       let(:merge)     { create(:merge_request, source_project: project2) }
       let(:reference) { merge.to_reference(project) }
 
-      context 'when user can access reference' do
-        before { allow_cross_reference! }
-
-        it 'links to a valid reference' do
-          doc = filter("See #{reference}")
-
-          expect(doc.css('a').first.attr('href')).
-            to eq urls.namespace_project_merge_request_url(project2.namespace,
-                                                          project, merge)
-        end
-
-        it 'links with adjacent text' do
-          doc = filter("Merge (#{reference}.)")
-          expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
-        end
-
-        it 'ignores invalid merge IDs on the referenced project' do
-          exp = act = "Merge #{invalidate_reference(reference)}"
+      it 'links to a valid reference' do
+        doc = filter("See #{reference}")
 
-          expect(filter(act).to_html).to eq exp
-        end
+        expect(doc.css('a').first.attr('href')).
+          to eq urls.namespace_project_merge_request_url(project2.namespace,
+                                                        project, merge)
+      end
 
-        it 'adds to the results hash' do
-          result = pipeline_result("Merge #{reference}")
-          expect(result[:references][:merge_request]).to eq [merge]
-        end
+      it 'links with adjacent text' do
+        doc = filter("Merge (#{reference}.)")
+        expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
       end
 
-      context 'when user cannot access reference' do
-        before { disallow_cross_reference! }
+      it 'ignores invalid merge IDs on the referenced project' do
+        exp = act = "Merge #{invalidate_reference(reference)}"
 
-        it 'ignores valid references' do
-          exp = act = "See #{reference}"
+        expect(filter(act).to_html).to eq exp
+      end
 
-          expect(filter(act).to_html).to eq exp
-        end
+      it 'adds to the results hash' do
+        result = reference_pipeline_result("Merge #{reference}")
+        expect(result[:references][:merge_request]).to eq [merge]
       end
     end
   end
diff --git a/spec/lib/gitlab/markdown/redactor_filter_spec.rb b/spec/lib/gitlab/markdown/redactor_filter_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..eea3f1cf370920b21d578a016a2a21fe5f3feea2
--- /dev/null
+++ b/spec/lib/gitlab/markdown/redactor_filter_spec.rb
@@ -0,0 +1,91 @@
+require 'spec_helper'
+
+module Gitlab::Markdown
+  describe RedactorFilter do
+    include ActionView::Helpers::UrlHelper
+    include FilterSpecHelper
+
+    it 'ignores non-GFM links' do
+      html = %(See <a href="https://google.com/">Google</a>)
+      doc = filter(html, current_user: double)
+
+      expect(doc.css('a').length).to eq 1
+    end
+
+    def reference_link(data)
+      link_to('text', '', class: 'gfm', data: data)
+    end
+
+    context 'with data-project' do
+      it 'removes unpermitted Project references' do
+        user = create(:user)
+        project = create(:empty_project)
+
+        link = reference_link(project: project.id, reference_filter: Gitlab::Markdown::ReferenceFilter.name)
+        doc = filter(link, current_user: user)
+
+        expect(doc.css('a').length).to eq 0
+      end
+
+      it 'allows permitted Project references' do
+        user = create(:user)
+        project = create(:empty_project)
+        project.team << [user, :master]
+
+        link = reference_link(project: project.id, reference_filter: Gitlab::Markdown::ReferenceFilter.name)
+        doc = filter(link, current_user: user)
+
+        expect(doc.css('a').length).to eq 1
+      end
+
+      it 'handles invalid Project references' do
+        link = reference_link(project: 12345, reference_filter: Gitlab::Markdown::ReferenceFilter.name)
+
+        expect { filter(link) }.not_to raise_error
+      end
+    end
+
+    context "for user references" do
+
+      context 'with data-group' do
+        it 'removes unpermitted Group references' do
+          user = create(:user)
+          group = create(:group)
+
+          link = reference_link(group: group.id, reference_filter: Gitlab::Markdown::UserReferenceFilter.name)
+          doc = filter(link, current_user: user)
+
+          expect(doc.css('a').length).to eq 0
+        end
+
+        it 'allows permitted Group references' do
+          user = create(:user)
+          group = create(:group)
+          group.add_developer(user)
+
+          link = reference_link(group: group.id, reference_filter: Gitlab::Markdown::UserReferenceFilter.name)
+          doc = filter(link, current_user: user)
+
+          expect(doc.css('a').length).to eq 1
+        end
+
+        it 'handles invalid Group references' do
+          link = reference_link(group: 12345, reference_filter: Gitlab::Markdown::UserReferenceFilter.name)
+
+          expect { filter(link) }.not_to raise_error
+        end
+      end
+
+      context 'with data-user' do
+        it 'allows any User reference' do
+          user = create(:user)
+
+          link = reference_link(user: user.id, reference_filter: Gitlab::Markdown::UserReferenceFilter.name)
+          doc = filter(link)
+
+          expect(doc.css('a').length).to eq 1
+        end
+      end
+    end
+  end
+end
diff --git a/spec/lib/gitlab/markdown/reference_gatherer_filter_spec.rb b/spec/lib/gitlab/markdown/reference_gatherer_filter_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..4fa473ad191a0daad3bf517add4d43f16a974e73
--- /dev/null
+++ b/spec/lib/gitlab/markdown/reference_gatherer_filter_spec.rb
@@ -0,0 +1,89 @@
+require 'spec_helper'
+
+module Gitlab::Markdown
+  describe ReferenceGathererFilter do
+    include ActionView::Helpers::UrlHelper
+    include FilterSpecHelper
+
+    def reference_link(data)
+      link_to('text', '', class: 'gfm', data: data)
+    end
+
+    context "for issue references" do
+
+      context 'with data-project' do
+        it 'removes unpermitted Project references' do
+          user = create(:user)
+          project = create(:empty_project)
+          issue = create(:issue, project: project)
+
+          link = reference_link(project: project.id, issue: issue.id, reference_filter: Gitlab::Markdown::IssueReferenceFilter.name)
+          result = pipeline_result(link, current_user: user)
+
+          expect(result[:references][:issue]).to be_empty
+        end
+
+        it 'allows permitted Project references' do
+          user = create(:user)
+          project = create(:empty_project)
+          issue = create(:issue, project: project)
+          project.team << [user, :master]
+
+          link = reference_link(project: project.id, issue: issue.id, reference_filter: Gitlab::Markdown::IssueReferenceFilter.name)
+          result = pipeline_result(link, current_user: user)
+
+          expect(result[:references][:issue]).to eq([issue])
+        end
+
+        it 'handles invalid Project references' do
+          link = reference_link(project: 12345, issue: 12345, reference_filter: Gitlab::Markdown::IssueReferenceFilter.name)
+
+          expect { pipeline_result(link) }.not_to raise_error
+        end
+      end
+    end
+
+    context "for user references" do
+
+      context 'with data-group' do
+        it 'removes unpermitted Group references' do
+          user = create(:user)
+          group = create(:group)
+
+          link = reference_link(group: group.id, reference_filter: Gitlab::Markdown::UserReferenceFilter.name)
+          result = pipeline_result(link, current_user: user)
+
+          expect(result[:references][:user]).to be_empty
+        end
+
+        it 'allows permitted Group references' do
+          user = create(:user)
+          group = create(:group)
+          group.add_developer(user)
+
+          link = reference_link(group: group.id, reference_filter: Gitlab::Markdown::UserReferenceFilter.name)
+          result = pipeline_result(link, current_user: user)
+
+          expect(result[:references][:user]).to eq([user])
+        end
+
+        it 'handles invalid Group references' do
+          link = reference_link(group: 12345, reference_filter: Gitlab::Markdown::UserReferenceFilter.name)
+
+          expect { pipeline_result(link) }.not_to raise_error
+        end
+      end
+
+      context 'with data-user' do
+        it 'allows any User reference' do
+          user = create(:user)
+
+          link = reference_link(user: user.id, reference_filter: Gitlab::Markdown::UserReferenceFilter.name)
+          result = pipeline_result(link)
+
+          expect(result[:references][:user]).to eq([user])
+        end
+      end
+    end
+  end
+end
diff --git a/spec/lib/gitlab/markdown/snippet_reference_filter_spec.rb b/spec/lib/gitlab/markdown/snippet_reference_filter_spec.rb
index fd3f0d20fadc0a55595c25da03c8d79bc49a0283..9d9652dba46b1a3f0badd95de2cabdaa41cc6266 100644
--- a/spec/lib/gitlab/markdown/snippet_reference_filter_spec.rb
+++ b/spec/lib/gitlab/markdown/snippet_reference_filter_spec.rb
@@ -4,7 +4,7 @@ module Gitlab::Markdown
   describe SnippetReferenceFilter do
     include FilterSpecHelper
 
-    let(:project)   { create(:empty_project) }
+    let(:project)   { create(:empty_project, :public) }
     let(:snippet)   { create(:project_snippet, project: project) }
     let(:reference) { snippet.to_reference }
 
@@ -55,12 +55,20 @@ module Gitlab::Markdown
         expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-snippet'
       end
 
-      it 'includes a data-project-id attribute' do
+      it 'includes a data-project attribute' do
         doc = filter("Snippet #{reference}")
         link = doc.css('a').first
 
-        expect(link).to have_attribute('data-project-id')
-        expect(link.attr('data-project-id')).to eq project.id.to_s
+        expect(link).to have_attribute('data-project')
+        expect(link.attr('data-project')).to eq project.id.to_s
+      end
+
+      it 'includes a data-snippet attribute' do
+        doc = filter("See #{reference}")
+        link = doc.css('a').first
+
+        expect(link).to have_attribute('data-snippet')
+        expect(link.attr('data-snippet')).to eq snippet.id.to_s
       end
 
       it 'supports an :only_path context' do
@@ -72,52 +80,38 @@ module Gitlab::Markdown
       end
 
       it 'adds to the results hash' do
-        result = pipeline_result("Snippet #{reference}")
+        result = reference_pipeline_result("Snippet #{reference}")
         expect(result[:references][:snippet]).to eq [snippet]
       end
     end
 
     context 'cross-project reference' do
       let(:namespace) { create(:namespace, name: 'cross-reference') }
-      let(:project2)  { create(:empty_project, namespace: namespace) }
+      let(:project2)  { create(:empty_project, :public, namespace: namespace) }
       let(:snippet)   { create(:project_snippet, project: project2) }
       let(:reference) { snippet.to_reference(project) }
 
-      context 'when user can access reference' do
-        before { allow_cross_reference! }
-
-        it 'links to a valid reference' do
-          doc = filter("See #{reference}")
-
-          expect(doc.css('a').first.attr('href')).
-            to eq urls.namespace_project_snippet_url(project2.namespace, project2, snippet)
-        end
-
-        it 'links with adjacent text' do
-          doc = filter("See (#{reference}.)")
-          expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
-        end
-
-        it 'ignores invalid snippet IDs on the referenced project' do
-          exp = act = "See #{invalidate_reference(reference)}"
+      it 'links to a valid reference' do
+        doc = filter("See #{reference}")
 
-          expect(filter(act).to_html).to eq exp
-        end
+        expect(doc.css('a').first.attr('href')).
+          to eq urls.namespace_project_snippet_url(project2.namespace, project2, snippet)
+      end
 
-        it 'adds to the results hash' do
-          result = pipeline_result("Snippet #{reference}")
-          expect(result[:references][:snippet]).to eq [snippet]
-        end
+      it 'links with adjacent text' do
+        doc = filter("See (#{reference}.)")
+        expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
       end
 
-      context 'when user cannot access reference' do
-        before { disallow_cross_reference! }
+      it 'ignores invalid snippet IDs on the referenced project' do
+        exp = act = "See #{invalidate_reference(reference)}"
 
-        it 'ignores valid references' do
-          exp = act = "See #{reference}"
+        expect(filter(act).to_html).to eq exp
+      end
 
-          expect(filter(act).to_html).to eq exp
-        end
+      it 'adds to the results hash' do
+        result = reference_pipeline_result("Snippet #{reference}")
+        expect(result[:references][:snippet]).to eq [snippet]
       end
     end
   end
diff --git a/spec/lib/gitlab/markdown/upload_link_filter_spec.rb b/spec/lib/gitlab/markdown/upload_link_filter_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..9ae45a6f5597e035e11e393b5424f34fca221ce9
--- /dev/null
+++ b/spec/lib/gitlab/markdown/upload_link_filter_spec.rb
@@ -0,0 +1,75 @@
+# encoding: UTF-8
+
+require 'spec_helper'
+
+module Gitlab::Markdown
+  describe UploadLinkFilter do
+    def filter(doc, contexts = {})
+      contexts.reverse_merge!({
+        project: project
+      })
+
+      described_class.call(doc, contexts)
+    end
+
+    def image(path)
+      %(<img src="#{path}" />)
+    end
+
+    def link(path)
+      %(<a href="#{path}">#{path}</a>)
+    end
+
+    let(:project) { create(:project) }
+
+    shared_examples :preserve_unchanged do
+      it 'does not modify any relative URL in anchor' do
+        doc = filter(link('README.md'))
+        expect(doc.at_css('a')['href']).to eq 'README.md'
+      end
+
+      it 'does not modify any relative URL in image' do
+        doc = filter(image('files/images/logo-black.png'))
+        expect(doc.at_css('img')['src']).to eq 'files/images/logo-black.png'
+      end
+    end
+
+    it 'does not raise an exception on invalid URIs' do
+      act = link("://foo")
+      expect { filter(act) }.not_to raise_error
+    end
+
+    context 'with a valid repository' do
+      it 'rebuilds relative URL for a link' do
+        doc = filter(link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'))
+        expect(doc.at_css('a')['href']).
+          to eq "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
+      end
+
+      it 'rebuilds relative URL for an image' do
+        doc = filter(link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'))
+        expect(doc.at_css('a')['href']).
+          to eq "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
+      end
+
+      it 'does not modify absolute URL' do
+        doc = filter(link('http://example.com'))
+        expect(doc.at_css('a')['href']).to eq 'http://example.com'
+      end
+
+      it 'supports Unicode filenames' do
+        path = '/uploads/한글.png'
+        escaped = Addressable::URI.escape(path)
+
+        # Stub these methods so the file doesn't actually need to be in the repo
+        allow_any_instance_of(described_class).
+          to receive(:file_exists?).and_return(true)
+        allow_any_instance_of(described_class).
+          to receive(:image?).with(path).and_return(true)
+
+        doc = filter(image(escaped))
+        expect(doc.at_css('img')['src']).to match "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/%ED%95%9C%EA%B8%80.png"
+      end
+    end
+  end
+end
diff --git a/spec/lib/gitlab/markdown/user_reference_filter_spec.rb b/spec/lib/gitlab/markdown/user_reference_filter_spec.rb
index b2155fab59b0099b5b5ed88fa03c18e1ab5d87eb..d9e0d7c42db7fd1bc83981d4b5bdeb0600596fbd 100644
--- a/spec/lib/gitlab/markdown/user_reference_filter_spec.rb
+++ b/spec/lib/gitlab/markdown/user_reference_filter_spec.rb
@@ -4,7 +4,7 @@ module Gitlab::Markdown
   describe UserReferenceFilter do
     include FilterSpecHelper
 
-    let(:project)   { create(:empty_project) }
+    let(:project)   { create(:empty_project, :public) }
     let(:user)      { create(:user) }
     let(:reference) { user.to_reference }
 
@@ -39,7 +39,7 @@ module Gitlab::Markdown
       end
 
       it 'adds to the results hash' do
-        result = pipeline_result("Hey #{reference}")
+        result = reference_pipeline_result("Hey #{reference}")
         expect(result[:references][:user]).to eq [project.creator]
       end
     end
@@ -64,59 +64,40 @@ module Gitlab::Markdown
         expect(doc.css('a').length).to eq 1
       end
 
-      it 'includes a data-user-id attribute' do
+      it 'includes a data-user attribute' do
         doc = filter("Hey #{reference}")
         link = doc.css('a').first
 
-        expect(link).to have_attribute('data-user-id')
-        expect(link.attr('data-user-id')).to eq user.namespace.owner_id.to_s
+        expect(link).to have_attribute('data-user')
+        expect(link.attr('data-user')).to eq user.namespace.owner_id.to_s
       end
 
       it 'adds to the results hash' do
-        result = pipeline_result("Hey #{reference}")
+        result = reference_pipeline_result("Hey #{reference}")
         expect(result[:references][:user]).to eq [user]
       end
     end
 
     context 'mentioning a group' do
       let(:group)     { create(:group) }
-      let(:user)      { create(:user) }
       let(:reference) { group.to_reference }
 
-      context 'that the current user can read' do
-        before do
-          group.add_developer(user)
-        end
-
-        it 'links to the Group' do
-          doc = filter("Hey #{reference}", current_user: user)
-          expect(doc.css('a').first.attr('href')).to eq urls.group_url(group)
-        end
-
-        it 'includes a data-group-id attribute' do
-          doc = filter("Hey #{reference}", current_user: user)
-          link = doc.css('a').first
+      it 'links to the Group' do
+        doc = filter("Hey #{reference}")
+        expect(doc.css('a').first.attr('href')).to eq urls.group_url(group)
+      end
 
-          expect(link).to have_attribute('data-group-id')
-          expect(link.attr('data-group-id')).to eq group.id.to_s
-        end
+      it 'includes a data-group attribute' do
+        doc = filter("Hey #{reference}")
+        link = doc.css('a').first
 
-        it 'adds to the results hash' do
-          result = pipeline_result("Hey #{reference}", current_user: user)
-          expect(result[:references][:user]).to eq group.users
-        end
+        expect(link).to have_attribute('data-group')
+        expect(link.attr('data-group')).to eq group.id.to_s
       end
 
-      context 'that the current user cannot read' do
-        it 'ignores references to the Group' do
-          doc = filter("Hey #{reference}", current_user: user)
-          expect(doc.to_html).to eq "Hey #{reference}"
-        end
-
-        it 'does not add to the results hash' do
-          result = pipeline_result("Hey #{reference}", current_user: user)
-          expect(result[:references][:user]).to eq []
-        end
+      it 'adds to the results hash' do
+        result = reference_pipeline_result("Hey #{reference}")
+        expect(result[:references][:user]).to eq group.users
       end
     end
 
diff --git a/spec/lib/gitlab/o_auth/user_spec.rb b/spec/lib/gitlab/o_auth/user_spec.rb
index c0083fc85be562fa9fc7818affceb551814d3690..fd3ab1fb7c86808e53f9639460605cb19a2da47e 100644
--- a/spec/lib/gitlab/o_auth/user_spec.rb
+++ b/spec/lib/gitlab/o_auth/user_spec.rb
@@ -19,10 +19,6 @@ describe Gitlab::OAuth::User do
     let!(:existing_user) { create(:omniauth_user, extern_uid: 'my-uid', provider: 'my-provider') }
 
     it "finds an existing user based on uid and provider (facebook)" do
-      # FIXME (rspeicher): It's unlikely that this test is actually doing anything
-      # `auth` is never used and removing it entirely doesn't break the test, so
-      # what's it doing?
-      auth = double(info: double(name: 'John'), uid: 'my-uid', provider: 'my-provider')
       expect( oauth_user.persisted? ).to be_truthy
     end
 
diff --git a/spec/lib/gitlab/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb
index 088e34f050c317ab91272c69f0a6d63e5c3d4467..ad84d2274e804736329c47fd087f7e91144da7c9 100644
--- a/spec/lib/gitlab/reference_extractor_spec.rb
+++ b/spec/lib/gitlab/reference_extractor_spec.rb
@@ -13,7 +13,7 @@ describe Gitlab::ReferenceExtractor do
     project.team << [@u_bar, :guest]
 
     subject.analyze('@foo, @baduser, @bar, and @offteam')
-    expect(subject.users).to eq([@u_foo, @u_bar, @u_offteam])
+    expect(subject.users).to match_array([@u_foo, @u_bar, @u_offteam])
   end
 
   it 'ignores user mentions inside specific elements' do
@@ -37,7 +37,7 @@ describe Gitlab::ReferenceExtractor do
 
       > @offteam
     })
-    expect(subject.users).to eq([])
+    expect(subject.users).to match_array([])
   end
 
   it 'accesses valid issue objects' do
@@ -45,7 +45,7 @@ describe Gitlab::ReferenceExtractor do
     @i1 = create(:issue, project: project)
 
     subject.analyze("#{@i0.to_reference}, #{@i1.to_reference}, and #{Issue.reference_prefix}999.")
-    expect(subject.issues).to eq([@i0, @i1])
+    expect(subject.issues).to match_array([@i0, @i1])
   end
 
   it 'accesses valid merge requests' do
@@ -53,7 +53,7 @@ describe Gitlab::ReferenceExtractor do
     @m1 = create(:merge_request, source_project: project, target_project: project, source_branch: 'feature_conflict')
 
     subject.analyze("!999, !#{@m1.iid}, and !#{@m0.iid}.")
-    expect(subject.merge_requests).to eq([@m1, @m0])
+    expect(subject.merge_requests).to match_array([@m1, @m0])
   end
 
   it 'accesses valid labels' do
@@ -62,7 +62,7 @@ describe Gitlab::ReferenceExtractor do
     @l2 = create(:label)
 
     subject.analyze("~#{@l0.id}, ~999, ~#{@l2.id}, ~#{@l1.id}")
-    expect(subject.labels).to eq([@l0, @l1])
+    expect(subject.labels).to match_array([@l0, @l1])
   end
 
   it 'accesses valid snippets' do
@@ -71,7 +71,7 @@ describe Gitlab::ReferenceExtractor do
     @s2 = create(:project_snippet)
 
     subject.analyze("$#{@s0.id}, $999, $#{@s2.id}, $#{@s1.id}")
-    expect(subject.snippets).to eq([@s0, @s1])
+    expect(subject.snippets).to match_array([@s0, @s1])
   end
 
   it 'accesses valid commits' do
@@ -109,7 +109,7 @@ describe Gitlab::ReferenceExtractor do
       subject.analyze("this refers issue #{issue.to_reference(project)}")
       extracted = subject.issues
       expect(extracted.size).to eq(1)
-      expect(extracted).to eq([issue])
+      expect(extracted).to match_array([issue])
     end
   end
 end
diff --git a/spec/lib/gitlab/uploads_transfer_spec.rb b/spec/lib/gitlab/uploads_transfer_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..260364a513e4d2646213999645cd09511ba0b85d
--- /dev/null
+++ b/spec/lib/gitlab/uploads_transfer_spec.rb
@@ -0,0 +1,50 @@
+require 'spec_helper'
+
+describe Gitlab::UploadsTransfer do
+  before do
+    @root_dir = File.join(Rails.root, "public", "uploads")
+    @upload_transfer = Gitlab::UploadsTransfer.new
+
+    @project_path_was = "test_project_was"
+    @project_path = "test_project"
+    @namespace_path_was = "test_namespace_was"
+    @namespace_path = "test_namespace"
+  end
+
+  after do
+    FileUtils.rm_rf([
+      File.join(@root_dir, @namespace_path),
+      File.join(@root_dir, @namespace_path_was)
+    ])
+  end
+
+  describe '#move_project' do
+    it "moves project upload to another namespace" do
+      FileUtils.mkdir_p(File.join(@root_dir, @namespace_path_was, @project_path))
+      @upload_transfer.move_project(@project_path, @namespace_path_was, @namespace_path)
+
+      expected_path = File.join(@root_dir, @namespace_path, @project_path)
+      expect(Dir.exist?(expected_path)).to be_truthy
+    end
+  end
+
+  describe '#rename_project' do
+    it "renames project" do
+      FileUtils.mkdir_p(File.join(@root_dir, @namespace_path, @project_path_was))
+      @upload_transfer.rename_project(@project_path_was, @project_path, @namespace_path)
+
+      expected_path = File.join(@root_dir, @namespace_path, @project_path)
+      expect(Dir.exist?(expected_path)).to be_truthy
+    end
+  end
+
+  describe '#rename_namespace' do
+    it "renames namespace" do
+      FileUtils.mkdir_p(File.join(@root_dir, @namespace_path_was, @project_path))
+      @upload_transfer.rename_namespace(@namespace_path_was, @namespace_path)
+
+      expected_path = File.join(@root_dir, @namespace_path, @project_path)
+      expect(Dir.exist?(expected_path)).to be_truthy
+    end
+  end
+end
diff --git a/spec/mailers/ci/notify_spec.rb b/spec/mailers/ci/notify_spec.rb
index 20d8ddcd135a0a4f33a64211b8b375c5d62dc4fb..b83fb41603bff1a5cb212e0d8387070806747f44 100644
--- a/spec/mailers/ci/notify_spec.rb
+++ b/spec/mailers/ci/notify_spec.rb
@@ -5,8 +5,7 @@ describe Ci::Notify do
   include EmailSpec::Matchers
 
   before do
-    @project = FactoryGirl.create :ci_project
-    @commit = FactoryGirl.create :ci_commit, project: @project
+    @commit = FactoryGirl.create :ci_commit
     @build = FactoryGirl.create :ci_build, commit: @commit
   end
 
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index 2c97a521d96217d701af3f6f4f56478e2c038fc4..cb67ec95d57469d11f09eb9b7b28422a66c3cfe7 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -52,6 +52,7 @@ describe Notify do
     end
 
     it 'has headers that reference an existing thread' do
+      is_expected.to have_header 'Message-ID',  /<(.*)@#{Gitlab.config.gitlab.host}>/
       is_expected.to have_header 'References',  /<#{thread_id_prefix}(.*)@#{Gitlab.config.gitlab.host}>/
       is_expected.to have_header 'In-Reply-To', /<#{thread_id_prefix}(.*)@#{Gitlab.config.gitlab.host}>/
       is_expected.to have_header 'X-GitLab-Project', /#{project.name}/
@@ -399,7 +400,7 @@ describe Notify do
     describe 'project was moved' do
       let(:project) { create(:project) }
       let(:user) { create(:user) }
-      subject { Notify.project_was_moved_email(project.id, user.id) }
+      subject { Notify.project_was_moved_email(project.id, user.id, "gitlab/gitlab") }
 
       it_behaves_like 'an email sent from GitLab'
 
diff --git a/spec/models/abuse_report_spec.rb b/spec/models/abuse_report_spec.rb
index 635a6e2518ce79a5baeca42d638c2af74c0f3954..d45319b25d425f38d5c10a0040821ddb2d46507b 100644
--- a/spec/models/abuse_report_spec.rb
+++ b/spec/models/abuse_report_spec.rb
@@ -16,4 +16,16 @@ RSpec.describe AbuseReport, type: :model do
   subject { create(:abuse_report) }
 
   it { expect(subject).to be_valid }
+
+  describe 'associations' do
+    it { is_expected.to belong_to(:reporter).class_name('User') }
+    it { is_expected.to belong_to(:user) }
+  end
+
+  describe 'validations' do
+    it { is_expected.to validate_presence_of(:reporter) }
+    it { is_expected.to validate_presence_of(:user) }
+    it { is_expected.to validate_presence_of(:message) }
+    it { is_expected.to validate_uniqueness_of(:user_id) }
+  end
 end
diff --git a/spec/models/broadcast_message_spec.rb b/spec/models/broadcast_message_spec.rb
index 8ab72151a690b1e37b60cffe94e0742955907f48..d80748f23a41f74baf8f07c83304f9b4d6bcda63 100644
--- a/spec/models/broadcast_message_spec.rb
+++ b/spec/models/broadcast_message_spec.rb
@@ -27,12 +27,12 @@ describe BroadcastMessage do
     end
 
     it "should return nil if time not come" do
-      broadcast_message = create(:broadcast_message, starts_at: Time.now.tomorrow, ends_at: Time.now + 2.days)
+      create(:broadcast_message, starts_at: Time.now.tomorrow, ends_at: Time.now + 2.days)
       expect(BroadcastMessage.current).to be_nil
     end
 
     it "should return nil if time has passed" do
-      broadcast_message = create(:broadcast_message, starts_at: Time.now - 2.days, ends_at: Time.now.yesterday)
+      create(:broadcast_message, starts_at: Time.now - 2.days, ends_at: Time.now.yesterday)
       expect(BroadcastMessage.current).to be_nil
     end
   end
diff --git a/spec/models/ci/build_spec.rb b/spec/models/build_spec.rb
similarity index 55%
rename from spec/models/ci/build_spec.rb
rename to spec/models/build_spec.rb
index ce80115204236b1e096fe7f2a47ad69693a6888d..7f5abb83ac2298813e596c95468be60fc16dbfc8 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/build_spec.rb
@@ -27,16 +27,12 @@ require 'spec_helper'
 
 describe Ci::Build do
   let(:project) { FactoryGirl.create :ci_project }
-  let(:commit) { FactoryGirl.create :ci_commit, project: project }
+  let(:gl_project) { FactoryGirl.create :empty_project, gitlab_ci_project: project }
+  let(:commit) { FactoryGirl.create :ci_commit, gl_project: gl_project }
   let(:build) { FactoryGirl.create :ci_build, commit: commit }
 
-  it { is_expected.to belong_to(:commit) }
-  it { is_expected.to validate_presence_of :status }
+  it { is_expected.to validate_presence_of :ref }
 
-  it { is_expected.to respond_to :success? }
-  it { is_expected.to respond_to :failed? }
-  it { is_expected.to respond_to :running? }
-  it { is_expected.to respond_to :pending? }
   it { is_expected.to respond_to :trace_html }
 
   describe :first_pending do
@@ -63,72 +59,6 @@ describe Ci::Build do
     end
   end
 
-  describe :started? do
-    subject { build.started? }
-
-    context 'without started_at' do
-      before { build.started_at = nil }
-
-      it { is_expected.to be_falsey }
-    end
-
-    %w(running success failed).each do |status|
-      context "if build status is #{status}" do
-        before { build.status = status }
-
-        it { is_expected.to be_truthy }
-      end
-    end
-
-    %w(pending canceled).each do |status|
-      context "if build status is #{status}" do
-        before { build.status = status }
-
-        it { is_expected.to be_falsey }
-      end
-    end
-  end
-
-  describe :active? do
-    subject { build.active? }
-
-    %w(pending running).each do |state|
-      context "if build.status is #{state}" do
-        before { build.status = state }
-
-        it { is_expected.to be_truthy }
-      end
-    end
-
-    %w(success failed canceled).each do |state|
-      context "if build.status is #{state}" do
-        before { build.status = state }
-
-        it { is_expected.to be_falsey }
-      end
-    end
-  end
-
-  describe :complete? do
-    subject { build.complete? }
-
-    %w(success failed canceled).each do |state|
-      context "if build.status is #{state}" do
-        before { build.status = state }
-
-        it { is_expected.to be_truthy }
-      end
-    end
-
-    %w(pending running).each do |state|
-      context "if build.status is #{state}" do
-        before { build.status = state }
-
-        it { is_expected.to be_falsey }
-      end
-    end
-  end
-
   describe :ignored? do
     subject { build.ignored? }
 
@@ -177,37 +107,23 @@ describe Ci::Build do
       it { is_expected.to include(text) }
       it { expect(subject.length).to be >= text.length }
     end
-  end
 
-  describe :timeout do
-    subject { build.timeout }
+    context 'if build.trace hides token' do
+      let(:token) { 'my_secret_token' }
 
-    it { is_expected.to eq(commit.project.timeout) }
-  end
-
-  describe :duration do
-    subject { build.duration }
-
-    it { is_expected.to eq(120.0) }
-
-    context 'if the building process has not started yet' do
       before do
-        build.started_at = nil
-        build.finished_at = nil
+        build.project.update_attributes(token: token)
+        build.update_attributes(trace: token)
       end
 
-      it { is_expected.to be_nil }
+      it { is_expected.to_not include(token) }
     end
+  end
 
-    context 'if the building process has started' do
-      before do
-        build.started_at = Time.now - 1.minute
-        build.finished_at = nil
-      end
+  describe :timeout do
+    subject { build.timeout }
 
-      it { is_expected.to be_a(Float) }
-      it { is_expected.to be > 0.0 }
-    end
+    it { is_expected.to eq(commit.project.timeout) }
   end
 
   describe :options do
@@ -224,30 +140,6 @@ describe Ci::Build do
     it { is_expected.to eq(options) }
   end
 
-  describe :ref do
-    subject { build.ref }
-
-    it { is_expected.to eq(commit.ref) }
-  end
-
-  describe :sha do
-    subject { build.sha }
-
-    it { is_expected.to eq(commit.sha) }
-  end
-
-  describe :short_sha do
-    subject { build.short_sha }
-
-    it { is_expected.to eq(commit.short_sha) }
-  end
-
-  describe :before_sha do
-    subject { build.before_sha }
-
-    it { is_expected.to eq(commit.before_sha) }
-  end
-
   describe :allow_git_fetch do
     subject { build.allow_git_fetch }
 
@@ -308,13 +200,34 @@ describe Ci::Build do
     context 'returns variables' do
       subject { build.variables }
 
-      let(:variables) do
+      let(:predefined_variables) do
+        [
+          { key: :CI_BUILD_NAME, value: 'test', public: true },
+          { key: :CI_BUILD_STAGE, value: 'stage', public: true },
+        ]
+      end
+
+      let(:yaml_variables) do
         [
           { key: :DB_NAME, value: 'postgres', public: true }
         ]
       end
 
-      it { is_expected.to eq(variables) }
+      before { build.update_attributes(stage: 'stage') }
+
+      it { is_expected.to eq(predefined_variables + yaml_variables) }
+
+      context 'for tag' do
+        let(:tag_variable) do
+          [
+            { key: :CI_BUILD_TAG, value: 'master', public: true }
+          ]
+        end
+
+        before { build.update_attributes(tag: true) }
+
+        it { is_expected.to eq(tag_variable + predefined_variables + yaml_variables) }
+      end
 
       context 'and secure variables' do
         let(:secure_variables) do
@@ -327,7 +240,7 @@ describe Ci::Build do
           build.project.variables << Ci::Variable.new(key: 'SECRET_KEY', value: 'secret_value')
         end
 
-        it { is_expected.to eq(variables + secure_variables) }
+        it { is_expected.to eq(predefined_variables + yaml_variables + secure_variables) }
 
         context 'and trigger variables' do
           let(:trigger) { FactoryGirl.create :ci_trigger, project: project }
@@ -337,14 +250,154 @@ describe Ci::Build do
               { key: :TRIGGER_KEY, value: 'TRIGGER_VALUE', public: false }
             ]
           end
+          let(:predefined_trigger_variable) do
+            [
+              { key: :CI_BUILD_TRIGGERED, value: 'true', public: true }
+            ]
+          end
 
           before do
             build.trigger_request = trigger_request
           end
 
-          it { is_expected.to eq(variables + secure_variables + trigger_variables) }
+          it { is_expected.to eq(predefined_variables + predefined_trigger_variable + yaml_variables + secure_variables + trigger_variables) }
         end
       end
     end
   end
+
+  describe :project_recipients do
+    let(:pusher_email) { 'pusher@gitlab.test' }
+    let(:user) { User.new(notification_email: pusher_email) }
+    subject { build.project_recipients }
+
+    before do
+      build.update_attributes(user: user)
+    end
+
+    it 'should return pusher_email as only recipient when no additional recipients are given' do
+      project.update_attributes(email_add_pusher: true,
+                                email_recipients: '')
+      is_expected.to eq([pusher_email])
+    end
+
+    it 'should return pusher_email and additional recipients' do
+      project.update_attributes(email_add_pusher: true,
+                                email_recipients: 'rec1 rec2')
+      is_expected.to eq(['rec1', 'rec2', pusher_email])
+    end
+
+    it 'should return recipients' do
+      project.update_attributes(email_add_pusher: false,
+                                email_recipients: 'rec1 rec2')
+      is_expected.to eq(['rec1', 'rec2'])
+    end
+
+    it 'should return unique recipients only' do
+      project.update_attributes(email_add_pusher: true,
+                                email_recipients: "rec1 rec1 #{pusher_email}")
+      is_expected.to eq(['rec1', pusher_email])
+    end
+  end
+
+  describe :can_be_served? do
+    let(:runner) { FactoryGirl.create :ci_specific_runner }
+
+    before { build.project.runners << runner }
+
+    context 'runner without tags' do
+      it 'can handle builds without tags' do
+        expect(build.can_be_served?(runner)).to be_truthy
+      end
+
+      it 'cannot handle build with tags' do
+        build.tag_list = ['aa']
+        expect(build.can_be_served?(runner)).to be_falsey
+      end
+    end
+
+    context 'runner with tags' do
+      before { runner.tag_list = ['bb', 'cc'] }
+
+      it 'can handle builds without tags' do
+        expect(build.can_be_served?(runner)).to be_truthy
+      end
+
+      it 'can handle build with matching tags' do
+        build.tag_list = ['bb']
+        expect(build.can_be_served?(runner)).to be_truthy
+      end
+
+      it 'cannot handle build with not matching tags' do
+        build.tag_list = ['aa']
+        expect(build.can_be_served?(runner)).to be_falsey
+      end
+    end
+  end
+
+  describe :any_runners_online? do
+    subject { build.any_runners_online? }
+
+    context 'when no runners' do
+      it { is_expected.to be_falsey }
+    end
+
+    context 'if there are runner' do
+      let(:runner) { FactoryGirl.create :ci_specific_runner }
+
+      before do
+        build.project.runners << runner
+        runner.update_attributes(contacted_at: 1.second.ago)
+      end
+
+      it { is_expected.to be_truthy }
+
+      it 'that is inactive' do
+        runner.update_attributes(active: false)
+        is_expected.to be_falsey
+      end
+
+      it 'that is not online' do
+        runner.update_attributes(contacted_at: nil)
+        is_expected.to be_falsey
+      end
+
+      it 'that cannot handle build' do
+        expect_any_instance_of(Ci::Build).to receive(:can_be_served?).and_return(false)
+        is_expected.to be_falsey
+      end
+
+    end
+  end
+
+  describe :show_warning? do
+    subject { build.show_warning? }
+
+    %w(pending).each do |state|
+      context "if commit_status.status is #{state}" do
+        before { build.status = state }
+
+        it { is_expected.to be_truthy }
+
+        context "and there are specific runner" do
+          let(:runner) { FactoryGirl.create :ci_specific_runner, contacted_at: 1.second.ago }
+
+          before do
+            build.project.runners << runner
+            runner.save
+          end
+
+          it { is_expected.to be_falsey }
+        end
+      end
+    end
+
+    %w(success failed canceled running).each do |state|
+      context "if commit_status.status is #{state}" do
+        before { build.status = state }
+
+        it { is_expected.to be_falsey }
+      end
+    end
+  end
 end
diff --git a/spec/models/ci/commit_spec.rb b/spec/models/ci/commit_spec.rb
index 586c9dc23a7dcd001b1b713b73a4b0b026a2b886..44dbd083f064cc193c9e056977e0d9dcaf048310 100644
--- a/spec/models/ci/commit_spec.rb
+++ b/spec/models/ci/commit_spec.rb
@@ -19,21 +19,37 @@ require 'spec_helper'
 
 describe Ci::Commit do
   let(:project) { FactoryGirl.create :ci_project }
-  let(:commit) { FactoryGirl.create :ci_commit, project: project }
-  let(:commit_with_project) { FactoryGirl.create :ci_commit, project: project }
-  let(:config_processor) { Ci::GitlabCiYamlProcessor.new(gitlab_ci_yaml) }
+  let(:gl_project) { FactoryGirl.create :empty_project, gitlab_ci_project: project }
+  let(:commit) { FactoryGirl.create :ci_commit, gl_project: gl_project }
 
-  it { is_expected.to belong_to(:project) }
+  it { is_expected.to belong_to(:gl_project) }
+  it { is_expected.to have_many(:statuses) }
+  it { is_expected.to have_many(:trigger_requests) }
   it { is_expected.to have_many(:builds) }
-  it { is_expected.to validate_presence_of :before_sha }
   it { is_expected.to validate_presence_of :sha }
-  it { is_expected.to validate_presence_of :ref }
-  it { is_expected.to validate_presence_of :push_data }
 
   it { is_expected.to respond_to :git_author_name }
   it { is_expected.to respond_to :git_author_email }
   it { is_expected.to respond_to :short_sha }
 
+  describe :ordered do
+    let(:project) { FactoryGirl.create :empty_project }
+
+    it 'returns ordered list of commits' do
+      commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, gl_project: project
+      commit2 = FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, gl_project: project
+      expect(project.ci_commits.ordered).to eq([commit2, commit1])
+    end
+
+    it 'returns commits ordered by committed_at and id, with nulls last' do
+      commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, gl_project: project
+      commit2 = FactoryGirl.create :ci_commit, committed_at: nil, gl_project: project
+      commit3 = FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, gl_project: project
+      commit4 = FactoryGirl.create :ci_commit, committed_at: nil, gl_project: project
+      expect(project.ci_commits.ordered).to eq([commit2, commit4, commit3, commit1])
+    end
+  end
+
   describe :last_build do
     subject { commit.last_build }
     before do
@@ -51,53 +67,12 @@ describe Ci::Commit do
       @second = FactoryGirl.create :ci_build, commit: commit
     end
 
-    it "creates new build" do
+    it "creates only a new build" do
       expect(commit.builds.count(:all)).to eq 2
+      expect(commit.statuses.count(:all)).to eq 2
       commit.retry
       expect(commit.builds.count(:all)).to eq 3
-    end
-  end
-
-  describe :project_recipients do
-
-    context 'always sending notification' do
-      it 'should return commit_pusher_email as only recipient when no additional recipients are given' do
-        project = FactoryGirl.create :ci_project,
-          email_add_pusher: true,
-          email_recipients: ''
-        commit =  FactoryGirl.create :ci_commit, project: project
-        expected = 'commit_pusher_email'
-        allow(commit).to receive(:push_data) { { user_email: expected } }
-        expect(commit.project_recipients).to eq([expected])
-      end
-
-      it 'should return commit_pusher_email and additional recipients' do
-        project = FactoryGirl.create :ci_project,
-          email_add_pusher: true,
-          email_recipients: 'rec1 rec2'
-        commit = FactoryGirl.create :ci_commit, project: project
-        expected = 'commit_pusher_email'
-        allow(commit).to receive(:push_data) { { user_email: expected } }
-        expect(commit.project_recipients).to eq(['rec1', 'rec2', expected])
-      end
-
-      it 'should return recipients' do
-        project = FactoryGirl.create :ci_project,
-          email_add_pusher: false,
-          email_recipients: 'rec1 rec2'
-        commit = FactoryGirl.create :ci_commit, project: project
-        expect(commit.project_recipients).to eq(['rec1', 'rec2'])
-      end
-
-      it 'should return unique recipients only' do
-        project = FactoryGirl.create :ci_project,
-          email_add_pusher: true,
-          email_recipients: 'rec1 rec1 rec2'
-        commit = FactoryGirl.create :ci_commit, project: project
-        expected = 'rec2'
-        allow(commit).to receive(:push_data) { { user_email: expected } }
-        expect(commit.project_recipients).to eq(['rec1', 'rec2'])
-      end
+      expect(commit.statuses.count(:all)).to eq 3
     end
   end
 
@@ -112,63 +87,122 @@ describe Ci::Commit do
     end
   end
 
-  describe :compare? do
-    subject { commit_with_project.compare? }
-
-    context 'if commit.before_sha are not nil' do
-      it { is_expected.to be_truthy }
-    end
-  end
-
   describe :short_sha do
-    subject { commit.short_before_sha }
+    subject { commit.short_sha }
 
     it 'has 8 items' do
       expect(subject.size).to eq(8)
     end
-    it { expect(commit.before_sha).to start_with(subject) }
+    it { expect(commit.sha).to start_with(subject) }
   end
 
-  describe :short_sha do
-    subject { commit.short_sha }
+  describe :stage do
+    subject { commit.stage }
 
-    it 'has 8 items' do
-      expect(subject.size).to eq(8)
+    before do
+      @second = FactoryGirl.create :commit_status, commit: commit, name: 'deploy', stage: 'deploy', stage_idx: 1, status: 'pending'
+      @first = FactoryGirl.create :commit_status, commit: commit, name: 'test', stage: 'test', stage_idx: 0, status: 'pending'
+    end
+
+    it 'returns first running stage' do
+      is_expected.to eq('test')
+    end
+
+    context 'first build succeeded' do
+      before do
+        @first.success
+      end
+
+      it 'returns last running stage' do
+        is_expected.to eq('deploy')
+      end
+    end
+
+    context 'all builds succeeded' do
+      before do
+        @first.success
+        @second.success
+      end
+
+      it 'returns nil' do
+        is_expected.to be_nil
+      end
     end
-    it { expect(commit.sha).to start_with(subject) }
   end
 
   describe :create_next_builds do
+  end
+
+  describe :refs do
+    subject { commit.refs }
+
     before do
-      allow(commit).to receive(:config_processor).and_return(config_processor)
+      FactoryGirl.create :commit_status, commit: commit, name: 'deploy'
+      FactoryGirl.create :commit_status, commit: commit, name: 'deploy', ref: 'develop'
+      FactoryGirl.create :commit_status, commit: commit, name: 'deploy', ref: 'master'
     end
 
-    it "creates builds for next type" do
-      expect(commit.create_builds).to be_truthy
-      commit.builds.reload
-      expect(commit.builds.size).to eq(2)
+    it 'returns all refs' do
+      is_expected.to contain_exactly('master', 'develop', nil)
+    end
+  end
 
-      expect(commit.create_next_builds(nil)).to be_truthy
-      commit.builds.reload
-      expect(commit.builds.size).to eq(4)
+  describe :retried do
+    subject { commit.retried }
 
-      expect(commit.create_next_builds(nil)).to be_truthy
-      commit.builds.reload
-      expect(commit.builds.size).to eq(5)
+    before do
+      @commit1 = FactoryGirl.create :ci_build, commit: commit, name: 'deploy'
+      @commit2 = FactoryGirl.create :ci_build, commit: commit, name: 'deploy'
+    end
 
-      expect(commit.create_next_builds(nil)).to be_falsey
+    it 'returns old builds' do
+      is_expected.to contain_exactly(@commit1)
     end
   end
 
   describe :create_builds do
-    before do
-      allow(commit).to receive(:config_processor).and_return(config_processor)
+    let!(:commit) { FactoryGirl.create :ci_commit, gl_project: gl_project }
+
+    def create_builds(trigger_request = nil)
+      commit.create_builds('master', false, nil, trigger_request)
+    end
+
+    def create_next_builds
+      commit.create_next_builds(commit.builds.order(:id).last)
     end
 
     it 'creates builds' do
-      expect(commit.create_builds).to be_truthy
-      commit.builds.reload
-      expect(commit.builds.size).to eq(2)
+      expect(create_builds).to be_truthy
+      commit.builds.update_all(status: "success")
+      expect(commit.builds.count(:all)).to eq(2)
+
+      expect(create_next_builds).to be_truthy
+      commit.builds.update_all(status: "success")
+      expect(commit.builds.count(:all)).to eq(4)
+
+      expect(create_next_builds).to be_truthy
+      commit.builds.update_all(status: "success")
+      expect(commit.builds.count(:all)).to eq(5)
+
+      expect(create_next_builds).to be_falsey
+    end
+
+    context 'for different ref' do
+      def create_develop_builds
+        commit.create_builds('develop', false, nil, nil)
+      end
+
+      it 'creates builds' do
+        expect(create_builds).to be_truthy
+        commit.builds.update_all(status: "success")
+        expect(commit.builds.count(:all)).to eq(2)
+
+        expect(create_develop_builds).to be_truthy
+        commit.builds.update_all(status: "success")
+        expect(commit.builds.count(:all)).to eq(4)
+        expect(commit.refs.size).to eq(2)
+        expect(commit.builds.pluck(:name).uniq.size).to eq(2)
+      end
     end
 
     context 'for build triggers' do
@@ -176,61 +210,179 @@ describe Ci::Commit do
       let(:trigger_request) { FactoryGirl.create :ci_trigger_request, commit: commit, trigger: trigger }
 
       it 'creates builds' do
-        expect(commit.create_builds(trigger_request)).to be_truthy
-        commit.builds.reload
-        expect(commit.builds.size).to eq(2)
+        expect(create_builds(trigger_request)).to be_truthy
+        expect(commit.builds.count(:all)).to eq(2)
       end
 
       it 'rebuilds commit' do
-        expect(commit.create_builds).to be_truthy
-        commit.builds.reload
-        expect(commit.builds.size).to eq(2)
+        expect(create_builds).to be_truthy
+        expect(commit.builds.count(:all)).to eq(2)
 
-        expect(commit.create_builds(trigger_request)).to be_truthy
-        commit.builds.reload
-        expect(commit.builds.size).to eq(4)
+        expect(create_builds(trigger_request)).to be_truthy
+        expect(commit.builds.count(:all)).to eq(4)
       end
 
       it 'creates next builds' do
-        expect(commit.create_builds(trigger_request)).to be_truthy
-        commit.builds.reload
-        expect(commit.builds.size).to eq(2)
+        expect(create_builds(trigger_request)).to be_truthy
+        expect(commit.builds.count(:all)).to eq(2)
+        commit.builds.update_all(status: "success")
 
-        expect(commit.create_next_builds(trigger_request)).to be_truthy
-        commit.builds.reload
-        expect(commit.builds.size).to eq(4)
+        expect(create_next_builds).to be_truthy
+        expect(commit.builds.count(:all)).to eq(4)
       end
 
       context 'for [ci skip]' do
         before do
-          commit.push_data[:commits][0][:message] = 'skip this commit [ci skip]'
-          commit.save
+          allow(commit).to receive(:git_commit_message) { 'message [ci skip]' }
         end
 
         it 'rebuilds commit' do
           expect(commit.status).to eq('skipped')
-          expect(commit.create_builds(trigger_request)).to be_truthy
-          commit.builds.reload
-          expect(commit.builds.size).to eq(2)
-          expect(commit.status).to eq('pending')
+          expect(create_builds).to be_truthy
+
+          # since everything in Ci::Commit is cached we need to fetch a new object
+          new_commit = Ci::Commit.find_by_id(commit.id)
+          expect(new_commit.status).to eq('pending')
         end
       end
     end
+
+    context 'properly creates builds when "when" is defined' do
+      let(:yaml) do
+        {
+          stages: ["build", "test", "test_failure", "deploy", "cleanup"],
+          build: {
+            stage: "build",
+            script: "BUILD",
+          },
+          test: {
+            stage: "test",
+            script: "TEST",
+          },
+          test_failure: {
+            stage: "test_failure",
+            script: "ON test failure",
+            when: "on_failure",
+          },
+          deploy: {
+            stage: "deploy",
+            script: "PUBLISH",
+          },
+          cleanup: {
+            stage: "cleanup",
+            script: "TIDY UP",
+            when: "always",
+          }
+        }
+      end
+
+      before do
+        stub_ci_commit_yaml_file(YAML.dump(yaml))
+      end
+
+      it 'properly creates builds' do
+        expect(create_builds).to be_truthy
+        expect(commit.builds.pluck(:name)).to contain_exactly('build')
+        expect(commit.builds.pluck(:status)).to contain_exactly('pending')
+        commit.builds.running_or_pending.each(&:success)
+
+        expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test')
+        expect(commit.builds.pluck(:status)).to contain_exactly('success', 'pending')
+        commit.builds.running_or_pending.each(&:success)
+
+        expect(commit.builds.pluck(:status)).to contain_exactly('success', 'success', 'pending')
+        expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy')
+        commit.builds.running_or_pending.each(&:success)
+
+        expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy', 'cleanup')
+        expect(commit.builds.pluck(:status)).to contain_exactly('success', 'success', 'success', 'pending')
+        commit.builds.running_or_pending.each(&:success)
+
+        expect(commit.builds.pluck(:status)).to contain_exactly('success', 'success', 'success', 'success')
+        expect(commit.status).to eq('success')
+      end
+
+      it 'properly creates builds when test fails' do
+        expect(create_builds).to be_truthy
+        expect(commit.builds.pluck(:name)).to contain_exactly('build')
+        expect(commit.builds.pluck(:status)).to contain_exactly('pending')
+        commit.builds.running_or_pending.each(&:success)
+
+        expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test')
+        expect(commit.builds.pluck(:status)).to contain_exactly('success', 'pending')
+        commit.builds.running_or_pending.each(&:drop)
+
+        expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure')
+        expect(commit.builds.pluck(:status)).to contain_exactly('success', 'failed', 'pending')
+        commit.builds.running_or_pending.each(&:success)
+
+        expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure', 'cleanup')
+        expect(commit.builds.pluck(:status)).to contain_exactly('success', 'failed', 'success', 'pending')
+        commit.builds.running_or_pending.each(&:success)
+
+        expect(commit.builds.pluck(:status)).to contain_exactly('success', 'failed', 'success', 'success')
+        expect(commit.status).to eq('failed')
+      end
+
+      it 'properly creates builds when test and test_failure fails' do
+        expect(create_builds).to be_truthy
+        expect(commit.builds.pluck(:name)).to contain_exactly('build')
+        expect(commit.builds.pluck(:status)).to contain_exactly('pending')
+        commit.builds.running_or_pending.each(&:success)
+
+        expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test')
+        expect(commit.builds.pluck(:status)).to contain_exactly('success', 'pending')
+        commit.builds.running_or_pending.each(&:drop)
+
+        expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure')
+        expect(commit.builds.pluck(:status)).to contain_exactly('success', 'failed', 'pending')
+        commit.builds.running_or_pending.each(&:drop)
+
+        expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure', 'cleanup')
+        expect(commit.builds.pluck(:status)).to contain_exactly('success', 'failed', 'failed', 'pending')
+        commit.builds.running_or_pending.each(&:success)
+
+        expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure', 'cleanup')
+        expect(commit.builds.pluck(:status)).to contain_exactly('success', 'failed', 'failed', 'success')
+        expect(commit.status).to eq('failed')
+      end
+
+      it 'properly creates builds when deploy fails' do
+        expect(create_builds).to be_truthy
+        expect(commit.builds.pluck(:name)).to contain_exactly('build')
+        expect(commit.builds.pluck(:status)).to contain_exactly('pending')
+        commit.builds.running_or_pending.each(&:success)
+
+        expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test')
+        expect(commit.builds.pluck(:status)).to contain_exactly('success', 'pending')
+        commit.builds.running_or_pending.each(&:success)
+
+        expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy')
+        expect(commit.builds.pluck(:status)).to contain_exactly('success', 'success', 'pending')
+        commit.builds.running_or_pending.each(&:drop)
+
+        expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy', 'cleanup')
+        expect(commit.builds.pluck(:status)).to contain_exactly('success', 'success', 'failed', 'pending')
+        commit.builds.running_or_pending.each(&:success)
+
+        expect(commit.builds.pluck(:status)).to contain_exactly('success', 'success', 'failed', 'success')
+        expect(commit.status).to eq('failed')
+      end
+    end
   end
 
   describe "#finished_at" do
-    let(:project) { FactoryGirl.create :ci_project }
-    let(:commit) { FactoryGirl.create :ci_commit, project: project }
+    let(:commit) { FactoryGirl.create :ci_commit }
 
     it "returns finished_at of latest build" do
       build = FactoryGirl.create :ci_build, commit: commit, finished_at: Time.now - 60
-      build1 = FactoryGirl.create :ci_build, commit: commit, finished_at: Time.now - 120
+      FactoryGirl.create :ci_build, commit: commit, finished_at: Time.now - 120
 
       expect(commit.finished_at.to_i).to eq(build.finished_at.to_i)
     end
 
     it "returns nil if there is no finished build" do
-      build = FactoryGirl.create :ci_not_started_build, commit: commit
+      FactoryGirl.create :ci_not_started_build, commit: commit
 
       expect(commit.finished_at).to be_nil
     end
@@ -238,7 +390,8 @@ describe Ci::Commit do
 
   describe "coverage" do
     let(:project) { FactoryGirl.create :ci_project, coverage_regex: "/.*/" }
-    let(:commit) { FactoryGirl.create :ci_commit, project: project }
+    let(:gl_project) { FactoryGirl.create :empty_project, gitlab_ci_project: project }
+    let(:commit) { FactoryGirl.create :ci_commit, gl_project: gl_project }
 
     it "calculates average when there are two builds with coverage" do
       FactoryGirl.create :ci_build, name: "rspec", coverage: 30, commit: commit
diff --git a/spec/models/ci/project_services/hip_chat_message_spec.rb b/spec/models/ci/project_services/hip_chat_message_spec.rb
index 49ac0860259982c007f2aa6eb970ca0e678eb453..e23d6ae2c2844ae7e090011910096f32ba5aa44b 100644
--- a/spec/models/ci/project_services/hip_chat_message_spec.rb
+++ b/spec/models/ci/project_services/hip_chat_message_spec.rb
@@ -3,72 +3,37 @@ require 'spec_helper'
 describe Ci::HipChatMessage do
   subject { Ci::HipChatMessage.new(build) }
 
-  let(:project) { FactoryGirl.create(:ci_project) }
+  let(:commit) { FactoryGirl.create(:ci_commit_with_two_jobs) }
 
-  context "One build" do
-    let(:commit) { FactoryGirl.create(:ci_commit_with_one_job, project: project) }
-
-    let(:build) do
-      commit.create_builds
-      commit.builds.first
-    end
-
-    context 'when build succeeds' do
-      it 'returns a successful message' do
-        build.update(status: "success")
-
-        expect( subject.status_color ).to eq 'green'
-        expect( subject.notify? ).to be_falsey
-        expect( subject.to_s ).to match(/Build '[^']+' #\d+/)
-        expect( subject.to_s ).to match(/Successful in \d+ second\(s\)\./)
-      end
-    end
-
-    context 'when build fails' do
-      it 'returns a failure message' do
-        build.update(status: "failed")
-
-        expect( subject.status_color ).to eq 'red'
-        expect( subject.notify? ).to be_truthy
-        expect( subject.to_s ).to match(/Build '[^']+' #\d+/)
-        expect( subject.to_s ).to match(/Failed in \d+ second\(s\)\./)
-      end
-    end
+  let(:build) do
+    commit.builds.first
   end
 
-  context "Several builds" do
-    let(:commit) { FactoryGirl.create(:ci_commit_with_two_jobs, project: project) }
-
-    let(:build) do
-      commit.builds.first
-    end
-
-    context 'when all matrix builds succeed' do
-      it 'returns a successful message' do
-        commit.create_builds
-        commit.builds.update_all(status: "success")
-        commit.reload
+  context 'when all matrix builds succeed' do
+    it 'returns a successful message' do
+      commit.create_builds('master', false, nil)
+      commit.builds.update_all(status: "success")
+      commit.reload
 
-        expect( subject.status_color ).to eq 'green'
-        expect( subject.notify? ).to be_falsey
-        expect( subject.to_s ).to match(/Commit #\d+/)
-        expect( subject.to_s ).to match(/Successful in \d+ second\(s\)\./)
-      end
+      expect(subject.status_color).to eq 'green'
+      expect(subject.notify?).to be_falsey
+      expect(subject.to_s).to match(/Commit #\d+/)
+      expect(subject.to_s).to match(/Successful in \d+ second\(s\)\./)
     end
+  end
 
-    context 'when at least one matrix build fails' do
-      it 'returns a failure message' do
-        commit.create_builds
-        first_build = commit.builds.first
-        second_build = commit.builds.last
-        first_build.update(status: "success")
-        second_build.update(status: "failed")
-
-        expect( subject.status_color ).to eq 'red'
-        expect( subject.notify? ).to be_truthy
-        expect( subject.to_s ).to match(/Commit #\d+/)
-        expect( subject.to_s ).to match(/Failed in \d+ second\(s\)\./)
-      end
+  context 'when at least one matrix build fails' do
+    it 'returns a failure message' do
+      commit.create_builds('master', false, nil)
+      first_build = commit.builds.first
+      second_build = commit.builds.last
+      first_build.update(status: "success")
+      second_build.update(status: "failed")
+
+      expect(subject.status_color).to eq 'red'
+      expect(subject.notify?).to be_truthy
+      expect(subject.to_s).to match(/Commit #\d+/)
+      expect(subject.to_s).to match(/Failed in \d+ second\(s\)\./)
     end
   end
 end
diff --git a/spec/models/ci/project_services/hip_chat_service_spec.rb b/spec/models/ci/project_services/hip_chat_service_spec.rb
index 063d46b84d4aede3ca01fd3aa92dd30229447666..d9ccc855edf57283989b104850192d6df976cf79 100644
--- a/spec/models/ci/project_services/hip_chat_service_spec.rb
+++ b/spec/models/ci/project_services/hip_chat_service_spec.rb
@@ -33,15 +33,14 @@ describe Ci::HipChatService do
   describe "Execute" do
 
     let(:service) { Ci::HipChatService.new }
-    let(:project) { FactoryGirl.create :ci_project }
-    let(:commit)  { FactoryGirl.create :ci_commit, project: project }
+    let(:commit)  { FactoryGirl.create :ci_commit }
     let(:build)   { FactoryGirl.create :ci_build, commit: commit, status: 'failed' }
     let(:api_url) { 'https://api.hipchat.com/v2/room/123/notification?auth_token=a1b2c3d4e5f6' }
 
     before do
       allow(service).to receive_messages(
-        project: project,
-        project_id: project.id,
+        project: commit.project,
+        project_id: commit.project_id,
         notify_only_broken_builds: false,
         hipchat_room: 123,
         hipchat_token: 'a1b2c3d4e5f6'
diff --git a/spec/models/ci/mail_service_spec.rb b/spec/models/ci/project_services/mail_service_spec.rb
similarity index 73%
rename from spec/models/ci/mail_service_spec.rb
rename to spec/models/ci/project_services/mail_service_spec.rb
index b5f37b349dbbf1cb772721e5c57325bc6216f380..d9b3d34ff1529bd04343f399b4b2fef6aac60a35 100644
--- a/spec/models/ci/mail_service_spec.rb
+++ b/spec/models/ci/project_services/mail_service_spec.rb
@@ -29,11 +29,13 @@ describe Ci::MailService do
 
   describe 'Sends email for' do
     let(:mail)   { Ci::MailService.new }
+    let(:user)   { User.new(notification_email: 'git@example.com')}
 
     describe 'failed build' do
       let(:project) { FactoryGirl.create(:ci_project, email_add_pusher: true) }
-      let(:commit) { FactoryGirl.create(:ci_commit, project: project) }
-      let(:build) { FactoryGirl.create(:ci_build, status: :failed, commit: commit) }
+      let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
+      let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
+      let(:build) { FactoryGirl.create(:ci_build, status: 'failed', commit: commit, user: user) }
 
       before do
         allow(mail).to receive_messages(
@@ -54,8 +56,9 @@ describe Ci::MailService do
 
     describe 'successfull build' do
       let(:project) { FactoryGirl.create(:ci_project, email_add_pusher: true, email_only_broken_builds: false) }
-      let(:commit) { FactoryGirl.create(:ci_commit, project: project) }
-      let(:build) { FactoryGirl.create(:ci_build, status: :success, commit: commit) }
+      let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
+      let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
+      let(:build) { FactoryGirl.create(:ci_build, status: 'success', commit: commit, user: user) }
 
       before do
         allow(mail).to receive_messages(
@@ -81,8 +84,9 @@ describe Ci::MailService do
                            email_only_broken_builds: false,
                            email_recipients: "jeroen@example.com")
       end
-      let(:commit) { FactoryGirl.create(:ci_commit, project: project) }
-      let(:build) { FactoryGirl.create(:ci_build, status: :success, commit: commit) }
+      let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
+      let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
+      let(:build) { FactoryGirl.create(:ci_build, status: 'success', commit: commit, user: user) }
 
       before do
         allow(mail).to receive_messages(
@@ -109,8 +113,9 @@ describe Ci::MailService do
                            email_only_broken_builds: true,
                            email_recipients: "jeroen@example.com")
       end
-      let(:commit) { FactoryGirl.create(:ci_commit, project: project) }
-      let(:build) { FactoryGirl.create(:ci_build, status: :success, commit: commit) }
+      let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
+      let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
+      let(:build) { FactoryGirl.create(:ci_build, status: 'success', commit: commit, user: user) }
 
       before do
         allow(mail).to receive_messages(
@@ -137,8 +142,9 @@ describe Ci::MailService do
                            email_only_broken_builds: false,
                            email_recipients: "jeroen@example.com")
       end
-      let(:commit) { FactoryGirl.create(:ci_commit, project: project) }
-      let(:build) { FactoryGirl.create(:ci_build, status: :success, commit: commit) }
+      let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
+      let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
+      let(:build) { FactoryGirl.create(:ci_build, status: 'success', commit: commit, user: user) }
 
       before do
         allow(mail).to receive_messages(
@@ -159,8 +165,9 @@ describe Ci::MailService do
                            email_only_broken_builds: true,
                            email_recipients: "jeroen@example.com")
       end
-      let(:commit) { FactoryGirl.create(:ci_commit, project: project) }
-      let(:build) { FactoryGirl.create(:ci_build, status: :failed, commit: commit) }
+      let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
+      let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
+      let(:build) { FactoryGirl.create(:ci_build, status: 'failed', commit: commit, user: user) }
 
       before do
         allow(mail).to receive_messages(
diff --git a/spec/models/ci/project_services/slack_message_spec.rb b/spec/models/ci/project_services/slack_message_spec.rb
index f533590372851716be6f063bbe00b925f558532f..8adda6c86ccc84950f35290142b0e59dae010e43 100644
--- a/spec/models/ci/project_services/slack_message_spec.rb
+++ b/spec/models/ci/project_services/slack_message_spec.rb
@@ -3,82 +3,41 @@ require 'spec_helper'
 describe Ci::SlackMessage do
   subject { Ci::SlackMessage.new(commit) }
 
-  let(:project) { FactoryGirl.create :ci_project }
+  let(:commit) { FactoryGirl.create(:ci_commit_with_two_jobs) }
 
-  context "One build" do
-    let(:commit) { FactoryGirl.create(:ci_commit_with_one_job, project: project) }
+  context 'when all matrix builds succeeded' do
+    let(:color) { 'good' }
 
-    let(:build) do
-      commit.create_builds
-      commit.builds.first
-    end
-
-    context 'when build succeeded' do
-      let(:color) { 'good' }
-
-      it 'returns a message with succeeded build' do
-        build.update(status: "success")
-
-        expect(subject.color).to eq(color)
-        expect(subject.fallback).to include('Build')
-        expect(subject.fallback).to include("\##{build.id}")
-        expect(subject.fallback).to include('succeeded')
-        expect(subject.attachments.first[:fields]).to be_empty
-      end
-    end
-
-    context 'when build failed' do
-      let(:color) { 'danger' }
-
-      it 'returns a message with failed build' do
-        build.update(status: "failed")
+    it 'returns a message with success' do
+      commit.create_builds('master', false, nil)
+      commit.builds.update_all(status: "success")
+      commit.reload
 
-        expect(subject.color).to eq(color)
-        expect(subject.fallback).to include('Build')
-        expect(subject.fallback).to include("\##{build.id}")
-        expect(subject.fallback).to include('failed')
-        expect(subject.attachments.first[:fields]).to be_empty
-      end
+      expect(subject.color).to eq(color)
+      expect(subject.fallback).to include('Commit')
+      expect(subject.fallback).to include("\##{commit.id}")
+      expect(subject.fallback).to include('succeeded')
+      expect(subject.attachments.first[:fields]).to be_empty
     end
   end
 
-  context "Several builds" do
-    let(:commit) { FactoryGirl.create(:ci_commit_with_two_jobs, project: project) }
-
-    context 'when all matrix builds succeeded' do
-      let(:color) { 'good' }
-
-      it 'returns a message with success' do
-        commit.create_builds
-        commit.builds.update_all(status: "success")
-        commit.reload
-
-        expect(subject.color).to eq(color)
-        expect(subject.fallback).to include('Commit')
-        expect(subject.fallback).to include("\##{commit.id}")
-        expect(subject.fallback).to include('succeeded')
-        expect(subject.attachments.first[:fields]).to be_empty
-      end
-    end
-
-    context 'when one of matrix builds failed' do
-      let(:color) { 'danger' }
-
-      it 'returns a message with information about failed build' do
-        commit.create_builds
-        first_build = commit.builds.first
-        second_build = commit.builds.last
-        first_build.update(status: "success")
-        second_build.update(status: "failed")
-
-        expect(subject.color).to eq(color)
-        expect(subject.fallback).to include('Commit')
-        expect(subject.fallback).to include("\##{commit.id}")
-        expect(subject.fallback).to include('failed')
-        expect(subject.attachments.first[:fields].size).to eq(1)
-        expect(subject.attachments.first[:fields].first[:title]).to eq(second_build.name)
-        expect(subject.attachments.first[:fields].first[:value]).to include("\##{second_build.id}")
-      end
+  context 'when one of matrix builds failed' do
+    let(:color) { 'danger' }
+
+    it 'returns a message with information about failed build' do
+      commit.create_builds('master', false, nil)
+      first_build = commit.builds.first
+      second_build = commit.builds.last
+      first_build.update(status: "success")
+      second_build.update(status: "failed")
+
+      expect(subject.color).to eq(color)
+      expect(subject.fallback).to include('Commit')
+      expect(subject.fallback).to include("\##{commit.id}")
+      expect(subject.fallback).to include('failed')
+      expect(subject.attachments.first[:fields].size).to eq(1)
+      expect(subject.attachments.first[:fields].first[:title]).to eq(second_build.name)
+      expect(subject.attachments.first[:fields].first[:value]).to include("\##{second_build.id}")
     end
   end
 end
diff --git a/spec/models/ci/project_services/slack_service_spec.rb b/spec/models/ci/project_services/slack_service_spec.rb
index 0524f4724327d7f842f5226d411cb087b46e86b1..1ac7dfe568da3332384fc312488d3bf747201306 100644
--- a/spec/models/ci/project_services/slack_service_spec.rb
+++ b/spec/models/ci/project_services/slack_service_spec.rb
@@ -31,16 +31,15 @@ describe Ci::SlackService do
 
   describe "Execute" do
     let(:slack)   { Ci::SlackService.new }
-    let(:project) { FactoryGirl.create :ci_project }
-    let(:commit)  { FactoryGirl.create :ci_commit, project: project }
+    let(:commit)  { FactoryGirl.create :ci_commit }
     let(:build)   { FactoryGirl.create :ci_build, commit: commit, status: 'failed' }
     let(:webhook_url) { 'https://hooks.slack.com/services/SVRWFV0VVAR97N/B02R25XN3/ZBqu7xMupaEEICInN685' }
     let(:notify_only_broken_builds) { false }
 
     before do
       allow(slack).to receive_messages(
-        project: project,
-        project_id: project.id,
+        project: commit.project,
+        project_id: commit.project_id,
         webhook: webhook_url,
         notify_only_broken_builds: notify_only_broken_builds
       )
diff --git a/spec/models/ci/project_spec.rb b/spec/models/ci/project_spec.rb
index 261ea69f5b494bbe8be99ed73709a9e4ccdcc66f..490c6a679821b02ddd09c1b3c957cf0ef829ece1 100644
--- a/spec/models/ci/project_spec.rb
+++ b/spec/models/ci/project_spec.rb
@@ -28,13 +28,20 @@
 require 'spec_helper'
 
 describe Ci::Project do
-  subject { FactoryGirl.build :ci_project }
+  let(:gl_project) { FactoryGirl.create :empty_project }
+  let(:project) { FactoryGirl.create :ci_project, gl_project: gl_project }
+  subject { project }
+
+  it { is_expected.to have_many(:runner_projects) }
+  it { is_expected.to have_many(:runners) }
+  it { is_expected.to have_many(:web_hooks) }
+  it { is_expected.to have_many(:events) }
+  it { is_expected.to have_many(:variables) }
+  it { is_expected.to have_many(:triggers) }
+  it { is_expected.to have_many(:services) }
 
-  it { is_expected.to have_many(:commits) }
-
-  it { is_expected.to validate_presence_of :name }
   it { is_expected.to validate_presence_of :timeout }
-  it { is_expected.to validate_presence_of :default_ref }
+  it { is_expected.to validate_presence_of :gitlab_id }
 
   describe 'before_validation' do
     it 'should set an random token if none provided' do
@@ -48,43 +55,89 @@ describe Ci::Project do
     end
   end
 
-  describe "ordered_by_last_commit_date" do
-    it "returns ordered projects" do
-      newest_project = FactoryGirl.create :ci_project
-      oldest_project = FactoryGirl.create :ci_project
-      project_without_commits = FactoryGirl.create :ci_project
+  describe :name_with_namespace do
+    subject { project.name_with_namespace }
+
+    it { is_expected.to eq(project.name) }
+    it { is_expected.to eq(gl_project.name_with_namespace) }
+  end
+
+  describe :path_with_namespace do
+    subject { project.path_with_namespace }
+
+    it { is_expected.to eq(project.path) }
+    it { is_expected.to eq(gl_project.path_with_namespace) }
+  end
+
+  describe :path_with_namespace do
+    subject { project.web_url }
+
+    it { is_expected.to eq(gl_project.web_url) }
+  end
+
+  describe :web_url do
+    subject { project.web_url }
+
+    it { is_expected.to eq(project.gitlab_url) }
+    it { is_expected.to eq(gl_project.web_url) }
+  end
+
+  describe :http_url_to_repo do
+    subject { project.http_url_to_repo }
+
+    it { is_expected.to eq(gl_project.http_url_to_repo) }
+  end
+
+  describe :ssh_url_to_repo do
+    subject { project.ssh_url_to_repo }
+
+    it { is_expected.to eq(gl_project.ssh_url_to_repo) }
+  end
 
-      FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, project: newest_project
-      FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, project: oldest_project
+  describe :commits do
+    subject { project.commits }
 
-      expect(Ci::Project.ordered_by_last_commit_date).to eq([newest_project, oldest_project, project_without_commits])
+    before do
+      FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, gl_project: gl_project
     end
+
+    it { is_expected.to eq(gl_project.ci_commits) }
   end
 
-  describe 'ordered commits' do
-    let(:project) { FactoryGirl.create :ci_project }
+  describe :builds do
+    subject { project.builds }
 
-    it 'returns ordered list of commits' do
-      commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, project: project
-      commit2 = FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, project: project
-      expect(project.commits).to eq([commit2, commit1])
+    before do
+      commit = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, gl_project: gl_project
+      FactoryGirl.create :ci_build, commit: commit
     end
 
-    it 'returns commits ordered by committed_at and id, with nulls last' do
-      commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, project: project
-      commit2 = FactoryGirl.create :ci_commit, committed_at: nil, project: project
-      commit3 = FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, project: project
-      commit4 = FactoryGirl.create :ci_commit, committed_at: nil, project: project
-      expect(project.commits).to eq([commit2, commit4, commit3, commit1])
+    it { is_expected.to eq(gl_project.ci_builds) }
+  end
+
+  describe "ordered_by_last_commit_date" do
+    it "returns ordered projects" do
+      newest_project = FactoryGirl.create :empty_project
+      newest_ci_project = newest_project.ensure_gitlab_ci_project
+      oldest_project = FactoryGirl.create :empty_project
+      oldest_ci_project = oldest_project.ensure_gitlab_ci_project
+      project_without_commits = FactoryGirl.create :empty_project
+      ci_project_without_commits = project_without_commits.ensure_gitlab_ci_project
+
+      FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, gl_project: newest_project
+      FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, gl_project: oldest_project
+
+      expect(Ci::Project.ordered_by_last_commit_date).to eq([newest_ci_project, oldest_ci_project, ci_project_without_commits])
     end
   end
 
   context :valid_project do
-    let(:project) { FactoryGirl.create :ci_project }
+    let(:commit) { FactoryGirl.create(:ci_commit) }
 
     context :project_with_commit_and_builds do
+      let(:project) { commit.project }
+
       before do
-        commit = FactoryGirl.create(:ci_commit, project: project)
         FactoryGirl.create(:ci_build, commit: commit)
       end
 
@@ -165,13 +218,6 @@ describe Ci::Project do
     it { is_expected.to include(project.gitlab_url[7..-1]) }
   end
 
-  describe :search do
-    let!(:project) { FactoryGirl.create(:ci_project, name: "foo") }
-
-    it { expect(Ci::Project.search('fo')).to include(project) }
-    it { expect(Ci::Project.search('bar')).to be_empty }
-  end
-
   describe :any_runners do
     it "there are no runners available" do
       project = FactoryGirl.create(:ci_project)
@@ -195,5 +241,18 @@ describe Ci::Project do
       FactoryGirl.create(:ci_shared_runner)
       expect(project.any_runners?).to be_falsey
     end
+
+    it "checks the presence of specific runner" do
+      project = FactoryGirl.create(:ci_project)
+      specific_runner = FactoryGirl.create(:ci_specific_runner)
+      project.runners << specific_runner
+      expect(project.any_runners? { |runner| runner == specific_runner }).to be_truthy
+    end
+
+    it "checks the presence of shared runner" do
+      project = FactoryGirl.create(:ci_project, shared_runners_enabled: true)
+      shared_runner = FactoryGirl.create(:ci_shared_runner)
+      expect(project.any_runners? { |runner| runner == shared_runner }).to be_truthy
+    end
   end
 end
diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb
index 757593a7ab8f090b80f9ad63cd8a926f84c5ae03..f8a51c29dc2c0216cd3187e2a5ec8514dd16902c 100644
--- a/spec/models/ci/runner_spec.rb
+++ b/spec/models/ci/runner_spec.rb
@@ -32,7 +32,7 @@ describe Ci::Runner do
     end
 
     it 'should return the token if the description is an empty string' do
-      runner = FactoryGirl.build(:ci_runner, description: '')
+      runner = FactoryGirl.build(:ci_runner, description: '', token: 'token')
       expect(runner.display_name).to eq runner.token
     end
   end
@@ -48,6 +48,71 @@ describe Ci::Runner do
     it { expect(shared_runner.only_for?(project)).to be_truthy }
   end
 
+  describe :online do
+    subject { Ci::Runner.online }
+
+    before do
+      @runner1 = FactoryGirl.create(:ci_shared_runner, contacted_at: 1.year.ago)
+      @runner2 = FactoryGirl.create(:ci_shared_runner, contacted_at: 1.second.ago)
+    end
+
+    it { is_expected.to eq([@runner2])}
+  end
+
+  describe :online? do
+    let(:runner) { FactoryGirl.create(:ci_shared_runner) }
+
+    subject { runner.online? }
+
+    context 'never contacted' do
+      before { runner.contacted_at = nil }
+
+      it { is_expected.to be_falsey }
+    end
+
+    context 'contacted long time ago time' do
+      before { runner.contacted_at = 1.year.ago }
+
+      it { is_expected.to be_falsey }
+    end
+
+    context 'contacted 1s ago' do
+      before { runner.contacted_at = 1.second.ago }
+
+      it { is_expected.to be_truthy }
+    end
+  end
+
+  describe :status do
+    let(:runner) { FactoryGirl.create(:ci_shared_runner, contacted_at: 1.second.ago) }
+
+    subject { runner.status }
+
+    context 'never connected' do
+      before { runner.contacted_at = nil }
+
+      it { is_expected.to eq(:not_connected) }
+    end
+
+    context 'contacted 1s ago' do
+      before { runner.contacted_at = 1.second.ago }
+
+      it { is_expected.to eq(:online) }
+    end
+
+    context 'contacted long time ago' do
+      before { runner.contacted_at = 1.year.ago }
+
+      it { is_expected.to eq(:offline) }
+    end
+
+    context 'inactive' do
+      before { runner.active = false }
+
+      it { is_expected.to eq(:paused) }
+    end
+  end
+
   describe "belongs_to_one_project?" do
     it "returns false if there are two projects runner assigned to" do
       runner = FactoryGirl.create(:ci_specific_runner)
diff --git a/spec/models/ci/service_spec.rb b/spec/models/ci/service_spec.rb
index 2c575056b087bdc692aaf18241da29eb5219f2b4..2df70e888881a4777fcaff2274bf93f3706cce04 100644
--- a/spec/models/ci/service_spec.rb
+++ b/spec/models/ci/service_spec.rb
@@ -29,13 +29,12 @@ describe Ci::Service do
     end
 
     describe "Testable" do
-      let(:project) { FactoryGirl.create :ci_project }
-      let(:commit) { FactoryGirl.create :ci_commit, project: project }
+      let(:commit) { FactoryGirl.create :ci_commit }
       let(:build) { FactoryGirl.create :ci_build, commit: commit }
 
       before do
         allow(@service).to receive_messages(
-          project: project
+          project: commit.project
         )
         build
         @testable = @service.can_test?
diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb
index e303a97e6b55edd290ced7c3b79f93f5d6934cfd..90be93249511f5b8eef45d4b5d65587758c37553 100644
--- a/spec/models/commit_spec.rb
+++ b/spec/models/commit_spec.rb
@@ -89,9 +89,9 @@ eos
   end
 
   it_behaves_like 'a mentionable' do
-    subject { commit }
+    subject { create(:project).commit }
 
-    let(:author) { create(:user, email: commit.author_email) }
+    let(:author) { create(:user, email: subject.author_email) }
     let(:backref_text) { "commit #{subject.id}" }
     let(:set_mentionable_text) do
       ->(txt) { allow(subject).to receive(:safe_message).and_return(txt) }
diff --git a/spec/models/commit_status_spec.rb b/spec/models/commit_status_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c96a606fdaab60445d7415e85763049530672317
--- /dev/null
+++ b/spec/models/commit_status_spec.rb
@@ -0,0 +1,164 @@
+require 'spec_helper'
+
+describe CommitStatus do
+  let(:commit) { FactoryGirl.create :ci_commit }
+  let(:commit_status) { FactoryGirl.create :commit_status, commit: commit }
+
+  it { is_expected.to belong_to(:commit) }
+  it { is_expected.to belong_to(:user) }
+  it { is_expected.to validate_presence_of(:name) }
+  it { is_expected.to validate_inclusion_of(:status).in_array(%w(pending running failed success canceled)) }
+
+  it { is_expected.to delegate_method(:sha).to(:commit) }
+  it { is_expected.to delegate_method(:short_sha).to(:commit) }
+  it { is_expected.to delegate_method(:gl_project).to(:commit) }
+  
+  it { is_expected.to respond_to :success? }
+  it { is_expected.to respond_to :failed? }
+  it { is_expected.to respond_to :running? }
+  it { is_expected.to respond_to :pending? }
+
+  describe :author do
+    subject { commit_status.author }
+    before { commit_status.author = User.new }
+
+    it { is_expected.to eq(commit_status.user) }
+  end
+
+  describe :started? do
+    subject { commit_status.started? }
+
+    context 'without started_at' do
+      before { commit_status.started_at = nil }
+
+      it { is_expected.to be_falsey }
+    end
+
+    %w(running success failed).each do |status|
+      context "if commit status is #{status}" do
+        before { commit_status.status = status }
+
+        it { is_expected.to be_truthy }
+      end
+    end
+
+    %w(pending canceled).each do |status|
+      context "if commit status is #{status}" do
+        before { commit_status.status = status }
+
+        it { is_expected.to be_falsey }
+      end
+    end
+  end
+
+  describe :active? do
+    subject { commit_status.active? }
+
+    %w(pending running).each do |state|
+      context "if commit_status.status is #{state}" do
+        before { commit_status.status = state }
+
+        it { is_expected.to be_truthy }
+      end
+    end
+
+    %w(success failed canceled).each do |state|
+      context "if commit_status.status is #{state}" do
+        before { commit_status.status = state }
+
+        it { is_expected.to be_falsey }
+      end
+    end
+  end
+
+  describe :complete? do
+    subject { commit_status.complete? }
+
+    %w(success failed canceled).each do |state|
+      context "if commit_status.status is #{state}" do
+        before { commit_status.status = state }
+
+        it { is_expected.to be_truthy }
+      end
+    end
+
+    %w(pending running).each do |state|
+      context "if commit_status.status is #{state}" do
+        before { commit_status.status = state }
+
+        it { is_expected.to be_falsey }
+      end
+    end
+  end
+
+  describe :duration do
+    subject { commit_status.duration }
+
+    it { is_expected.to eq(120.0) }
+
+    context 'if the building process has not started yet' do
+      before do
+        commit_status.started_at = nil
+        commit_status.finished_at = nil
+      end
+
+      it { is_expected.to be_nil }
+    end
+
+    context 'if the building process has started' do
+      before do
+        commit_status.started_at = Time.now - 1.minute
+        commit_status.finished_at = nil
+      end
+
+      it { is_expected.to be_a(Float) }
+      it { is_expected.to be > 0.0 }
+    end
+  end
+  
+  describe :latest do
+    subject { CommitStatus.latest.order(:id) }
+
+    before do
+      @commit1 = FactoryGirl.create :commit_status, commit: commit, name: 'aa', ref: 'bb', status: 'running'
+      @commit2 = FactoryGirl.create :commit_status, commit: commit, name: 'cc', ref: 'cc', status: 'pending'
+      @commit3 = FactoryGirl.create :commit_status, commit: commit, name: 'aa', ref: 'cc', status: 'success'
+      @commit4 = FactoryGirl.create :commit_status, commit: commit, name: 'cc', ref: 'bb', status: 'success'
+      @commit5 = FactoryGirl.create :commit_status, commit: commit, name: 'aa', ref: 'bb', status: 'success'
+    end
+
+    it 'return unique statuses' do
+      is_expected.to eq([@commit2, @commit3, @commit4, @commit5])
+    end
+  end
+
+  describe :for_ref do
+    subject { CommitStatus.for_ref('bb').order(:id) }
+
+    before do
+      @commit1 = FactoryGirl.create :commit_status, commit: commit, name: 'aa', ref: 'bb', status: 'running'
+      @commit2 = FactoryGirl.create :commit_status, commit: commit, name: 'cc', ref: 'cc', status: 'pending'
+      @commit3 = FactoryGirl.create :commit_status, commit: commit, name: 'aa', ref: nil, status: 'success'
+    end
+
+    it 'return statuses with equal and nil ref set' do
+      is_expected.to eq([@commit1])
+    end
+  end
+
+  describe :running_or_pending do
+    subject { CommitStatus.running_or_pending.order(:id) }
+
+    before do
+      @commit1 = FactoryGirl.create :commit_status, commit: commit, name: 'aa', ref: 'bb', status: 'running'
+      @commit2 = FactoryGirl.create :commit_status, commit: commit, name: 'cc', ref: 'cc', status: 'pending'
+      @commit3 = FactoryGirl.create :commit_status, commit: commit, name: 'aa', ref: nil, status: 'success'
+      @commit4 = FactoryGirl.create :commit_status, commit: commit, name: 'dd', ref: nil, status: 'failed'
+      @commit5 = FactoryGirl.create :commit_status, commit: commit, name: 'ee', ref: nil, status: 'canceled'
+    end
+
+    it 'return statuses that are running or pending' do
+      is_expected.to eq([@commit1, @commit2])
+    end
+  end
+end
diff --git a/spec/models/concerns/case_sensitivity_spec.rb b/spec/models/concerns/case_sensitivity_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..f7ed30f81984a27a5e2b6a1f21bebee1f9e8feb0
--- /dev/null
+++ b/spec/models/concerns/case_sensitivity_spec.rb
@@ -0,0 +1,189 @@
+require 'spec_helper'
+
+describe CaseSensitivity do
+  describe '.iwhere' do
+    let(:connection) { ActiveRecord::Base.connection }
+    let(:model)      { Class.new { include CaseSensitivity } }
+
+    describe 'using PostgreSQL' do
+      before do
+        allow(Gitlab::Database).to receive(:postgresql?).and_return(true)
+        allow(Gitlab::Database).to receive(:mysql?).and_return(false)
+      end
+
+      describe 'with a single column/value pair' do
+        it 'returns the criteria for a column and a value' do
+          criteria = double(:criteria)
+
+          expect(connection).to receive(:quote_table_name).
+            with(:foo).
+            and_return('"foo"')
+
+          expect(model).to receive(:where).
+            with(%q{LOWER("foo") = LOWER(:value)}, value: 'bar').
+            and_return(criteria)
+
+          expect(model.iwhere(foo: 'bar')).to eq(criteria)
+        end
+
+        it 'returns the criteria for a column with a table, and a value' do
+          criteria = double(:criteria)
+
+          expect(connection).to receive(:quote_table_name).
+            with(:'foo.bar').
+            and_return('"foo"."bar"')
+
+          expect(model).to receive(:where).
+            with(%q{LOWER("foo"."bar") = LOWER(:value)}, value: 'bar').
+            and_return(criteria)
+
+          expect(model.iwhere(:'foo.bar' => 'bar')).to eq(criteria)
+        end
+      end
+
+      describe 'with multiple column/value pairs' do
+        it 'returns the criteria for a column and a value' do
+          initial = double(:criteria)
+          final   = double(:criteria)
+
+          expect(connection).to receive(:quote_table_name).
+            with(:foo).
+            and_return('"foo"')
+
+          expect(connection).to receive(:quote_table_name).
+            with(:bar).
+            and_return('"bar"')
+
+          expect(model).to receive(:where).
+            with(%q{LOWER("foo") = LOWER(:value)}, value: 'bar').
+            and_return(initial)
+
+          expect(initial).to receive(:where).
+            with(%q{LOWER("bar") = LOWER(:value)}, value: 'baz').
+            and_return(final)
+
+          got = model.iwhere(foo: 'bar', bar: 'baz')
+
+          expect(got).to eq(final)
+        end
+
+        it 'returns the criteria for a column with a table, and a value' do
+          initial = double(:criteria)
+          final   = double(:criteria)
+
+          expect(connection).to receive(:quote_table_name).
+            with(:'foo.bar').
+            and_return('"foo"."bar"')
+
+          expect(connection).to receive(:quote_table_name).
+            with(:'foo.baz').
+            and_return('"foo"."baz"')
+
+          expect(model).to receive(:where).
+            with(%q{LOWER("foo"."bar") = LOWER(:value)}, value: 'bar').
+            and_return(initial)
+
+          expect(initial).to receive(:where).
+            with(%q{LOWER("foo"."baz") = LOWER(:value)}, value: 'baz').
+            and_return(final)
+
+          got = model.iwhere(:'foo.bar' => 'bar',
+                             :'foo.baz' => 'baz')
+
+          expect(got).to eq(final)
+        end
+      end
+    end
+
+    describe 'using MySQL' do
+      before do
+        allow(Gitlab::Database).to receive(:postgresql?).and_return(false)
+        allow(Gitlab::Database).to receive(:mysql?).and_return(true)
+      end
+
+      describe 'with a single column/value pair' do
+        it 'returns the criteria for a column and a value' do
+          criteria = double(:criteria)
+
+          expect(connection).to receive(:quote_table_name).
+            with(:foo).
+            and_return('`foo`')
+
+          expect(model).to receive(:where).
+            with(%q{`foo` = :value}, value: 'bar').
+            and_return(criteria)
+
+          expect(model.iwhere(foo: 'bar')).to eq(criteria)
+        end
+
+        it 'returns the criteria for a column with a table, and a value' do
+          criteria = double(:criteria)
+
+          expect(connection).to receive(:quote_table_name).
+            with(:'foo.bar').
+            and_return('`foo`.`bar`')
+
+          expect(model).to receive(:where).
+            with(%q{`foo`.`bar` = :value}, value: 'bar').
+            and_return(criteria)
+
+          expect(model.iwhere(:'foo.bar' => 'bar')).
+            to eq(criteria)
+        end
+      end
+
+      describe 'with multiple column/value pairs' do
+        it 'returns the criteria for a column and a value' do
+          initial = double(:criteria)
+          final   = double(:criteria)
+
+          expect(connection).to receive(:quote_table_name).
+            with(:foo).
+            and_return('`foo`')
+
+          expect(connection).to receive(:quote_table_name).
+            with(:bar).
+            and_return('`bar`')
+
+          expect(model).to receive(:where).
+            with(%q{`foo` = :value}, value: 'bar').
+            and_return(initial)
+
+          expect(initial).to receive(:where).
+            with(%q{`bar` = :value}, value: 'baz').
+            and_return(final)
+
+          got = model.iwhere(foo: 'bar', bar: 'baz')
+
+          expect(got).to eq(final)
+        end
+
+        it 'returns the criteria for a column with a table, and a value' do
+          initial = double(:criteria)
+          final   = double(:criteria)
+
+          expect(connection).to receive(:quote_table_name).
+            with(:'foo.bar').
+            and_return('`foo`.`bar`')
+
+          expect(connection).to receive(:quote_table_name).
+            with(:'foo.baz').
+            and_return('`foo`.`baz`')
+
+          expect(model).to receive(:where).
+            with(%q{`foo`.`bar` = :value}, value: 'bar').
+            and_return(initial)
+
+          expect(initial).to receive(:where).
+            with(%q{`foo`.`baz` = :value}, value: 'baz').
+            and_return(final)
+
+          got = model.iwhere(:'foo.bar' => 'bar',
+                             :'foo.baz' => 'baz')
+
+          expect(got).to eq(final)
+        end
+      end
+    end
+  end
+end
diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb
index 8f706f8934b419eaca5e269d16712fbcb7f85100..0f13c4410cdc482943c7d9e17c25b804e81acb57 100644
--- a/spec/models/concerns/issuable_spec.rb
+++ b/spec/models/concerns/issuable_spec.rb
@@ -68,7 +68,6 @@ describe Issue, "Issuable" do
     end
   end
 
-
   describe "#to_hook_data" do
     let(:hook_data) { issue.to_hook_data(user) }
 
diff --git a/spec/models/concerns/mentionable_spec.rb b/spec/models/concerns/mentionable_spec.rb
index 2d6fe003215599acaf050a959299ab5d42ceadf6..6179882e93591f4556ddc9062b5c3ebba2dd14c0 100644
--- a/spec/models/concerns/mentionable_spec.rb
+++ b/spec/models/concerns/mentionable_spec.rb
@@ -25,7 +25,7 @@ describe Issue, "Mentionable" do
     it 'correctly removes already-mentioned Commits' do
       expect(SystemNoteService).not_to receive(:cross_reference)
 
-      issue.create_cross_references!(project, author, [commit2])
+      issue.create_cross_references!(author, [commit2])
     end
   end
 
diff --git a/spec/models/generic_commit_status_spec.rb b/spec/models/generic_commit_status_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..f442fa5fbe5f608b80f68dcddca4d215575e23b3
--- /dev/null
+++ b/spec/models/generic_commit_status_spec.rb
@@ -0,0 +1,39 @@
+require 'spec_helper'
+
+describe GenericCommitStatus do
+  let(:commit) { FactoryGirl.create :ci_commit }
+  let(:generic_commit_status) { FactoryGirl.create :generic_commit_status, commit: commit }
+
+  describe :context do
+    subject { generic_commit_status.context }
+    before { generic_commit_status.context = 'my_context' }
+
+    it { is_expected.to eq(generic_commit_status.name) }
+  end
+
+  describe :tags do
+    subject { generic_commit_status.tags }
+
+    it { is_expected.to eq([:external]) }
+  end
+
+  describe :set_default_values do
+    before do
+      generic_commit_status.context = nil
+      generic_commit_status.stage = nil
+      generic_commit_status.save
+    end
+
+    describe :context do
+      subject { generic_commit_status.context }
+
+      it { is_expected.to_not be_nil }
+    end
+
+    describe :stage do
+      subject { generic_commit_status.stage }
+
+      it { is_expected.to_not be_nil }
+    end
+  end
+end
diff --git a/spec/models/hooks/project_hook_spec.rb b/spec/models/hooks/project_hook_spec.rb
index dae7e399cfb44007112d639dfe44febb43c57138..a2dc66fce3ea4df78eb27a8469b6a66323cbc140 100644
--- a/spec/models/hooks/project_hook_spec.rb
+++ b/spec/models/hooks/project_hook_spec.rb
@@ -22,7 +22,7 @@ describe ProjectHook do
   describe '.push_hooks' do
     it 'should return hooks for push events only' do
       hook = create(:project_hook, push_events: true)
-      hook2 = create(:project_hook, push_events: false)
+      create(:project_hook, push_events: false)
       expect(ProjectHook.push_hooks).to eq([hook])
     end
   end
@@ -30,7 +30,7 @@ describe ProjectHook do
   describe '.tag_push_hooks' do
     it 'should return hooks for tag push events only' do
       hook = create(:project_hook, tag_push_events: true)
-      hook2 = create(:project_hook, tag_push_events: false)
+      create(:project_hook, tag_push_events: false)
       expect(ProjectHook.tag_push_hooks).to eq([hook])
     end
   end
diff --git a/spec/models/hooks/service_hook_spec.rb b/spec/models/hooks/service_hook_spec.rb
index 4c8b8910ae7e40651e79d1b62db3ac9b7465ce9b..16641c12124d865df1a8a2596af8b0542f5e5046 100644
--- a/spec/models/hooks/service_hook_spec.rb
+++ b/spec/models/hooks/service_hook_spec.rb
@@ -39,8 +39,6 @@ describe ServiceHook do
     end
 
     it "POSTs the data as JSON" do
-      json = @data.to_json
-
       @service_hook.execute(@data)
       expect(WebMock).to have_requested(:post, @service_hook.url).with(
         headers: { 'Content-Type'=>'application/json', 'X-Gitlab-Event'=>'Service Hook' }
diff --git a/spec/models/hooks/web_hook_spec.rb b/spec/models/hooks/web_hook_spec.rb
index 23f30881d99a7e7af0bd83ad33af5bc5e01b5120..2fdc49f02ee26bee5043a558e835507f68244dfe 100644
--- a/spec/models/hooks/web_hook_spec.rb
+++ b/spec/models/hooks/web_hook_spec.rb
@@ -60,8 +60,6 @@ describe ProjectHook do
     end
 
     it "POSTs the data as JSON" do
-      json = @data.to_json
-
       @project_hook.execute(@data, 'push_hooks')
       expect(WebMock).to have_requested(:post, @project_hook.url).with(
         headers: { 'Content-Type'=>'application/json', 'X-Gitlab-Event'=>'Push Hook' }
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index cf336d829579ee7c4477bf06b27a9497ae65479d..c9aa1b063c660cd04f8bd9ab6b0984c1df4052fb 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -68,8 +68,45 @@ describe Issue do
     end
   end
 
+  describe '#closed_by_merge_requests' do
+    let(:project) { create(:project) }
+    let(:issue)   { create(:issue, project: project, state: "opened")}
+    let(:closed_issue) { build(:issue, project: project, state: "closed")}
+
+    let(:mr) do
+      opts = {
+        title: 'Awesome merge_request',
+        description: "Fixes #{issue.to_reference}",
+        source_branch: 'feature',
+        target_branch: 'master'
+      }
+      MergeRequests::CreateService.new(project, project.owner, opts).execute
+    end
+
+    let(:closed_mr) do
+      opts = {
+        title: 'Awesome merge_request 2',
+        description: "Fixes #{issue.to_reference}",
+        source_branch: 'feature',
+        target_branch: 'master',
+        state: 'closed'
+      }
+      MergeRequests::CreateService.new(project, project.owner, opts).execute
+    end
+
+    it 'returns the merge request to close this issue' do
+      allow(mr).to receive(:closes_issue?).with(issue).and_return(true)
+
+      expect(issue.closed_by_merge_requests).to eq([mr])
+    end
+
+    it "returns an empty array when the current issue is closed already" do
+      expect(closed_issue.closed_by_merge_requests).to eq([])
+    end
+  end
+
   it_behaves_like 'an editable mentionable' do
-    subject { create(:issue, project: project) }
+    subject { create(:issue) }
 
     let(:backref_text) { "issue #{subject.to_reference}" }
     let(:set_mentionable_text) { ->(txt){ subject.description = txt } }
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 17a49013d2515bb4f1e7349808c0990b4a57219b..6aaf1c036b05aa231ed9a7fdd9a64865b1f80d9a 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -165,6 +165,17 @@ describe MergeRequest do
     end
   end
 
+  describe "#hook_attrs" do
+    it "has all the required keys" do
+      attrs = subject.hook_attrs
+      attrs = attrs.to_h
+      expect(attrs).to include(:source)
+      expect(attrs).to include(:target)
+      expect(attrs).to include(:last_commit)
+      expect(attrs).to include(:work_in_progress)
+    end
+  end
+
   it_behaves_like 'an editable mentionable' do
     subject { create(:merge_request) }
 
diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb
index 36352e1ecce2688fdde11a6b5415a59258670f64..77c586273220685649cfe4f42a7604cf732b39b9 100644
--- a/spec/models/milestone_spec.rb
+++ b/spec/models/milestone_spec.rb
@@ -111,8 +111,8 @@ describe Milestone do
 
   describe :is_empty? do
     before do
-      issue = create :closed_issue, milestone: milestone
-      merge_request = create :merge_request, milestone: milestone
+      create :closed_issue, milestone: milestone
+      create :merge_request, milestone: milestone
     end
 
     it 'Should return total count of issues and merge requests assigned to milestone' do
@@ -125,7 +125,7 @@ describe Milestone do
       milestone = create :milestone
       create :closed_issue, milestone: milestone
 
-      issue = create :issue
+      create :issue
     end
 
     it 'should be true if milestone active and all nested issues closed' do
@@ -140,4 +140,32 @@ describe Milestone do
     end
   end
 
+  describe '#sort_issues' do
+    let(:milestone) { create(:milestone) }
+
+    let(:issue1) { create(:issue, milestone: milestone, position: 1) }
+    let(:issue2) { create(:issue, milestone: milestone, position: 2) }
+    let(:issue3) { create(:issue, milestone: milestone, position: 3) }
+    let(:issue4) { create(:issue, position: 42) }
+
+    it 'sorts the given issues' do
+      milestone.sort_issues([issue3.id, issue2.id, issue1.id])
+
+      issue1.reload
+      issue2.reload
+      issue3.reload
+
+      expect(issue1.position).to eq(3)
+      expect(issue2.position).to eq(2)
+      expect(issue3.position).to eq(1)
+    end
+
+    it 'ignores issues not part of the milestone' do
+      milestone.sort_issues([issue3.id, issue2.id, issue1.id, issue4.id])
+
+      issue4.reload
+
+      expect(issue4.position).to eq(42)
+    end
+  end
 end
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index 3a0b194ba1e236d49d4a87c54400d280a710c084..75564839dcfb6baac5c2b44357b1184cd5fc0b73 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -192,10 +192,9 @@ describe Note do
   end
 
   it_behaves_like 'an editable mentionable' do
-    subject { create :note, noteable: issue, project: project }
+    subject { create :note, noteable: issue, project: issue.project }
 
-    let(:project) { create(:project) }
-    let(:issue) { create :issue, project: project }
+    let(:issue) { create :issue }
     let(:backref_text) { issue.gfm_reference }
     let(:set_mentionable_text) { ->(txt) { subject.note = txt } }
   end
diff --git a/spec/models/project_services/bamboo_service_spec.rb b/spec/models/project_services/bamboo_service_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c34b2487ecfa6721dc88bb115d11f0cb991517c4
--- /dev/null
+++ b/spec/models/project_services/bamboo_service_spec.rb
@@ -0,0 +1,94 @@
+# == Schema Information
+#
+# Table name: services
+#
+#  id                    :integer          not null, primary key
+#  type                  :string(255)
+#  title                 :string(255)
+#  project_id            :integer
+#  created_at            :datetime
+#  updated_at            :datetime
+#  active                :boolean          default(FALSE), not null
+#  properties            :text
+#  template              :boolean          default(FALSE)
+#  push_events           :boolean          default(TRUE)
+#  issues_events         :boolean          default(TRUE)
+#  merge_requests_events :boolean          default(TRUE)
+#  tag_push_events       :boolean          default(TRUE)
+#  note_events           :boolean          default(TRUE), not null
+#
+
+require 'spec_helper'
+
+describe BambooService, models: true do
+  describe "Associations" do
+    it { is_expected.to belong_to :project }
+    it { is_expected.to have_one :service_hook }
+  end
+
+  describe "Execute" do
+    let(:user)    { create(:user) }
+    let(:project) { create(:project) }
+
+    context "when a password was previously set" do
+      before do
+        @bamboo_service = BambooService.create(
+          project: create(:project),
+          properties: {
+            bamboo_url: 'http://gitlab.com',
+            username: 'mic',
+            password: "password"
+          }
+        )
+      end
+  
+      it "reset password if url changed" do
+        @bamboo_service.bamboo_url = 'http://gitlab1.com'
+        @bamboo_service.save
+        expect(@bamboo_service.password).to be_nil
+      end
+  
+      it "does not reset password if username changed" do
+        @bamboo_service.username = "some_name"
+        @bamboo_service.save
+        expect(@bamboo_service.password).to eq("password")
+      end
+
+      it "does not reset password if new url is set together with password, even if it's the same password" do
+        @bamboo_service.bamboo_url = 'http://gitlab_edited.com'
+        @bamboo_service.password = 'password'
+        @bamboo_service.save
+        expect(@bamboo_service.password).to eq("password")
+        expect(@bamboo_service.bamboo_url).to eq("http://gitlab_edited.com")
+      end
+
+      it "should reset password if url changed, even if setter called multiple times" do
+        @bamboo_service.bamboo_url = 'http://gitlab1.com'
+        @bamboo_service.bamboo_url = 'http://gitlab1.com'
+        @bamboo_service.save
+        expect(@bamboo_service.password).to be_nil
+      end
+    end
+    
+    context "when no password was previously set" do
+      before do
+        @bamboo_service = BambooService.create(
+          project: create(:project),
+          properties: {
+            bamboo_url: 'http://gitlab.com',
+            username: 'mic'
+          }
+        )
+      end
+
+      it "saves password if new url is set together with password" do
+        @bamboo_service.bamboo_url = 'http://gitlab_edited.com'
+        @bamboo_service.password = 'password'
+        @bamboo_service.save
+        expect(@bamboo_service.password).to eq("password")
+        expect(@bamboo_service.bamboo_url).to eq("http://gitlab_edited.com")
+      end
+
+    end
+  end
+end
diff --git a/spec/models/project_services/gitlab_ci_service_spec.rb b/spec/models/project_services/gitlab_ci_service_spec.rb
index 8cdd551a0cae9c14f2a8b2863de64c413beb34f0..842089ebe0d66b9eae8fffda30c069838931b054 100644
--- a/spec/models/project_services/gitlab_ci_service_spec.rb
+++ b/spec/models/project_services/gitlab_ci_service_spec.rb
@@ -39,8 +39,7 @@ describe GitlabCiService do
     end
 
     describe :build_page do
-      it { expect(@service.build_page("2ab7834c", 'master')).to eq("http://localhost/ci/projects/#{@ci_project.id}/refs/master/commits/2ab7834c")}
-      it { expect(@service.build_page("issue#2", 'master')).to eq("http://localhost/ci/projects/#{@ci_project.id}/refs/master/commits/issue%232")}
+      it { expect(@service.build_page("2ab7834c", 'master')).to eq("http://localhost/#{@ci_project.gl_project.path_with_namespace}/commit/2ab7834c/ci")}
     end
 
     describe "execute" do
@@ -48,33 +47,11 @@ describe GitlabCiService do
       let(:project) { create(:project, name: 'project') }
       let(:push_sample_data) { Gitlab::PushDataBuilder.build_sample(project, user) }
 
-      it "calls ci_yaml_file" do
-        service_hook = double
-        expect(@service).to receive(:ci_yaml_file).with(push_sample_data[:checkout_sha])
+      it "calls CreateCommitService" do
+        expect_any_instance_of(Ci::CreateCommitService).to receive(:execute).with(@ci_project, user, push_sample_data)
 
         @service.execute(push_sample_data)
       end
     end
   end
-
-  describe "Fork registration" do
-    before do
-      @old_project = create(:ci_project).gl_project
-      @project = create(:empty_project)
-      @user = create(:user)
-
-      @service = GitlabCiService.new
-      allow(@service).to receive_messages(
-        service_hook: true,
-        project_url: 'http://ci.gitlab.org/projects/2',
-        token: 'verySecret',
-        project: @old_project
-      )
-    end
-
-    it "creates fork on CI" do
-      expect_any_instance_of(Ci::CreateProjectService).to receive(:execute)
-      @service.fork_registration(@project, @user)
-    end
-  end
 end
diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb
index 65d16beef9114286ecbaa5c0e5271260ec00c049..f67d7b309808a395b6a1616ddbc98eb15221843c 100644
--- a/spec/models/project_services/hipchat_service_spec.rb
+++ b/spec/models/project_services/hipchat_service_spec.rb
@@ -87,7 +87,7 @@ describe HipchatService do
       it "should create a push message" do
         message = hipchat.send(:create_push_message, push_sample_data)
 
-        obj_attr = push_sample_data[:object_attributes]
+        push_sample_data[:object_attributes]
         branch = push_sample_data[:ref].gsub('refs/heads/', '')
         expect(message).to include("#{user.name} pushed to branch " \
             "<a href=\"#{project.web_url}/commits/#{branch}\">#{branch}</a> of " \
@@ -107,7 +107,7 @@ describe HipchatService do
       it "should create a tag push message" do
         message = hipchat.send(:create_push_message, push_sample_data)
 
-        obj_attr = push_sample_data[:object_attributes]
+        push_sample_data[:object_attributes]
         expect(message).to eq("#{user.name} pushed new tag " \
             "<a href=\"#{project.web_url}/commits/test\">test</a> to " \
             "<a href=\"#{project.web_url}\">#{project_name}</a>\n")
diff --git a/spec/models/project_services/teamcity_service_spec.rb b/spec/models/project_services/teamcity_service_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..f26b47a856c5058091ba31184b1af6ca1ef2853f
--- /dev/null
+++ b/spec/models/project_services/teamcity_service_spec.rb
@@ -0,0 +1,93 @@
+# == Schema Information
+#
+# Table name: services
+#
+#  id                    :integer          not null, primary key
+#  type                  :string(255)
+#  title                 :string(255)
+#  project_id            :integer
+#  created_at            :datetime
+#  updated_at            :datetime
+#  active                :boolean          default(FALSE), not null
+#  properties            :text
+#  template              :boolean          default(FALSE)
+#  push_events           :boolean          default(TRUE)
+#  issues_events         :boolean          default(TRUE)
+#  merge_requests_events :boolean          default(TRUE)
+#  tag_push_events       :boolean          default(TRUE)
+#  note_events           :boolean          default(TRUE), not null
+#
+
+require 'spec_helper'
+
+describe TeamcityService, models: true do
+  describe "Associations" do
+    it { is_expected.to belong_to :project }
+    it { is_expected.to have_one :service_hook }
+  end
+
+  describe "Execute" do
+    let(:user)    { create(:user) }
+    let(:project) { create(:project) }
+
+    context "when a password was previously set" do
+      before do
+        @teamcity_service = TeamcityService.create(
+          project: create(:project),
+          properties: {
+            teamcity_url: 'http://gitlab.com',
+            username: 'mic',
+            password: "password"
+          }
+        )
+      end
+  
+      it "reset password if url changed" do
+        @teamcity_service.teamcity_url = 'http://gitlab1.com'
+        @teamcity_service.save
+        expect(@teamcity_service.password).to be_nil
+      end
+  
+      it "does not reset password if username changed" do
+        @teamcity_service.username = "some_name"
+        @teamcity_service.save
+        expect(@teamcity_service.password).to eq("password")
+      end
+
+      it "does not reset password if new url is set together with password, even if it's the same password" do
+        @teamcity_service.teamcity_url = 'http://gitlab_edited.com'
+        @teamcity_service.password = 'password'
+        @teamcity_service.save
+        expect(@teamcity_service.password).to eq("password")
+        expect(@teamcity_service.teamcity_url).to eq("http://gitlab_edited.com")
+      end
+
+      it "should reset password if url changed, even if setter called multiple times" do
+        @teamcity_service.teamcity_url = 'http://gitlab1.com'
+        @teamcity_service.teamcity_url = 'http://gitlab1.com'
+        @teamcity_service.save
+        expect(@teamcity_service.password).to be_nil
+      end
+    end
+    
+    context "when no password was previously set" do
+      before do
+        @teamcity_service = TeamcityService.create(
+          project: create(:project),
+          properties: {
+            teamcity_url: 'http://gitlab.com',
+            username: 'mic'
+          }
+        )
+      end
+
+      it "saves password if new url is set together with password" do
+        @teamcity_service.teamcity_url = 'http://gitlab_edited.com'
+        @teamcity_service.password = 'password'
+        @teamcity_service.save
+        expect(@teamcity_service.password).to eq("password")
+        expect(@teamcity_service.teamcity_url).to eq("http://gitlab_edited.com")
+      end
+    end
+  end
+end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 9e7b6f5cb30ee5ffce3f16b76757437f16588692..f93935ebe3b057e8e69be5c6b8bf12f4382f34a3 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -140,7 +140,7 @@ describe Project do
 
     describe 'last_activity_date' do
       it 'returns the creation date of the project\'s last event if present' do
-        last_activity_event = create(:event, project: project)
+        create(:event, project: project)
         expect(project.last_activity_at.to_i).to eq(last_event.created_at.to_i)
       end
 
@@ -220,6 +220,7 @@ describe Project do
       end
 
       it { expect(Project.find_with_namespace('gitlab/gitlabhq')).to eq(@project) }
+      it { expect(Project.find_with_namespace('GitLab/GitlabHQ')).to eq(@project) }
       it { expect(Project.find_with_namespace('gitlab-ci')).to be_nil }
     end
   end
@@ -404,21 +405,60 @@ describe Project do
 
   describe :ci_commit do
     let(:project) { create :project }
-    let(:ci_project) { create :ci_project, gl_project: project }
-    let(:commit) { create :ci_commit, project: ci_project }
+    let(:commit) { create :ci_commit, gl_project: project }
 
-    before { project.create_gitlab_ci_service(active: true) }
+    before do
+      project.ensure_gitlab_ci_project
+      project.create_gitlab_ci_service(active: true)
+    end
 
     it { expect(project.ci_commit(commit.sha)).to eq(commit) }
   end
 
   describe :enable_ci do
     let(:project) { create :project }
-    let(:user) { create :user }
 
-    before { project.enable_ci(user) }
+    before { project.enable_ci }
 
     it { expect(project.gitlab_ci?).to be_truthy }
     it { expect(project.gitlab_ci_project).to be_a(Ci::Project) }
   end
+
+  describe '.trending' do
+    let(:group)    { create(:group) }
+    let(:project1) { create(:empty_project, :public, group: group) }
+    let(:project2) { create(:empty_project, :public, group: group) }
+
+    before do
+      2.times do
+        create(:note_on_commit, project: project1)
+      end
+
+      create(:note_on_commit, project: project2)
+    end
+
+    describe 'without an explicit start date' do
+      subject { described_class.trending.to_a }
+
+      it 'sorts Projects by the amount of notes in descending order' do
+        expect(subject).to eq([project1, project2])
+      end
+    end
+
+    describe 'with an explicit start date' do
+      let(:date) { 2.months.ago }
+
+      subject { described_class.trending(date).to_a }
+
+      before do
+        2.times do
+          create(:note_on_commit, project: project2, created_at: date)
+        end
+      end
+
+      it 'sorts Projects by the amount of notes in descending order' do
+        expect(subject).to eq([project2, project1])
+      end
+    end
+  end
 end
diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb
index cc1138490a05e1b87b6b579565f9ce8c9fb8ae2b..26e8fdae472cdcee832d28ffe0f8fdee50840955 100644
--- a/spec/models/project_team_spec.rb
+++ b/spec/models/project_team_spec.rb
@@ -66,4 +66,16 @@ describe ProjectTeam do
       it { expect(project.team.member?(guest)).to be_truthy }
     end
   end
+
+  describe "#human_max_access" do
+    it "return master role" do
+      user = create :user
+      group = create :group
+      group.add_users([user.id], GroupMember::MASTER)
+      project = create(:project, namespace: group)
+      project.team << [user, :guest]
+
+      expect(project.team.human_max_access(user.id)).to eq("Master")
+    end
+  end
 end
diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb
index f785203af7d963cc50fefc1ca02f31c75826a4fc..94802dcfb79f7486c7ca36ce4c618bac9aca611e 100644
--- a/spec/models/project_wiki_spec.rb
+++ b/spec/models/project_wiki_spec.rb
@@ -231,7 +231,7 @@ describe ProjectWiki do
   end
 
   def commit_details
-    commit = { name: user.name, email: user.email, message: "test commit" }
+    { name: user.name, email: user.email, message: "test commit" }
   end
 
   def create_page(name, content)
diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb
index a213ffe6c4b33bbdda75fb6f9d6a44fe33f3de4a..692e5fda3ba9e7ead1d78e1b57bd42a6281f1b38 100644
--- a/spec/models/service_spec.rb
+++ b/spec/models/service_spec.rb
@@ -103,4 +103,125 @@ describe Service do
       end
     end
   end
+
+  describe "{property}_changed?" do
+    let(:service) do
+      BambooService.create(
+        project: create(:project),
+        properties: {
+          bamboo_url: 'http://gitlab.com',
+          username: 'mic',
+          password: "password"
+        }
+      )
+    end
+
+    it "returns false when the property has not been assigned a new value" do
+      service.username = "key_changed"
+      expect(service.bamboo_url_changed?).to be_falsy
+    end
+
+    it "returns true when the property has been assigned a different value" do
+      service.bamboo_url = "http://example.com"
+      expect(service.bamboo_url_changed?).to be_truthy
+    end
+
+    it "returns true when the property has been assigned a different value twice" do
+      service.bamboo_url = "http://example.com"
+      service.bamboo_url = "http://example.com"
+      expect(service.bamboo_url_changed?).to be_truthy
+    end
+
+    it "returns false when the property has been re-assigned the same value" do
+      service.bamboo_url = 'http://gitlab.com'
+      expect(service.bamboo_url_changed?).to be_falsy
+    end
+
+    it "returns false when the property has been assigned a new value then saved" do
+      service.bamboo_url = 'http://example.com'
+      service.save
+      expect(service.bamboo_url_changed?).to be_falsy
+    end
+  end
+
+  describe "{property}_touched?" do
+    let(:service) do
+      BambooService.create(
+        project: create(:project),
+        properties: {
+          bamboo_url: 'http://gitlab.com',
+          username: 'mic',
+          password: "password"
+        }
+      )
+    end
+
+    it "returns false when the property has not been assigned a new value" do
+      service.username = "key_changed"
+      expect(service.bamboo_url_touched?).to be_falsy
+    end
+
+    it "returns true when the property has been assigned a different value" do
+      service.bamboo_url = "http://example.com"
+      expect(service.bamboo_url_touched?).to be_truthy
+    end
+
+    it "returns true when the property has been assigned a different value twice" do
+      service.bamboo_url = "http://example.com"
+      service.bamboo_url = "http://example.com"
+      expect(service.bamboo_url_touched?).to be_truthy
+    end
+
+    it "returns true when the property has been re-assigned the same value" do
+      service.bamboo_url = 'http://gitlab.com'
+      expect(service.bamboo_url_touched?).to be_truthy
+    end
+
+    it "returns false when the property has been assigned a new value then saved" do
+      service.bamboo_url = 'http://example.com'
+      service.save
+      expect(service.bamboo_url_changed?).to be_falsy
+    end
+  end
+
+  describe "{property}_was" do
+    let(:service) do
+      BambooService.create(
+        project: create(:project),
+        properties: {
+          bamboo_url: 'http://gitlab.com',
+          username: 'mic',
+          password: "password"
+        }
+      )
+    end
+
+
+    it "returns nil when the property has not been assigned a new value" do
+      service.username = "key_changed"
+      expect(service.bamboo_url_was).to be_nil
+    end
+
+    it "returns the previous value when the property has been assigned a different value" do
+      service.bamboo_url = "http://example.com"
+      expect(service.bamboo_url_was).to eq('http://gitlab.com')
+    end
+
+    it "returns initial value when the property has been re-assigned the same value" do
+      service.bamboo_url = 'http://gitlab.com'
+      expect(service.bamboo_url_was).to eq('http://gitlab.com')
+    end
+
+    it "returns initial value when the property has been assigned multiple values" do
+      service.bamboo_url = "http://example.com"
+      service.bamboo_url = "http://example2.com"
+      expect(service.bamboo_url_was).to eq('http://gitlab.com')
+    end
+
+    it "returns nil when the property has been assigned a new value then saved" do
+      service.bamboo_url = 'http://example.com'
+      service.save
+      expect(service.bamboo_url_was).to be_nil
+    end
+  end
 end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 480950859a29391485d424e9d31875077031f32d..c71cfb3ebe341bde2f5364835130b74b34e5326c 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -85,6 +85,7 @@ describe User do
     it { is_expected.to have_many(:merge_requests).dependent(:destroy) }
     it { is_expected.to have_many(:assigned_merge_requests).dependent(:destroy) }
     it { is_expected.to have_many(:identities).dependent(:destroy) }
+    it { is_expected.to have_one(:abuse_report) }
   end
 
   describe 'validations' do
@@ -227,6 +228,26 @@ describe User do
     end
   end
 
+  describe '#recently_sent_password_reset?' do
+    it 'is false when reset_password_sent_at is nil' do
+      user = build_stubbed(:user, reset_password_sent_at: nil)
+
+      expect(user.recently_sent_password_reset?).to eq false
+    end
+
+    it 'is false when sent more than one minute ago' do
+      user = build_stubbed(:user, reset_password_sent_at: 5.minutes.ago)
+
+      expect(user.recently_sent_password_reset?).to eq false
+    end
+
+    it 'is true when sent less than one minute ago' do
+      user = build_stubbed(:user, reset_password_sent_at: Time.now)
+
+      expect(user.recently_sent_password_reset?).to eq true
+    end
+  end
+
   describe '#disable_two_factor!' do
     it 'clears all 2FA-related fields' do
       user = create(:user, :two_factor)
diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb
index dc84a14bb40141785e4f64a72a46cc74de328098..d7802d1734f7274cde8c83a41d7b651b9e9a8450 100644
--- a/spec/models/wiki_page_spec.rb
+++ b/spec/models/wiki_page_spec.rb
@@ -196,7 +196,7 @@ describe WikiPage do
   end
 
   def commit_details
-    commit = { name: user.name, email: user.email, message: "test commit" }
+    { name: user.name, email: user.email, message: "test commit" }
   end
 
   def create_page(name, content)
diff --git a/spec/requests/api/commit_status_spec.rb b/spec/requests/api/commit_status_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..b9e6dfc15a796c5ac5b6db2bd0c343ef11e5d594
--- /dev/null
+++ b/spec/requests/api/commit_status_spec.rb
@@ -0,0 +1,135 @@
+require 'spec_helper'
+
+describe API::API, api: true do
+  include ApiHelpers
+  let(:user) { create(:user) }
+  let(:user2) { create(:user) }
+  let!(:project) { create(:project, creator_id: user.id) }
+  let!(:reporter) { create(:project_member, user: user, project: project, access_level: ProjectMember::REPORTER) }
+  let!(:guest) { create(:project_member, user: user2, project: project, access_level: ProjectMember::GUEST) }
+  let(:commit) { project.repository.commit }
+  let!(:ci_commit) { project.ensure_ci_commit(commit.id) }
+  let(:commit_status) { create(:commit_status, commit: ci_commit) }
+
+  describe "GET /projects/:id/repository/commits/:sha/statuses" do
+    context "reporter user" do
+      let(:statuses_id) { json_response.map { |status| status['id'] } }
+
+      before do
+        @status1 = create(:commit_status, commit: ci_commit, status: 'running')
+        @status2 = create(:commit_status, commit: ci_commit, name: 'coverage', status: 'pending')
+        @status3 = create(:commit_status, commit: ci_commit, name: 'coverage', ref: 'develop', status: 'running')
+        @status4 = create(:commit_status, commit: ci_commit, name: 'coverage', status: 'success')
+        @status5 = create(:commit_status, commit: ci_commit, ref: 'develop', status: 'success')
+        @status6 = create(:commit_status, commit: ci_commit, status: 'success')
+      end
+
+      it "should return latest commit statuses" do
+        get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses", user)
+        expect(response.status).to eq(200)
+
+        expect(json_response).to be_an Array
+        expect(statuses_id).to contain_exactly(@status3.id, @status4.id, @status5.id, @status6.id)
+      end
+
+      it "should return all commit statuses" do
+        get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses?all=1", user)
+        expect(response.status).to eq(200)
+
+        expect(json_response).to be_an Array
+        expect(statuses_id).to contain_exactly(@status1.id, @status2.id, @status3.id, @status4.id, @status5.id, @status6.id)
+      end
+
+      it "should return latest commit statuses for specific ref" do
+        get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses?ref=develop", user)
+        expect(response.status).to eq(200)
+
+        expect(json_response).to be_an Array
+        expect(statuses_id).to contain_exactly(@status3.id, @status5.id)
+      end
+
+      it "should return latest commit statuses for specific name" do
+        get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses?name=coverage", user)
+        expect(response.status).to eq(200)
+
+        expect(json_response).to be_an Array
+        expect(statuses_id).to contain_exactly(@status3.id, @status4.id)
+      end
+    end
+
+    context "guest user" do
+      it "should not return project commits" do
+        get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses", user2)
+        expect(response.status).to eq(403)
+      end
+    end
+
+    context "unauthorized user" do
+      it "should not return project commits" do
+        get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses")
+        expect(response.status).to eq(401)
+      end
+    end
+  end
+
+  describe 'POST /projects/:id/statuses/:sha' do
+    let(:post_url) { "/projects/#{project.id}/statuses/#{commit.id}" }
+
+    context 'reporter user' do
+      context 'should create commit status' do
+        it 'with only required parameters' do
+          post api(post_url, user), state: 'success'
+          expect(response.status).to eq(201)
+          expect(json_response['sha']).to eq(commit.id)
+          expect(json_response['status']).to eq('success')
+          expect(json_response['name']).to eq('default')
+          expect(json_response['ref']).to be_nil
+          expect(json_response['target_url']).to be_nil
+          expect(json_response['description']).to be_nil
+        end
+
+        it 'with all optional parameters' do
+          post api(post_url, user), state: 'success', context: 'coverage', ref: 'develop', target_url: 'url', description: 'test'
+          expect(response.status).to eq(201)
+          expect(json_response['sha']).to eq(commit.id)
+          expect(json_response['status']).to eq('success')
+          expect(json_response['name']).to eq('coverage')
+          expect(json_response['ref']).to eq('develop')
+          expect(json_response['target_url']).to eq('url')
+          expect(json_response['description']).to eq('test')
+        end
+      end
+
+      context 'should not create commit status' do
+        it 'with invalid state' do
+          post api(post_url, user), state: 'invalid'
+          expect(response.status).to eq(400)
+        end
+
+        it 'without state' do
+          post api(post_url, user)
+          expect(response.status).to eq(400)
+        end
+
+        it 'invalid commit' do
+          post api("/projects/#{project.id}/statuses/invalid_sha", user), state: 'running'
+          expect(response.status).to eq(404)
+        end
+      end
+    end
+
+    context 'guest user' do
+      it 'should not create commit status' do
+        post api(post_url, user2)
+        expect(response.status).to eq(403)
+      end
+    end
+
+    context 'unauthorized user' do
+      it 'should not create commit status' do
+        post api(post_url)
+        expect(response.status).to eq(401)
+      end
+    end
+  end
+end
diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb
index a1c248c636eb4fa699777f8accd71e6fb84a30f2..49acc3368f43a536b972df9e8015e117d82db02e 100644
--- a/spec/requests/api/commits_spec.rb
+++ b/spec/requests/api/commits_spec.rb
@@ -47,6 +47,19 @@ describe API::API, api: true  do
         get api("/projects/#{project.id}/repository/commits/invalid_sha", user)
         expect(response.status).to eq(404)
       end
+
+      it "should return not_found for CI status" do
+        get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user)
+        expect(response.status).to eq(200)
+        expect(json_response['status']).to eq('not_found')
+      end
+
+      it "should return status for CI" do
+        ci_commit = project.ensure_ci_commit(project.repository.commit.sha)
+        get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user)
+        expect(response.status).to eq(200)
+        expect(json_response['status']).to eq(ci_commit.status)
+      end
     end
 
     context "unauthorized user" do
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 35b3d3e296abd08148dee80c60adfd20737ac42b..a68c7b1e461d3fbee2f5d3bcf7c95d15a56b430e 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -379,9 +379,14 @@ describe API::API, api: true  do
 
   describe "POST /projects/:id/merge_request/:merge_request_id/comments" do
     it "should return comment" do
+      original_count = merge_request.notes.size
+
       post api("/projects/#{project.id}/merge_request/#{merge_request.id}/comments", user), note: "My comment"
       expect(response.status).to eq(201)
       expect(json_response['note']).to eq('My comment')
+      expect(json_response['author']['name']).to eq(user.name)
+      expect(json_response['author']['username']).to eq(user.username)
+      expect(merge_request.notes.size).to eq(original_count + 1)
     end
 
     it "should return 400 if note is missing" do
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 580bbec77d18b93faed215a926a2b92c19723c8e..e9de9e0826dc109fd71b71a196a5c08e009e8ef8 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -606,28 +606,42 @@ describe API::API, api: true  do
 
     describe 'DELETE /projects/:id/fork' do
 
-      it "shouldn't available for non admin users" do
+      it "shouldn't be visible to users outside group" do
         delete api("/projects/#{project_fork_target.id}/fork", user)
-        expect(response.status).to eq(403)
+        expect(response.status).to eq(404)
       end
 
-      it 'should make forked project unforked' do
-        post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
-        project_fork_target.reload
-        expect(project_fork_target.forked_from_project).not_to be_nil
-        expect(project_fork_target.forked?).to be_truthy
-        delete api("/projects/#{project_fork_target.id}/fork", admin)
-        expect(response.status).to eq(200)
-        project_fork_target.reload
-        expect(project_fork_target.forked_from_project).to be_nil
-        expect(project_fork_target.forked?).not_to be_truthy
-      end
+      context 'when users belong to project group' do
+        let(:project_fork_target) { create(:project, group: create(:group)) }
 
-      it 'should be idempotent if not forked' do
-        expect(project_fork_target.forked_from_project).to be_nil
-        delete api("/projects/#{project_fork_target.id}/fork", admin)
-        expect(response.status).to eq(200)
-        expect(project_fork_target.reload.forked_from_project).to be_nil
+        before do
+          project_fork_target.group.add_owner user
+          project_fork_target.group.add_developer user2
+        end
+
+        it 'should be forbidden to non-owner users' do
+          delete api("/projects/#{project_fork_target.id}/fork", user2)
+          expect(response.status).to eq(403)
+        end
+
+        it 'should make forked project unforked' do
+          post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
+          project_fork_target.reload
+          expect(project_fork_target.forked_from_project).not_to be_nil
+          expect(project_fork_target.forked?).to be_truthy
+          delete api("/projects/#{project_fork_target.id}/fork", admin)
+          expect(response.status).to eq(200)
+          project_fork_target.reload
+          expect(project_fork_target.forked_from_project).to be_nil
+          expect(project_fork_target.forked?).not_to be_truthy
+        end
+
+        it 'should be idempotent if not forked' do
+          expect(project_fork_target.forked_from_project).to be_nil
+          delete api("/projects/#{project_fork_target.id}/fork", admin)
+          expect(response.status).to eq(200)
+          expect(project_fork_target.reload.forked_from_project).to be_nil
+        end
       end
     end
   end
diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb
index 09a79553f729cab2d5d53320f474c4ff6fb01b72..1149f7e79895d80c58cf594302d39b5e6a5bd844 100644
--- a/spec/requests/api/repositories_spec.rb
+++ b/spec/requests/api/repositories_spec.rb
@@ -166,24 +166,21 @@ describe API::API, api: true  do
       get api("/projects/#{project.id}/repository/archive", user)
       repo_name = project.repository.name.gsub("\.git", "")
       expect(response.status).to eq(200)
-      expect(response.headers['Content-Disposition']).to match(/filename\=\"#{repo_name}\-[^\.]+\.tar.gz\"/)
-      expect(response.content_type).to eq(MIME::Types.type_for('file.tar.gz').first.content_type)
+      expect(json_response['ArchivePath']).to match(/#{repo_name}\-[^\.]+\.tar.gz/)
     end
 
     it "should get the archive.zip" do
       get api("/projects/#{project.id}/repository/archive.zip", user)
       repo_name = project.repository.name.gsub("\.git", "")
       expect(response.status).to eq(200)
-      expect(response.headers['Content-Disposition']).to match(/filename\=\"#{repo_name}\-[^\.]+\.zip\"/)
-      expect(response.content_type).to eq(MIME::Types.type_for('file.zip').first.content_type)
+      expect(json_response['ArchivePath']).to match(/#{repo_name}\-[^\.]+\.zip/)
     end
 
     it "should get the archive.tar.bz2" do
       get api("/projects/#{project.id}/repository/archive.tar.bz2", user)
       repo_name = project.repository.name.gsub("\.git", "")
       expect(response.status).to eq(200)
-      expect(response.headers['Content-Disposition']).to match(/filename\=\"#{repo_name}\-[^\.]+\.tar.bz2\"/)
-      expect(response.content_type).to eq(MIME::Types.type_for('file.tar.bz2').first.content_type)
+      expect(json_response['ArchivePath']).to match(/#{repo_name}\-[^\.]+\.tar.bz2/)
     end
 
     it "should return 404 for invalid sha" do
diff --git a/spec/requests/api/services_spec.rb b/spec/requests/api/services_spec.rb
index 9aa60826f21448cd4360eafde6b5049a2562eec8..c0226605a2320aebc5f85bea2daaeb5e6ba8ba86 100644
--- a/spec/requests/api/services_spec.rb
+++ b/spec/requests/api/services_spec.rb
@@ -3,6 +3,8 @@ require "spec_helper"
 describe API::API, api: true  do
   include ApiHelpers
   let(:user) { create(:user) }
+  let(:admin) { create(:admin) }
+  let(:user2) { create(:user) }
   let(:project) {create(:project, creator_id: user.id, namespace: user.namespace) }
 
   Service.available_services_names.each do |service|
@@ -51,11 +53,40 @@ describe API::API, api: true  do
     describe "GET /projects/:id/services/#{service.dasherize}" do
       include_context service
 
-      it "should get #{service} settings" do
+      # inject some properties into the service
+      before do
+        project.build_missing_services
+        service_object = project.send(service_method)
+        service_object.properties = service_attrs
+        service_object.save
+      end
+
+      it 'should return authentication error when unauthenticated' do
+        get api("/projects/#{project.id}/services/#{dashed_service}")
+        expect(response.status).to eq(401)
+      end
+      
+      it "should return all properties of service #{service} when authenticated as admin" do
+        get api("/projects/#{project.id}/services/#{dashed_service}", admin)
+        
+        expect(response.status).to eq(200)
+        expect(json_response['properties'].keys.map(&:to_sym)).to match_array(service_attrs_list.map)
+      end
+
+      it "should return properties of service #{service} other than passwords when authenticated as project owner" do
         get api("/projects/#{project.id}/services/#{dashed_service}", user)
 
         expect(response.status).to eq(200)
+        expect(json_response['properties'].keys.map(&:to_sym)).to match_array(service_attrs_list_without_passwords)
       end
+
+      it "should return error when authenticated but not a project owner" do
+        project.team << [user2, :developer]
+        get api("/projects/#{project.id}/services/#{dashed_service}", user2)
+        
+        expect(response.status).to eq(403)
+      end
+
     end
   end
 end
diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb
index c25d1823306bb73d7e6fddb45b2267aa8a7ef2d8..88218a93e1f589b90e015b20bde21c28fe9d59c4 100644
--- a/spec/requests/ci/api/builds_spec.rb
+++ b/spec/requests/ci/api/builds_spec.rb
@@ -5,10 +5,16 @@ describe Ci::API::API do
 
   let(:runner) { FactoryGirl.create(:ci_runner, tag_list: ["mysql", "ruby"]) }
   let(:project) { FactoryGirl.create(:ci_project) }
+  let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
+
+  before do
+    stub_ci_commit_to_return_yaml_file
+  end
 
   describe "Builds API for runners" do
     let(:shared_runner) { FactoryGirl.create(:ci_runner, token: "SharedRunner") }
     let(:shared_project) { FactoryGirl.create(:ci_project, name: "SharedProject") }
+    let(:shared_gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: shared_project) }
 
     before do
       FactoryGirl.create :ci_runner_project, project_id: project.id, runner_id: runner.id
@@ -16,8 +22,8 @@ describe Ci::API::API do
 
     describe "POST /builds/register" do
       it "should start a build" do
-        commit = FactoryGirl.create(:ci_commit, project: project)
-        commit.create_builds
+        commit = FactoryGirl.create(:ci_commit, gl_project: gl_project)
+        commit.create_builds('master', false, nil)
         build = commit.builds.first
 
         post ci_api("/builds/register"), token: runner.token, info: { platform: :darwin }
@@ -34,7 +40,7 @@ describe Ci::API::API do
       end
 
       it "should return 404 error if no builds for specific runner" do
-        commit = FactoryGirl.create(:ci_commit, project: shared_project)
+        commit = FactoryGirl.create(:ci_commit, gl_project: shared_gl_project)
         FactoryGirl.create(:ci_build, commit: commit, status: 'pending' )
 
         post ci_api("/builds/register"), token: runner.token
@@ -43,7 +49,7 @@ describe Ci::API::API do
       end
 
       it "should return 404 error if no builds for shared runner" do
-        commit = FactoryGirl.create(:ci_commit, project: project)
+        commit = FactoryGirl.create(:ci_commit, gl_project: gl_project)
         FactoryGirl.create(:ci_build, commit: commit, status: 'pending' )
 
         post ci_api("/builds/register"), token: shared_runner.token
@@ -52,8 +58,8 @@ describe Ci::API::API do
       end
 
       it "returns options" do
-        commit = FactoryGirl.create(:ci_commit, project: project)
-        commit.create_builds
+        commit = FactoryGirl.create(:ci_commit, gl_project: gl_project)
+        commit.create_builds('master', false, nil)
 
         post ci_api("/builds/register"), token: runner.token, info: { platform: :darwin }
 
@@ -62,14 +68,16 @@ describe Ci::API::API do
       end
 
       it "returns variables" do
-        commit = FactoryGirl.create(:ci_commit, project: project)
-        commit.create_builds
+        commit = FactoryGirl.create(:ci_commit, gl_project: gl_project)
+        commit.create_builds('master', false, nil)
         project.variables << Ci::Variable.new(key: "SECRET_KEY", value: "secret_value")
 
         post ci_api("/builds/register"), token: runner.token, info: { platform: :darwin }
 
         expect(response.status).to eq(201)
         expect(json_response["variables"]).to eq([
+          { "key" => "CI_BUILD_NAME", "value" => "spinach", "public" => true },
+          { "key" => "CI_BUILD_STAGE", "value" => "test", "public" => true },
           { "key" => "DB_NAME", "value" => "postgres", "public" => true },
           { "key" => "SECRET_KEY", "value" => "secret_value", "public" => false },
         ])
@@ -77,16 +85,19 @@ describe Ci::API::API do
 
       it "returns variables for triggers" do
         trigger = FactoryGirl.create(:ci_trigger, project: project)
-        commit = FactoryGirl.create(:ci_commit, project: project)
+        commit = FactoryGirl.create(:ci_commit, gl_project: gl_project)
 
         trigger_request = FactoryGirl.create(:ci_trigger_request_with_variables, commit: commit, trigger: trigger)
-        commit.create_builds(trigger_request)
+        commit.create_builds('master', false, nil, trigger_request)
         project.variables << Ci::Variable.new(key: "SECRET_KEY", value: "secret_value")
 
         post ci_api("/builds/register"), token: runner.token, info: { platform: :darwin }
 
         expect(response.status).to eq(201)
         expect(json_response["variables"]).to eq([
+          { "key" => "CI_BUILD_NAME", "value" => "spinach", "public" => true },
+          { "key" => "CI_BUILD_STAGE", "value" => "test", "public" => true },
+          { "key" => "CI_BUILD_TRIGGERED", "value" => "true", "public" => true },
           { "key" => "DB_NAME", "value" => "postgres", "public" => true },
           { "key" => "SECRET_KEY", "value" => "secret_value", "public" => false },
           { "key" => "TRIGGER_KEY", "value" => "TRIGGER_VALUE", "public" => false },
@@ -95,7 +106,7 @@ describe Ci::API::API do
     end
 
     describe "PUT /builds/:id" do
-      let(:commit) { FactoryGirl.create(:ci_commit, project: project)}
+      let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project)}
       let(:build) { FactoryGirl.create(:ci_build, commit: commit, runner_id: runner.id) }
 
       it "should update a running build" do
diff --git a/spec/requests/ci/api/commits_spec.rb b/spec/requests/ci/api/commits_spec.rb
index e89b6651499b93ac1175bfca5a1011335766513d..6049135fd104f799c8757e81824dfc185a7c5495 100644
--- a/spec/requests/ci/api/commits_spec.rb
+++ b/spec/requests/ci/api/commits_spec.rb
@@ -4,7 +4,8 @@ describe Ci::API::API, 'Commits' do
   include ApiHelpers
 
   let(:project) { FactoryGirl.create(:ci_project) }
-  let(:commit) { FactoryGirl.create(:ci_commit, project: project) }
+  let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
+  let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
 
   let(:options) do
     {
@@ -43,8 +44,7 @@ describe Ci::API::API, 'Commits' do
               "email" => "jordi@softcatala.org",
             }
           }
-        ],
-        ci_yaml_file: gitlab_ci_yaml
+        ]
       }
     end
 
diff --git a/spec/requests/ci/api/projects_spec.rb b/spec/requests/ci/api/projects_spec.rb
index 409f47fa448756579759e36cda61ca6a55739d7f..53f7f91cc1f7c0a89583ceb294ae794f721c03ff 100644
--- a/spec/requests/ci/api/projects_spec.rb
+++ b/spec/requests/ci/api/projects_spec.rb
@@ -134,7 +134,7 @@ describe Ci::API::API do
 
   describe "PUT /projects/:id" do
     let!(:project) { FactoryGirl.create(:ci_project) }
-    let!(:project_info) { { name: "An updated name!" } }
+    let!(:project_info) { { default_ref: "develop" } }
 
     before do
       options.merge!(project_info)
@@ -144,7 +144,7 @@ describe Ci::API::API do
       project.gl_project.team << [user, :master]
       put ci_api("/projects/#{project.id}"), options
       expect(response.status).to eq(200)
-      expect(json_response["name"]).to eq(project_info[:name])
+      expect(json_response["default_ref"]).to eq(project_info[:default_ref])
     end
 
     it "fails to update a non-existing project" do
@@ -181,12 +181,10 @@ describe Ci::API::API do
   end
 
   describe "POST /projects" do
+    let(:gl_project) { FactoryGirl.create :empty_project }
     let(:project_info) do
       {
-        name: "My project",
-        gitlab_id: 1,
-        path: "testing/testing",
-        ssh_url_to_repo: "ssh://example.com/testing/testing.git"
+        gitlab_id: gl_project.id
       }
     end
 
@@ -200,7 +198,7 @@ describe Ci::API::API do
       it "should create a project with valid data" do
         post ci_api("/projects"), options
         expect(response.status).to eq(201)
-        expect(json_response['name']).to eq(project_info[:name])
+        expect(json_response['name']).to eq(gl_project.name_with_namespace)
       end
     end
 
diff --git a/spec/requests/ci/api/triggers_spec.rb b/spec/requests/ci/api/triggers_spec.rb
index ff6fdbdd6f113e0ac55230ae5df23e7f7afe48b4..93617fc4b3f2dc9eee0b9656a3d53f1aab77b7e3 100644
--- a/spec/requests/ci/api/triggers_spec.rb
+++ b/spec/requests/ci/api/triggers_spec.rb
@@ -5,7 +5,8 @@ describe Ci::API::API do
 
   describe 'POST /projects/:project_id/refs/:ref/trigger' do
     let!(:trigger_token) { 'secure token' }
-    let!(:project) { FactoryGirl.create(:ci_project) }
+    let!(:gl_project) { FactoryGirl.create(:project) }
+    let!(:project) { FactoryGirl.create(:ci_project, gl_project: gl_project) }
     let!(:project2) { FactoryGirl.create(:ci_project) }
     let!(:trigger) { FactoryGirl.create(:ci_trigger, project: project, token: trigger_token) }
     let(:options) do
@@ -14,6 +15,10 @@ describe Ci::API::API do
       }
     end
 
+    before do
+      stub_ci_commit_to_return_yaml_file
+    end
+
     context 'Handles errors' do
       it 'should return bad request if token is missing' do
         post ci_api("/projects/#{project.id}/refs/master/trigger")
@@ -32,15 +37,13 @@ describe Ci::API::API do
     end
 
     context 'Have a commit' do
-      before do
-        @commit = FactoryGirl.create(:ci_commit, project: project)
-      end
+      let(:commit) { project.commits.last }
 
       it 'should create builds' do
         post ci_api("/projects/#{project.id}/refs/master/trigger"), options
         expect(response.status).to eq(201)
-        @commit.builds.reload
-        expect(@commit.builds.size).to eq(2)
+        commit.builds.reload
+        expect(commit.builds.size).to eq(2)
       end
 
       it 'should return bad request with no builds created if there\'s no commit for that ref' do
@@ -69,8 +72,8 @@ describe Ci::API::API do
         it 'create trigger request with variables' do
           post ci_api("/projects/#{project.id}/refs/master/trigger"), options.merge(variables: variables)
           expect(response.status).to eq(201)
-          @commit.builds.reload
-          expect(@commit.builds.first.trigger_request.variables).to eq(variables)
+          commit.builds.reload
+          expect(commit.builds.first.trigger_request.variables).to eq(variables)
         end
       end
     end
diff --git a/spec/requests/ci/builds_spec.rb b/spec/requests/ci/builds_spec.rb
deleted file mode 100644
index 998c386ead49733218144feb36e7159cd5f030e7..0000000000000000000000000000000000000000
--- a/spec/requests/ci/builds_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require 'spec_helper'
-
-describe "Builds" do
-  before do
-    @project = FactoryGirl.create :ci_project
-    @commit = FactoryGirl.create :ci_commit, project: @project
-    @build = FactoryGirl.create :ci_build, commit: @commit
-  end
-
-  describe "GET /:project/builds/:id/status.json" do
-    before do
-      get status_ci_project_build_path(@project, @build), format: :json
-    end
-
-    it { expect(response.status).to eq(200) }
-    it { expect(response.body).to include(@build.sha) }
-  end
-end
diff --git a/spec/requests/ci/commits_spec.rb b/spec/requests/ci/commits_spec.rb
deleted file mode 100644
index fb3176703394b010086b4b59d53f0c42921570f6..0000000000000000000000000000000000000000
--- a/spec/requests/ci/commits_spec.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-require 'spec_helper'
-
-describe "Commits" do
-  before do
-    @project = FactoryGirl.create :ci_project
-    @commit = FactoryGirl.create :ci_commit, project: @project
-  end
-
-  describe "GET /:project/refs/:ref_name/commits/:id/status.json" do
-    before do
-      get status_ci_project_ref_commits_path(@project, @commit.ref, @commit.sha), format: :json
-    end
-
-    it { expect(response.status).to eq(200) }
-    it { expect(response.body).to include(@commit.sha) }
-  end
-end
diff --git a/spec/services/archive_repository_service_spec.rb b/spec/services/archive_repository_service_spec.rb
index 0ec70c51b3a42d10b552bb7be52bacd7db131925..f7a36cd96705025a15ba2ce40b15a19f37cdc3fb 100644
--- a/spec/services/archive_repository_service_spec.rb
+++ b/spec/services/archive_repository_service_spec.rb
@@ -6,14 +6,14 @@ describe ArchiveRepositoryService do
 
   describe "#execute" do
     it "cleans old archives" do
-      expect(project.repository).to receive(:clean_old_archives)
+      expect(RepositoryArchiveCacheWorker).to receive(:perform_async)
 
       subject.execute(timeout: 0.0)
     end
 
     context "when the repository doesn't have an archive file path" do
       before do
-        allow(project.repository).to receive(:archive_file_path).and_return(nil)
+        allow(project.repository).to receive(:archive_metadata).and_return(Hash.new)
       end
 
       it "raises an error" do
@@ -21,70 +21,5 @@ describe ArchiveRepositoryService do
       end
     end
 
-    context "when the repository has an archive file path" do
-      let(:file_path)     { "/archive.zip" }
-      let(:pid_file_path) { "/archive.zip.pid" }
-
-      before do
-        allow(project.repository).to receive(:archive_file_path).and_return(file_path)
-        allow(project.repository).to receive(:archive_pid_file_path).and_return(pid_file_path)
-      end
-
-      context "when the archive file already exists" do
-        before do
-          allow(File).to receive(:exist?).with(file_path).and_return(true)
-        end
-
-        it "returns the file path" do
-          expect(subject.execute(timeout: 0.0)).to eq(file_path)
-        end
-      end
-
-      context "when the archive file doesn't exist yet" do
-        before do
-          allow(File).to receive(:exist?).with(file_path).and_return(false)
-          allow(File).to receive(:exist?).with(pid_file_path).and_return(true)
-        end
-
-        context "when the archive pid file doesn't exist yet" do
-          before do
-            allow(File).to receive(:exist?).with(pid_file_path).and_return(false)
-          end
-
-          it "queues the RepositoryArchiveWorker" do
-            expect(RepositoryArchiveWorker).to receive(:perform_async)
-
-            subject.execute(timeout: 0.0)
-          end
-        end
-
-        context "when the archive pid file already exists" do
-          it "doesn't queue the RepositoryArchiveWorker" do
-            expect(RepositoryArchiveWorker).not_to receive(:perform_async)
-
-            subject.execute(timeout: 0.0)
-          end
-        end
-
-        context "when the archive file exists after a little while" do
-          before do
-            Thread.new do
-              sleep 0.1
-              allow(File).to receive(:exist?).with(file_path).and_return(true)
-            end
-          end
-
-          it "returns the file path" do
-            expect(subject.execute(timeout: 0.2)).to eq(file_path)
-          end
-        end
-
-        context "when the archive file doesn't exist after the timeout" do
-          it "returns nil" do
-            expect(subject.execute(timeout: 0.0)).to eq(nil)
-          end
-        end
-      end
-    end
   end
 end
diff --git a/spec/services/ci/create_commit_service_spec.rb b/spec/services/ci/create_commit_service_spec.rb
index 84ab0a615dd603882b22a37ac6e3fefe643131c0..e3a8fe9681b6c87a84c1ff7732deae4d8f9be062 100644
--- a/spec/services/ci/create_commit_service_spec.rb
+++ b/spec/services/ci/create_commit_service_spec.rb
@@ -4,15 +4,19 @@ module Ci
   describe CreateCommitService do
     let(:service) { CreateCommitService.new }
     let(:project) { FactoryGirl.create(:ci_project) }
+    let(:user) { nil }
+
+    before do
+      stub_ci_commit_to_return_yaml_file
+    end
 
     describe :execute do
       context 'valid params' do
         let(:commit) do
-          service.execute(project,
+          service.execute(project, user,
             ref: 'refs/heads/master',
             before: '00000000',
             after: '31das312',
-            ci_yaml_file: gitlab_ci_yaml,
             commits: [ { message: "Message" } ]
           )
         end
@@ -26,11 +30,10 @@ module Ci
 
       context "skip tag if there is no build for it" do
         it "creates commit if there is appropriate job" do
-          result = service.execute(project,
+          result = service.execute(project, user,
             ref: 'refs/tags/0_1',
             before: '00000000',
             after: '31das312',
-            ci_yaml_file: gitlab_ci_yaml,
             commits: [ { message: "Message" } ]
           )
           expect(result).to be_persisted
@@ -38,12 +41,12 @@ module Ci
 
         it "creates commit if there is no appropriate job but deploy job has right ref setting" do
           config = YAML.dump({ deploy: { deploy: "ls", only: ["0_1"] } })
+          stub_ci_commit_yaml_file(config)
 
-          result = service.execute(project,
+          result = service.execute(project, user,
             ref: 'refs/heads/0_1',
             before: '00000000',
             after: '31das312',
-            ci_yaml_file: config,
             commits: [ { message: "Message" } ]
           )
           expect(result).to be_persisted
@@ -51,11 +54,11 @@ module Ci
       end
 
       it 'fails commits without .gitlab-ci.yml' do
-        result = service.execute(project,
+        stub_ci_commit_yaml_file(nil)
+        result = service.execute(project, user,
                                  ref: 'refs/heads/0_1',
                                  before: '00000000',
                                  after: '31das312',
-                                 ci_yaml_file: config,
                                  commits: [ { message: 'Message' } ]
         )
         expect(result).to be_persisted
@@ -64,41 +67,46 @@ module Ci
       end
 
       describe :ci_skip? do
+        let(:message) { "some message[ci skip]" }
+
+        before do
+          allow_any_instance_of(Ci::Commit).to receive(:git_commit_message) { message }
+        end
+
         it "skips builds creation if there is [ci skip] tag in commit message" do
-          commits = [{ message: "some message[ci skip]" }]
-          commit = service.execute(project,
+          commits = [{ message: message }]
+          commit = service.execute(project, user,
             ref: 'refs/tags/0_1',
             before: '00000000',
             after: '31das312',
-            commits: commits,
-            ci_yaml_file: gitlab_ci_yaml
+            commits: commits
           )
           expect(commit.builds.any?).to be false
           expect(commit.status).to eq("skipped")
         end
 
         it "does not skips builds creation if there is no [ci skip] tag in commit message" do
-          commits = [{ message: "some message" }]
+          allow_any_instance_of(Ci::Commit).to receive(:git_commit_message) { "some message" }
 
-          commit = service.execute(project,
+          commits = [{ message: "some message" }]
+          commit = service.execute(project, user,
             ref: 'refs/tags/0_1',
             before: '00000000',
             after: '31das312',
-            commits: commits,
-            ci_yaml_file: gitlab_ci_yaml
+            commits: commits
           )
 
           expect(commit.builds.first.name).to eq("staging")
         end
 
         it "skips builds creation if there is [ci skip] tag in commit message and yaml is invalid" do
-          commits = [{ message: "some message[ci skip]" }]
-          commit = service.execute(project,
+          stub_ci_commit_yaml_file('invalid: file')
+          commits = [{ message: message }]
+          commit = service.execute(project, user,
                                    ref: 'refs/tags/0_1',
                                    before: '00000000',
                                    after: '31das312',
-                                   commits: commits,
-                                   ci_yaml_file: "invalid: file"
+                                   commits: commits
           )
           expect(commit.builds.any?).to be false
           expect(commit.status).to eq("skipped")
@@ -106,35 +114,36 @@ module Ci
       end
 
       it "skips build creation if there are already builds" do
+        allow_any_instance_of(Ci::Commit).to receive(:ci_yaml_file) { gitlab_ci_yaml }
+
         commits = [{ message: "message" }]
-        commit = service.execute(project,
+        commit = service.execute(project, user,
           ref: 'refs/heads/master',
           before: '00000000',
           after: '31das312',
-          commits: commits,
-          ci_yaml_file: gitlab_ci_yaml
+          commits: commits
         )
         expect(commit.builds.count(:all)).to  eq(2)
 
-        commit = service.execute(project,
+        commit = service.execute(project, user,
           ref: 'refs/heads/master',
           before: '00000000',
           after: '31das312',
-          commits: commits,
-          ci_yaml_file: gitlab_ci_yaml
+          commits: commits
         )
         expect(commit.builds.count(:all)).to eq(2)
       end
 
       it "creates commit with failed status if yaml is invalid" do
+        stub_ci_commit_yaml_file('invalid: file')
+
         commits = [{ message: "some message" }]
 
-        commit = service.execute(project,
+        commit = service.execute(project, user,
                                  ref: 'refs/tags/0_1',
                                  before: '00000000',
                                  after: '31das312',
-                                 commits: commits,
-                                 ci_yaml_file: "invalid: file"
+                                 commits: commits
         )
 
         expect(commit.status).to eq("failed")
diff --git a/spec/services/ci/create_project_service_spec.rb b/spec/services/ci/create_project_service_spec.rb
deleted file mode 100644
index 2de7b0deca79ea4dccabc7ba21bc164679a385f3..0000000000000000000000000000000000000000
--- a/spec/services/ci/create_project_service_spec.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-require 'spec_helper'
-
-describe Ci::CreateProjectService do
-  let(:service) { Ci::CreateProjectService.new }
-  let(:current_user) { double.as_null_object }
-  let(:project) { FactoryGirl.create :project }
-
-  describe :execute do
-    context 'valid params' do
-      subject { service.execute(current_user, project) }
-
-      it { is_expected.to be_kind_of(Ci::Project) }
-      it { is_expected.to be_persisted }
-    end
-
-    context 'without project dump' do
-      it 'should raise exception' do
-        expect { service.execute(current_user, '', '') }.
-          to raise_error(NoMethodError)
-      end
-    end
-
-    context "forking" do
-      let(:ci_origin_project) do
-        FactoryGirl.create(:ci_project, shared_runners_enabled: true, public: true, allow_git_fetch: true)
-      end
-
-      subject { service.execute(current_user, project, ci_origin_project) }
-
-      it "uses project as a template for settings and jobs" do
-        expect(subject.shared_runners_enabled).to be_truthy
-        expect(subject.public).to be_truthy
-        expect(subject.allow_git_fetch).to be_truthy
-      end
-    end
-  end
-end
diff --git a/spec/services/ci/create_trigger_request_service_spec.rb b/spec/services/ci/create_trigger_request_service_spec.rb
index d12cd9773dce98bdfb36c906b0ee6cb3dae23ea6..fcafae386448090f89f881b6b5dd5d7508847855 100644
--- a/spec/services/ci/create_trigger_request_service_spec.rb
+++ b/spec/services/ci/create_trigger_request_service_spec.rb
@@ -2,19 +2,20 @@ require 'spec_helper'
 
 describe Ci::CreateTriggerRequestService do
   let(:service) { Ci::CreateTriggerRequestService.new }
-  let(:project) { FactoryGirl.create :ci_project }
-  let(:trigger) { FactoryGirl.create :ci_trigger, project: project }
+  let(:gl_project) { create(:project) }
+  let(:project) { create(:ci_project, gl_project: gl_project) }
+  let(:trigger) { create(:ci_trigger, project: project) }
+
+  before do
+    stub_ci_commit_to_return_yaml_file
+  end
 
   describe :execute do
     context 'valid params' do
       subject { service.execute(project, trigger, 'master') }
 
-      before do
-        @commit = FactoryGirl.create :ci_commit, project: project
-      end
-
       it { expect(subject).to be_kind_of(Ci::TriggerRequest) }
-      it { expect(subject.commit).to eq(@commit) }
+      it { expect(subject.builds.first).to be_kind_of(Ci::Build) }
     end
 
     context 'no commit for ref' do
@@ -27,26 +28,11 @@ describe Ci::CreateTriggerRequestService do
       subject { service.execute(project, trigger, 'master') }
 
       before do
-        FactoryGirl.create :ci_commit_without_jobs, project: project
+        stub_ci_commit_yaml_file('{}')
+        FactoryGirl.create :ci_commit, gl_project: gl_project
       end
 
       it { expect(subject).to be_nil }
     end
-
-    context 'for multiple commits' do
-      subject { service.execute(project, trigger, 'master') }
-
-      before do
-        @commit1 = FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, project: project
-        @commit2 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, project: project
-        @commit3 = FactoryGirl.create :ci_commit, committed_at: 3.hour.ago, project: project
-      end
-
-      context 'retries latest one' do
-        it { expect(subject).to be_kind_of(Ci::TriggerRequest) }
-        it { expect(subject).to be_persisted }
-        it { expect(subject.commit).to eq(@commit2) }
-      end
-    end
   end
 end
diff --git a/spec/services/ci/event_service_spec.rb b/spec/services/ci/event_service_spec.rb
index 9b330a90ae29f4afec271cbc640ed99d9fe4fb0f..1264e17ff5ecea89f36d1b6d3b845f507435d209 100644
--- a/spec/services/ci/event_service_spec.rb
+++ b/spec/services/ci/event_service_spec.rb
@@ -1,7 +1,7 @@
 require 'spec_helper'
 
 describe Ci::EventService do
-  let(:project) { FactoryGirl.create :ci_project, name: "GitLab / gitlab-shell" }
+  let(:project) { FactoryGirl.create :ci_project }
   let(:user)   { double(username: "root", id: 1) }
 
   before do
@@ -12,7 +12,7 @@ describe Ci::EventService do
     it "creates event" do
       Ci::EventService.new.remove_project(user, project)
 
-      expect(Ci::Event.admin.last.description).to eq("Project \"GitLab / gitlab-shell\" has been removed by root")
+      expect(Ci::Event.admin.last.description).to eq("Project \"#{project.name_with_namespace}\" has been removed by root")
     end
   end
 
@@ -20,7 +20,7 @@ describe Ci::EventService do
     it "creates event" do
       Ci::EventService.new.create_project(user, project)
 
-      expect(Ci::Event.admin.last.description).to eq("Project \"GitLab / gitlab-shell\" has been created by root")
+      expect(Ci::Event.admin.last.description).to eq("Project \"#{project.name_with_namespace}\" has been created by root")
     end
   end
 
diff --git a/spec/services/ci/image_for_build_service_spec.rb b/spec/services/ci/image_for_build_service_spec.rb
index 7565eb8f03281d83b6ca046c403b22fa490f200e..d7242d684c63a9dad5ffbc7625f46f77970639ff 100644
--- a/spec/services/ci/image_for_build_service_spec.rb
+++ b/spec/services/ci/image_for_build_service_spec.rb
@@ -4,7 +4,8 @@ module Ci
   describe ImageForBuildService do
     let(:service) { ImageForBuildService.new }
     let(:project) { FactoryGirl.create(:ci_project) }
-    let(:commit) { FactoryGirl.create(:ci_commit, project: project, ref: 'master') }
+    let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
+    let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project, ref: 'master') }
     let(:build) { FactoryGirl.create(:ci_build, commit: commit) }
 
     describe :execute do
diff --git a/spec/services/ci/register_build_service_spec.rb b/spec/services/ci/register_build_service_spec.rb
index 7b5af6c3dd067447c7047a3e01dd3c9f84b22b62..781764627aca0cb80274d093cc992d5f36f14388 100644
--- a/spec/services/ci/register_build_service_spec.rb
+++ b/spec/services/ci/register_build_service_spec.rb
@@ -3,14 +3,14 @@ require 'spec_helper'
 module Ci
   describe RegisterBuildService do
     let!(:service) { RegisterBuildService.new }
-    let!(:project) { FactoryGirl.create :ci_project }
-    let!(:commit) { FactoryGirl.create :ci_commit, project: project }
-    let!(:pending_build) { FactoryGirl.create :ci_build, project: project, commit: commit }
+    let!(:gl_project) { FactoryGirl.create :empty_project }
+    let!(:commit) { FactoryGirl.create :ci_commit, gl_project: gl_project }
+    let!(:pending_build) { FactoryGirl.create :ci_build, commit: commit }
     let!(:shared_runner) { FactoryGirl.create(:ci_runner, is_shared: true) }
     let!(:specific_runner) { FactoryGirl.create(:ci_runner, is_shared: false) }
 
     before do
-      specific_runner.assign_to(project)
+      specific_runner.assign_to(gl_project.ensure_gitlab_ci_project)
     end
 
     describe :execute do
@@ -47,8 +47,7 @@ module Ci
 
       context 'allow shared runners' do
         before do
-          project.shared_runners_enabled = true
-          project.save
+          gl_project.gitlab_ci_project.update(shared_runners_enabled: true)
         end
 
         context 'shared runner' do
diff --git a/spec/services/ci/web_hook_service_spec.rb b/spec/services/ci/web_hook_service_spec.rb
index cebdd145e40a948179f85927b432f45bfe8fd27a..aa48fcbcbfd4b5f79fed6da3d9253e94614c4bca 100644
--- a/spec/services/ci/web_hook_service_spec.rb
+++ b/spec/services/ci/web_hook_service_spec.rb
@@ -2,7 +2,8 @@ require 'spec_helper'
 
 describe Ci::WebHookService do
   let(:project) { FactoryGirl.create :ci_project }
-  let(:commit)  { FactoryGirl.create :ci_commit, project: project }
+  let(:gl_project) { FactoryGirl.create :empty_project, gitlab_ci_project: project }
+  let(:commit)  { FactoryGirl.create :ci_commit, gl_project: gl_project }
   let(:build)   { FactoryGirl.create :ci_build, commit: commit }
   let(:hook)    { FactoryGirl.create :ci_web_hook, project: project }
 
diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb
index c483060fd73994235eb2c069bb936b79ce78ad60..17015d29e511c13a7cecc97f7a6b0bce7af62eee 100644
--- a/spec/services/git_push_service_spec.rb
+++ b/spec/services/git_push_service_spec.rb
@@ -112,6 +112,14 @@ describe GitPushService do
     it { expect(@event.project).to eq(project) }
     it { expect(@event.action).to eq(Event::PUSHED) }
     it { expect(@event.data).to eq(service.push_data) }
+
+    context "Updates merge requests" do
+      it "when pushing a new branch for the first time" do
+        expect(project).to receive(:update_merge_requests).
+                               with(@blankrev, 'newrev', 'refs/heads/master', user)
+        service.execute(project, user, @blankrev, 'newrev', 'refs/heads/master')
+      end
+    end
   end
 
   describe "Web Hooks" do
@@ -155,7 +163,7 @@ describe GitPushService do
 
     before do
       allow(commit).to receive_messages(
-        safe_message: "this commit \n mentions ##{issue.id}",
+        safe_message: "this commit \n mentions #{issue.to_reference}",
         references: [issue],
         author_name: commit_author.name,
         author_email: commit_author.email
diff --git a/spec/services/merge_requests/merge_service_spec.rb b/spec/services/merge_requests/merge_service_spec.rb
index 7b564d34d7b40d2b9c3812d6d200ea44775210e2..7483f51de034d65d2b8fcfec1d6b02748fbc6b25 100644
--- a/spec/services/merge_requests/merge_service_spec.rb
+++ b/spec/services/merge_requests/merge_service_spec.rb
@@ -35,5 +35,19 @@ describe MergeRequests::MergeService do
         expect(note.note).to include 'Status changed to merged'
       end
     end
+
+    context "error handling" do
+      let(:service) { MergeRequests::MergeService.new(project, user, {}) }
+
+      it 'saves error if there is an exception' do
+        allow(service).to receive(:repository).and_raise("error")
+
+        allow(service).to receive(:execute_hooks)
+
+        service.execute(merge_request, 'Awesome message')
+
+        expect(merge_request.merge_error).to eq("Something went wrong during merge")
+      end
+    end
   end
 end
diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb
index 9516e7936d84dfa5b744fdc1076c35bf71477cc3..227ac995ec2ca4237b96a90cdf9f1adce7d2a78b 100644
--- a/spec/services/merge_requests/refresh_service_spec.rb
+++ b/spec/services/merge_requests/refresh_service_spec.rb
@@ -106,6 +106,27 @@ describe MergeRequests::RefreshService do
       it { expect(@fork_merge_request.notes).to be_empty }
     end
 
+    context 'push new branch that exists in a merge request' do
+      let(:refresh_service) { service.new(@fork_project, @user) }
+
+      it 'refreshes the merge request' do
+        expect(refresh_service).to receive(:execute_hooks).
+                                       with(@fork_merge_request, 'update')
+        allow_any_instance_of(Repository).to receive(:merge_base).and_return(@oldrev)
+
+        refresh_service.execute(Gitlab::Git::BLANK_SHA, @newrev, 'refs/heads/master')
+        reload_mrs
+
+        expect(@merge_request.notes).to be_empty
+        expect(@merge_request).to be_open
+
+        notes = @fork_merge_request.notes.reorder(:created_at).map(&:note)
+        expect(notes[0]).to include('Restored source branch `master`')
+        expect(notes[1]).to include('Added 4 commits')
+        expect(@fork_merge_request).to be_open
+      end
+    end
+
     def reload_mrs
       @merge_request.reload
       @fork_merge_request.reload
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index 8865335d0d17d641bc4e021cef7a634585a59f4a..520140917aae2e9f588df8aa5a4a93a1f954c96a 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -427,15 +427,15 @@ describe NotificationService do
         should_email(@u_watcher.id)
         should_email(@u_participating.id)
         should_not_email(@u_disabled.id)
-        notification.project_was_moved(project)
+        notification.project_was_moved(project, "gitlab/gitlab")
       end
 
       def should_email(user_id)
-        expect(Notify).to receive(:project_was_moved_email).with(project.id, user_id)
+        expect(Notify).to receive(:project_was_moved_email).with(project.id, user_id, "gitlab/gitlab")
       end
 
       def should_not_email(user_id)
-        expect(Notify).not_to receive(:project_was_moved_email).with(project.id, user_id)
+        expect(Notify).not_to receive(:project_was_moved_email).with(project.id, user_id, "gitlab/gitlab")
       end
     end
   end
diff --git a/spec/services/projects/download_service_spec.rb b/spec/services/projects/download_service_spec.rb
index f12e09c58c36fb0f53bc9e8c0fb4c3e047bf8a82..ddee2e62dfcfed6e9289b4ef6be404566406f74a 100644
--- a/spec/services/projects/download_service_spec.rb
+++ b/spec/services/projects/download_service_spec.rb
@@ -37,7 +37,6 @@ describe Projects::DownloadService do
         it { expect(@link_to_file).to have_key('url') }
         it { expect(@link_to_file).to have_key('is_image') }
         it { expect(@link_to_file['is_image']).to be true }
-        it { expect(@link_to_file['url']).to match("/#{@project.path_with_namespace}") }
         it { expect(@link_to_file['url']).to match('rails_sample.jpg') }
         it { expect(@link_to_file['alt']).to eq('rails_sample') }
       end
@@ -52,7 +51,6 @@ describe Projects::DownloadService do
         it { expect(@link_to_file).to have_key('url') }
         it { expect(@link_to_file).to have_key('is_image') }
         it { expect(@link_to_file['is_image']).to be false }
-        it { expect(@link_to_file['url']).to match("/#{@project.path_with_namespace}") }
         it { expect(@link_to_file['url']).to match('doc_sample.txt') }
         it { expect(@link_to_file['alt']).to eq('doc_sample.txt') }
       end
diff --git a/spec/services/projects/fork_service_spec.rb b/spec/services/projects/fork_service_spec.rb
index 18ab333c1d17a5805fd2d4eba7098daae632b6aa..65a8c81204d3c3a509b4c302934c05cd9fb9b539 100644
--- a/spec/services/projects/fork_service_spec.rb
+++ b/spec/services/projects/fork_service_spec.rb
@@ -43,14 +43,10 @@ describe Projects::ForkService do
     end
 
     context 'GitLab CI is enabled' do
-      it "calls fork registrator for CI" do
-        create(:ci_project, gl_project: @from_project)
-        @from_project.build_missing_services
-        @from_project.gitlab_ci_service.update_attributes(active: true)
-
-        expect_any_instance_of(Ci::CreateProjectService).to receive(:execute)
-
-        fork_project(@from_project, @to_user)
+      it "fork and enable CI for fork" do
+        @from_project.enable_ci
+        @to_project = fork_project(@from_project, @to_user)
+        expect(@to_project.gitlab_ci?).to be_truthy
       end
     end
   end
diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb
index bb7da33b12e15f8eedc4bde0488268766bfacab1..47755bfc990311bdc420d1c0bf94d1fb75fab2d6 100644
--- a/spec/services/projects/transfer_service_spec.rb
+++ b/spec/services/projects/transfer_service_spec.rb
@@ -7,6 +7,8 @@ describe Projects::TransferService do
 
   context 'namespace -> namespace' do
     before do
+      allow_any_instance_of(Gitlab::UploadsTransfer).
+        to receive(:move_project).and_return(true)
       group.add_owner(user)
       @result = transfer_project(project, user, group)
     end
diff --git a/spec/services/projects/upload_service_spec.rb b/spec/services/projects/upload_service_spec.rb
index fa4ff6b01ad9993cfcc6fa2d1ed112e2dc08f347..1b1a80d1fe731931de7fabe31826750a5fb6b8d3 100644
--- a/spec/services/projects/upload_service_spec.rb
+++ b/spec/services/projects/upload_service_spec.rb
@@ -18,7 +18,6 @@ describe Projects::UploadService do
       it { expect(@link_to_file).to have_key(:is_image) }
       it { expect(@link_to_file).to have_value('banana_sample') }
       it { expect(@link_to_file[:is_image]).to equal(true) }
-      it { expect(@link_to_file[:url]).to match("/#{@project.path_with_namespace}") }
       it { expect(@link_to_file[:url]).to match('banana_sample.gif') }
     end
 
@@ -34,7 +33,6 @@ describe Projects::UploadService do
       it { expect(@link_to_file).to have_value('dk') }
       it { expect(@link_to_file).to have_key(:is_image) }
       it { expect(@link_to_file[:is_image]).to equal(true) }
-      it { expect(@link_to_file[:url]).to match("/#{@project.path_with_namespace}") }
       it { expect(@link_to_file[:url]).to match('dk.png') }
     end
 
@@ -49,7 +47,6 @@ describe Projects::UploadService do
       it { expect(@link_to_file).to have_key(:is_image) }
       it { expect(@link_to_file).to have_value('rails_sample') }
       it { expect(@link_to_file[:is_image]).to equal(true) }
-      it { expect(@link_to_file[:url]).to match("/#{@project.path_with_namespace}") }
       it { expect(@link_to_file[:url]).to match('rails_sample.jpg') }
     end
 
@@ -64,7 +61,6 @@ describe Projects::UploadService do
       it { expect(@link_to_file).to have_key(:is_image) }
       it { expect(@link_to_file).to have_value('doc_sample.txt') }
       it { expect(@link_to_file[:is_image]).to equal(false) }
-      it { expect(@link_to_file[:url]).to match("/#{@project.path_with_namespace}") }
       it { expect(@link_to_file[:url]).to match('doc_sample.txt') }
     end
 
diff --git a/spec/services/system_hooks_service_spec.rb b/spec/services/system_hooks_service_spec.rb
index 48c49e2f717bb4c7337ba5a38ae0711791bd96aa..a31fc1e4b0762ca49f8462e98646d0947f14e787 100644
--- a/spec/services/system_hooks_service_spec.rb
+++ b/spec/services/system_hooks_service_spec.rb
@@ -13,8 +13,8 @@ describe SystemHooksService do
     it { expect(event_data(user, :destroy)).to include(:event_name, :name, :created_at, :email, :user_id) }
     it { expect(event_data(project, :create)).to include(:event_name, :name, :created_at, :path, :project_id, :owner_name, :owner_email, :project_visibility) }
     it { expect(event_data(project, :destroy)).to include(:event_name, :name, :created_at, :path, :project_id, :owner_name, :owner_email, :project_visibility) }
-    it { expect(event_data(project_member, :create)).to include(:event_name, :created_at, :project_name, :project_path, :project_id, :user_name, :user_email, :access_level, :project_visibility) }
-    it { expect(event_data(project_member, :destroy)).to include(:event_name, :created_at, :project_name, :project_path, :project_id, :user_name, :user_email, :access_level, :project_visibility) }
+    it { expect(event_data(project_member, :create)).to include(:event_name, :created_at, :project_name, :project_path, :project_path_with_namespace, :project_id, :user_name, :user_email, :access_level, :project_visibility) }
+    it { expect(event_data(project_member, :destroy)).to include(:event_name, :created_at, :project_name, :project_path, :project_path_with_namespace, :project_id, :user_name, :user_email, :access_level, :project_visibility) }
     it { expect(event_data(key, :create)).to include(:username, :key, :id) }
     it { expect(event_data(key, :destroy)).to include(:username, :key, :id) }
 
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index 2658576640c2f4f53caa0e73976ce79b3f636cd8..a45130bd473232cf9de5f426d15315b34d17481c 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -242,6 +242,18 @@ describe SystemNoteService do
     end
   end
 
+  describe '.change_branch_presence' do
+    subject { described_class.change_branch_presence(noteable, project, author, :source, 'feature', :delete) }
+
+    it_behaves_like 'a system note'
+
+    context 'when source branch deleted' do
+      it 'sets the note text' do
+        expect(subject.note).to eq "Deleted source branch `feature`"
+      end
+    end
+  end
+
   describe '.cross_reference' do
     subject { described_class.cross_reference(noteable, mentioner, author) }
 
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index dfe855926c63cee43c8b6b6f8d8da66917f5bd9a..2be13bb3e6a0dd95d1c8962724b12e18517011e0 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -14,6 +14,7 @@ require File.expand_path("../../config/environment", __FILE__)
 require 'rspec/rails'
 require 'shoulda/matchers'
 require 'sidekiq/testing/inline'
+require 'benchmark/ips'
 
 # Requires supporting ruby files with custom matchers and macros, etc,
 # in spec/support/ and its subdirectories.
@@ -32,7 +33,7 @@ RSpec.configure do |config|
   config.include TestEnv
   config.include StubGitlabCalls
   config.include StubGitlabData
-
+  config.include BenchmarkMatchers, benchmark: true
 
   config.infer_spec_type_from_file_location!
   config.raise_errors_for_deprecations!
@@ -42,4 +43,8 @@ RSpec.configure do |config|
   end
 end
 
+FactoryGirl::SyntaxRunner.class_eval do
+  include RSpec::Mocks::ExampleMethods
+end
+
 ActiveRecord::Migration.maintain_test_schema!
diff --git a/spec/support/filter_spec_helper.rb b/spec/support/filter_spec_helper.rb
index 203117aee7011dfbd9f01f63b4b544a577e5e22f..97e5c270a59b994222f05f7067702a9665bcec0a 100644
--- a/spec/support/filter_spec_helper.rb
+++ b/spec/support/filter_spec_helper.rb
@@ -29,12 +29,19 @@ module FilterSpecHelper
   #
   # Returns the Hash
   def pipeline_result(body, contexts = {})
-    contexts.reverse_merge!(project: project)
+    contexts.reverse_merge!(project: project) if defined?(project)
 
     pipeline = HTML::Pipeline.new([described_class], contexts)
     pipeline.call(body)
   end
 
+  def reference_pipeline_result(body, contexts = {})
+    contexts.reverse_merge!(project: project) if defined?(project)
+
+    pipeline = HTML::Pipeline.new([described_class, Gitlab::Markdown::ReferenceGathererFilter], contexts)
+    pipeline.call(body)
+  end
+
   # Modify a String reference to make it invalid
   #
   # Commit SHAs get reversed, IDs get incremented by 1, all other Strings get
@@ -55,20 +62,6 @@ module FilterSpecHelper
     end
   end
 
-  # Stub CrossProjectReference#user_can_reference_project? to return true for
-  # the current test
-  def allow_cross_reference!
-    allow_any_instance_of(described_class).
-      to receive(:user_can_reference_project?).and_return(true)
-  end
-
-  # Stub CrossProjectReference#user_can_reference_project? to return false for
-  # the current test
-  def disallow_cross_reference!
-    allow_any_instance_of(described_class).
-      to receive(:user_can_reference_project?).and_return(false)
-  end
-
   # Shortcut to Rails' auto-generated routes helpers, to avoid including the
   # module
   def urls
diff --git a/spec/support/markdown_feature.rb b/spec/support/markdown_feature.rb
index 39a643914604076f99dfc11350ad8bed6c737325..bedc1a7f1db47960b8c8c53137782fdf9fbb5a5f 100644
--- a/spec/support/markdown_feature.rb
+++ b/spec/support/markdown_feature.rb
@@ -15,18 +15,17 @@ class MarkdownFeature
   end
 
   def group
-    unless @group
-      @group = create(:group)
-      @group.add_developer(user)
+    @group ||= create(:group).tap do |group|
+      group.add_developer(user)
     end
-
-    @group
   end
 
   # Direct references ----------------------------------------------------------
 
   def project
-    @project ||= create(:project)
+    @project ||= create(:project).tap do |project|
+      project.team << [user, :master]
+    end
   end
 
   def issue
@@ -46,12 +45,10 @@ class MarkdownFeature
   end
 
   def commit_range
-    unless @commit_range
+    @commit_range ||= begin
       commit2 = project.commit('HEAD~3')
-      @commit_range = CommitRange.new("#{commit.id}...#{commit2.id}", project)
+      CommitRange.new("#{commit.id}...#{commit2.id}", project)
     end
-
-    @commit_range
   end
 
   def simple_label
@@ -65,13 +62,12 @@ class MarkdownFeature
   # Cross-references -----------------------------------------------------------
 
   def xproject
-    unless @xproject
+    @xproject ||= begin
       namespace = create(:namespace, name: 'cross-reference')
-      @xproject = create(:project, namespace: namespace)
-      @xproject.team << [user, :developer]
+      create(:project, namespace: namespace) do |project|
+        project.team << [user, :developer]
+      end
     end
-
-    @xproject
   end
 
   def xissue
@@ -91,12 +87,10 @@ class MarkdownFeature
   end
 
   def xcommit_range
-    unless @xcommit_range
+    @xcommit_range ||= begin
       xcommit2 = xproject.commit('HEAD~2')
-      @xcommit_range = CommitRange.new("#{xcommit.id}...#{xcommit2.id}", xproject)
+      CommitRange.new("#{xcommit.id}...#{xcommit2.id}", xproject)
     end
-
-    @xcommit_range
   end
 
   def raw_markdown
diff --git a/spec/support/matchers/benchmark_matchers.rb b/spec/support/matchers/benchmark_matchers.rb
new file mode 100644
index 0000000000000000000000000000000000000000..84f655c2119613d05d13a07ad05a70098ea2b777
--- /dev/null
+++ b/spec/support/matchers/benchmark_matchers.rb
@@ -0,0 +1,61 @@
+module BenchmarkMatchers
+  extend RSpec::Matchers::DSL
+
+  def self.included(into)
+    into.extend(ClassMethods)
+  end
+
+  matcher :iterate_per_second do |min_iterations|
+    supports_block_expectations
+
+    match do |block|
+      @max_stddev ||= 30
+
+      @entry = benchmark(&block)
+
+      expect(@entry.ips).to be >= min_iterations
+      expect(@entry.stddev_percentage).to be <= @max_stddev
+    end
+
+    chain :with_maximum_stddev do |value|
+      @max_stddev = value
+    end
+
+    description do
+      "run at least #{min_iterations} iterations per second"
+    end
+
+    failure_message do
+      ips    = @entry.ips.round(2)
+      stddev = @entry.stddev_percentage.round(2)
+
+      "expected at least #{min_iterations} iterations per second " \
+        "with a maximum stddev of #{@max_stddev}%, instead of " \
+        "#{ips} iterations per second with a stddev of #{stddev}%"
+    end
+  end
+
+  # Benchmarks the given block and returns a Benchmark::IPS::Report::Entry.
+  def benchmark(&block)
+    report = Benchmark.ips(quiet: true) do |bench|
+      bench.report do
+        instance_eval(&block)
+      end
+    end
+
+    report.entries[0]
+  end
+
+  module ClassMethods
+    # Wraps around rspec's subject method so you can write:
+    #
+    #     benchmark_subject { SomeClass.some_method }
+    #
+    # instead of:
+    #
+    #     subject { -> { SomeClass.some_method } }
+    def benchmark_subject(&block)
+      subject { block }
+    end
+  end
+end
diff --git a/spec/support/mentionable_shared_examples.rb b/spec/support/mentionable_shared_examples.rb
index e3de0afb44825a6b84a7bb9723e22754dfb7538b..3bb568f4d494858c432f259cf37c20ef7465f535 100644
--- a/spec/support/mentionable_shared_examples.rb
+++ b/spec/support/mentionable_shared_examples.rb
@@ -5,7 +5,7 @@
 # - let(:set_mentionable_text) { lambda { |txt| "block that assigns txt to the subject's mentionable_text" } }
 
 def common_mentionable_setup
-  let(:project) { create :project }
+  let(:project) { subject.project }
   let(:author)  { subject.author }
 
   let(:mentioned_issue)  { create(:issue, project: project) }
@@ -50,6 +50,8 @@ def common_mentionable_setup
     }
     extra_commits.each { |c| commitmap[c.short_id] = c }
 
+    allow(Project).to receive(:find).and_call_original
+    allow(Project).to receive(:find).with(project.id.to_s).and_return(project)
     allow(project.repository).to receive(:commit) { |sha| commitmap[sha] }
 
     set_mentionable_text.call(ref_string)
@@ -65,7 +67,7 @@ shared_examples 'a mentionable' do
 
   it "extracts references from its reference property" do
     # De-duplicate and omit itself
-    refs = subject.references(project)
+    refs = subject.referenced_mentionables
     expect(refs.size).to eq(6)
     expect(refs).to include(mentioned_issue)
     expect(refs).to include(mentioned_mr)
@@ -84,14 +86,7 @@ shared_examples 'a mentionable' do
         with(referenced, subject.local_reference, author)
     end
 
-    subject.create_cross_references!(project, author)
-  end
-
-  it 'detects existing cross-references' do
-    SystemNoteService.cross_reference(mentioned_issue, subject.local_reference, author)
-
-    expect(subject).to have_mentioned(mentioned_issue)
-    expect(subject).not_to have_mentioned(mentioned_mr)
+    subject.create_cross_references!
   end
 end
 
@@ -143,6 +138,6 @@ shared_examples 'an editable mentionable' do
     end
 
     set_mentionable_text.call(new_text)
-    subject.create_new_cross_references!(project, author)
+    subject.create_new_cross_references!(author)
   end
 end
diff --git a/spec/support/services_shared_context.rb b/spec/support/services_shared_context.rb
index 4d007ae55ee1391874cb528172d67cb14b9d057a..d1c999cad4de8d2625964478f90b86f6d7b55cd2 100644
--- a/spec/support/services_shared_context.rb
+++ b/spec/support/services_shared_context.rb
@@ -3,7 +3,13 @@ Service.available_services_names.each do |service|
     let(:dashed_service) { service.dasherize }
     let(:service_method) { "#{service}_service".to_sym }
     let(:service_klass) { "#{service}_service".classify.constantize }
-    let(:service_attrs_list) { service_klass.new.fields.inject([]) {|arr, hash| arr << hash[:name].to_sym } }
+    let(:service_fields) { service_klass.new.fields }
+    let(:service_attrs_list) { service_fields.inject([]) {|arr, hash| arr << hash[:name].to_sym } }
+    let(:service_attrs_list_without_passwords) do
+      service_fields.
+        select { |field| field[:type] != 'password' }.
+        map { |field| field[:name].to_sym}
+    end
     let(:service_attrs) do
       service_attrs_list.inject({}) do |hash, k|
         if k =~ /^(token*|.*_token|.*_key)/
diff --git a/spec/support/setup_builds_storage.rb b/spec/support/setup_builds_storage.rb
index a3e596461873c9c669a99e9cb1a6a5037e89d7c6..a4f21e953381cf58797158bd8c7734a9f91b8e31 100644
--- a/spec/support/setup_builds_storage.rb
+++ b/spec/support/setup_builds_storage.rb
@@ -10,8 +10,10 @@ RSpec.configure do |config|
   end
 
   config.after(:suite) do
-    Dir.chdir(builds_path) do
-      `ls | grep -v .gitkeep | xargs rm -r`
+    Dir[File.join(builds_path, '*')].each do |path|
+      next if File.basename(path) == '.gitkeep'
+
+      FileUtils.rm_rf(path)
     end
   end
 end
diff --git a/spec/support/stub_gitlab_calls.rb b/spec/support/stub_gitlab_calls.rb
index 5e6744afda120a338235015e1f88f8a693e2237b..5b3eb1bfc5f26f9ea7a1140fc439e716014f1068 100644
--- a/spec/support/stub_gitlab_calls.rb
+++ b/spec/support/stub_gitlab_calls.rb
@@ -13,6 +13,14 @@ module StubGitlabCalls
     allow_any_instance_of(Network).to receive(:projects) { project_hash_array }
   end
 
+  def stub_ci_commit_to_return_yaml_file
+    stub_ci_commit_yaml_file(gitlab_ci_yaml)
+  end
+
+  def stub_ci_commit_yaml_file(ci_yaml)
+    allow_any_instance_of(Ci::Commit).to receive(:ci_yaml_file) { ci_yaml }
+  end
+
   private
 
   def gitlab_url
diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb
index 3eab74ba9860be6207a74236e9cf4c91e6afcc74..d12ba25b71b85ea9c51dcbe4d9f8c19522c65ce6 100644
--- a/spec/support/test_env.rb
+++ b/spec/support/test_env.rb
@@ -9,7 +9,7 @@ module TestEnv
     'flatten-dir'      => 'e56497b',
     'feature'          => '0b4bc9a',
     'feature_conflict' => 'bb5206f',
-    'fix'              => '12d65c8',
+    'fix'              => '48f0be4',
     'improve/awesome'  => '5937ac0',
     'markdown'         => '0ed8c6c',
     'master'           => '5937ac0',
diff --git a/spec/tasks/gitlab/backup_rake_spec.rb b/spec/tasks/gitlab/backup_rake_spec.rb
index 2e63e5f36af42a62f2327445f970cce15081452b..3be7dd4e52b59b10e03335116f86b267ffdbcceb 100644
--- a/spec/tasks/gitlab/backup_rake_spec.rb
+++ b/spec/tasks/gitlab/backup_rake_spec.rb
@@ -159,7 +159,7 @@ describe 'gitlab:app namespace rake task' do
     end
 
     it "does not contain skipped item" do
-      tar_contents, exit_status = Gitlab::Popen.popen(
+      tar_contents, _exit_status = Gitlab::Popen.popen(
         %W{tar -tvf #{@backup_tar} db uploads repositories builds}
       )
 
diff --git a/spec/workers/repository_archive_worker_spec.rb b/spec/workers/repository_archive_worker_spec.rb
deleted file mode 100644
index a914d0ac8dcff64d8da122480c7d4055bd8d310a..0000000000000000000000000000000000000000
--- a/spec/workers/repository_archive_worker_spec.rb
+++ /dev/null
@@ -1,79 +0,0 @@
-require 'spec_helper'
-
-describe RepositoryArchiveWorker do
-  let(:project) { create(:project) }
-  subject { RepositoryArchiveWorker.new }
-
-  before do
-    allow(Project).to receive(:find).and_return(project)
-  end
-
-  describe "#perform" do
-    it "cleans old archives" do
-      expect(project.repository).to receive(:clean_old_archives)
-
-      subject.perform(project.id, "master", "zip")
-    end
-
-    context "when the repository doesn't have an archive file path" do
-      before do
-        allow(project.repository).to receive(:archive_file_path).and_return(nil)
-      end
-
-      it "doesn't archive the repo" do
-        expect(project.repository).not_to receive(:archive_repo)
-
-        subject.perform(project.id, "master", "zip")
-      end
-    end
-
-    context "when the repository has an archive file path" do
-      let(:file_path)     { "/archive.zip" }
-      let(:pid_file_path) { "/archive.zip.pid" }
-
-      before do
-        allow(project.repository).to receive(:archive_file_path).and_return(file_path)
-        allow(project.repository).to receive(:archive_pid_file_path).and_return(pid_file_path)
-      end
-
-      context "when the archive file already exists" do
-        before do
-          allow(File).to receive(:exist?).with(file_path).and_return(true)
-        end
-
-        it "doesn't archive the repo" do
-          expect(project.repository).not_to receive(:archive_repo)
-
-          subject.perform(project.id, "master", "zip")
-        end
-      end
-
-      context "when the archive file doesn't exist yet" do
-        before do
-          allow(File).to receive(:exist?).with(file_path).and_return(false)
-          allow(File).to receive(:exist?).with(pid_file_path).and_return(true)
-        end
-
-        context "when the archive pid file doesn't exist yet" do
-          before do
-            allow(File).to receive(:exist?).with(pid_file_path).and_return(false)
-          end
-
-          it "archives the repo" do
-            expect(project.repository).to receive(:archive_repo)
-
-            subject.perform(project.id, "master", "zip")
-          end
-        end
-
-        context "when the archive pid file already exists" do
-          it "doesn't archive the repo" do
-            expect(project.repository).not_to receive(:archive_repo)
-
-            subject.perform(project.id, "master", "zip")
-          end
-        end
-      end
-    end
-  end
-end
diff --git a/tmp/.gitkeep b/tmp/.gitkeep
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000